summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorAndrew Morton <akpm@digeo.com>2003-06-20 08:13:46 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2003-06-20 08:13:46 -0700
commit0d5ff9d0ca5801ccc5dd8f1f6023629bbc6090da (patch)
treef4a9726adeb5f41185eb042ba3cb78d1e10eb859 /arch
parent660a73583d38e35da377963eaa7657104ed758c1 (diff)
[PATCH] show_stack() portability and cleanup patch
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
Diffstat (limited to 'arch')
-rw-r--r--arch/alpha/kernel/traps.c4
-rw-r--r--arch/i386/kernel/process.c2
-rw-r--r--arch/i386/kernel/traps.c14
-rw-r--r--arch/ppc64/kernel/process.c17
4 files changed, 20 insertions, 17 deletions
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index ddea651cb87e..412cd3672573 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -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
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 8cb6adb50b8a..61bc3326e287 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -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 --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index c6bc1936f45b..7fcedfd5cc4b 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -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)
diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c
index 949425d44cb3..c22a54fe544f 100644
--- a/arch/ppc64/kernel/process.c
+++ b/arch/ppc64/kernel/process.c
@@ -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);
}