From: David Mosberger <davidm@napali.hpl.hp.com>

This is an attempt at sanitizing the interface for stack trace dumping
somewhat.  Here is the rationale: modern calling conventions don't maintain
a frame pointer and it's not possible to get a reliable stack trace with
only a stack pointer as the starting point.  You really need more machine
state to start with.  For a while, I thought the solution is to pass a task
pointer to show_stack(), but it turns out that this would negatively impact
x86 because it's sometimes useful to show only portions of a stack trace
(e.g., starting from the point at which a trap occurred).  Thus, this patch
_adds_ the task pointer instead:

 extern void show_stack(struct task_struct *tsk, unsigned long *sp);

The idea here is that show_stack(tsk, sp) will show the backtrace of task
"tsk", starting from the stack frame that "sp" is pointing to.  If tsk is
NULL, the trace will be for the current task.  If "sp" is NULL, all stack
frames of the task are shown.  If both are NULL, you'll get the full trace
of the current task.

I _think_ this should make everyone happy.

The patch also removes the declaration of show_trace() in linux/sched.h (it
never was a generic function; some platforms, in particular x86, may want
to update accordingly).

Finally, the patch replaces the one call to show_trace_task() with the
equivalent call show_stack(task, NULL).

The patch below is for Alpha and i386, since I can (compile-)test those
(I'll provide the ia64 update through my regular updates).  The other
arches will break visibly and updating the code should be trivial:

- add a task pointer argument to show_stack() and pass NULL as the first
  argument where needed

- remove show_trace_task()

- declare show_trace() in a platform-specific header file if you really
  want to keep it around



 arch/alpha/kernel/traps.c    |    4 ++--
 arch/i386/kernel/process.c   |    2 +-
 arch/i386/kernel/traps.c     |   14 +++++++-------
 include/asm-i386/processor.h |    1 +
 include/linux/sched.h        |    9 +++++++--
 kernel/sched.c               |    5 +----
 6 files changed, 19 insertions(+), 16 deletions(-)

diff -puN arch/alpha/kernel/traps.c~show_stack-cleanup arch/alpha/kernel/traps.c
--- 25/arch/alpha/kernel/traps.c~show_stack-cleanup	2003-06-14 14:51:46.000000000 -0700
+++ 25-akpm/arch/alpha/kernel/traps.c	2003-06-14 14:51:46.000000000 -0700
@@ -148,7 +148,7 @@ void show_trace_task(struct task_struct 
 
 static int kstack_depth_to_print = 24;
 
-void show_stack(unsigned long *sp)
+void show_stack(struct task_struct *task, unsigned long *sp)
 {
 	unsigned long *stack;
 	int i;
@@ -174,7 +174,7 @@ void show_stack(unsigned long *sp)
 
 void dump_stack(void)
 {
-	show_stack(NULL);
+	show_stack(NULL, NULL);
 }
 
 void
diff -puN arch/i386/kernel/process.c~show_stack-cleanup arch/i386/kernel/process.c
--- 25/arch/i386/kernel/process.c~show_stack-cleanup	2003-06-14 14:51:46.000000000 -0700
+++ 25-akpm/arch/i386/kernel/process.c	2003-06-14 14:51:46.000000000 -0700
@@ -190,7 +190,7 @@ void show_regs(struct pt_regs * regs)
 		".previous			\n"
 		: "=r" (cr4): "0" (0));
 	printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4);
-	show_trace(&regs->esp);
+	show_trace(NULL, &regs->esp);
 }
 
 /*
diff -puN arch/i386/kernel/traps.c~show_stack-cleanup arch/i386/kernel/traps.c
--- 25/arch/i386/kernel/traps.c~show_stack-cleanup	2003-06-14 14:51:46.000000000 -0700
+++ 25-akpm/arch/i386/kernel/traps.c	2003-06-14 14:51:46.000000000 -0700
@@ -32,9 +32,9 @@
 
 #ifdef CONFIG_MCA
 #include <linux/mca.h>
-#include <asm/processor.h>
 #endif
 
+#include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -128,7 +128,7 @@ void breakpoint(void)
 
 static int kstack_depth_to_print = 24;
 
-void show_trace(unsigned long * stack)
+void show_trace(struct task_struct *task, unsigned long * stack)
 {
 	int i;
 	unsigned long addr;
@@ -158,10 +158,10 @@ void show_trace_task(struct task_struct 
 	/* User space on another CPU? */
 	if ((esp ^ (unsigned long)tsk->thread_info) & (PAGE_MASK<<1))
 		return;
-	show_trace((unsigned long *)esp);
+	show_trace(tsk, (unsigned long *)esp);
 }
 
-void show_stack(unsigned long * esp)
+void show_stack(struct task_struct *task, unsigned long * esp)
 {
 	unsigned long *stack;
 	int i;
@@ -181,7 +181,7 @@ void show_stack(unsigned long * esp)
 		printk("%08lx ", *stack++);
 	}
 	printk("\n");
-	show_trace(esp);
+	show_trace(task, esp);
 }
 
 /*
@@ -191,7 +191,7 @@ void dump_stack(void)
 {
 	unsigned long stack;
 
-	show_trace(&stack);
+	show_trace(current, &stack);
 }
 
 void show_registers(struct pt_regs *regs)
@@ -228,7 +228,7 @@ void show_registers(struct pt_regs *regs
 	if (in_kernel) {
 
 		printk("\nStack: ");
-		show_stack((unsigned long*)esp);
+		show_stack(NULL, (unsigned long*)esp);
 
 		printk("Code: ");
 		if(regs->eip < PAGE_OFFSET)
diff -puN include/linux/sched.h~show_stack-cleanup include/linux/sched.h
--- 25/include/linux/sched.h~show_stack-cleanup	2003-06-14 14:51:46.000000000 -0700
+++ 25-akpm/include/linux/sched.h	2003-06-14 14:51:46.000000000 -0700
@@ -148,10 +148,15 @@ extern void sched_init(void);
 extern void init_idle(task_t *idle, int cpu);
 
 extern void show_state(void);
-extern void show_trace(unsigned long *stack);
-extern void show_stack(unsigned long *stack);
 extern void show_regs(struct pt_regs *);
 
+/*
+ * TASK is a pointer to the task whose backtrace we want to see (or NULL for current
+ * task), SP is the stack pointer of the first frame that should be shown in the back
+ * trace (or NULL if the entire call-chain of the task should be shown).
+ */
+extern void show_stack(struct task_struct *task, unsigned long *sp);
+
 void io_schedule(void);
 long io_schedule_timeout(long timeout);
 
diff -puN kernel/sched.c~show_stack-cleanup kernel/sched.c
--- 25/kernel/sched.c~show_stack-cleanup	2003-06-14 14:51:46.000000000 -0700
+++ 25-akpm/kernel/sched.c	2003-06-14 14:51:46.000000000 -0700
@@ -2189,10 +2189,7 @@ static void show_task(task_t * p)
 	else
 		printk(" (NOTLB)\n");
 
-	{
-		extern void show_trace_task(task_t *tsk);
-		show_trace_task(p);
-	}
+	show_stack(p, NULL);
 }
 
 void show_state(void)
diff -puN include/asm-i386/processor.h~show_stack-cleanup include/asm-i386/processor.h
--- 25/include/asm-i386/processor.h~show_stack-cleanup	2003-06-14 14:51:46.000000000 -0700
+++ 25-akpm/include/asm-i386/processor.h	2003-06-14 14:51:46.000000000 -0700
@@ -472,6 +472,7 @@ extern void prepare_to_copy(struct task_
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 extern unsigned long thread_saved_pc(struct task_struct *tsk);
+void show_trace(struct task_struct *task, unsigned long *stack);
 
 unsigned long get_wchan(struct task_struct *p);
 #define KSTK_EIP(tsk)	(((unsigned long *)(4096+(unsigned long)(tsk)->thread_info))[1019])

_