From 2b32a31ca3484e23ff35b71b7349d361ba187ee3 Mon Sep 17 00:00:00 2001 From: rpaulo Date: Sun, 22 Aug 2010 10:53:32 +0000 Subject: Kernel DTrace support for: o uregs (sson@) o ustack (sson@) o /dev/dtrace/helper device (needed for USDT probes) The work done by me was: Sponsored by: The FreeBSD Foundation --- .../contrib/opensolaris/uts/common/dtrace/dtrace.c | 50 ++-- .../opensolaris/uts/common/sys/dtrace_impl.h | 2 +- sys/cddl/dev/dtrace/amd64/dtrace_isa.c | 198 +++++++------- sys/cddl/dev/dtrace/amd64/regset.h | 127 +++++++++ sys/cddl/dev/dtrace/dtrace_ioctl.c | 49 ++++ sys/cddl/dev/dtrace/dtrace_load.c | 5 +- sys/cddl/dev/dtrace/i386/dtrace_isa.c | 285 ++++++++++++--------- sys/cddl/dev/dtrace/i386/regset.h | 127 +++++++++ sys/cddl/dev/systrace/systrace.c | 15 +- sys/sys/sysent.h | 3 +- 10 files changed, 614 insertions(+), 247 deletions(-) create mode 100644 sys/cddl/dev/dtrace/amd64/regset.h create mode 100644 sys/cddl/dev/dtrace/i386/regset.h diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c index 70282e9..a4684bd 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c +++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c @@ -551,20 +551,16 @@ static void dtrace_enabling_provide(dtrace_provider_t *); static int dtrace_enabling_match(dtrace_enabling_t *, int *); static void dtrace_enabling_matchall(void); static dtrace_state_t *dtrace_anon_grab(void); -#if defined(sun) static uint64_t dtrace_helper(int, dtrace_mstate_t *, dtrace_state_t *, uint64_t, uint64_t); static dtrace_helpers_t *dtrace_helpers_create(proc_t *); -#endif static void dtrace_buffer_drop(dtrace_buffer_t *); static intptr_t dtrace_buffer_reserve(dtrace_buffer_t *, size_t, size_t, dtrace_state_t *, dtrace_mstate_t *); static int dtrace_state_option(dtrace_state_t *, dtrace_optid_t, dtrace_optval_t); static int dtrace_ecb_create_enable(dtrace_probe_t *, void *); -#if defined(sun) static void dtrace_helper_provider_destroy(dtrace_helper_provider_t *); -#endif uint16_t dtrace_load16(uintptr_t); uint32_t dtrace_load32(uintptr_t); uint64_t dtrace_load64(uintptr_t); @@ -2784,6 +2780,21 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v, return (dtrace_getreg(lwp->lwp_regs, ndx)); return (0); } +#else + case DIF_VAR_UREGS: { + struct trapframe *tframe; + + if (!dtrace_priv_proc(state)) + return (0); + + if ((tframe = curthread->td_frame) == NULL) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); + cpu_core[curcpu].cpuc_dtrace_illval = 0; + return (0); + } + + return (dtrace_getreg(tframe, ndx)); + } #endif case DIF_VAR_CURTHREAD: @@ -2839,7 +2850,6 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v, } return (mstate->dtms_stackdepth); -#if defined(sun) case DIF_VAR_USTACKDEPTH: if (!dtrace_priv_proc(state)) return (0); @@ -2859,7 +2869,6 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v, mstate->dtms_present |= DTRACE_MSTATE_USTACKDEPTH; } return (mstate->dtms_ustackdepth); -#endif case DIF_VAR_CALLER: if (!dtrace_priv_kernel(state)) @@ -2896,7 +2905,6 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v, } return (mstate->dtms_caller); -#if defined(sun) case DIF_VAR_UCALLER: if (!dtrace_priv_proc(state)) return (0); @@ -2920,7 +2928,6 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v, } return (mstate->dtms_ucaller); -#endif case DIF_VAR_PROBEPROV: ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE); @@ -5736,7 +5743,6 @@ dtrace_action_chill(dtrace_mstate_t *mstate, hrtime_t val) cpu->cpu_dtrace_chilled += val; } -#if defined(sun) static void dtrace_action_ustack(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t *buf, uint64_t arg) @@ -5849,7 +5855,6 @@ dtrace_action_ustack(dtrace_mstate_t *mstate, dtrace_state_t *state, out: mstate->dtms_scratch_ptr = old; } -#endif /* * If you're looking for the epicenter of DTrace, you just found it. This @@ -6172,7 +6177,6 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1, (uint32_t *)arg0); continue; -#if defined(sun) case DTRACEACT_JSTACK: case DTRACEACT_USTACK: if (!dtrace_priv_proc(state)) @@ -6214,7 +6218,6 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1, DTRACE_USTACK_NFRAMES(rec->dtrd_arg) + 1); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); continue; -#endif default: break; @@ -8141,7 +8144,6 @@ dtrace_helper_provide(dof_helper_t *dhp, pid_t pid) dtrace_enabling_matchall(); } -#if defined(sun) static void dtrace_helper_provider_remove_one(dof_helper_t *dhp, dof_sec_t *sec, pid_t pid) { @@ -8189,7 +8191,6 @@ dtrace_helper_provider_remove(dof_helper_t *dhp, pid_t pid) dtrace_helper_provider_remove_one(dhp, sec, pid); } } -#endif /* * DTrace Meta Provider-to-Framework API Functions @@ -8729,7 +8730,6 @@ dtrace_difo_validate(dtrace_difo_t *dp, dtrace_vstate_t *vstate, uint_t nregs, return (err); } -#if defined(sun) /* * Validate a DTrace DIF object that it is to be used as a helper. Helpers * are much more constrained than normal DIFOs. Specifically, they may @@ -8887,7 +8887,6 @@ dtrace_difo_validate_helper(dtrace_difo_t *dp) return (err); } -#endif /* * Returns 1 if the expression in the DIF object can be cached on a per-thread @@ -13791,7 +13790,6 @@ dtrace_anon_property(void) } } -#if defined(sun) /* * DTrace Helper Functions */ @@ -13855,9 +13853,7 @@ dtrace_helper_trace(dtrace_helper_action_t *helper, ((uint64_t *)(uintptr_t)svar->dtsv_data)[curcpu]; } } -#endif -#if defined(sun) static uint64_t dtrace_helper(int which, dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t arg0, uint64_t arg1) @@ -13865,7 +13861,7 @@ dtrace_helper(int which, dtrace_mstate_t *mstate, uint16_t *flags = &cpu_core[curcpu].cpuc_dtrace_flags; uint64_t sarg0 = mstate->dtms_arg[0]; uint64_t sarg1 = mstate->dtms_arg[1]; - uint64_t rval; + uint64_t rval = 0; dtrace_helpers_t *helpers = curproc->p_dtrace_helpers; dtrace_helper_action_t *helper; dtrace_vstate_t *vstate; @@ -14056,9 +14052,7 @@ dtrace_helper_destroygen(int gen) return (0); } -#endif -#if defined(sun) static int dtrace_helper_validate(dtrace_helper_action_t *helper) { @@ -14073,9 +14067,7 @@ dtrace_helper_validate(dtrace_helper_action_t *helper) return (err == 0); } -#endif -#if defined(sun) static int dtrace_helper_action_add(int which, dtrace_ecbdesc_t *ep) { @@ -14622,6 +14614,7 @@ dtrace_helpers_create(proc_t *p) return (help); } +#if defined(sun) static void dtrace_helpers_destroy(void) { @@ -16466,6 +16459,7 @@ _fini(void) #else static d_ioctl_t dtrace_ioctl; +static d_ioctl_t dtrace_ioctl_helper; static void dtrace_load(void *); static int dtrace_unload(void); #if __FreeBSD_version < 800039 @@ -16474,6 +16468,7 @@ static struct clonedevs *dtrace_clones; /* Ptr to the array of cloned devices. static eventhandler_tag eh_tag; /* Event handler tag. */ #else static struct cdev *dtrace_dev; +static struct cdev *helper_dev; #endif void dtrace_invop_init(void); @@ -16488,6 +16483,13 @@ static struct cdevsw dtrace_cdevsw = { .d_name = "dtrace", }; +static struct cdevsw helper_cdevsw = { + .d_version = D_VERSION, + .d_flags = D_TRACKCLOSE | D_NEEDMINOR, + .d_ioctl = dtrace_ioctl_helper, + .d_name = "helper", +}; + #include #if __FreeBSD_version < 800039 #include diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace_impl.h b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace_impl.h index 369d41a..6870a0b 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace_impl.h +++ b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace_impl.h @@ -1268,7 +1268,7 @@ extern void dtrace_copyout(uintptr_t, uintptr_t, size_t, volatile uint16_t *); extern void dtrace_copyoutstr(uintptr_t, uintptr_t, size_t, volatile uint16_t *); extern void dtrace_getpcstack(pc_t *, int, int, uint32_t *); -extern ulong_t dtrace_getreg(struct regs *, uint_t); +extern ulong_t dtrace_getreg(struct trapframe *, uint_t); extern int dtrace_getstackdepth(int); extern void dtrace_getupcstack(uint64_t *, int); extern void dtrace_getufpstack(uint64_t *, uint64_t *, int); diff --git a/sys/cddl/dev/dtrace/amd64/dtrace_isa.c b/sys/cddl/dev/dtrace/amd64/dtrace_isa.c index c58e88e..d9ed080 100644 --- a/sys/cddl/dev/dtrace/amd64/dtrace_isa.c +++ b/sys/cddl/dev/dtrace/amd64/dtrace_isa.c @@ -42,6 +42,7 @@ #include #include +#include "regset.h" uint8_t dtrace_fuword8_nocheck(void *); uint16_t dtrace_fuword16_nocheck(void *); @@ -103,12 +104,11 @@ dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, { volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; - struct amd64_frame *frame; int ret = 0; ASSERT(pcstack == NULL || pcstack_limit > 0); - while (pc != 0 && sp != 0) { + while (pc != 0) { ret++; if (pcstack != NULL) { *pcstack++ = (uint64_t)pc; @@ -117,10 +117,12 @@ dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, break; } - frame = (struct amd64_frame *) sp; + if (sp == 0) + break; - pc = dtrace_fulword(&frame->f_retaddr); - sp = dtrace_fulword(&frame->f_frame); + pc = dtrace_fuword64((void *)(sp + + offsetof(struct amd64_frame, f_retaddr))); + sp = dtrace_fuword64((void *)sp); /* * This is totally bogus: if we faulted, we're going to clear @@ -141,7 +143,7 @@ dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) { proc_t *p = curproc; struct trapframe *tf; - uintptr_t pc, sp; + uintptr_t pc, sp, fp; volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; int n; @@ -165,18 +167,28 @@ dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) return; pc = tf->tf_rip; + fp = tf->tf_rbp; sp = tf->tf_rsp; if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { + /* + * In an entry probe. The frame pointer has not yet been + * pushed (that happens in the function prologue). The + * best approach is to add the current pc as a missing top + * of stack and back the pc up to the caller, which is stored + * at the current stack pointer address since the call + * instruction puts it there right before the branch. + */ + *pcstack++ = (uint64_t)pc; pcstack_limit--; if (pcstack_limit <= 0) return; - pc = dtrace_fulword((void *) sp); + pc = dtrace_fuword64((void *) sp); } - n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp); + n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp); ASSERT(n >= 0); ASSERT(n <= pcstack_limit); @@ -193,7 +205,7 @@ dtrace_getustackdepth(void) { proc_t *p = curproc; struct trapframe *tf; - uintptr_t pc, sp; + uintptr_t pc, fp, sp; int n = 0; if (p == NULL || (tf = curthread->td_frame) == NULL) @@ -203,30 +215,40 @@ dtrace_getustackdepth(void) return (-1); pc = tf->tf_rip; + fp = tf->tf_rbp; sp = tf->tf_rsp; if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { - n++; + /* + * In an entry probe. The frame pointer has not yet been + * pushed (that happens in the function prologue). The + * best approach is to add the current pc as a missing top + * of stack and back the pc up to the caller, which is stored + * at the current stack pointer address since the call + * instruction puts it there right before the branch. + */ - pc = dtrace_fulword((void *) sp); + pc = dtrace_fuword64((void *) sp); + n++; } - n += dtrace_getustack_common(NULL, 0, pc, sp); + n += dtrace_getustack_common(NULL, 0, pc, fp); return (n); } -#ifdef notyet void dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) { - klwp_t *lwp = ttolwp(curthread); proc_t *p = curproc; - struct regs *rp; - uintptr_t pc, sp, oldcontext; + struct trapframe *tf; + uintptr_t pc, sp, fp; volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; +#ifdef notyet /* XXX signal stack */ + uintptr_t oldcontext; size_t s1, s2; +#endif if (*flags & CPU_DTRACE_FAULT) return; @@ -237,7 +259,7 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) /* * If there's no user context we still need to zero the stack. */ - if (lwp == NULL || p == NULL || (rp = lwp->lwp_regs) == NULL) + if (p == NULL || (tf = curthread->td_frame) == NULL) goto zero; *pcstack++ = (uint64_t)p->p_pid; @@ -246,12 +268,15 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) if (pcstack_limit <= 0) return; - pc = rp->r_pc; - sp = rp->r_fp; - oldcontext = lwp->lwp_oldcontext; + pc = tf->tf_rip; + sp = tf->tf_rsp; + fp = tf->tf_rbp; +#ifdef notyet /* XXX signal stack */ + oldcontext = lwp->lwp_oldcontext; s1 = sizeof (struct xframe) + 2 * sizeof (long); s2 = s1 + sizeof (siginfo_t); +#endif if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { *pcstack++ = (uint64_t)pc; @@ -260,19 +285,20 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) if (pcstack_limit <= 0) return; - if (p->p_model == DATAMODEL_NATIVE) - pc = dtrace_fulword((void *)rp->r_sp); - else - pc = dtrace_fuword32((void *)rp->r_sp); + pc = dtrace_fuword64((void *)sp); } - while (pc != 0 && sp != 0) { + while (pc != 0) { *pcstack++ = (uint64_t)pc; - *fpstack++ = sp; + *fpstack++ = fp; pcstack_limit--; if (pcstack_limit <= 0) break; + if (fp == 0) + break; + +#ifdef notyet /* XXX signal stack */ if (oldcontext == sp + s1 || oldcontext == sp + s2) { ucontext_t *ucp = (ucontext_t *)oldcontext; greg_t *gregs = ucp->uc_mcontext.gregs; @@ -281,11 +307,12 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) pc = dtrace_fulword(&gregs[REG_PC]); oldcontext = dtrace_fulword(&ucp->uc_link); - } else { - struct xframe *fr = (struct xframe *)sp; - - pc = dtrace_fulword(&fr->fr_savpc); - sp = dtrace_fulword(&fr->fr_savfp); + } else +#endif /* XXX */ + { + pc = dtrace_fuword64((void *)(fp + + offsetof(struct amd64_frame, f_retaddr))); + fp = dtrace_fuword64((void *)fp); } /* @@ -301,9 +328,8 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) zero: while (pcstack_limit-- > 0) - *pcstack++ = NULL; + *pcstack++ = 0; } -#endif /*ARGSUSED*/ uint64_t @@ -412,31 +438,30 @@ dtrace_getstackdepth(int aframes) return depth - aframes; } -#ifdef notyet ulong_t -dtrace_getreg(struct regs *rp, uint_t reg) +dtrace_getreg(struct trapframe *rp, uint_t reg) { -#if defined(__amd64) + /* This table is dependent on reg.d. */ int regmap[] = { - REG_GS, /* GS */ - REG_FS, /* FS */ - REG_ES, /* ES */ - REG_DS, /* DS */ - REG_RDI, /* EDI */ - REG_RSI, /* ESI */ - REG_RBP, /* EBP */ - REG_RSP, /* ESP */ - REG_RBX, /* EBX */ - REG_RDX, /* EDX */ - REG_RCX, /* ECX */ - REG_RAX, /* EAX */ - REG_TRAPNO, /* TRAPNO */ - REG_ERR, /* ERR */ - REG_RIP, /* EIP */ - REG_CS, /* CS */ - REG_RFL, /* EFL */ - REG_RSP, /* UESP */ - REG_SS /* SS */ + REG_GS, /* 0 GS */ + REG_FS, /* 1 FS */ + REG_ES, /* 2 ES */ + REG_DS, /* 3 DS */ + REG_RDI, /* 4 EDI */ + REG_RSI, /* 5 ESI */ + REG_RBP, /* 6 EBP, REG_FP */ + REG_RSP, /* 7 ESP */ + REG_RBX, /* 8 EBX, REG_R1 */ + REG_RDX, /* 9 EDX */ + REG_RCX, /* 10 ECX */ + REG_RAX, /* 11 EAX, REG_R0 */ + REG_TRAPNO, /* 12 TRAPNO */ + REG_ERR, /* 13 ERR */ + REG_RIP, /* 14 EIP, REG_PC */ + REG_CS, /* 15 CS */ + REG_RFL, /* 16 EFL, REG_PS */ + REG_RSP, /* 17 UESP, REG_SP */ + REG_SS /* 18 SS */ }; if (reg <= SS) { @@ -447,77 +472,68 @@ dtrace_getreg(struct regs *rp, uint_t reg) reg = regmap[reg]; } else { + /* This is dependent on reg.d. */ reg -= SS + 1; } switch (reg) { case REG_RDI: - return (rp->r_rdi); + return (rp->tf_rdi); case REG_RSI: - return (rp->r_rsi); + return (rp->tf_rsi); case REG_RDX: - return (rp->r_rdx); + return (rp->tf_rdx); case REG_RCX: - return (rp->r_rcx); + return (rp->tf_rcx); case REG_R8: - return (rp->r_r8); + return (rp->tf_r8); case REG_R9: - return (rp->r_r9); + return (rp->tf_r9); case REG_RAX: - return (rp->r_rax); + return (rp->tf_rax); case REG_RBX: - return (rp->r_rbx); + return (rp->tf_rbx); case REG_RBP: - return (rp->r_rbp); + return (rp->tf_rbp); case REG_R10: - return (rp->r_r10); + return (rp->tf_r10); case REG_R11: - return (rp->r_r11); + return (rp->tf_r11); case REG_R12: - return (rp->r_r12); + return (rp->tf_r12); case REG_R13: - return (rp->r_r13); + return (rp->tf_r13); case REG_R14: - return (rp->r_r14); + return (rp->tf_r14); case REG_R15: - return (rp->r_r15); + return (rp->tf_r15); case REG_DS: - return (rp->r_ds); + return (rp->tf_ds); case REG_ES: - return (rp->r_es); + return (rp->tf_es); case REG_FS: - return (rp->r_fs); + return (rp->tf_fs); case REG_GS: - return (rp->r_gs); + return (rp->tf_gs); case REG_TRAPNO: - return (rp->r_trapno); + return (rp->tf_trapno); case REG_ERR: - return (rp->r_err); + return (rp->tf_err); case REG_RIP: - return (rp->r_rip); + return (rp->tf_rip); case REG_CS: - return (rp->r_cs); + return (rp->tf_cs); case REG_SS: - return (rp->r_ss); + return (rp->tf_ss); case REG_RFL: - return (rp->r_rfl); + return (rp->tf_rflags); case REG_RSP: - return (rp->r_rsp); + return (rp->tf_rsp); default: DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return (0); } - -#else - if (reg > SS) { - DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); - return (0); - } - - return ((&rp->r_gs)[reg]); -#endif } -#endif static int dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) diff --git a/sys/cddl/dev/dtrace/amd64/regset.h b/sys/cddl/dev/dtrace/amd64/regset.h new file mode 100644 index 0000000..d6732ff --- /dev/null +++ b/sys/cddl/dev/dtrace/amd64/regset.h @@ -0,0 +1,127 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * $FreeBSD$ + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#ifndef _REGSET_H +#define _REGSET_H + +/* + * #pragma ident "@(#)regset.h 1.11 05/06/08 SMI" + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The names and offsets defined here should be specified by the + * AMD64 ABI suppl. + * + * We make fsbase and gsbase part of the lwp context (since they're + * the only way to access the full 64-bit address range via the segment + * registers) and thus belong here too. However we treat them as + * read-only; if %fs or %gs are updated, the results of the descriptor + * table lookup that those updates implicitly cause will be reflected + * in the corresponding fsbase and/or gsbase values the next time the + * context can be inspected. However it is NOT possible to override + * the fsbase/gsbase settings via this interface. + * + * Direct modification of the base registers (thus overriding the + * descriptor table base address) can be achieved with _lwp_setprivate. + */ + +#define REG_GSBASE 27 +#define REG_FSBASE 26 +#define REG_DS 25 +#define REG_ES 24 + +#define REG_GS 23 +#define REG_FS 22 +#define REG_SS 21 +#define REG_RSP 20 +#define REG_RFL 19 +#define REG_CS 18 +#define REG_RIP 17 +#define REG_ERR 16 +#define REG_TRAPNO 15 +#define REG_RAX 14 +#define REG_RCX 13 +#define REG_RDX 12 +#define REG_RBX 11 +#define REG_RBP 10 +#define REG_RSI 9 +#define REG_RDI 8 +#define REG_R8 7 +#define REG_R9 6 +#define REG_R10 5 +#define REG_R11 4 +#define REG_R12 3 +#define REG_R13 2 +#define REG_R14 1 +#define REG_R15 0 + +/* + * The names and offsets defined here are specified by i386 ABI suppl. + */ + +#define SS 18 /* only stored on a privilege transition */ +#define UESP 17 /* only stored on a privilege transition */ +#define EFL 16 +#define CS 15 +#define EIP 14 +#define ERR 13 +#define TRAPNO 12 +#define EAX 11 +#define ECX 10 +#define EDX 9 +#define EBX 8 +#define ESP 7 +#define EBP 6 +#define ESI 5 +#define EDI 4 +#define DS 3 +#define ES 2 +#define FS 1 +#define GS 0 + +#define REG_PC EIP +#define REG_FP EBP +#define REG_SP UESP +#define REG_PS EFL +#define REG_R0 EAX +#define REG_R1 EDX + +#ifdef __cplusplus +} +#endif + +#endif /* _REGSET_H */ diff --git a/sys/cddl/dev/dtrace/dtrace_ioctl.c b/sys/cddl/dev/dtrace/dtrace_ioctl.c index bc408c4..79fea7b 100644 --- a/sys/cddl/dev/dtrace/dtrace_ioctl.c +++ b/sys/cddl/dev/dtrace/dtrace_ioctl.c @@ -27,6 +27,55 @@ SYSCTL_INT(_debug_dtrace, OID_AUTO, verbose_ioctl, CTLFLAG_RW, &dtrace_verbose_i #define DTRACE_IOCTL_PRINTF(fmt, ...) if (dtrace_verbose_ioctl) printf(fmt, ## __VA_ARGS__ ) +static int +dtrace_ioctl_helper(struct cdev *dev, u_long cmd, caddr_t addr, int flags, + struct thread *td) +{ + int rval; + dof_helper_t *dhp = NULL; + dof_hdr_t *dof = NULL; + + switch (cmd) { + case DTRACEHIOC_ADDDOF: + dhp = (dof_helper_t *)addr; + /* XXX all because dofhp_dof is 64 bit */ +#ifdef __i386 + addr = (caddr_t)(uint32_t)dhp->dofhp_dof; +#else + addr = (caddr_t)dhp->dofhp_dof; +#endif + /* FALLTHROUGH */ + case DTRACEHIOC_ADD: + dof = dtrace_dof_copyin((intptr_t)addr, &rval); + + if (dof == NULL) + return (rval); + + mutex_enter(&dtrace_lock); + if ((rval = dtrace_helper_slurp((dof_hdr_t *)dof, dhp)) != -1) { + if (dhp) { + dhp->gen = rval; + copyout(dhp, addr, sizeof(*dhp)); + } + rval = 0; + } else { + rval = EINVAL; + } + mutex_exit(&dtrace_lock); + return (rval); + case DTRACEHIOC_REMOVE: + mutex_enter(&dtrace_lock); + rval = dtrace_helper_destroygen((int)*addr); + mutex_exit(&dtrace_lock); + + return (rval); + default: + break; + } + + return (ENOTTY); +} + /* ARGSUSED */ static int dtrace_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, diff --git a/sys/cddl/dev/dtrace/dtrace_load.c b/sys/cddl/dev/dtrace/dtrace_load.c index accee47..912fe97 100644 --- a/sys/cddl/dev/dtrace/dtrace_load.c +++ b/sys/cddl/dev/dtrace/dtrace_load.c @@ -161,7 +161,10 @@ dtrace_load(void *dummy) /* Setup device cloning events. */ eh_tag = EVENTHANDLER_REGISTER(dev_clone, dtrace_clone, 0, 1000); #else - dtrace_dev = make_dev(&dtrace_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "dtrace/dtrace"); + dtrace_dev = make_dev(&dtrace_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, + "dtrace/dtrace"); + helper_dev = make_dev(&helper_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, + "dtrace/helper"); #endif return; diff --git a/sys/cddl/dev/dtrace/i386/dtrace_isa.c b/sys/cddl/dev/dtrace/i386/dtrace_isa.c index bf891aa..3f73a50 100644 --- a/sys/cddl/dev/dtrace/i386/dtrace_isa.c +++ b/sys/cddl/dev/dtrace/i386/dtrace_isa.c @@ -33,13 +33,17 @@ #include #include +#include #include +#include #include #include #include #include +#include "regset.h" + extern uintptr_t kernbase; uintptr_t kernelbase = (uintptr_t) &kernbase; @@ -100,21 +104,22 @@ dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, } } -#ifdef notyet static int dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, uintptr_t sp) { - klwp_t *lwp = ttolwp(curthread); +#ifdef notyet proc_t *p = curproc; - uintptr_t oldcontext = lwp->lwp_oldcontext; + uintptr_t oldcontext = lwp->lwp_oldcontext; /* XXX signal stack. */ + size_t s1, s2; +#endif volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; - size_t s1, s2; int ret = 0; ASSERT(pcstack == NULL || pcstack_limit > 0); +#ifdef notyet /* XXX signal stack. */ if (p->p_model == DATAMODEL_NATIVE) { s1 = sizeof (struct frame) + 2 * sizeof (long); s2 = s1 + sizeof (siginfo_t); @@ -122,8 +127,9 @@ dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, s1 = sizeof (struct frame32) + 3 * sizeof (int); s2 = s1 + sizeof (siginfo32_t); } +#endif - while (pc != 0 && sp != 0) { + while (pc != 0) { ret++; if (pcstack != NULL) { *pcstack++ = (uint64_t)pc; @@ -132,6 +138,10 @@ dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, break; } + if (sp == 0) + break; + +#ifdef notyet /* XXX signal stack. */ if (oldcontext == sp + s1 || oldcontext == sp + s2) { if (p->p_model == DATAMODEL_NATIVE) { ucontext_t *ucp = (ucontext_t *)oldcontext; @@ -163,6 +173,11 @@ dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, sp = dtrace_fuword32(&fr->fr_savfp); } } +#else + pc = dtrace_fuword32((void *)(sp + + offsetof(struct i386_frame, f_retaddr))); + sp = dtrace_fuword32((void *)sp); +#endif /* ! notyet */ /* * This is totally bogus: if we faulted, we're going to clear @@ -181,10 +196,9 @@ dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, void dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) { - klwp_t *lwp = ttolwp(curthread); proc_t *p = curproc; - struct regs *rp; - uintptr_t pc, sp; + struct trapframe *tf; + uintptr_t pc, sp, fp; volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; int n; @@ -198,7 +212,7 @@ dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) /* * If there's no user context we still need to zero the stack. */ - if (lwp == NULL || p == NULL || (rp = lwp->lwp_regs) == NULL) + if (p == NULL || (tf = curthread->td_frame) == NULL) goto zero; *pcstack++ = (uint64_t)p->p_pid; @@ -207,19 +221,26 @@ dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) if (pcstack_limit <= 0) return; - pc = rp->r_pc; - sp = rp->r_fp; + pc = tf->tf_eip; + fp = tf->tf_ebp; + sp = tf->tf_esp; if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { + /* + * In an entry probe. The frame pointer has not yet been + * pushed (that happens in the function prologue). The + * best approach is to add the current pc as a missing top + * of stack and back the pc up to the caller, which is stored + * at the current stack pointer address since the call + * instruction puts it there right before the branch. + */ + *pcstack++ = (uint64_t)pc; pcstack_limit--; if (pcstack_limit <= 0) return; - if (p->p_model == DATAMODEL_NATIVE) - pc = dtrace_fulword((void *)rp->r_sp); - else - pc = dtrace_fuword32((void *)rp->r_sp); + pc = dtrace_fuword32((void *) sp); } n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp); @@ -231,24 +252,58 @@ dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) zero: while (pcstack_limit-- > 0) - *pcstack++ = NULL; + *pcstack++ = 0; } int dtrace_getustackdepth(void) { + proc_t *p = curproc; + struct trapframe *tf; + uintptr_t pc, fp, sp; + int n = 0; + + if (p == NULL || (tf = curthread->td_frame) == NULL) + return (0); + + if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) + return (-1); + + pc = tf->tf_eip; + fp = tf->tf_ebp; + sp = tf->tf_esp; + + if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { + /* + * In an entry probe. The frame pointer has not yet been + * pushed (that happens in the function prologue). The + * best approach is to add the current pc as a missing top + * of stack and back the pc up to the caller, which is stored + * at the current stack pointer address since the call + * instruction puts it there right before the branch. + */ + + pc = dtrace_fuword32((void *) sp); + n++; + } + + n += dtrace_getustack_common(NULL, 0, pc, fp); + + return (n); } void dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) { - klwp_t *lwp = ttolwp(curthread); proc_t *p = curproc; - struct regs *rp; - uintptr_t pc, sp, oldcontext; + struct trapframe *tf; + uintptr_t pc, sp, fp; volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; +#ifdef notyet /* XXX signal stack */ + uintptr_t oldcontext; size_t s1, s2; +#endif if (*flags & CPU_DTRACE_FAULT) return; @@ -259,7 +314,7 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) /* * If there's no user context we still need to zero the stack. */ - if (lwp == NULL || p == NULL || (rp = lwp->lwp_regs) == NULL) + if (p == NULL || (tf = curthread->td_frame) == NULL) goto zero; *pcstack++ = (uint64_t)p->p_pid; @@ -268,8 +323,11 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) if (pcstack_limit <= 0) return; - pc = rp->r_pc; - sp = rp->r_fp; + pc = tf->tf_eip; + fp = tf->tf_ebp; + sp = tf->tf_esp; + +#ifdef notyet /* XXX signal stack */ oldcontext = lwp->lwp_oldcontext; if (p->p_model == DATAMODEL_NATIVE) { @@ -279,6 +337,7 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) s1 = sizeof (struct frame32) + 3 * sizeof (int); s2 = s1 + sizeof (siginfo32_t); } +#endif if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { *pcstack++ = (uint64_t)pc; @@ -287,19 +346,20 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) if (pcstack_limit <= 0) return; - if (p->p_model == DATAMODEL_NATIVE) - pc = dtrace_fulword((void *)rp->r_sp); - else - pc = dtrace_fuword32((void *)rp->r_sp); + pc = dtrace_fuword32((void *)sp); } - while (pc != 0 && sp != 0) { + while (pc != 0) { *pcstack++ = (uint64_t)pc; - *fpstack++ = sp; + *fpstack++ = fp; pcstack_limit--; if (pcstack_limit <= 0) break; + if (fp == 0) + break; + +#ifdef notyet /* XXX signal stack */ if (oldcontext == sp + s1 || oldcontext == sp + s2) { if (p->p_model == DATAMODEL_NATIVE) { ucontext_t *ucp = (ucontext_t *)oldcontext; @@ -318,18 +378,12 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) oldcontext = dtrace_fuword32(&ucp->uc_link); } - } else { - if (p->p_model == DATAMODEL_NATIVE) { - struct frame *fr = (struct frame *)sp; - - pc = dtrace_fulword(&fr->fr_savpc); - sp = dtrace_fulword(&fr->fr_savfp); - } else { - struct frame32 *fr = (struct frame32 *)sp; - - pc = dtrace_fuword32(&fr->fr_savpc); - sp = dtrace_fuword32(&fr->fr_savfp); - } + } else +#endif /* XXX */ + { + pc = dtrace_fuword32((void *)(fp + + offsetof(struct i386_frame, f_retaddr))); + fp = dtrace_fuword32((void *)fp); } /* @@ -345,9 +399,8 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) zero: while (pcstack_limit-- > 0) - *pcstack++ = NULL; + *pcstack++ = 0; } -#endif uint64_t dtrace_getarg(int arg, int aframes) @@ -424,112 +477,92 @@ dtrace_getstackdepth(int aframes) return depth - aframes; } -#ifdef notyet ulong_t -dtrace_getreg(struct regs *rp, uint_t reg) +dtrace_getreg(struct trapframe *rp, uint_t reg) { -#if defined(__amd64) - int regmap[] = { - REG_GS, /* GS */ - REG_FS, /* FS */ - REG_ES, /* ES */ - REG_DS, /* DS */ - REG_RDI, /* EDI */ - REG_RSI, /* ESI */ - REG_RBP, /* EBP */ - REG_RSP, /* ESP */ - REG_RBX, /* EBX */ - REG_RDX, /* EDX */ - REG_RCX, /* ECX */ - REG_RAX, /* EAX */ - REG_TRAPNO, /* TRAPNO */ - REG_ERR, /* ERR */ - REG_RIP, /* EIP */ - REG_CS, /* CS */ - REG_RFL, /* EFL */ - REG_RSP, /* UESP */ - REG_SS /* SS */ + struct pcb *pcb; + int regmap[] = { /* Order is dependent on reg.d */ + REG_GS, /* 0 GS */ + REG_FS, /* 1 FS */ + REG_ES, /* 2 ES */ + REG_DS, /* 3 DS */ + REG_RDI, /* 4 EDI */ + REG_RSI, /* 5 ESI */ + REG_RBP, /* 6 EBP, REG_FP */ + REG_RSP, /* 7 ESP */ + REG_RBX, /* 8 EBX */ + REG_RDX, /* 9 EDX, REG_R1 */ + REG_RCX, /* 10 ECX */ + REG_RAX, /* 11 EAX, REG_R0 */ + REG_TRAPNO, /* 12 TRAPNO */ + REG_ERR, /* 13 ERR */ + REG_RIP, /* 14 EIP, REG_PC */ + REG_CS, /* 15 CS */ + REG_RFL, /* 16 EFL, REG_PS */ + REG_RSP, /* 17 UESP, REG_SP */ + REG_SS /* 18 SS */ }; - if (reg <= SS) { - if (reg >= sizeof (regmap) / sizeof (int)) { - DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); - return (0); - } + if (reg > SS) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); + return (0); + } - reg = regmap[reg]; - } else { - reg -= SS + 1; + if (reg >= sizeof (regmap) / sizeof (int)) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); + return (0); } - switch (reg) { + reg = regmap[reg]; + + switch(reg) { + case REG_GS: + if ((pcb = curthread->td_pcb) == NULL) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); + return (0); + } + return (pcb->pcb_gs); + case REG_FS: + return (rp->tf_fs); + case REG_ES: + return (rp->tf_es); + case REG_DS: + return (rp->tf_ds); case REG_RDI: - return (rp->r_rdi); + return (rp->tf_edi); case REG_RSI: - return (rp->r_rsi); - case REG_RDX: - return (rp->r_rdx); + return (rp->tf_esi); + case REG_RBP: + return (rp->tf_ebp); + case REG_RSP: + return (rp->tf_isp); + case REG_RBX: + return (rp->tf_ebx); case REG_RCX: - return (rp->r_rcx); - case REG_R8: - return (rp->r_r8); - case REG_R9: - return (rp->r_r9); + return (rp->tf_ecx); case REG_RAX: - return (rp->r_rax); - case REG_RBX: - return (rp->r_rbx); - case REG_RBP: - return (rp->r_rbp); - case REG_R10: - return (rp->r_r10); - case REG_R11: - return (rp->r_r11); - case REG_R12: - return (rp->r_r12); - case REG_R13: - return (rp->r_r13); - case REG_R14: - return (rp->r_r14); - case REG_R15: - return (rp->r_r15); - case REG_DS: - return (rp->r_ds); - case REG_ES: - return (rp->r_es); - case REG_FS: - return (rp->r_fs); - case REG_GS: - return (rp->r_gs); + return (rp->tf_eax); case REG_TRAPNO: - return (rp->r_trapno); + return (rp->tf_trapno); case REG_ERR: - return (rp->r_err); + return (rp->tf_err); case REG_RIP: - return (rp->r_rip); + return (rp->tf_eip); case REG_CS: - return (rp->r_cs); - case REG_SS: - return (rp->r_ss); + return (rp->tf_cs); case REG_RFL: - return (rp->r_rfl); + return (rp->tf_eflags); +#if 0 case REG_RSP: - return (rp->r_rsp); + return (rp->tf_esp); +#endif + case REG_SS: + return (rp->tf_ss); default: DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return (0); } - -#else - if (reg > SS) { - DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); - return (0); - } - - return ((&rp->r_gs)[reg]); -#endif } -#endif static int dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) diff --git a/sys/cddl/dev/dtrace/i386/regset.h b/sys/cddl/dev/dtrace/i386/regset.h new file mode 100644 index 0000000..d6732ff --- /dev/null +++ b/sys/cddl/dev/dtrace/i386/regset.h @@ -0,0 +1,127 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * $FreeBSD$ + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#ifndef _REGSET_H +#define _REGSET_H + +/* + * #pragma ident "@(#)regset.h 1.11 05/06/08 SMI" + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The names and offsets defined here should be specified by the + * AMD64 ABI suppl. + * + * We make fsbase and gsbase part of the lwp context (since they're + * the only way to access the full 64-bit address range via the segment + * registers) and thus belong here too. However we treat them as + * read-only; if %fs or %gs are updated, the results of the descriptor + * table lookup that those updates implicitly cause will be reflected + * in the corresponding fsbase and/or gsbase values the next time the + * context can be inspected. However it is NOT possible to override + * the fsbase/gsbase settings via this interface. + * + * Direct modification of the base registers (thus overriding the + * descriptor table base address) can be achieved with _lwp_setprivate. + */ + +#define REG_GSBASE 27 +#define REG_FSBASE 26 +#define REG_DS 25 +#define REG_ES 24 + +#define REG_GS 23 +#define REG_FS 22 +#define REG_SS 21 +#define REG_RSP 20 +#define REG_RFL 19 +#define REG_CS 18 +#define REG_RIP 17 +#define REG_ERR 16 +#define REG_TRAPNO 15 +#define REG_RAX 14 +#define REG_RCX 13 +#define REG_RDX 12 +#define REG_RBX 11 +#define REG_RBP 10 +#define REG_RSI 9 +#define REG_RDI 8 +#define REG_R8 7 +#define REG_R9 6 +#define REG_R10 5 +#define REG_R11 4 +#define REG_R12 3 +#define REG_R13 2 +#define REG_R14 1 +#define REG_R15 0 + +/* + * The names and offsets defined here are specified by i386 ABI suppl. + */ + +#define SS 18 /* only stored on a privilege transition */ +#define UESP 17 /* only stored on a privilege transition */ +#define EFL 16 +#define CS 15 +#define EIP 14 +#define ERR 13 +#define TRAPNO 12 +#define EAX 11 +#define ECX 10 +#define EDX 9 +#define EBX 8 +#define ESP 7 +#define EBP 6 +#define ESI 5 +#define EDI 4 +#define DS 3 +#define ES 2 +#define FS 1 +#define GS 0 + +#define REG_PC EIP +#define REG_FP EBP +#define REG_SP UESP +#define REG_PS EFL +#define REG_R0 EAX +#define REG_R1 EDX + +#ifdef __cplusplus +} +#endif + +#endif /* _REGSET_H */ diff --git a/sys/cddl/dev/systrace/systrace.c b/sys/cddl/dev/systrace/systrace.c index 72c25e4..3e992e3 100644 --- a/sys/cddl/dev/systrace/systrace.c +++ b/sys/cddl/dev/systrace/systrace.c @@ -153,22 +153,24 @@ static dtrace_provider_id_t systrace_id; * compat syscall from something like Linux. */ static void -systrace_probe(u_int32_t id, int sysnum, struct sysent *sysent, void *params) +systrace_probe(u_int32_t id, int sysnum, struct sysent *sysent, void *params, + int ret) { int n_args = 0; u_int64_t uargs[8]; + memset(uargs, 0, sizeof(uargs)); /* * Check if this syscall has an argument conversion function * registered. */ - if (sysent->sy_systrace_args_func != NULL) + if (params && sysent->sy_systrace_args_func != NULL) { /* * Convert the syscall parameters using the registered * function. */ (*sysent->sy_systrace_args_func)(sysnum, params, uargs, &n_args); - else + } else if (params) { /* * Use the built-in system call argument conversion * function to translate the syscall structure fields @@ -176,6 +178,13 @@ systrace_probe(u_int32_t id, int sysnum, struct sysent *sysent, void *params) * expects. */ systrace_args(sysnum, params, uargs, &n_args); + } else { + /* + * Since params is NULL, this is a 'return' probe. + * Set arg0 and arg1 as the return value of this syscall. + */ + uargs[0] = uargs[1] = ret; + } /* Process the probe using the converted argments. */ dtrace_probe(id, uargs[0], uargs[1], uargs[2], uargs[3], uargs[4]); diff --git a/sys/sys/sysent.h b/sys/sys/sysent.h index 4754f54..e726fce 100644 --- a/sys/sys/sysent.h +++ b/sys/sys/sysent.h @@ -42,7 +42,8 @@ struct ksiginfo; typedef int sy_call_t(struct thread *, void *); /* Used by the machine dependent syscall() code. */ -typedef void (*systrace_probe_func_t)(u_int32_t, int, struct sysent *, void *); +typedef void (*systrace_probe_func_t)(u_int32_t, int, struct sysent *, void *, + int); /* * Used by loaded syscalls to convert arguments to a DTrace array -- cgit v1.1