]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] show_stack() portability and cleanup patch
authorAndrew Morton <akpm@digeo.com>
Fri, 20 Jun 2003 15:13:46 +0000 (08:13 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Fri, 20 Jun 2003 15:13:46 +0000 (08:13 -0700)
From: David Mosberger <davidm@napali.hpl.hp.com>

This is an attempt at sanitizing the interface for stack trace dumping
somewhat.  It's basically the last thing which prevents 2.5.x from working
out-of-the-box for ia64.  ia64 apparently cannot reasonably implement the
show_stack interface declared in sched.h.

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
arch/i386/kernel/process.c
arch/i386/kernel/traps.c
arch/ppc64/kernel/process.c
include/asm-i386/processor.h
include/linux/sched.h
kernel/sched.c

index ddea651cb87e4c8645e620d53c8d272e31c60c0e..412cd3672573e88319772458e3edb1a1c0fb34ea 100644 (file)
@@ -148,7 +148,7 @@ void show_trace_task(struct task_struct * tsk)
 
 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
index 8cb6adb50b8aa1d253c11161f48b66d05baad76b..61bc3326e287be6545ec682537df8cd6e3c4d98b 100644 (file)
@@ -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);
 }
 
 /*
index c6bc1936f45bdcf5acbb9c1d1addb06a442f2c49..7fcedfd5cc4b5428e488c2b0e6fdc3838a6ec1bf 100644 (file)
@@ -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>
@@ -92,7 +92,7 @@ asmlinkage void machine_check(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;
@@ -122,10 +122,10 @@ void show_trace_task(struct task_struct *tsk)
        /* 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;
@@ -145,7 +145,7 @@ void show_stack(unsigned long * esp)
                printk("%08lx ", *stack++);
        }
        printk("\n");
-       show_trace(esp);
+       show_trace(task, esp);
 }
 
 /*
@@ -155,7 +155,7 @@ void dump_stack(void)
 {
        unsigned long stack;
 
-       show_trace(&stack);
+       show_trace(current, &stack);
 }
 
 void show_registers(struct pt_regs *regs)
@@ -192,7 +192,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)
index 949425d44cb33ab22f5998364c97f5ef0f603c21..c22a54fe544f652c874be483ebedb985d623fd01 100644 (file)
@@ -129,7 +129,6 @@ struct task_struct *__switch_to(struct task_struct *prev,
        return last;
 }
 
-static void show_tsk_stack(struct task_struct *p, unsigned long sp);
 char *ppc_find_proc_name(unsigned *p, char *buf, unsigned buflen);
 
 void show_regs(struct pt_regs * regs)
@@ -172,7 +171,7 @@ void show_regs(struct pt_regs * regs)
        printk("NIP [%016lx] ", regs->nip);
        printk("%s\n", ppc_find_proc_name((unsigned *)regs->nip,
               name_buf, 256));
-       show_tsk_stack(current, regs->gpr[1]);
+       show_stack(current, (unsigned long *)regs->gpr[1]);
 }
 
 void exit_thread(void)
@@ -517,22 +516,26 @@ unsigned long get_wchan(struct task_struct *p)
        return 0;
 }
 
-static void show_tsk_stack(struct task_struct *p, unsigned long sp)
+void show_stack(struct task_struct *p, unsigned long *_sp)
 {
        unsigned long ip;
        unsigned long stack_page = (unsigned long)p->thread_info;
        int count = 0;
        char name_buf[256];
+       unsigned long sp = (unsigned long)_sp;
 
        if (!p)
                return;
 
+       if (sp == 0)
+               sp = p->thread.ksp;
        printk("Call Trace:\n");
        do {
                if (__get_user(sp, (unsigned long *)sp))
                        break;
-               if (sp < (stack_page + sizeof(struct thread_struct)) ||
-                   sp >= (stack_page + THREAD_SIZE))
+               if (sp < stack_page + sizeof(struct thread_struct))
+                       break;
+               if (sp >= stack_page + THREAD_SIZE)
                        break;
                if (__get_user(ip, (unsigned long *)(sp + 16)))
                        break;
@@ -544,10 +547,10 @@ static void show_tsk_stack(struct task_struct *p, unsigned long sp)
 
 void dump_stack(void)
 {
-       show_tsk_stack(current, (unsigned long)_get_SP());
+       show_stack(current, (unsigned long *)_get_SP());
 }
 
 void show_trace_task(struct task_struct *tsk)
 {
-       show_tsk_stack(tsk, tsk->thread.ksp);
+       show_stack(tsk, (unsigned long *)tsk->thread.ksp);
 }
index 770938129032e8f96ad0e86880c464a1922079e2..ac14135d83ba9ce3af4808101bcabb3f6819eff3 100644 (file)
@@ -468,6 +468,7 @@ extern void prepare_to_copy(struct task_struct *tsk);
 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])
index d313e2ccbf424ef874488c8db58c65ddaddc1248..f5cdfefc5b054eb2b4a3b35557b958f9c262ef03 100644 (file)
@@ -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);
 
index c603aaa677900e56642767f421d85dd83301de5e..aa79183f1453f13e73f30794449c678a5af681d6 100644 (file)
@@ -2182,10 +2182,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)