[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