mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
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
This commit is contained in:
parent
58f668bba5
commit
c6f5742f90
10 changed files with 625 additions and 258 deletions
|
|
@ -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 <dtrace_anon.c>
|
||||
#if __FreeBSD_version < 800039
|
||||
#include <dtrace_clone.c>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#include <vm/vm_param.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#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)
|
||||
|
|
|
|||
127
sys/cddl/dev/dtrace/amd64/regset.h
Normal file
127
sys/cddl/dev/dtrace/amd64/regset.h
Normal file
|
|
@ -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 */
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -33,13 +33,17 @@
|
|||
#include <sys/stack.h>
|
||||
#include <sys/pcpu.h>
|
||||
|
||||
#include <machine/frame.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/pcb.h>
|
||||
#include <machine/stack.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_param.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
reg = regmap[reg];
|
||||
} else {
|
||||
reg -= SS + 1;
|
||||
}
|
||||
|
||||
switch (reg) {
|
||||
case REG_RDI:
|
||||
return (rp->r_rdi);
|
||||
case REG_RSI:
|
||||
return (rp->r_rsi);
|
||||
case REG_RDX:
|
||||
return (rp->r_rdx);
|
||||
case REG_RCX:
|
||||
return (rp->r_rcx);
|
||||
case REG_R8:
|
||||
return (rp->r_r8);
|
||||
case REG_R9:
|
||||
return (rp->r_r9);
|
||||
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);
|
||||
case REG_TRAPNO:
|
||||
return (rp->r_trapno);
|
||||
case REG_ERR:
|
||||
return (rp->r_err);
|
||||
case REG_RIP:
|
||||
return (rp->r_rip);
|
||||
case REG_CS:
|
||||
return (rp->r_cs);
|
||||
case REG_SS:
|
||||
return (rp->r_ss);
|
||||
case REG_RFL:
|
||||
return (rp->r_rfl);
|
||||
case REG_RSP:
|
||||
return (rp->r_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]);
|
||||
if (reg >= sizeof (regmap) / sizeof (int)) {
|
||||
DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
|
||||
return (0);
|
||||
}
|
||||
|
||||
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->tf_edi);
|
||||
case REG_RSI:
|
||||
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->tf_ecx);
|
||||
case REG_RAX:
|
||||
return (rp->tf_eax);
|
||||
case REG_TRAPNO:
|
||||
return (rp->tf_trapno);
|
||||
case REG_ERR:
|
||||
return (rp->tf_err);
|
||||
case REG_RIP:
|
||||
return (rp->tf_eip);
|
||||
case REG_CS:
|
||||
return (rp->tf_cs);
|
||||
case REG_RFL:
|
||||
return (rp->tf_eflags);
|
||||
#if 0
|
||||
case REG_RSP:
|
||||
return (rp->tf_esp);
|
||||
#endif
|
||||
case REG_SS:
|
||||
return (rp->tf_ss);
|
||||
default:
|
||||
DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
|
||||
|
|
|
|||
127
sys/cddl/dev/dtrace/i386/regset.h
Normal file
127
sys/cddl/dev/dtrace/i386/regset.h
Normal file
|
|
@ -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 */
|
||||
|
|
@ -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]);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue