From 1df0f0ff7e56f6dcb1351b9490d55ebf91ff4bd8 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Tue, 26 Sep 2006 23:44:01 +0900 Subject: [MIPS] lockdep: Add STACKTRACE_SUPPORT and enable LOCKDEP_SUPPORT Implement stacktrace interface by using unwind_stack() and enable lockdep support in Kconfig. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/kernel/stacktrace.c | 111 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 arch/mips/kernel/stacktrace.c (limited to 'arch/mips/kernel/stacktrace.c') diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c new file mode 100644 index 000000000000..f851d0cc245f --- /dev/null +++ b/arch/mips/kernel/stacktrace.c @@ -0,0 +1,111 @@ +/* + * arch/mips/kernel/stacktrace.c + * + * Stack trace management functions + * + * Copyright (C) 2006 Atsushi Nemoto + */ +#include +#include +#include + +/* + * Save stack-backtrace addresses into a stack_trace buffer: + */ +static void save_raw_context_stack(struct stack_trace *trace, + unsigned int skip, unsigned long reg29) +{ + unsigned long *sp = (unsigned long *)reg29; + unsigned long addr; + + while (!kstack_end(sp)) { + addr = *sp++; + if (__kernel_text_address(addr)) { + if (!skip) + trace->entries[trace->nr_entries++] = addr; + else + skip--; + if (trace->nr_entries >= trace->max_entries) + break; + } + } +} + +static struct pt_regs * save_context_stack(struct stack_trace *trace, + unsigned int skip, struct task_struct *task, struct pt_regs *regs) +{ + unsigned long sp = regs->regs[29]; +#ifdef CONFIG_KALLSYMS + unsigned long ra = regs->regs[31]; + unsigned long pc = regs->cp0_epc; + extern void ret_from_irq(void); + + if (raw_show_trace || !__kernel_text_address(pc)) { + save_raw_context_stack(trace, skip, sp); + return NULL; + } + do { + if (!skip) + trace->entries[trace->nr_entries++] = pc; + else + skip--; + if (trace->nr_entries >= trace->max_entries) + break; + /* + * If we reached the bottom of interrupt context, + * return saved pt_regs. + */ + if (pc == (unsigned long)ret_from_irq) { + unsigned long stack_page = + (unsigned long)task_stack_page(task); + if (!stack_page || + sp < stack_page || + sp > stack_page + THREAD_SIZE - 32) + break; + return (struct pt_regs *)sp; + } + pc = unwind_stack(task, &sp, pc, ra); + ra = 0; + } while (pc); +#else + save_raw_context_stack(sp); +#endif + + return NULL; +} + +/* + * Save stack-backtrace addresses into a stack_trace buffer. + * If all_contexts is set, all contexts (hardirq, softirq and process) + * are saved. If not set then only the current context is saved. + */ +void save_stack_trace(struct stack_trace *trace, + struct task_struct *task, int all_contexts, + unsigned int skip) +{ + struct pt_regs dummyregs; + struct pt_regs *regs = &dummyregs; + + WARN_ON(trace->nr_entries || !trace->max_entries); + + if (task && task != current) { + regs->regs[29] = task->thread.reg29; + regs->regs[31] = 0; + regs->cp0_epc = task->thread.reg31; + } else { + if (!task) + task = current; + prepare_frametrace(regs); + } + + while (1) { + regs = save_context_stack(trace, skip, task, regs); + if (!all_contexts || !regs || + trace->nr_entries >= trace->max_entries) + break; + trace->entries[trace->nr_entries++] = ULONG_MAX; + if (trace->nr_entries >= trace->max_entries) + break; + skip = 0; + } +} -- cgit v1.2.2 From 23126692e30ec22760e0ef932c3c2fff00d440bb Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Thu, 28 Sep 2006 19:15:33 +0900 Subject: [MIPS] Stacktrace build-fix and improvement Fix build error due to stacktrace API change. Now save_stack_trace() tries to save all kernel context, including interrupts and exception. Also some asm code are changed a bit so that we can detect the end of current context easily. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/kernel/stacktrace.c | 52 +++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 29 deletions(-) (limited to 'arch/mips/kernel/stacktrace.c') diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c index f851d0cc245f..676e6f69d24b 100644 --- a/arch/mips/kernel/stacktrace.c +++ b/arch/mips/kernel/stacktrace.c @@ -13,7 +13,7 @@ * Save stack-backtrace addresses into a stack_trace buffer: */ static void save_raw_context_stack(struct stack_trace *trace, - unsigned int skip, unsigned long reg29) + unsigned long reg29) { unsigned long *sp = (unsigned long *)reg29; unsigned long addr; @@ -21,10 +21,10 @@ static void save_raw_context_stack(struct stack_trace *trace, while (!kstack_end(sp)) { addr = *sp++; if (__kernel_text_address(addr)) { - if (!skip) - trace->entries[trace->nr_entries++] = addr; + if (trace->skip > 0) + trace->skip--; else - skip--; + trace->entries[trace->nr_entries++] = addr; if (trace->nr_entries >= trace->max_entries) break; } @@ -32,37 +32,40 @@ static void save_raw_context_stack(struct stack_trace *trace, } static struct pt_regs * save_context_stack(struct stack_trace *trace, - unsigned int skip, struct task_struct *task, struct pt_regs *regs) + struct task_struct *task, struct pt_regs *regs) { unsigned long sp = regs->regs[29]; #ifdef CONFIG_KALLSYMS unsigned long ra = regs->regs[31]; unsigned long pc = regs->cp0_epc; + unsigned long stack_page = + (unsigned long)task_stack_page(task); extern void ret_from_irq(void); + extern void ret_from_exception(void); if (raw_show_trace || !__kernel_text_address(pc)) { - save_raw_context_stack(trace, skip, sp); + if (stack_page && sp >= stack_page && + sp <= stack_page + THREAD_SIZE - 32) + save_raw_context_stack(trace, sp); return NULL; } do { - if (!skip) - trace->entries[trace->nr_entries++] = pc; + if (trace->skip > 0) + trace->skip--; else - skip--; + trace->entries[trace->nr_entries++] = pc; if (trace->nr_entries >= trace->max_entries) break; /* * If we reached the bottom of interrupt context, * return saved pt_regs. */ - if (pc == (unsigned long)ret_from_irq) { - unsigned long stack_page = - (unsigned long)task_stack_page(task); - if (!stack_page || - sp < stack_page || - sp > stack_page + THREAD_SIZE - 32) - break; - return (struct pt_regs *)sp; + if (pc == (unsigned long)ret_from_irq || + pc == (unsigned long)ret_from_exception) { + if (stack_page && sp >= stack_page && + sp <= stack_page + THREAD_SIZE - 32) + return (struct pt_regs *)sp; + break; } pc = unwind_stack(task, &sp, pc, ra); ra = 0; @@ -76,12 +79,8 @@ static struct pt_regs * save_context_stack(struct stack_trace *trace, /* * Save stack-backtrace addresses into a stack_trace buffer. - * If all_contexts is set, all contexts (hardirq, softirq and process) - * are saved. If not set then only the current context is saved. */ -void save_stack_trace(struct stack_trace *trace, - struct task_struct *task, int all_contexts, - unsigned int skip) +void save_stack_trace(struct stack_trace *trace, struct task_struct *task) { struct pt_regs dummyregs; struct pt_regs *regs = &dummyregs; @@ -99,13 +98,8 @@ void save_stack_trace(struct stack_trace *trace, } while (1) { - regs = save_context_stack(trace, skip, task, regs); - if (!all_contexts || !regs || - trace->nr_entries >= trace->max_entries) - break; - trace->entries[trace->nr_entries++] = ULONG_MAX; - if (trace->nr_entries >= trace->max_entries) + regs = save_context_stack(trace, task, regs); + if (!regs || trace->nr_entries >= trace->max_entries) break; - skip = 0; } } -- cgit v1.2.2 From 1924600cdb3143cdcc32b6fa43325739503659b9 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Fri, 29 Sep 2006 18:02:51 +0900 Subject: [MIPS] Make unwind_stack() can dig into interrupted context If the PC was ret_from_irq or ret_from_exception, there will be no more normal stackframe. Instead of stopping the unwinding, use PC and RA saved by an exception handler to continue unwinding into the interrupted context. This also simplifies the CONFIG_STACKTRACE code. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/kernel/stacktrace.c | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) (limited to 'arch/mips/kernel/stacktrace.c') diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c index 676e6f69d24b..4aabe526a68e 100644 --- a/arch/mips/kernel/stacktrace.c +++ b/arch/mips/kernel/stacktrace.c @@ -31,23 +31,21 @@ static void save_raw_context_stack(struct stack_trace *trace, } } -static struct pt_regs * save_context_stack(struct stack_trace *trace, +static void save_context_stack(struct stack_trace *trace, struct task_struct *task, struct pt_regs *regs) { unsigned long sp = regs->regs[29]; #ifdef CONFIG_KALLSYMS unsigned long ra = regs->regs[31]; unsigned long pc = regs->cp0_epc; - unsigned long stack_page = - (unsigned long)task_stack_page(task); - extern void ret_from_irq(void); - extern void ret_from_exception(void); if (raw_show_trace || !__kernel_text_address(pc)) { + unsigned long stack_page = + (unsigned long)task_stack_page(task); if (stack_page && sp >= stack_page && sp <= stack_page + THREAD_SIZE - 32) save_raw_context_stack(trace, sp); - return NULL; + return; } do { if (trace->skip > 0) @@ -56,25 +54,11 @@ static struct pt_regs * save_context_stack(struct stack_trace *trace, trace->entries[trace->nr_entries++] = pc; if (trace->nr_entries >= trace->max_entries) break; - /* - * If we reached the bottom of interrupt context, - * return saved pt_regs. - */ - if (pc == (unsigned long)ret_from_irq || - pc == (unsigned long)ret_from_exception) { - if (stack_page && sp >= stack_page && - sp <= stack_page + THREAD_SIZE - 32) - return (struct pt_regs *)sp; - break; - } - pc = unwind_stack(task, &sp, pc, ra); - ra = 0; + pc = unwind_stack(task, &sp, pc, &ra); } while (pc); #else save_raw_context_stack(sp); #endif - - return NULL; } /* @@ -97,9 +81,5 @@ void save_stack_trace(struct stack_trace *trace, struct task_struct *task) prepare_frametrace(regs); } - while (1) { - regs = save_context_stack(trace, task, regs); - if (!regs || trace->nr_entries >= trace->max_entries) - break; - } + save_context_stack(trace, task, regs); } -- cgit v1.2.2