void dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *intrpc) { int depth = 0; uintptr_t osp, sp; vm_offset_t callpc; pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; osp = PAGE_SIZE; if (intrpc != 0) pcstack[depth++] = (pc_t) intrpc; aframes++; sp = dtrace_getfp(); while (depth < pcstack_limit) { if (sp <= osp) break; if (!dtrace_sp_inkernel(sp)) break; callpc = dtrace_get_pc(sp); if (aframes > 0) { aframes--; if ((aframes == 0) && (caller != 0)) { pcstack[depth++] = caller; } } else { pcstack[depth++] = callpc; } osp = sp; sp = dtrace_next_sp(sp); } for (; depth < pcstack_limit; depth++) { pcstack[depth] = 0; } }
void dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *intrpc) { int depth = 0; register_t sp; vm_offset_t callpc; pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; if (intrpc != 0) pcstack[depth++] = (pc_t) intrpc; aframes++; sp = dtrace_getfp(); while (depth < pcstack_limit) { if (!INKERNEL((long) sp)) break; callpc = *(uintptr_t *)(sp + RETURN_OFFSET); if (!INKERNEL(callpc)) break; if (aframes > 0) { aframes--; if ((aframes == 0) && (caller != 0)) { pcstack[depth++] = caller; } } else { pcstack[depth++] = callpc; } sp = *(uintptr_t*)sp; } for (; depth < pcstack_limit; depth++) { pcstack[depth] = 0; } }
/*ARGSUSED*/ int dtrace_getstackdepth(int aframes) { # if 1 TODO(); return 0; # else struct frame *fp = (struct frame *)dtrace_getfp(); struct frame *nextfp, *minfp, *stacktop; int depth = 0; int is_intr = 0; int on_intr; uintptr_t pc; if ((on_intr = CPU_ON_INTR(CPU)) != 0) stacktop = (struct frame *)(CPU->cpu_intr_stack + SA(MINFRAME)); else stacktop = (struct frame *)curthread->t_stk; minfp = fp; aframes++; for (;;) { depth++; if (is_intr) { struct regs *rp = (struct regs *)fp; nextfp = (struct frame *)rp->r_fp; pc = rp->r_pc; } else { nextfp = (struct frame *)fp->fr_savfp; pc = fp->fr_savpc; } if (nextfp <= minfp || nextfp >= stacktop) { if (on_intr) { /* * Hop from interrupt stack to thread stack. */ stacktop = (struct frame *)curthread->t_stk; minfp = (struct frame *)curthread->t_stkbase; on_intr = 0; continue; } break; } is_intr = pc - (uintptr_t)_interrupt < _interrupt_size || pc - (uintptr_t)_allsyscalls < _allsyscalls_size || pc - (uintptr_t)_cmntrap < _cmntrap_size; fp = nextfp; minfp = fp; } if (depth <= aframes) return (0); return (depth - aframes); # endif }
/*ARGSUSED*/ uint64_t dtrace_getarg(int arg, int aframes) { uintptr_t val; struct frame *fp; uintptr_t *stack; int i; #if defined(__amd64) /***********************************************/ /* First 6 args in a register. */ /***********************************************/ int inreg = 5; /*int inreg = offsetof(struct regs, r_r9) / sizeof (greg_t);*/ #endif DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); fp = (struct frame *)dtrace_getfp(); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); //printk("dtrace_getarg: fp=%p %p\n", fp, fp->fr_savfp); //printk("arg=%d aframes=%d\n", arg, aframes); for (i = 1; i <= aframes; i++) { pc_t savpc; DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); fp = (struct frame *)(fp->fr_savfp); savpc = fp->fr_savpc; DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); //printk("fp=%p savpc=%p\n", fp, savpc); if (savpc == (pc_t)dtrace_invop_callsite) { #if !defined(__amd64) /* * 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. */ stack = ((uintptr_t **)&fp[1])[1] + 1; #else /* * In the case of amd64, we will use the pointer to the * regs structure that was pushed when we took the * trap. To get this structure, we must increment * beyond the frame structure, and then again beyond * the calling RIP stored in dtrace_invop(). If the * argument that we're seeking is passed on the stack, * 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 * load it directly. */ struct regs *rp = (struct regs *)((uintptr_t)&fp[1] + sizeof (uintptr_t)); if (arg <= inreg) { stack = (uintptr_t *)&rp->r_rdi; } else { stack = (uintptr_t *)(rp->r_rsp); arg -= inreg; } #endif goto load; } } /* * We know that we did not come through a trap to get into * dtrace_probe() -- the provider simply called dtrace_probe() * directly. As this is the case, we need to shift the argument * that we're looking for: the probe ID is the first argument to * dtrace_probe(), so the argument n will actually be found where * one would expect to find argument (n + 1). */ arg++; #if defined(__amd64) if (arg <= inreg) { /* * This shouldn't happen. If the argument is passed in a * register then it should have been, well, passed in a * register... */ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return (0); } arg -= (inreg + 1); #endif stack = (uintptr_t *)&fp[1]; load: DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); val = stack[arg]; DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); return (val); }
/*ARGSUSED*/ uint64_t sdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, int aframes) { uintptr_t val; struct frame *fp = (struct frame *)dtrace_getfp(); uintptr_t *stack = NULL; int i; #if defined(__amd64) /* * A total of 6 arguments are passed via registers; any argument with * index of 5 or lower is therefore in a register. */ int inreg = 5; #endif /* for (i = 1; i <= aframes+2; i++) { fp = (struct frame *)(fp->fr_savfp); printk("stk %d: %p: %p %p %p %p\n%p %p %p\n", i, fp, ((long *) fp)[0], ((long *) fp)[1], ((long *) fp)[2], ((long *) fp)[3], ((long *) fp)[4], ((long *) fp)[5], ((long *) fp)[6], ((long *) fp)[7] ); } fp = dtrace_getfp(); */ for (i = 1; i <= aframes; i++) { //printk("i=%d fp=%p aframes=%d pc:%p\n", i, fp, aframes, fp->fr_savpc); fp = (struct frame *)(fp->fr_savfp); #if defined(linux) /***********************************************/ /* Temporary hack - not sure which stack we */ /* have here and it is faultiing us. */ /***********************************************/ if (fp == NULL) return 0; #endif if (fp->fr_savpc == (pc_t)dtrace_invop_callsite) { #if !defined(__amd64) /* * 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. */ stack = ((uintptr_t **)&fp[1])[1]; #else /* * In the case of amd64, we will use the pointer to the * regs structure that was pushed when we took the * trap. To get this structure, we must increment * beyond the frame structure. If the argument that * we're seeking is passed on the stack, 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 * load it directly. */ struct regs *rp = (struct regs *)((uintptr_t)&fp[1] + sizeof (uintptr_t)); if (argno <= inreg) { stack = (uintptr_t *)&rp->r_rdi; } else { stack = (uintptr_t *)(rp->r_rsp); argno -= (inreg + 1); } #endif goto load; } } //printk("stack %d: %p %p %p %p\n", i, ((long *) fp)[0], ((long *) fp)[1], ((long *) fp)[2], ((long *) fp)[3], ((long *) fp)[4]); /* * We know that we did not come through a trap to get into * dtrace_probe() -- the provider simply called dtrace_probe() * directly. As this is the case, we need to shift the argument * that we're looking for: the probe ID is the first argument to * dtrace_probe(), so the argument n will actually be found where * one would expect to find argument (n + 1). */ argno++; #if defined(__amd64) if (argno <= inreg) { /* * This shouldn't happen. If the argument is passed in a * register then it should have been, well, passed in a * register... */ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return (0); } argno -= (inreg + 1); #endif stack = (uintptr_t *)&fp[1]; load: DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); val = stack[argno]; DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); printk("sdt_getarg#%d: %lx aframes=%d\n", argno, val, aframes); return (val); }
void dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *intrpc) { struct frame *fp = (struct frame *)dtrace_getfp(); struct frame *nextfp, *minfp, *stacktop; int depth = 0; int last = 0; uintptr_t pc; uintptr_t caller = CPU->cpu_dtrace_caller; int on_intr; if ((on_intr = CPU_ON_INTR(CPU)) != 0) stacktop = (struct frame *)dtrace_get_cpu_int_stack_top(); else stacktop = (struct frame *)(dtrace_get_kernel_stack(current_thread()) + KERNEL_STACK_SIZE); minfp = fp; aframes++; if (intrpc != NULL && depth < pcstack_limit) pcstack[depth++] = (pc_t)intrpc; while (depth < pcstack_limit) { nextfp = *(struct frame **)fp; pc = *(uintptr_t *)(((uint32_t)fp) + RETURN_OFFSET); if (nextfp <= minfp || nextfp >= stacktop) { if (on_intr) { /* * Hop from interrupt stack to thread stack. */ vm_offset_t kstack_base = dtrace_get_kernel_stack(current_thread()); minfp = (struct frame *)kstack_base; stacktop = (struct frame *)(kstack_base + KERNEL_STACK_SIZE); on_intr = 0; continue; } /* * This is the last frame we can process; indicate * that we should return after processing this frame. */ last = 1; } if (aframes > 0) { if (--aframes == 0 && caller != 0) { /* * We've just run out of artificial frames, * and we have a valid caller -- fill it in * now. */ ASSERT(depth < pcstack_limit); pcstack[depth++] = (pc_t)caller; caller = 0; } } else { if (depth < pcstack_limit) pcstack[depth++] = (pc_t)pc; } if (last) { while (depth < pcstack_limit) pcstack[depth++] = 0; return; } fp = nextfp; minfp = fp; } }
/*ARGSUSED*/ uint64_t dtrace_getarg(int arg, int aframes) { uintptr_t val; uintptr_t *fp = (uintptr_t *)dtrace_getfp(); uintptr_t *stack; int i; /* * A total of 8 arguments are passed via registers; any argument with * index of 7 or lower is therefore in a register. */ int inreg = 7; for (i = 1; i <= aframes; i++) { fp = (uintptr_t *)*fp; /* * On ppc32 AIM, and booke, trapexit() is the immediately following * label. On ppc64 AIM trapexit() follows a nop. */ #ifdef __powerpc64__ if ((long)(fp[2]) + 4 == (long)trapexit) { #else if ((long)(fp[1]) == (long)trapexit) { #endif /* * In the case of powerpc, we will use the pointer to the regs * structure that was pushed when we took the trap. To get this * structure, we must increment beyond the frame structure. If the * argument that we're seeking is passed on the stack, 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 * load it directly. */ #ifdef __powerpc64__ struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 48); #else struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 8); #endif if (arg <= inreg) { stack = &rp->fixreg[3]; } else { stack = (uintptr_t *)(rp->fixreg[1]); arg -= inreg; } goto load; } } /* * We know that we did not come through a trap to get into * dtrace_probe() -- the provider simply called dtrace_probe() * directly. As this is the case, we need to shift the argument * that we're looking for: the probe ID is the first argument to * dtrace_probe(), so the argument n will actually be found where * one would expect to find argument (n + 1). */ arg++; if (arg <= inreg) { /* * This shouldn't happen. If the argument is passed in a * register then it should have been, well, passed in a * register... */ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return (0); } arg -= (inreg + 1); stack = fp + 2; load: DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); val = stack[arg]; DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); return (val); } int dtrace_getstackdepth(int aframes) { int depth = 0; uintptr_t osp, sp; vm_offset_t callpc; osp = PAGE_SIZE; aframes++; sp = dtrace_getfp(); depth++; for(;;) { if (sp <= osp) break; if (!dtrace_sp_inkernel(sp)) break; if (aframes == 0) depth++; else aframes--; osp = sp; sp = dtrace_next_sp(sp); } if (depth < aframes) return (0); return (depth); }