diff options
author | andrew <andrew@FreeBSD.org> | 2015-02-19 12:20:21 +0000 |
---|---|---|
committer | andrew <andrew@FreeBSD.org> | 2015-02-19 12:20:21 +0000 |
commit | c560f15fa85ae389cef41cccd341e86818691111 (patch) | |
tree | ffb91cefc8748f598e6292f4b0ab1aeed2cb80cb | |
parent | 47da3760fceac0bdb179d9f743cb7f90c2f02490 (diff) | |
download | FreeBSD-src-c560f15fa85ae389cef41cccd341e86818691111.zip FreeBSD-src-c560f15fa85ae389cef41cccd341e86818691111.tar.gz |
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
-rw-r--r-- | sys/cddl/dev/dtrace/arm/dtrace_isa.c | 119 | ||||
-rw-r--r-- | sys/conf/files.arm | 2 |
2 files changed, 30 insertions, 91 deletions
diff --git a/sys/cddl/dev/dtrace/arm/dtrace_isa.c b/sys/cddl/dev/dtrace/arm/dtrace_isa.c index 7d3dc2e..14adb4c 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 diff --git a/sys/conf/files.arm b/sys/conf/files.arm index 7fbccd1..9556e50 100644 --- a/sys/conf/files.arm +++ b/sys/conf/files.arm @@ -57,7 +57,7 @@ arm/arm/trap.c optional !armv6 arm/arm/trap-v6.c optional armv6 arm/arm/uio_machdep.c standard arm/arm/undefined.c standard -arm/arm/unwind.c optional ddb +arm/arm/unwind.c optional ddb | kdtrace_hooks arm/arm/vm_machdep.c standard arm/arm/vfp.c standard board_id.h standard \ |