diff options
| author | Steven J. Magnani <steve@digidescorp.com> | 2010-04-27 13:37:54 -0400 |
|---|---|---|
| committer | Michal Simek <monstr@monstr.eu> | 2010-08-04 04:22:35 -0400 |
| commit | ce3266c047389443d5f433d605c769e878cbe46e (patch) | |
| tree | e638a255d5d0f1b000a81b512dc605b92d0b8701 /arch/microblaze/kernel/stacktrace.c | |
| parent | ba9c4f88d747836bf35c3eee36aa18d2e164f493 (diff) | |
microblaze: Add stack unwinder
Implement intelligent backtracing by searching for stack frame creation,
and emitting only return addresses. Use print_hex_dump() to display the
entire binary kernel stack.
Limitation: MMU kernels are not currently able to trace beyond a system trap
(interrupt, syscall, etc.). It is the intent of this patch to provide
infrastructure that can be extended to add this capability later.
Changes from V1:
* Removed checks in find_frame_creation() that prevented location of the frame
creation instruction in heavily optimized code
* Various formatting/commenting/file location tweaks per review comments
* Dropped Kconfig option to enable STACKTRACE as something logically separate
Signed-off-by: Steven J. Magnani <steve@digidescorp.com>
Diffstat (limited to 'arch/microblaze/kernel/stacktrace.c')
| -rw-r--r-- | arch/microblaze/kernel/stacktrace.c | 44 |
1 files changed, 5 insertions, 39 deletions
diff --git a/arch/microblaze/kernel/stacktrace.c b/arch/microblaze/kernel/stacktrace.c index 123692f22647..84bc6686102c 100644 --- a/arch/microblaze/kernel/stacktrace.c +++ b/arch/microblaze/kernel/stacktrace.c | |||
| @@ -14,52 +14,18 @@ | |||
| 14 | #include <linux/thread_info.h> | 14 | #include <linux/thread_info.h> |
| 15 | #include <linux/ptrace.h> | 15 | #include <linux/ptrace.h> |
| 16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <asm/unwind.h> | ||
| 17 | 18 | ||
| 18 | /* FIXME initial support */ | ||
| 19 | void save_stack_trace(struct stack_trace *trace) | 19 | void save_stack_trace(struct stack_trace *trace) |
| 20 | { | 20 | { |
| 21 | unsigned long *sp; | 21 | /* Exclude our helper functions from the trace*/ |
| 22 | unsigned long addr; | 22 | trace->skip += 2; |
| 23 | asm("addik %0, r1, 0" : "=r" (sp)); | 23 | microblaze_unwind(NULL, trace); |
| 24 | |||
| 25 | while (!kstack_end(sp)) { | ||
| 26 | addr = *sp++; | ||
| 27 | if (__kernel_text_address(addr)) { | ||
| 28 | if (trace->skip > 0) | ||
| 29 | trace->skip--; | ||
| 30 | else | ||
| 31 | trace->entries[trace->nr_entries++] = addr; | ||
| 32 | |||
| 33 | if (trace->nr_entries >= trace->max_entries) | ||
| 34 | break; | ||
| 35 | } | ||
| 36 | } | ||
| 37 | } | 24 | } |
| 38 | EXPORT_SYMBOL_GPL(save_stack_trace); | 25 | EXPORT_SYMBOL_GPL(save_stack_trace); |
| 39 | 26 | ||
| 40 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | 27 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) |
| 41 | { | 28 | { |
| 42 | unsigned int *sp; | 29 | microblaze_unwind(tsk, trace); |
| 43 | unsigned long addr; | ||
| 44 | |||
| 45 | struct thread_info *ti = task_thread_info(tsk); | ||
| 46 | |||
| 47 | if (tsk == current) | ||
| 48 | asm("addik %0, r1, 0" : "=r" (sp)); | ||
| 49 | else | ||
| 50 | sp = (unsigned int *)ti->cpu_context.r1; | ||
| 51 | |||
| 52 | while (!kstack_end(sp)) { | ||
| 53 | addr = *sp++; | ||
| 54 | if (__kernel_text_address(addr)) { | ||
| 55 | if (trace->skip > 0) | ||
| 56 | trace->skip--; | ||
| 57 | else | ||
| 58 | trace->entries[trace->nr_entries++] = addr; | ||
| 59 | |||
| 60 | if (trace->nr_entries >= trace->max_entries) | ||
| 61 | break; | ||
| 62 | } | ||
| 63 | } | ||
| 64 | } | 30 | } |
| 65 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); | 31 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); |
