[parisc-linux-cvs] linux-2.6 tausq

Randolph Chung randolph at tausq.org
Fri Aug 13 10:34:05 MDT 2004


> Modified files:
> 	arch/parisc/kernel: unwind.c 
> 	include/asm-parisc: assembly.h 
> 
> Log message:
> - fix unwind table search so it works reliably
> - add special case handling for ret_from_kernel_thread and _switch_to_ret
> - tidy up the code a bit

the special case handling of asm functions is quite ugly atm. i'll clean
it up some more.

Index: arch/parisc/kernel/unwind.c
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/kernel/unwind.c,v
retrieving revision 1.6
diff -u -p -r1.6 unwind.c
--- arch/parisc/kernel/unwind.c	9 Aug 2004 16:38:41 -0000	1.6
+++ arch/parisc/kernel/unwind.c	13 Aug 2004 16:32:43 -0000
@@ -12,8 +12,10 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/kallsyms.h>
 
 #include <asm/uaccess.h>
+#include <asm/assembly.h>
 
 #include <asm/unwind.h>
 
@@ -43,22 +45,24 @@ find_unwind_entry_in_table(const struct 
 	const struct unwind_table_entry *e = 0;
 	unsigned long lo, hi, mid;
 
-	for (lo = 0, hi = table->length; lo < hi; )
-	{
-		mid = (lo + hi) / 2;
+	lo = 0; 
+	hi = table->length - 1; 
+	
+	while (lo <= hi) {
+		mid = (hi - lo) / 2 + lo;
 		e = &table->table[mid];
 		if (addr < e->region_start)
-			hi = mid;
+			hi = mid - 1;
 		else if (addr > e->region_end)
 			lo = mid + 1;
 		else
-			break;
+			return e;
 	}
 
-	return e;
+	return NULL;
 }
 
-static inline const struct unwind_table_entry *
+static const struct unwind_table_entry *
 find_unwind_entry(unsigned long addr)
 {
 	struct unwind_table *table = unwind_tables;
@@ -68,8 +72,7 @@ find_unwind_entry(unsigned long addr)
 	    addr <= kernel_unwind_table.end)
 		e = find_unwind_entry_in_table(&kernel_unwind_table, addr);
 	else
-		for (; table; table = table->next)
-		{
+		for (; table; table = table->next) {
 			if (addr >= table->start && 
 			    addr <= table->end)
 				e = find_unwind_entry_in_table(table, addr);
@@ -99,6 +102,11 @@ unwind_table_init(struct unwind_table *t
 	table->next = NULL;
 
 	for (; start <= end; start++) {
+		if (start < end && 
+		    start->region_end > (start+1)->region_start) {
+			printk("WARNING: Out of order unwind entry! %p and %p\n", start, start+1);
+		}
+
 		start->region_start += base_addr;
 		start->region_end += base_addr;
 	}
@@ -170,12 +178,40 @@ static void unwind_frame_regs(struct unw
 	int looking_for_rp, rpoffset = 0;
 
 	e = find_unwind_entry(info->ip);
-	if (!e) {
+	if (e == NULL) {
 		unsigned long sp;
 		extern char _stext[], _etext[];
 
 		dbg("Cannot find unwind entry for 0x%lx; forced unwinding\n", info->ip);
 
+#ifdef CONFIG_KALLSYMS
+		/* Handle some frequent special cases.... */
+		{
+			char symname[KSYM_NAME_LEN+1];
+			char *modname;
+			unsigned long symsize, offset;
+
+			kallsyms_lookup(info->ip, &symsize, &offset,
+					&modname, symname);
+
+			dbg("info->ip = 0x%lx, name = %s\n", info->ip, symname);
+
+			if (strcmp(symname, "_switch_to_ret") == 0) {
+				info->prev_sp = info->sp - CALLEE_SAVE_FRAME_SIZE;
+				info->prev_ip = *(unsigned long *)(info->prev_sp - RP_OFFSET);
+				dbg("_switch_to_ret @ %lx - setting "
+				    "prev_sp=%lx prev_ip=%lx\n", 
+				    info->ip, info->prev_sp, 
+				    info->prev_ip);
+				return;
+			} else if (strcmp(symname, "ret_from_kernel_thread") == 0 ||
+				   strcmp(symname, "syscall_exit") == 0) {
+				info->prev_ip = info->prev_sp = 0;
+				return;
+			}
+		}
+#endif
+
 		/* Since we are doing the unwinding blind, we don't know if
 		   we are adjusting the stack correctly or extracting the rp
 		   correctly. The rp is checked to see if it belongs to the
@@ -199,16 +235,22 @@ static void unwind_frame_regs(struct unw
 		} 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 {
+		info->rp = 0;
 
-		dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, Save_RP = %d size = %u\n",
-				e->region_start, e->region_end, e->Save_SP, e->Save_RP, e->Total_frame_size);
+		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", e->region_start, 
+		    e->region_end, e->Save_SP, e->Save_RP, 
+		    e->Total_frame_size);
 
 		looking_for_rp = e->Save_RP;
 
 		for (npc = e->region_start; 
-		     (frame_size < (e->Total_frame_size << 3) || looking_for_rp) && 
+		     (frame_size < (e->Total_frame_size << 3) || 
+		      looking_for_rp) && 
 		     npc < info->ip; 
 		     npc += 4) {
 
@@ -219,22 +261,28 @@ 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) {
+				dbg("analyzing func @ %lx, insn=%08x @ "
+				    "%lx, frame_size = %ld\n", info->ip,
+				    insn, npc, frame_size);
+			} else if ((insn & 0xffe00008) == 0x73c00008) {
 				/* 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);
+				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);
+				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);
+				dbg("analyzing func @ %lx, insn=std rp,"
+				    "-16(sp) @ %lx\n", info->ip, npc);
 			}
 		}
 
@@ -244,7 +292,9 @@ static void unwind_frame_regs(struct unw
 		info->prev_ip = info->rp;
 		info->rp = 0;
 
-		dbg("analyzing func @ %lx, setting prev_sp=%lx prev_ip=%lx\n", info->ip, info->prev_sp, info->prev_ip);
+		dbg("analyzing func @ %lx, setting prev_sp=%lx "
+		    "prev_ip=%lx npc=%lx\n", info->ip, info->prev_sp, 
+		    info->prev_ip, npc);
 	}
 }
 
@@ -257,7 +307,8 @@ void unwind_frame_init(struct unwind_fra
 	info->ip = ip;
 	info->rp = rp;
 
-	dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n", t ? (int)t->pid : 0, info->sp, info->ip);
+	dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n", 
+	    t ? (int)t->pid : -1, info->sp, info->ip);
 }
 
 void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t)
@@ -285,7 +336,9 @@ int unwind_once(struct unwind_frame_info
 	next_frame->prev_sp = 0;
 	next_frame->prev_ip = 0;
 
-	dbg("(%d) Continue unwind to sp=%08lx ip=%08lx\n", (int)next_frame->t->pid, next_frame->sp, next_frame->ip);
+	dbg("(%d) Continue unwind to sp=%08lx ip=%08lx\n", 
+	    next_frame->t ? (int)next_frame->t->pid : -1, 
+	    next_frame->sp, next_frame->ip);
 
 	return 0;
 }
Index: include/asm-parisc/assembly.h
===================================================================
RCS file: /var/cvs/linux-2.6/include/asm-parisc/assembly.h,v
retrieving revision 1.4
diff -u -p -r1.4 assembly.h
--- include/asm-parisc/assembly.h	9 Aug 2004 02:23:45 -0000	1.4
+++ include/asm-parisc/assembly.h	13 Aug 2004 16:32:43 -0000
@@ -29,6 +29,7 @@
 #define STREGM	std,ma
 #define RP_OFFSET	16
 #define FRAME_SIZE	128
+#define CALLEE_SAVE_FRAME_SIZE	144
 #else
 #define LDREG	ldw
 #define STREG	stw
@@ -37,6 +38,7 @@
 #define STREGM	stwm
 #define RP_OFFSET	20
 #define FRAME_SIZE	64
+#define CALLEE_SAVE_FRAME_SIZE	128
 #endif
 
 #ifdef CONFIG_PA20
@@ -292,7 +294,7 @@
 
 #ifdef __LP64__
 	.macro	callee_save
-	std,ma	  %r3,	144(%r30)
+	std,ma	  %r3,	CALLEE_SAVE_FRAME_SIZE(%r30)
 	mfctl	  %cr27, %r3
 	std	  %r4,	-136(%r30)
 	std	  %r5,	-128(%r30)
@@ -330,13 +332,13 @@
 	ldd	-128(%r30),    %r5
 	ldd	-136(%r30),    %r4
 	mtctl	%r3, %cr27
-	ldd,mb	-144(%r30),    %r3
+	ldd,mb	-CALLEE_SAVE_FRAME_SIZE(%r30),    %r3
 	.endm
 
 #else /* ! __LP64__ */
 
 	.macro	callee_save
-	stw,ma	 %r3,	128(%r30)
+	stw,ma	 %r3,	CALLEE_SAVE_FRAME_SIZE(%r30)
 	mfctl	 %cr27, %r3
 	stw	 %r4,	-124(%r30)
 	stw	 %r5,	-120(%r30)
@@ -374,7 +376,7 @@
 	ldw	-120(%r30),   %r5
 	ldw	-124(%r30),   %r4
 	mtctl	%r3, %cr27
-	ldw,mb	-128(%r30),   %r3
+	ldw,mb	-CALLEE_SAVE_FRAME_SIZE(%r30),   %r3
 	.endm
 #endif /* ! __LP64__ */
 


More information about the parisc-linux-cvs mailing list