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>
This commit is contained in:
Steven J. Magnani
2010-04-27 12:37:54 -05:00
committed by Michal Simek
parent ba9c4f88d7
commit ce3266c047
10 changed files with 454 additions and 95 deletions
+5 -39
View File
@@ -14,52 +14,18 @@
#include <linux/thread_info.h>
#include <linux/ptrace.h>
#include <linux/module.h>
#include <asm/unwind.h>
/* FIXME initial support */
void save_stack_trace(struct stack_trace *trace)
{
unsigned long *sp;
unsigned long addr;
asm("addik %0, r1, 0" : "=r" (sp));
while (!kstack_end(sp)) {
addr = *sp++;
if (__kernel_text_address(addr)) {
if (trace->skip > 0)
trace->skip--;
else
trace->entries[trace->nr_entries++] = addr;
if (trace->nr_entries >= trace->max_entries)
break;
}
}
/* Exclude our helper functions from the trace*/
trace->skip += 2;
microblaze_unwind(NULL, trace);
}
EXPORT_SYMBOL_GPL(save_stack_trace);
void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
{
unsigned int *sp;
unsigned long addr;
struct thread_info *ti = task_thread_info(tsk);
if (tsk == current)
asm("addik %0, r1, 0" : "=r" (sp));
else
sp = (unsigned int *)ti->cpu_context.r1;
while (!kstack_end(sp)) {
addr = *sp++;
if (__kernel_text_address(addr)) {
if (trace->skip > 0)
trace->skip--;
else
trace->entries[trace->nr_entries++] = addr;
if (trace->nr_entries >= trace->max_entries)
break;
}
}
microblaze_unwind(tsk, trace);
}
EXPORT_SYMBOL_GPL(save_stack_trace_tsk);