Make the second argument of dtrace_invop() a trapframe pointer.

Currently this argument is a pointer into the stack which is used by FBT
to fetch the first five probe arguments. On all non-x86 architectures it's
simply the trapframe address, so this change has no functional impact. On
amd64 it's a pointer into the trapframe such that stack[1 .. 5] gives the
first five argument registers, which are deliberately grouped together in
the amd64 trapframe definition.

A trapframe argument simplifies the invop handlers on !x86 and makes the
x86 FBT invop handler easier to understand. Moreover, it allows for invop
handlers that may want to modify the register set of the interrupted thread.
This commit is contained in:
Mark Johnston 2016-04-17 23:08:47 +00:00
parent 1551be3402
commit 6c2806594b
16 changed files with 100 additions and 75 deletions

View File

@ -2398,8 +2398,9 @@ extern int dtrace_instr_size(uchar_t *instr);
extern int dtrace_instr_size_isa(uchar_t *, model_t, int *);
extern void dtrace_invop_callsite(void);
#endif
extern void dtrace_invop_add(int (*)(uintptr_t, uintptr_t *, uintptr_t));
extern void dtrace_invop_remove(int (*)(uintptr_t, uintptr_t *, uintptr_t));
extern void dtrace_invop_add(int (*)(uintptr_t, struct trapframe *, uintptr_t));
extern void dtrace_invop_remove(int (*)(uintptr_t, struct trapframe *,
uintptr_t));
#ifdef __sparc
extern int dtrace_blksuword32(uintptr_t, uint32_t *, int);
@ -2427,7 +2428,9 @@ extern void dtrace_helpers_destroy(proc_t *);
#if defined(__i386) || defined(__amd64)
#define DTRACE_INVOP_PUSHL_EBP 1
#define DTRACE_INVOP_PUSHQ_RBP DTRACE_INVOP_PUSHL_EBP
#define DTRACE_INVOP_POPL_EBP 2
#define DTRACE_INVOP_POPQ_RBP DTRACE_INVOP_POPL_EBP
#define DTRACE_INVOP_LEAVE 3
#define DTRACE_INVOP_NOP 4
#define DTRACE_INVOP_RET 5

View File

@ -49,25 +49,25 @@ extern dtrace_id_t dtrace_probeid_error;
extern int (*dtrace_invop_jump_addr)(struct trapframe *);
extern void dtrace_getnanotime(struct timespec *tsp);
int dtrace_invop(uintptr_t, uintptr_t *, uintptr_t);
int dtrace_invop(uintptr_t, struct trapframe *, uintptr_t);
void dtrace_invop_init(void);
void dtrace_invop_uninit(void);
typedef struct dtrace_invop_hdlr {
int (*dtih_func)(uintptr_t, uintptr_t *, uintptr_t);
int (*dtih_func)(uintptr_t, struct trapframe *, uintptr_t);
struct dtrace_invop_hdlr *dtih_next;
} dtrace_invop_hdlr_t;
dtrace_invop_hdlr_t *dtrace_invop_hdlr;
int
dtrace_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax)
dtrace_invop(uintptr_t addr, struct trapframe *frame, uintptr_t eax)
{
dtrace_invop_hdlr_t *hdlr;
int rval;
for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next)
if ((rval = hdlr->dtih_func(addr, stack, eax)) != 0)
if ((rval = hdlr->dtih_func(addr, frame, eax)) != 0)
return (rval);
return (0);
@ -75,7 +75,7 @@ dtrace_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax)
void
dtrace_invop_add(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
dtrace_invop_add(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
{
dtrace_invop_hdlr_t *hdlr;
@ -86,7 +86,7 @@ dtrace_invop_add(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
}
void
dtrace_invop_remove(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
dtrace_invop_remove(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
{
dtrace_invop_hdlr_t *hdlr, *prev;
@ -240,7 +240,7 @@ dtrace_invop_start(struct trapframe *frame)
int tmp;
int i;
invop = dtrace_invop(frame->tf_elr, (uintptr_t *)frame, frame->tf_elr);
invop = dtrace_invop(frame->tf_elr, frame, frame->tf_elr);
tmp = (invop & LDP_STP_MASK);
if (tmp == STP_64 || tmp == LDP_64) {

View File

@ -69,13 +69,10 @@
*/
movq TF_RIP(%rsp), %rdi
decq %rdi
movq TF_RSP(%rsp), %rsi
movq TF_RAX(%rsp), %rdx
pushq (%rsi)
movq %rsp, %rsi
movq TF_RAX(%rsp), %rdx
call dtrace_invop
ALTENTRY(dtrace_invop_callsite)
addq $8, %rsp
cmpl $DTRACE_INVOP_PUSHL_EBP, %eax
je bp_push
cmpl $DTRACE_INVOP_LEAVE, %eax

View File

@ -382,11 +382,10 @@ dtrace_getarg(int arg, int aframes)
* we'll pull the true stack pointer out of the saved
* registers and decrement our argument by the number
* of arguments passed in registers; if the argument
* we're seeking is passed in regsiters, we can just
* we're seeking is passed in registers, we can just
* load it directly.
*/
struct trapframe *tf = (struct trapframe *)
((uintptr_t)&fp[1] + sizeof(uintptr_t));
struct trapframe *tf = (struct trapframe *)&fp[1];
if (arg <= inreg) {
switch (arg) {

View File

@ -46,30 +46,30 @@
extern void dtrace_getnanotime(struct timespec *tsp);
int dtrace_invop(uintptr_t, uintptr_t *, uintptr_t);
int dtrace_invop(uintptr_t, struct trapframe *, uintptr_t);
typedef struct dtrace_invop_hdlr {
int (*dtih_func)(uintptr_t, uintptr_t *, uintptr_t);
int (*dtih_func)(uintptr_t, struct trapframe *, uintptr_t);
struct dtrace_invop_hdlr *dtih_next;
} dtrace_invop_hdlr_t;
dtrace_invop_hdlr_t *dtrace_invop_hdlr;
int
dtrace_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax)
dtrace_invop(uintptr_t addr, struct trapframe *frame, uintptr_t eax)
{
dtrace_invop_hdlr_t *hdlr;
int rval;
for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next)
if ((rval = hdlr->dtih_func(addr, stack, eax)) != 0)
if ((rval = hdlr->dtih_func(addr, frame, eax)) != 0)
return (rval);
return (0);
}
void
dtrace_invop_add(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
dtrace_invop_add(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
{
dtrace_invop_hdlr_t *hdlr;
@ -80,7 +80,7 @@ dtrace_invop_add(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
}
void
dtrace_invop_remove(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
dtrace_invop_remove(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
{
dtrace_invop_hdlr_t *hdlr = dtrace_invop_hdlr, *prev = NULL;

View File

@ -55,25 +55,25 @@ extern dtrace_id_t dtrace_probeid_error;
extern int (*dtrace_invop_jump_addr)(struct trapframe *);
extern void dtrace_getnanotime(struct timespec *tsp);
int dtrace_invop(uintptr_t, uintptr_t *, uintptr_t);
int dtrace_invop(uintptr_t, struct trapframe *, uintptr_t);
void dtrace_invop_init(void);
void dtrace_invop_uninit(void);
typedef struct dtrace_invop_hdlr {
int (*dtih_func)(uintptr_t, uintptr_t *, uintptr_t);
int (*dtih_func)(uintptr_t, struct trapframe *, uintptr_t);
struct dtrace_invop_hdlr *dtih_next;
} dtrace_invop_hdlr_t;
dtrace_invop_hdlr_t *dtrace_invop_hdlr;
int
dtrace_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax)
dtrace_invop(uintptr_t addr, struct trapframe *frame, uintptr_t eax)
{
dtrace_invop_hdlr_t *hdlr;
int rval;
for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next)
if ((rval = hdlr->dtih_func(addr, stack, eax)) != 0)
if ((rval = hdlr->dtih_func(addr, frame, eax)) != 0)
return (rval);
return (0);
@ -81,7 +81,7 @@ dtrace_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax)
void
dtrace_invop_add(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
dtrace_invop_add(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
{
dtrace_invop_hdlr_t *hdlr;
@ -92,7 +92,7 @@ dtrace_invop_add(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
}
void
dtrace_invop_remove(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
dtrace_invop_remove(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
{
dtrace_invop_hdlr_t *hdlr = dtrace_invop_hdlr, *prev = NULL;
@ -237,7 +237,7 @@ dtrace_invop_start(struct trapframe *frame)
register_t *r0, *sp;
int data, invop, reg, update_sp;
invop = dtrace_invop(frame->tf_pc, (uintptr_t *)frame, frame->tf_pc);
invop = dtrace_invop(frame->tf_pc, frame, frame->tf_pc);
switch (invop & DTRACE_INVOP_MASK) {
case DTRACE_INVOP_PUSHM:
sp = (register_t *)frame->tf_svc_sp;

View File

@ -38,7 +38,7 @@
pushl %eax /* push %eax -- may be return value */
pushl %esp /* push stack pointer */
addl $48, (%esp) /* adjust to incoming args */
subl $8, (%esp) /* skip first arg and segment regs */
pushl 40(%esp) /* push calling EIP */
/*

View File

@ -423,9 +423,9 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
uint64_t
dtrace_getarg(int arg, int aframes)
{
uintptr_t val;
struct trapframe *frame;
struct i386_frame *fp = (struct i386_frame *)dtrace_getfp();
uintptr_t *stack;
uintptr_t *stack, val;
int i;
for (i = 1; i <= aframes; i++) {
@ -435,13 +435,18 @@ dtrace_getarg(int arg, int aframes)
(long)dtrace_invop_callsite) {
/*
* If we pass through the invalid op handler, we will
* use the pointer that it passed to the stack as the
* second argument to dtrace_invop() as the pointer to
* the stack. When using this stack, we must step
* beyond the EIP/RIP that was pushed when the trap was
* taken -- hence the "+ 1" below.
* use the trap frame pointer that it pushed on the
* stack as the second argument to dtrace_invop() as
* the pointer to the stack. When using this stack, we
* must skip the third argument to dtrace_invop(),
* which is included in the i386_frame.
*/
stack = ((uintptr_t **)&fp[1])[0] + 1;
frame = (struct trapframe *)(((uintptr_t **)&fp[1])[0]);
/*
* Skip the three hardware-saved registers and the
* return address.
*/
stack = (uintptr_t *)frame->tf_isp + 4;
goto load;
}

View File

@ -49,30 +49,30 @@ extern uintptr_t kernelbase;
extern void dtrace_getnanotime(struct timespec *tsp);
int dtrace_invop(uintptr_t, uintptr_t *, uintptr_t);
int dtrace_invop(uintptr_t, struct trapframe *, uintptr_t);
typedef struct dtrace_invop_hdlr {
int (*dtih_func)(uintptr_t, uintptr_t *, uintptr_t);
int (*dtih_func)(uintptr_t, struct trapframe *, uintptr_t);
struct dtrace_invop_hdlr *dtih_next;
} dtrace_invop_hdlr_t;
dtrace_invop_hdlr_t *dtrace_invop_hdlr;
int
dtrace_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax)
dtrace_invop(uintptr_t addr, struct trapframe *frame, uintptr_t eax)
{
dtrace_invop_hdlr_t *hdlr;
int rval;
for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next)
if ((rval = hdlr->dtih_func(addr, stack, eax)) != 0)
if ((rval = hdlr->dtih_func(addr, frame, eax)) != 0)
return (rval);
return (0);
}
void
dtrace_invop_add(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
dtrace_invop_add(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
{
dtrace_invop_hdlr_t *hdlr;
@ -83,7 +83,7 @@ dtrace_invop_add(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
}
void
dtrace_invop_remove(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
dtrace_invop_remove(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
{
dtrace_invop_hdlr_t *hdlr = dtrace_invop_hdlr, *prev = NULL;

View File

@ -48,7 +48,7 @@ __FBSDID("$FreeBSD$");
extern dtrace_id_t dtrace_probeid_error;
int dtrace_invop(uintptr_t, uintptr_t *, uintptr_t);
int dtrace_invop(uintptr_t, struct trapframe *, uintptr_t);
typedef struct dtrace_invop_hdlr {
int (*dtih_func)(uintptr_t, uintptr_t *, uintptr_t);
@ -58,7 +58,7 @@ typedef struct dtrace_invop_hdlr {
dtrace_invop_hdlr_t *dtrace_invop_hdlr;
int
dtrace_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax)
dtrace_invop(uintptr_t addr, struct trapframe *stack, uintptr_t eax)
{
dtrace_invop_hdlr_t *hdlr;
int rval;

View File

@ -51,32 +51,32 @@ extern int (*dtrace_invop_jump_addr)(struct trapframe *);
extern void dtrace_getnanotime(struct timespec *tsp);
int dtrace_invop(uintptr_t, uintptr_t *, uintptr_t);
int dtrace_invop(uintptr_t, struct trapframe *, uintptr_t);
void dtrace_invop_init(void);
void dtrace_invop_uninit(void);
typedef struct dtrace_invop_hdlr {
int (*dtih_func)(uintptr_t, uintptr_t *, uintptr_t);
int (*dtih_func)(uintptr_t, struct trapframe *, uintptr_t);
struct dtrace_invop_hdlr *dtih_next;
} dtrace_invop_hdlr_t;
dtrace_invop_hdlr_t *dtrace_invop_hdlr;
int
dtrace_invop(uintptr_t addr, uintptr_t *stack, uintptr_t arg0)
dtrace_invop(uintptr_t addr, struct trapframe *frame, uintptr_t arg0)
{
dtrace_invop_hdlr_t *hdlr;
int rval;
for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next)
if ((rval = hdlr->dtih_func(addr, stack, arg0)) != 0)
if ((rval = hdlr->dtih_func(addr, frame, arg0)) != 0)
return (rval);
return (0);
}
void
dtrace_invop_add(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
dtrace_invop_add(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
{
dtrace_invop_hdlr_t *hdlr;
@ -87,7 +87,7 @@ dtrace_invop_add(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
}
void
dtrace_invop_remove(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
dtrace_invop_remove(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
{
dtrace_invop_hdlr_t *hdlr = dtrace_invop_hdlr, *prev = NULL;
@ -326,7 +326,8 @@ dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which,
static int
dtrace_invop_start(struct trapframe *frame)
{
switch (dtrace_invop(frame->srr0, (uintptr_t *)frame, frame->fixreg[3])) {
switch (dtrace_invop(frame->srr0, frame, frame->fixreg[3])) {
case DTRACE_INVOP_JUMP:
break;
case DTRACE_INVOP_BCTR:
@ -341,9 +342,7 @@ dtrace_invop_start(struct trapframe *frame)
break;
default:
return (-1);
break;
}
return (0);
}

View File

@ -46,13 +46,11 @@
#define FBT_RETURN "return"
int
fbt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval)
fbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t rval)
{
struct trapframe *frame;
solaris_cpu_t *cpu;
fbt_probe_t *fbt;
frame = (struct trapframe *)stack;
cpu = &solaris_cpu[curcpu];
fbt = fbt_probetab[FBT_ADDR2NDX(addr)];

View File

@ -49,9 +49,8 @@
#define FBT_RETURN "return"
int
fbt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval)
fbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t rval)
{
struct trapframe *frame = (struct trapframe *)stack;
solaris_cpu_t *cpu = &solaris_cpu[curcpu];
fbt_probe_t *fbt = fbt_probetab[FBT_ADDR2NDX(addr)];
register_t fifthparam;

View File

@ -51,8 +51,9 @@ typedef struct fbt_probe {
struct linker_file;
struct linker_symval;
struct trapframe;
int fbt_invop(uintptr_t, uintptr_t *, uintptr_t);
int fbt_invop(uintptr_t, struct trapframe *, uintptr_t);
void fbt_patch_tracepoint(fbt_probe_t *, fbt_patchval_t);
int fbt_provide_module_function(struct linker_file *, int,
struct linker_symval *, void *);

View File

@ -51,9 +51,8 @@
#define FBT_AFRAMES 7
int
fbt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval)
fbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t rval)
{
struct trapframe *frame = (struct trapframe *)stack;
solaris_cpu_t *cpu = &solaris_cpu[curcpu];
fbt_probe_t *fbt = fbt_probetab[FBT_ADDR2NDX(addr)];
uintptr_t tmp;

View File

@ -58,16 +58,40 @@
#define FBT_RETURN "return"
int
fbt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval)
fbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t rval)
{
solaris_cpu_t *cpu = &solaris_cpu[curcpu];
uintptr_t stack0, stack1, stack2, stack3, stack4;
fbt_probe_t *fbt = fbt_probetab[FBT_ADDR2NDX(addr)];
solaris_cpu_t *cpu;
uintptr_t *stack;
uintptr_t arg0, arg1, arg2, arg3, arg4;
fbt_probe_t *fbt;
#ifdef __amd64__
stack = (uintptr_t *)frame->tf_rsp;
#else
/* Skip hardware-saved registers. */
stack = (uintptr_t *)frame->tf_isp + 3;
#endif
cpu = &solaris_cpu[curcpu];
fbt = fbt_probetab[FBT_ADDR2NDX(addr)];
for (; fbt != NULL; fbt = fbt->fbtp_hashnext) {
if ((uintptr_t)fbt->fbtp_patchpoint == addr) {
if (fbt->fbtp_roffset == 0) {
#ifdef __amd64__
/* fbt->fbtp_rval == DTRACE_INVOP_PUSHQ_RBP */
DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
cpu->cpu_dtrace_caller = stack[0];
DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT |
CPU_DTRACE_BADADDR);
arg0 = frame->tf_rdi;
arg1 = frame->tf_rsi;
arg2 = frame->tf_rdx;
arg3 = frame->tf_rcx;
arg4 = frame->tf_r8;
#else
int i = 0;
/*
* When accessing the arguments on the stack,
* we must protect against accessing beyond
@ -77,16 +101,17 @@ fbt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval)
*/
DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
cpu->cpu_dtrace_caller = stack[i++];
stack0 = stack[i++];
stack1 = stack[i++];
stack2 = stack[i++];
stack3 = stack[i++];
stack4 = stack[i++];
arg0 = stack[i++];
arg1 = stack[i++];
arg2 = stack[i++];
arg3 = stack[i++];
arg4 = stack[i++];
DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT |
CPU_DTRACE_BADADDR);
#endif
dtrace_probe(fbt->fbtp_id, stack0, stack1,
stack2, stack3, stack4);
dtrace_probe(fbt->fbtp_id, arg0, arg1,
arg2, arg3, arg4);
cpu->cpu_dtrace_caller = 0;
} else {
@ -94,7 +119,7 @@ fbt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval)
/*
* On amd64, we instrument the ret, not the
* leave. We therefore need to set the caller
* to assure that the top frame of a stack()
* to ensure that the top frame of a stack()
* action is correct.
*/
DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);