[parisc-linux-cvs] linux-2.6 tausq
Randolph Chung
tausq at debian.org
Fri Aug 6 13:20:54 MDT 2004
> Modified files:
> arch/parisc/kernel: traps.c unwind.c
> include/asm-parisc: unwind.h
>
> Log message:
> Fix unwinding so that it actually uses the unwind data
> Change traps.c to use the unwinding infrastructure
should work better now, but probably still has some issues...
this makes our oops messages a bit less verbose (no more binary stack
dumps)... if this is not satisfactory we can put the binary dump back...
(does anyone go and manually decode the stack? :)
randolph
Index: arch/parisc/kernel/traps.c
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/kernel/traps.c,v
retrieving revision 1.15
diff -u -p -r1.15 traps.c
--- arch/parisc/kernel/traps.c 20 Jul 2004 22:05:39 -0000 1.15
+++ arch/parisc/kernel/traps.c 6 Aug 2004 19:17:45 -0000
@@ -38,6 +38,7 @@
#include <asm/smp.h>
#include <asm/pdc.h>
#include <asm/pdc_chassis.h>
+#include <asm/unwind.h>
#include "../math-emu/math-emu.h" /* for handle_fpe() */
@@ -129,73 +130,36 @@ void show_regs(struct pt_regs *regs)
void dump_stack(void)
{
- unsigned long stack;
- show_trace(current, &stack);
+ show_stack(NULL, NULL);
}
EXPORT_SYMBOL(dump_stack);
-#ifndef __LP64__
-static int kstack_depth_to_print = 64 * 4;
-#else
-static int kstack_depth_to_print = 128 * 4;
-#endif
-
-void show_stack(struct task_struct *task, unsigned long *sp)
+void show_stack(struct task_struct *task, unsigned long *s)
{
- unsigned long *stack;
- int i;
+ int i = 1;
+ struct unwind_frame_info info;
- /*
- * debugging aid: "show_stack(NULL);" prints the
- * back trace for this cpu.
- */
- if (task==NULL)
- sp = (unsigned long*)&sp;
- else if(sp == NULL)
- sp = (unsigned long*)task->thread.regs.ksp;
-
- stack = sp;
- printk("\n" KERN_CRIT "Stack Dump:\n");
- printk(KERN_CRIT " " RFMT ": ", (unsigned long) stack);
- for (i=0; i < kstack_depth_to_print; i++) {
- if (((long) stack & (THREAD_SIZE-1)) == 0)
- break;
- if (i && ((i & 0x03) == 0))
- printk("\n" KERN_CRIT " " RFMT ": ",
- (unsigned long) stack);
- printk(RFMT " ", *stack--);
- }
- printk("\n" KERN_CRIT "\n");
- show_trace(task, sp);
-}
+ if (!task) {
+ unsigned long sp, ip;
+HERE:
+ sp = (unsigned long)&i;
+ ip = (unsigned long)&&HERE;
+ unwind_frame_init(&info, current, sp, ip);
+ } else {
+ unwind_frame_init_from_blocked_task(&info, task);
+ }
-void show_trace(struct task_struct *task, unsigned long *stack)
-{
- unsigned long *startstack;
- unsigned long addr;
- int i;
+ printk("Backtrace:\n");
+ while (i <= 16) {
+ if (unwind_once(&info) < 0 || info.ip == 0)
+ break;
- startstack = (unsigned long *)((unsigned long)stack & ~(THREAD_SIZE - 1));
- i = 1;
- stack = (long *)((long)(stack + 32) &~ (FRAME_SIZE-1)); /* Align */
- printk("Kernel addresses on the stack:\n");
- while (stack > startstack) {
- stack -= 16; /* Stack frames are a multiple of 16 words */
- addr = stack[16 - RP_OFFSET / sizeof(long)];
- /*
- * If the address is either in the text segment of the
- * kernel, or in the region which contains vmalloc'ed
- * memory, it *may* be the address of a calling
- * routine; if so, print it so that someone tracing
- * down the cause of the crash will be able to figure
- * out the call path that was taken.
- */
- if (__kernel_text_address(addr)) {
- printk(" [<" RFMT ">] ", addr);
+ if (__kernel_text_address(info.ip)) {
+ printk(" [<" RFMT ">] ", info.ip);
#ifdef CONFIG_KALLSYMS
- print_symbol("%s\n", addr);
+ print_symbol("%s\n", info.ip);
#else
if ((i & 0x03) == 0)
printk("\n");
Index: arch/parisc/kernel/unwind.c
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/kernel/unwind.c,v
retrieving revision 1.3
diff -u -p -r1.3 unwind.c
--- arch/parisc/kernel/unwind.c 6 Aug 2004 17:20:39 -0000 1.3
+++ arch/parisc/kernel/unwind.c 6 Aug 2004 19:17:45 -0000
@@ -8,18 +8,6 @@
* understand what is happening here
*/
-/*
- * J. David Anglin writes:
- *
- * "You have to adjust the current sp to that at the begining of the function.
- * There can be up to two stack additions to allocate the frame in the
- * prologue. Similar things happen in the epilogue. In the presence of
- * interrupts, you have to be concerned about where you are in the function
- * and what stack adjustments have taken place."
- *
- * For now these cases are not handled, but they should be!
- */
-
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -36,8 +24,8 @@
#define dbg(x...)
#endif
-extern const struct unwind_table_entry __start___unwind[];
-extern const struct unwind_table_entry __stop___unwind[];
+extern struct unwind_table_entry __start___unwind[];
+extern struct unwind_table_entry __stop___unwind[];
static spinlock_t unwind_lock;
/*
@@ -55,8 +43,6 @@ find_unwind_entry_in_table(const struct
const struct unwind_table_entry *e = 0;
unsigned long lo, hi, mid;
- addr -= table->base_addr;
-
for (lo = 0, hi = table->length; lo < hi; )
{
mid = (lo + hi) / 2;
@@ -97,10 +83,11 @@ find_unwind_entry(unsigned long addr)
static void
unwind_table_init(struct unwind_table *table, const char *name,
unsigned long base_addr, unsigned long gp,
- const void *table_start, const void *table_end)
+ void *table_start, void *table_end)
{
- const struct unwind_table_entry *start = table_start;
- const struct unwind_table_entry *end = table_end - 1;
+ struct unwind_table_entry *start = table_start;
+ struct unwind_table_entry *end =
+ (struct unwind_table_entry *)table_end - 1;
table->name = name;
table->base_addr = base_addr;
@@ -108,14 +95,19 @@ unwind_table_init(struct unwind_table *t
table->start = base_addr + start->region_start;
table->end = base_addr + end->region_end;
table->table = (struct unwind_table_entry *)table_start;
- table->length = end - start;
+ table->length = end - start + 1;
table->next = NULL;
+
+ for (; start <= end; start++) {
+ start->region_start += base_addr;
+ start->region_end += base_addr;
+ }
}
void *
unwind_table_add(const char *name, unsigned long base_addr,
unsigned long gp,
- const void *start, const void *end)
+ void *start, void *end)
{
struct unwind_table *table;
unsigned long flags;
@@ -206,6 +198,8 @@ static void unwind_frame_regs(struct unw
sp = info->prev_sp;
} while (info->prev_ip < (unsigned long)_stext ||
info->prev_ip > (unsigned long)_etext);
+
+ dbg("analyzing func @ %lx with no unwind info, setting prev_sp=%lx prev_ip=%lx\n", info->ip, info->prev_sp, info->prev_ip);
} else {
dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, Save_RP = %d size = %u\n",
@@ -225,24 +219,30 @@ static void unwind_frame_regs(struct unw
/* ldo X(sp), sp, or stwm X,D(sp) */
frame_size += (insn & 0x1 ? -1 << 13 : 0) |
((insn & 0x3fff) >> 1);
+ dbg("analyzing func @ %lx, insn=%08x @ %lx, frame_size = %ld\n", info->ip, insn, npc, frame_size);
} else if ((insn & 0xffe00008) == 0x7ec00008) {
/* std,ma X,D(sp) */
frame_size += (insn & 0x1 ? -1 << 13 : 0) |
(((insn >> 4) & 0x3ff) << 3);
+ dbg("analyzing func @ %lx, insn=%08x @ %lx, frame_size = %ld\n", info->ip, insn, npc, frame_size);
} else if (insn == 0x6bc23fd9) {
/* stw rp,-20(sp) */
rpoffset = 20;
looking_for_rp = 0;
+ dbg("analyzing func @ %lx, insn=stw rp,-20(sp) @ %lx\n", info->ip, npc);
} else if (insn == 0x0fc212c1) {
/* std rp,-16(sr0,sp) */
rpoffset = 16;
looking_for_rp = 0;
+ dbg("analyzing func @ %lx, insn=std rp,-16(sp) @ %lx\n", info->ip, npc);
}
}
info->prev_sp = info->sp - frame_size;
if (rpoffset)
info->prev_ip = *(unsigned long *)(info->prev_sp - rpoffset);
+
+ dbg("analyzing func @ %lx, setting prev_sp=%lx prev_ip=%lx\n", info->ip, info->prev_sp, info->prev_ip);
}
}
@@ -254,7 +254,7 @@ void unwind_frame_init(struct unwind_fra
info->sp = sp;
info->ip = ip;
- dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n", (int)t->pid, info->sp, info->ip);
+ dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n", t ? (int)t->pid : 0, info->sp, info->ip);
}
void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t)
Index: include/asm-parisc/unwind.h
===================================================================
RCS file: /var/cvs/linux-2.6/include/asm-parisc/unwind.h,v
retrieving revision 1.2
diff -u -p -r1.2 unwind.h
--- include/asm-parisc/unwind.h 6 Aug 2004 17:20:39 -0000 1.2
+++ include/asm-parisc/unwind.h 6 Aug 2004 19:17:45 -0000
@@ -62,7 +62,7 @@ struct unwind_frame_info {
void * unwind_table_add(const char *name, unsigned long base_addr,
unsigned long gp,
- const void *start, const void *end);
+ void *start, void *end);
void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t,
unsigned long sp, unsigned long ip);
void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t);
--
Randolph Chung
Debian GNU/Linux Developer, hppa/ia64 ports
http://www.tausq.org/
More information about the parisc-linux-cvs
mailing list