diff options
| author | Ken Chen <kenchen@google.com> | 2008-11-10 11:26:08 +0300 | 
|---|---|---|
| committer | Alexey Dobriyan <adobriyan@gmail.com> | 2009-01-05 12:27:44 +0300 | 
| commit | 2ec220e27f5040aec1e88901c1b6ea3d135787ad (patch) | |
| tree | 06ed111c8e331d47927d9b46386f4063b74ec419 | |
| parent | 631f9c1868b970197747c80fc5168ad7d9fd5d53 (diff) | |
| download | olio-linux-3.10-2ec220e27f5040aec1e88901c1b6ea3d135787ad.tar.xz olio-linux-3.10-2ec220e27f5040aec1e88901c1b6ea3d135787ad.zip  | |
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>
| -rw-r--r-- | Documentation/filesystems/proc.txt | 1 | ||||
| -rw-r--r-- | arch/mips/kernel/stacktrace.c | 24 | ||||
| -rw-r--r-- | fs/proc/base.c | 38 | 
3 files changed, 57 insertions, 6 deletions
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index 71df353e367..334ef2f983f 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -140,6 +140,7 @@ Table 1-1: Process specific entries in /proc   statm		Process memory status information   status		Process status in human readable form   wchan		If CONFIG_KALLSYMS is set, a pre-decoded wchan + stack		Report full stack trace, enable via CONFIG_STACKTRACE   smaps		Extension based on maps, the rss size for each mapped file  .............................................................................. diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c index 0632e2a849c..58f5cd76c8c 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,  	}  } -static void save_context_stack(struct stack_trace *trace, struct pt_regs *regs) +static void save_context_stack(struct stack_trace *trace, +	struct task_struct *tsk, struct pt_regs *regs)  {  	unsigned long sp = regs->regs[29];  #ifdef CONFIG_KALLSYMS @@ -41,7 +42,7 @@ static void save_context_stack(struct stack_trace *trace, struct pt_regs *regs)  	if (raw_show_trace || !__kernel_text_address(pc)) {  		unsigned long stack_page = -			(unsigned long)task_stack_page(current); +			(unsigned long)task_stack_page(tsk);  		if (stack_page && sp >= stack_page &&  		    sp <= stack_page + THREAD_SIZE - 32)  			save_raw_context_stack(trace, sp); @@ -54,7 +55,7 @@ static void save_context_stack(struct stack_trace *trace, struct pt_regs *regs)  			trace->entries[trace->nr_entries++] = pc;  		if (trace->nr_entries >= trace->max_entries)  			break; -		pc = unwind_stack(current, &sp, pc, &ra); +		pc = unwind_stack(tsk, &sp, pc, &ra);  	} while (pc);  #else  	save_raw_context_stack(trace, sp); @@ -66,12 +67,23 @@ static void save_context_stack(struct stack_trace *trace, struct pt_regs *regs)   */  void save_stack_trace(struct stack_trace *trace)  { +	save_stack_trace_tsk(current, trace); +} +EXPORT_SYMBOL_GPL(save_stack_trace); + +void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) +{  	struct pt_regs dummyregs;  	struct pt_regs *regs = &dummyregs;  	WARN_ON(trace->nr_entries || !trace->max_entries); -	prepare_frametrace(regs); -	save_context_stack(trace, regs); +	if (tsk != current) { +		regs->regs[29] = tsk->thread.reg29; +		regs->regs[31] = 0; +		regs->cp0_epc = tsk->thread.reg31; +	} else +		prepare_frametrace(regs); +	save_context_stack(trace, tsk, regs);  } -EXPORT_SYMBOL_GPL(save_stack_trace); +EXPORT_SYMBOL_GPL(save_stack_trace_tsk); diff --git a/fs/proc/base.c b/fs/proc/base.c index ce7a6da1b6a..eb7b4654d6a 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -65,6 +65,7 @@  #include <linux/mm.h>  #include <linux/rcupdate.h>  #include <linux/kallsyms.h> +#include <linux/stacktrace.h>  #include <linux/resource.h>  #include <linux/module.h>  #include <linux/mount.h> @@ -337,6 +338,37 @@ static int proc_pid_wchan(struct task_struct *task, char *buffer)  }  #endif /* CONFIG_KALLSYMS */ +#ifdef CONFIG_STACKTRACE + +#define MAX_STACK_TRACE_DEPTH	64 + +static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns, +			  struct pid *pid, struct task_struct *task) +{ +	struct stack_trace trace; +	unsigned long *entries; +	int i; + +	entries = kmalloc(MAX_STACK_TRACE_DEPTH * sizeof(*entries), GFP_KERNEL); +	if (!entries) +		return -ENOMEM; + +	trace.nr_entries	= 0; +	trace.max_entries	= MAX_STACK_TRACE_DEPTH; +	trace.entries		= entries; +	trace.skip		= 0; +	save_stack_trace_tsk(task, &trace); + +	for (i = 0; i < trace.nr_entries; i++) { +		seq_printf(m, "[<%p>] %pS\n", +			   (void *)entries[i], (void *)entries[i]); +	} +	kfree(entries); + +	return 0; +} +#endif +  #ifdef CONFIG_SCHEDSTATS  /*   * Provides /proc/PID/schedstat @@ -2500,6 +2532,9 @@ static const struct pid_entry tgid_base_stuff[] = {  #ifdef CONFIG_KALLSYMS  	INF("wchan",      S_IRUGO, proc_pid_wchan),  #endif +#ifdef CONFIG_STACKTRACE +	ONE("stack",      S_IRUSR, proc_pid_stack), +#endif  #ifdef CONFIG_SCHEDSTATS  	INF("schedstat",  S_IRUGO, proc_pid_schedstat),  #endif @@ -2835,6 +2870,9 @@ static const struct pid_entry tid_base_stuff[] = {  #ifdef CONFIG_KALLSYMS  	INF("wchan",     S_IRUGO, proc_pid_wchan),  #endif +#ifdef CONFIG_STACKTRACE +	ONE("stack",      S_IRUSR, proc_pid_stack), +#endif  #ifdef CONFIG_SCHEDSTATS  	INF("schedstat", S_IRUGO, proc_pid_schedstat),  #endif  |