diff options
author | Andrew Turner <andrew@FreeBSD.org> | 2015-02-19 12:20:21 +0000 |
---|---|---|
committer | Andrew Turner <andrew@FreeBSD.org> | 2015-02-19 12:20:21 +0000 |
commit | aeca5b8bc9036db95d1910de3716d00a5f74ad99 (patch) | |
tree | ffb91cefc8748f598e6292f4b0ab1aeed2cb80cb /sys/cddl/dev/dtrace/arm | |
parent | 1b23f9b9c34838e7a25eda010af005d1ca8c5cf7 (diff) | |
download | src-aeca5b8bc9036db95d1910de3716d00a5f74ad99.tar.gz src-aeca5b8bc9036db95d1910de3716d00a5f74ad99.zip |
Use the ARM unwinder with dtrace to extract the stack when asked. With this
dtrace is able to display a stack trace similar to the one below.
# dtrace -p 603 -n 'tcp:kernel::receive { stack(); }'
0 70 :receive
kernel`ip_input+0x140
kernel`netisr_dispatch_src+0xb8
kernel`ether_demux+0x1c4
kernel`ether_nh_input+0x3a8
kernel`netisr_dispatch_src+0xb8
kernel`ether_input+0x60
kernel`cpsw_intr_rx+0xac
kernel`intr_event_execute_handlers+0x128
kernel`ithread_loop+0xb4
kernel`fork_exit+0x84
kernel`swi_exit
kernel`swi_exit
Tested by: gnn
Sponsored by: ABT Systems Ltd
Notes
Notes:
svn path=/head/; revision=278997
Diffstat (limited to 'sys/cddl/dev/dtrace/arm')
-rw-r--r-- | sys/cddl/dev/dtrace/arm/dtrace_isa.c | 119 |
1 files changed, 29 insertions, 90 deletions
diff --git a/sys/cddl/dev/dtrace/arm/dtrace_isa.c b/sys/cddl/dev/dtrace/arm/dtrace_isa.c index 7d3dc2e03801..14adb4c3b5d7 100644 --- a/sys/cddl/dev/dtrace/arm/dtrace_isa.c +++ b/sys/cddl/dev/dtrace/arm/dtrace_isa.c @@ -69,9 +69,10 @@ void dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *intrpc) { - u_int32_t *frame, *lastframe; - int scp_offset; - int depth = 0; + struct unwind_state state; + register_t sp; + int scp_offset; + int depth = 0; pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; if (intrpc != 0) @@ -79,23 +80,17 @@ dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, aframes++; - frame = (u_int32_t *)__builtin_frame_address(0);; - lastframe = NULL; - scp_offset = -(get_pc_str_offset() >> 2); + __asm __volatile("mov %0, sp" : "=&r" (sp)); - while ((frame != NULL) && (depth < pcstack_limit)) { - db_addr_t scp; -#if 0 - u_int32_t savecode; - int r; - u_int32_t *rp; -#endif + state.registers[FP] = (uint32_t)__builtin_frame_address(0); + state.registers[SP] = sp; + state.registers[LR] = (uint32_t)__builtin_return_address(0); + state.registers[PC] = (uint32_t)dtrace_getpcstack; - /* - * In theory, the SCP isn't guaranteed to be in the function - * that generated the stack frame. We hope for the best. - */ - scp = frame[FR_SCP]; + while (depth < pcstack_limit) { + int done; + + done = unwind_stack_one(&state, 1); if (aframes > 0) { aframes--; @@ -104,39 +99,10 @@ dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, } } else { - pcstack[depth++] = scp; + pcstack[depth++] = state.registers[PC]; } -#if 0 - savecode = ((u_int32_t *)scp)[scp_offset]; - if ((savecode & 0x0e100000) == 0x08000000) { - /* Looks like an STM */ - rp = frame - 4; - for (r = 10; r >= 0; r--) { - if (savecode & (1 << r)) { - /* register r == *rp-- */ - } - } - } -#endif - - /* - * Switch to next frame up - */ - if (frame[FR_RFP] == 0) - break; /* Top of stack */ - - lastframe = frame; - frame = (u_int32_t *)(frame[FR_RFP]); - - if (INKERNEL((int)frame)) { - /* staying in kernel */ - if (frame <= lastframe) { - /* bad frame pointer */ - break; - } - } - else + if (done) break; } @@ -176,55 +142,28 @@ dtrace_getarg(int arg, int aframes) int dtrace_getstackdepth(int aframes) { - u_int32_t *frame, *lastframe; - int scp_offset; - int depth = 1; - - frame = (u_int32_t *)__builtin_frame_address(0);; - lastframe = NULL; - scp_offset = -(get_pc_str_offset() >> 2); - - while (frame != NULL) { - db_addr_t scp; -#if 0 - u_int32_t savecode; - int r; - u_int32_t *rp; -#endif - - /* - * In theory, the SCP isn't guaranteed to be in the function - * that generated the stack frame. We hope for the best. - */ - scp = frame[FR_SCP]; - - depth++; + struct unwind_state state; + register_t sp; + int scp_offset; + int done = 0; + int depth = 1; - /* - * Switch to next frame up - */ - if (frame[FR_RFP] == 0) - break; /* Top of stack */ + __asm __volatile("mov %0, sp" : "=&r" (sp)); - lastframe = frame; - frame = (u_int32_t *)(frame[FR_RFP]); + state.registers[FP] = (uint32_t)__builtin_frame_address(0); + state.registers[SP] = sp; + state.registers[LR] = (uint32_t)__builtin_return_address(0); + state.registers[PC] = (uint32_t)dtrace_getstackdepth; - if (INKERNEL((int)frame)) { - /* staying in kernel */ - if (frame <= lastframe) { - /* bad frame pointer */ - break; - } - } - else - break; - } + do { + done = unwind_stack_one(&state, 1); + depth++; + } while (!done); if (depth < aframes) return 0; else return depth - aframes; - } ulong_t |