aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel
diff options
context:
space:
mode:
authorKen Chen <kenchen@google.com>2008-11-10 03:26:08 -0500
committerAlexey Dobriyan <adobriyan@gmail.com>2009-01-05 04:27:44 -0500
commit2ec220e27f5040aec1e88901c1b6ea3d135787ad (patch)
tree06ed111c8e331d47927d9b46386f4063b74ec419 /arch/mips/kernel
parent631f9c1868b970197747c80fc5168ad7d9fd5d53 (diff)
proc: add /proc/*/stack
/proc/*/stack adds the ability to query a task's stack trace. It is more useful than /proc/*/wchan as it provides full stack trace instead of single depth. Example output: $ cat /proc/self/stack [<c010a271>] save_stack_trace_tsk+0x17/0x35 [<c01827b4>] proc_pid_stack+0x4a/0x76 [<c018312d>] proc_single_show+0x4a/0x5e [<c016bdec>] seq_read+0xf3/0x29f [<c015a004>] vfs_read+0x6d/0x91 [<c015a0c1>] sys_read+0x3b/0x60 [<c0102eda>] syscall_call+0x7/0xb [<ffffffff>] 0xffffffff [add save_stack_trace_tsk() on mips, ACK Ralf --adobriyan] Signed-off-by: Ken Chen <kenchen@google.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/stacktrace.c24
1 files changed, 18 insertions, 6 deletions
diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c
index 0632e2a849c0..58f5cd76c8c3 100644
--- a/arch/mips/kernel/stacktrace.c
+++ b/arch/mips/kernel/stacktrace.c
@@ -32,7 +32,8 @@ static void save_raw_context_stack(struct stack_trace *trace,
32 } 32 }
33} 33}
34 34
35static void save_context_stack(struct stack_trace *trace, struct pt_regs *regs) 35static void save_context_stack(struct stack_trace *trace,
36 struct task_struct *tsk, struct pt_regs *regs)
36{ 37{
37 unsigned long sp = regs->regs[29]; 38 unsigned long sp = regs->regs[29];
38#ifdef CONFIG_KALLSYMS 39#ifdef CONFIG_KALLSYMS
@@ -41,7 +42,7 @@ static void save_context_stack(struct stack_trace *trace, struct pt_regs *regs)
41 42
42 if (raw_show_trace || !__kernel_text_address(pc)) { 43 if (raw_show_trace || !__kernel_text_address(pc)) {
43 unsigned long stack_page = 44 unsigned long stack_page =
44 (unsigned long)task_stack_page(current); 45 (unsigned long)task_stack_page(tsk);
45 if (stack_page && sp >= stack_page && 46 if (stack_page && sp >= stack_page &&
46 sp <= stack_page + THREAD_SIZE - 32) 47 sp <= stack_page + THREAD_SIZE - 32)
47 save_raw_context_stack(trace, sp); 48 save_raw_context_stack(trace, sp);
@@ -54,7 +55,7 @@ static void save_context_stack(struct stack_trace *trace, struct pt_regs *regs)
54 trace->entries[trace->nr_entries++] = pc; 55 trace->entries[trace->nr_entries++] = pc;
55 if (trace->nr_entries >= trace->max_entries) 56 if (trace->nr_entries >= trace->max_entries)
56 break; 57 break;
57 pc = unwind_stack(current, &sp, pc, &ra); 58 pc = unwind_stack(tsk, &sp, pc, &ra);
58 } while (pc); 59 } while (pc);
59#else 60#else
60 save_raw_context_stack(trace, sp); 61 save_raw_context_stack(trace, sp);
@@ -66,12 +67,23 @@ static void save_context_stack(struct stack_trace *trace, struct pt_regs *regs)
66 */ 67 */
67void save_stack_trace(struct stack_trace *trace) 68void save_stack_trace(struct stack_trace *trace)
68{ 69{
70 save_stack_trace_tsk(current, trace);
71}
72EXPORT_SYMBOL_GPL(save_stack_trace);
73
74void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
75{
69 struct pt_regs dummyregs; 76 struct pt_regs dummyregs;
70 struct pt_regs *regs = &dummyregs; 77 struct pt_regs *regs = &dummyregs;
71 78
72 WARN_ON(trace->nr_entries || !trace->max_entries); 79 WARN_ON(trace->nr_entries || !trace->max_entries);
73 80
74 prepare_frametrace(regs); 81 if (tsk != current) {
75 save_context_stack(trace, regs); 82 regs->regs[29] = tsk->thread.reg29;
83 regs->regs[31] = 0;
84 regs->cp0_epc = tsk->thread.reg31;
85 } else
86 prepare_frametrace(regs);
87 save_context_stack(trace, tsk, regs);
76} 88}
77EXPORT_SYMBOL_GPL(save_stack_trace); 89EXPORT_SYMBOL_GPL(save_stack_trace_tsk);