/*ARGSUSED*/ void dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *ignored) { int depth; #if !defined(HAVE_STACKTRACE_OPS) /***********************************************/ /* This is a basic stack walker - we dont */ /* care about omit-frame-pointer, and we */ /* can have false positives. We also dont */ /* handle exception stacks properly - but */ /* this is for older kernels, where the */ /* kernel wont help us, so they may not */ /* have exception stacks anyhow. */ /***********************************************/ cpu_core_t *this_cpu = cpu_get_this(); struct pt_regs *regs = this_cpu->cpuc_regs; uintptr_t *sp = (uintptr_t *) ®s->r_rsp; uintptr_t *spend; if (regs == NULL) sp = (uintptr_t *) &depth; spend = sp + THREAD_SIZE / sizeof(uintptr_t); for (depth = 0; depth < pcstack_limit && sp < spend; ) { if (sp && is_kernel_text((unsigned long) *sp)) { pcstack[depth++] = *sp; } sp++; } #else dmutex_enter(&dtrace_stack_mutex); g_depth = 0; g_pcstack = pcstack; g_pcstack_limit = pcstack_limit; #if FUNC_DUMP_TRACE_ARGS == 6 dump_trace(NULL, NULL, NULL, 0, &print_trace_ops, NULL); #else dump_trace(NULL, NULL, NULL, &print_trace_ops, NULL); #endif depth = g_depth; dmutex_exit(&dtrace_stack_mutex); #endif while (depth < pcstack_limit) pcstack[depth++] = (pc_t) NULL; }
/*ARGSUSED*/ void dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *ignored) { int depth; #if !defined(HAVE_STACKTRACE_OPS) int lim; /***********************************************/ /* This is a basic stack walker - we dont */ /* care about omit-frame-pointer, and we */ /* can have false positives. We also dont */ /* handle exception stacks properly - but */ /* this is for older kernels, where the */ /* kernel wont help us, so they may not */ /* have exception stacks anyhow. */ /***********************************************/ /***********************************************/ /* 20121125 Lets use this always - it avoid */ /* kernel specific issues in the official */ /* stack walker and will give us a vehicle */ /* later for adding reliable vs guess-work */ /* stack entries. */ /***********************************************/ cpu_core_t *this_cpu = cpu_get_this(); struct pt_regs *regs = this_cpu->cpuc_regs; struct thread_info *context; uintptr_t *sp; uintptr_t *spend; /***********************************************/ /* For syscalls, we will have a null */ /* cpuc_regs, since we dont intercept the */ /* trap, but instead intercept the C */ /* syscall function. */ /***********************************************/ if (regs == NULL) sp = (uintptr_t *) &depth; else sp = (uintptr_t *) regs->r_rsp; /***********************************************/ /* Daisy chain the interrupt and any other */ /* stacks. Limit ourselves in case of bad */ /* corruptions. */ /***********************************************/ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); depth = 0; for (lim = 0; lim < 3 && depth < pcstack_limit; lim++) { int ndepth = depth; uintptr_t *prev_esp; context = (struct thread_info *) ((unsigned long) sp & (~(THREAD_SIZE - 1))); spend = (uintptr_t *) ((unsigned long) sp | (THREAD_SIZE - 1)); for ( ; depth < pcstack_limit && sp < spend; sp++) { if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) goto end_stack; if (*sp && is_kernel_text((unsigned long) *sp)) { pcstack[depth++] = *sp; } } if (depth >= pcstack_limit || ndepth == depth) break; prev_esp = (uintptr_t *) ((char *) context + sizeof(struct thread_info)); if ((sp = prev_esp) == NULL) break; /***********************************************/ /* Special signal to mark the IRQ stack. */ /***********************************************/ if (depth < pcstack_limit) { pcstack[depth++] = 1; } } end_stack: DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_FAULT); #else /***********************************************/ /* I'm a little tired of the kernel dying */ /* in the callback, so lets avoid relying */ /* on the kernel stack walker. */ /***********************************************/ dmutex_enter(&dtrace_stack_mutex); g_depth = 0; g_pcstack = pcstack; g_pcstack_limit = pcstack_limit; #if FUNC_DUMP_TRACE_ARGS == 6 dump_trace(NULL, NULL, NULL, 0, &print_trace_ops, NULL); #else dump_trace(NULL, NULL, NULL, &print_trace_ops, NULL); #endif depth = g_depth; dmutex_exit(&dtrace_stack_mutex); #endif while (depth < pcstack_limit) pcstack[depth++] = (pc_t) NULL; }