public inbox for linux-ia64@vger.kernel.org
 help / color / mirror / Atom feed
* [Linux-ia64] [patch] 2.4.20 unwind.c to handle multiple struct pt_regs
@ 2003-02-17  6:16 Keith Owens
  2003-02-19 19:21 ` David Mosberger
  0 siblings, 1 reply; 2+ messages in thread
From: Keith Owens @ 2003-02-17  6:16 UTC (permalink / raw)
  To: linux-ia64

This patch has been running inside SGI for 2 months.  It handles kernel
stacks with multiple struct pt_regs, as found while debugging the
kernel.  The debugging statements in the unwind code were awkward to
use and inconsistent in what was being dumped and when, I ended up
changing almost all the unwind debugging code while tracking down this
problem.

Patch is against 2.4.20-ia64-021210, it fits 2.4.19 as well.

--- include/asm-ia64/unwind.h	Sun Aug  5 13:29:36 2001
+++ include/asm-ia64/unwind.h	Tue Feb  4 12:24:01 2003
@@ -60,6 +60,7 @@
 	unsigned long ip;		/* instruction pointer value */
 	unsigned long pr;		/* current predicate values */
 	unsigned long *cfm_loc;		/* cfm save location (or NULL) */
+	unsigned long pt;		/* struct pt_regs location */
 
 	struct task_struct *task;
 	struct switch_stack *sw;
--- arch/ia64/kernel/unwind_i.h	Fri Nov 29 11:39:02 2002
+++ arch/ia64/kernel/unwind_i.h	Tue Feb  4 12:13:47 2003
@@ -137,7 +137,8 @@
 	UNW_INSN_SETNAT_MEMSTK,		/* s[dst+1].nat.type = MEMSTK;
 					   s[dst+1].nat.off = *s.pri_unat - s[dst] */
 	UNW_INSN_SETNAT_TYPE,		/* s[dst+1].nat.type = val */
-	UNW_INSN_LOAD			/* s[dst] = *s[val] */
+	UNW_INSN_LOAD,			/* s[dst] = *s[val] */
+	UNW_INSN_MOVE_SCRATCH,		/* s[dst] = scratch reg "val" */
 };
 
 struct unw_insn {
--- arch/ia64/kernel/unwind.c	Fri Nov 29 11:39:02 2002
+++ arch/ia64/kernel/unwind.c	Tue Feb  4 12:13:47 2003
@@ -51,18 +51,24 @@
 #define UNW_LOG_HASH_SIZE	(UNW_LOG_CACHE_SIZE + 1)
 #define UNW_HASH_SIZE		(1 << UNW_LOG_HASH_SIZE)
 
-#define UNW_DEBUG	0
 #define UNW_STATS	0	/* WARNING: this disabled interrupts for long time-spans!! */
 
-#if UNW_DEBUG
-  static long unw_debug_level = 255;
-# define debug(level,format...)	if (unw_debug_level > level) printk(format)
-# define dprintk(format...)	printk(format)
-# define inline
-#else
-# define debug(level,format...)
-# define dprintk(format...)
-#endif
+#ifdef UNW_DEBUG
+  static unsigned int unw_debug_level = UNW_DEBUG;
+  #ifdef CONFIG_KDB
+    #include <linux/kdb.h>
+    #define UNW_DEBUG_ON(n)  (unw_debug_level >= n && !KDB_IS_RUNNING())
+    #define UNW_DEBUG_PRINT(n, ...)  if (UNW_DEBUG_ON(n)) kdb_printf(__VA_ARGS__)
+  #else	/* !CONFIG_KDB */
+    #define UNW_DEBUG_ON(n)  unw_debug_level >= n
+    /* Do not code a printk level, not all debug lines end in newline */
+    #define UNW_DEBUG_PRINT(n, ...)  if (UNW_DEBUG_ON(n)) printk(__VA_ARGS__)
+  #endif	/* CONFIG_KDB */
+  #define inline
+#else	/* !UNW_DEBUG */
+  #define UNW_DEBUG_ON(n)  0
+  #define UNW_DEBUG_PRINT(n, ...)
+#endif	/* UNW_DEBUG */
 
 #if UNW_STATS
 # define STAT(x...)	x
@@ -111,7 +117,7 @@
 	/* script cache: */
 	struct unw_script cache[UNW_CACHE_SIZE];
 
-# if UNW_DEBUG
+# ifdef UNW_DEBUG
 	const char *preg_name[UNW_NUM_REGS];
 # endif
 # if UNW_STATS
@@ -190,7 +196,7 @@
 		struct_offset(struct unw_frame_info, fr_loc[31 - 16])/8,
 	},
 	hash : { [0 ... UNW_HASH_SIZE - 1] = -1 },
-#if UNW_DEBUG
+#ifdef UNW_DEBUG
 	preg_name: {
 		"pri_unat_gr", "pri_unat_mem", "bsp", "bspstore", "ar.pfs", "ar.rnat", "psp", "rp",
 		"r4", "r5", "r6", "r7",
@@ -223,19 +229,31 @@
 	else if (reg <= 31)
 		off = struct_offset(struct pt_regs, r16) + 8*(reg - 16);
 	else
-		dprintk("unwind: bad scratch reg r%lu\n", reg);
+		UNW_DEBUG_PRINT(0, "unwind.%s: bad scratch reg r%lu\n", __FUNCTION__, reg);
 	return off;
 }
 
+static void
+dump_info_pt(struct unw_frame_info *info, const char *func)
+{
+	/* WAR for no struct pt_regs, may be caused by bad unwind data.  KAO */
+	if (!info->pt) {
+		UNW_DEBUG_PRINT(0, "unwind.%s: sp 0x%lx pt 0x%lx, set to 0x%lx\n", func, info->sp, info->pt, info->sp - 16);
+		info->pt = info->sp - 16;
+	}
+	else {
+		UNW_DEBUG_PRINT(3, "unwind.%s: sp 0x%lx pt 0x%lx\n", func, info->sp, info->pt);
+	}
+}
+
 int
 unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char *nat, int write)
 {
 	unsigned long *addr, *nat_addr, nat_mask = 0, dummy_nat;
 	struct unw_ireg *ireg;
-	struct pt_regs *pt;
 
 	if ((unsigned) regnum - 1 >= 127) {
-		dprintk("unwind: trying to access non-existent r%u\n", regnum);
+		UNW_DEBUG_PRINT(0, "unwind.%s: trying to access non-existent r%u\n", __FUNCTION__, regnum);
 		return -1;
 	}
 
@@ -280,8 +298,9 @@
 					if ((unsigned long) addr < info->regstk.limit
 					    || (unsigned long) addr >= info->regstk.top)
 					{
-						dprintk("unwind: %p outside of regstk "
-							"[0x%lx-0x%lx)\n", (void *) addr,
+						UNW_DEBUG_PRINT(0, "unwind.%s: %p outside of regstk "
+							"[0x%lx-0x%lx)\n",
+							__FUNCTION__, (void *) addr,
 							info->regstk.limit,
 							info->regstk.top);
 						return -1;
@@ -298,11 +317,8 @@
 			}
 		} else {
 			/* access a scratch register */
-			if (info->flags & UNW_FLAG_INTERRUPT_FRAME)
-				pt = (struct pt_regs *) info->psp - 1;
-			else
-				pt = (struct pt_regs *) info->sp - 1;
-			addr = (unsigned long *) ((long) pt + pt_regs_off(regnum));
+			dump_info_pt(info,  __FUNCTION__);
+			addr = (unsigned long *) (info->pt + pt_regs_off(regnum));
 			if (info->pri_unat_loc)
 				nat_addr = info->pri_unat_loc;
 			else
@@ -316,7 +332,7 @@
 		if ((unsigned long) addr < info->regstk.limit
 		    || (unsigned long) addr >= info->regstk.top)
 		{
-			dprintk("unwind: ignoring attempt to access register outside of rbs\n");
+			UNW_DEBUG_PRINT(0, "unwind.%s: ignoring attempt to access register outside of rbs\n",  __FUNCTION__);
 			return -1;
 		}
 		if ((unsigned long) nat_addr >= info->regstk.top)
@@ -348,10 +364,8 @@
 	unsigned long *addr;
 	struct pt_regs *pt;
 
-	if (info->flags & UNW_FLAG_INTERRUPT_FRAME)
-		pt = (struct pt_regs *) info->psp - 1;
-	else
-		pt = (struct pt_regs *) info->sp - 1;
+	dump_info_pt(info,  __FUNCTION__);
+	pt = (struct pt_regs *)info->pt;
 	switch (regnum) {
 		/* scratch: */
 	      case 0: addr = &pt->b0; break;
@@ -366,7 +380,7 @@
 		break;
 
 	      default:
-		dprintk("unwind: trying to access non-existent b%u\n", regnum);
+		UNW_DEBUG_PRINT(0, "unwind.%s: trying to access non-existent b%u\n", __FUNCTION__, regnum);
 		return -1;
 	}
 	if (write)
@@ -383,14 +397,12 @@
 	struct pt_regs *pt;
 
 	if ((unsigned) (regnum - 2) >= 126) {
-		dprintk("unwind: trying to access non-existent f%u\n", regnum);
+		UNW_DEBUG_PRINT(0, "unwind.%s: trying to access non-existent f%u\n", __FUNCTION__, regnum);
 		return -1;
 	}
 
-	if (info->flags & UNW_FLAG_INTERRUPT_FRAME)
-		pt = (struct pt_regs *) info->psp - 1;
-	else
-		pt = (struct pt_regs *) info->sp - 1;
+	dump_info_pt(info,  __FUNCTION__);
+	pt = (struct pt_regs *)info->pt;
 
 	if (regnum <= 5) {
 		addr = *(&info->f2_loc + (regnum - 2));
@@ -428,10 +440,8 @@
 	unsigned long *addr;
 	struct pt_regs *pt;
 
-	if (info->flags & UNW_FLAG_INTERRUPT_FRAME)
-		pt = (struct pt_regs *) info->psp - 1;
-	else
-		pt = (struct pt_regs *) info->sp - 1;
+	dump_info_pt(info,  __FUNCTION__);
+	pt = (struct pt_regs *)info->pt;
 
 	switch (regnum) {
 	      case UNW_AR_BSP:
@@ -495,7 +505,7 @@
 		break;
 
 	      default:
-		dprintk("unwind: trying to access non-existent ar%u\n", regnum);
+		UNW_DEBUG_PRINT(0, "unwind.%s: trying to access non-existent ar%u\n", __FUNCTION__, regnum);
 		return -1;
 	}
 
@@ -532,7 +542,7 @@
 
 	rs = alloc_reg_state();
 	if (!rs) {
-		printk("unwind: cannot stack reg state!\n");
+		UNW_DEBUG_PRINT(0, "unwind.%s: cannot stack reg state!\n", __FUNCTION__);
 		return;
 	}
 	memcpy(rs, &sr->curr, sizeof(*rs));
@@ -545,7 +555,7 @@
 	struct unw_reg_state *rs = sr->curr.next;
 
 	if (!rs) {
-		printk("unwind: stack underflow!\n");
+		UNW_DEBUG_PRINT(0, "unwind.%s: stack underflow!\n",  __FUNCTION__);
 		return;
 	}
 	memcpy(&sr->curr, rs, sizeof(*rs));
@@ -561,7 +571,7 @@
 	while (rs) {
 		copy = alloc_reg_state();
 		if (!copy) {
-			printk ("unwind.dup_state_stack: out of memory\n");
+			UNW_DEBUG_PRINT(0, "unwind.%s: out of memory\n",  __FUNCTION__);
 			return NULL;
 		}
 		memcpy(copy, rs, sizeof(*copy));
@@ -612,7 +622,7 @@
 	      default:
 		break;
 	}
-	dprintk("unwind: bad abreg=0x%x\n", abreg);
+	UNW_DEBUG_PRINT(0, "unwind.%s: bad abreg=0x%x\n", __FUNCTION__, abreg);
 	return UNW_REG_LC;
 }
 
@@ -652,7 +662,7 @@
 			return;
 		}
 	}
-	dprintk("unwind: excess spill!\n");
+	UNW_DEBUG_PRINT(0, "unwind.%s: excess spill!\n",  __FUNCTION__);
 }
 
 static inline void
@@ -765,10 +775,13 @@
 static inline void
 desc_abi (unsigned char abi, unsigned char context, struct unw_state_record *sr)
 {
-	if (abi = 0 && context = 'i')
+	if (abi = 0 && context = 'i') {
 		sr->flags |= UNW_FLAG_INTERRUPT_FRAME;
+		UNW_DEBUG_PRINT(3, "unwind.%s: interrupt frame\n",  __FUNCTION__);
+	}
 	else
-		dprintk("unwind: ignoring unwabi(abi=0x%x,context=0x%x)\n", abi, context);
+		UNW_DEBUG_PRINT(0, "unwind%s: ignoring unwabi(abi=0x%x,context=0x%x)\n",
+				__FUNCTION__, abi, context);
 }
 
 static inline void
@@ -951,7 +964,7 @@
 			return;
 		}
 	}
-	printk("unwind: failed to find state labeled 0x%lx\n", label);
+	UNW_DEBUG_PRINT(0, "unwind.%s: failed to find state labeled 0x%lx\n", __FUNCTION__, label);
 }
 
 static inline void
@@ -961,7 +974,7 @@
 
 	ls = alloc_labeled_state();
 	if (!ls) {
-		printk("unwind.desc_label_state(): out of memory\n");
+		UNW_DEBUG_PRINT(0, "unwind.%s: out of memory\n",  __FUNCTION__);
 		return;
 	}
 	ls->label = label;
@@ -1055,7 +1068,7 @@
 	r->val = 4*spoff;
 }
 
-#define UNW_DEC_BAD_CODE(code)			printk("unwind: unknown code 0x%02x\n", code);
+#define UNW_DEC_BAD_CODE(code)			UNW_DEBUG_PRINT(0, "unwind.%s: unknown code 0x%02x\n", __FUNCTION__, code);
 
 /*
  * region headers:
@@ -1134,6 +1147,8 @@
 	struct unw_script *script = unw.cache + info->hint;
 	unsigned short index;
 	unsigned long ip, pr;
+	if (UNW_DEBUG_ON(0))
+		return 0;	/* Always regenerate scripts in debug mode */
 
 	STAT(++unw.stat.cache.lookups);
 
@@ -1259,8 +1274,8 @@
 script_emit (struct unw_script *script, struct unw_insn insn)
 {
 	if (script->count >= UNW_MAX_SCRIPT_LEN) {
-		dprintk("unwind: script exceeds maximum size of %u instructions!\n",
-			UNW_MAX_SCRIPT_LEN);
+		UNW_DEBUG_PRINT(0, "unwind.%s: script exceeds maximum size of %u instructions!\n",
+			__FUNCTION__, UNW_MAX_SCRIPT_LEN);
 		return;
 	}
 	script->insn[script->count++] = insn;
@@ -1301,7 +1316,7 @@
 		break;
 
 	      default:
-		dprintk("unwind: don't know how to emit nat info for where = %u\n", r->where);
+		UNW_DEBUG_PRINT(0, "unwind.%s: don't know how to emit nat info for where = %u\n", __FUNCTION__, r->where);
 		return;
 	}
 	insn.opc = opc;
@@ -1338,8 +1353,9 @@
 			}
 			val = unw.preg_index[UNW_REG_R4 + (rval - 4)];
 		} else {
-			opc = UNW_INSN_ADD_SP;
-			val = -sizeof(struct pt_regs) + pt_regs_off(rval);
+			/* register got spilled to a scratch register */
+			opc = UNW_INSN_MOVE_SCRATCH;
+			val = pt_regs_off(rval);
 		}
 		break;
 
@@ -1349,12 +1365,11 @@
 		else if (rval >= 16 && rval <= 31)
 			val = unw.preg_index[UNW_REG_F16 + (rval - 16)];
 		else {
-			opc = UNW_INSN_ADD_SP;
-			val = -sizeof(struct pt_regs);
+			opc = UNW_INSN_MOVE_SCRATCH;
 			if (rval <= 9)
-				val += struct_offset(struct pt_regs, f6) + 16*(rval - 6);
+				val = struct_offset(struct pt_regs, f6) + 16*(rval - 6);
 			else
-				dprintk("unwind: kernel may not touch f%lu\n", rval);
+				UNW_DEBUG_PRINT(0, "unwind.%s: kernel may not touch f%lu\n", __FUNCTION__, rval);
 		}
 		break;
 
@@ -1362,14 +1377,13 @@
 		if (rval >= 1 && rval <= 5)
 			val = unw.preg_index[UNW_REG_B1 + (rval - 1)];
 		else {
-			opc = UNW_INSN_ADD_SP;
-			val = -sizeof(struct pt_regs);
+			opc = UNW_INSN_MOVE_SCRATCH;
 			if (rval = 0)
-				val += struct_offset(struct pt_regs, b0);
+				val = struct_offset(struct pt_regs, b0);
 			else if (rval = 6)
-				val += struct_offset(struct pt_regs, b6);
+				val = struct_offset(struct pt_regs, b6);
 			else
-				val += struct_offset(struct pt_regs, b7);
+				val = struct_offset(struct pt_regs, b7);
 		}
 		break;
 
@@ -1382,7 +1396,7 @@
 		break;
 
 	      default:
-		dprintk("unwind: register %u has unexpected `where' value of %u\n", i, r->where);
+		UNW_DEBUG_PRINT(0, "unwind%s: register %u has unexpected `where' value of %u\n", __FUNCTION__, i, r->where);
 		break;
 	}
 	insn.opc = opc;
@@ -1455,9 +1469,10 @@
 		r->when = UNW_WHEN_NEVER;
 	sr.pr_val = info->pr;
 
+	UNW_DEBUG_PRINT(3, "unwind.%s: ip 0x%lx\n", __FUNCTION__, ip);
 	script = script_new(ip);
 	if (!script) {
-		dprintk("unwind: failed to create unwind script\n");
+		UNW_DEBUG_PRINT(0, "unwind.%s: failed to create unwind script\n",  __FUNCTION__);
 		STAT(unw.stat.script.build_time += ia64_get_itc() - start);
 		return 0;
 	}
@@ -1475,8 +1490,8 @@
 	}
 	if (!e) {
 		/* no info, return default unwinder (leaf proc, no mem stack, no saved regs)  */
-		dprintk("unwind: no unwind info for ip=0x%lx (prev ip=0x%lx)\n", ip,
-			unw.cache[info->prev_script].ip);
+		UNW_DEBUG_PRINT(1, "unwind.%s: no unwind info for ip=0x%lx (prev ip=0x%lx)\n",
+			__FUNCTION__, ip, unw.cache[info->prev_script].ip);
 		sr.curr.reg[UNW_REG_RP].where = UNW_WHERE_BR;
 		sr.curr.reg[UNW_REG_RP].when = -1;
 		sr.curr.reg[UNW_REG_RP].val = 0;
@@ -1524,26 +1539,28 @@
 		sr.curr.reg[UNW_REG_RP].where = UNW_WHERE_BR;
 		sr.curr.reg[UNW_REG_RP].when = -1;
 		sr.curr.reg[UNW_REG_RP].val = sr.return_link_reg;
+		UNW_DEBUG_PRINT(1, "unwind.%s: using default for rp at ip=0x%lx where=%d val=0x%lx\n",
+			__FUNCTION__, ip, sr.curr.reg[UNW_REG_RP].where, sr.curr.reg[UNW_REG_RP].val);
 	}
 
-#if UNW_DEBUG
-	printk("unwind: state record for func 0x%lx, t=%u:\n",
-	       table->segment_base + e->start_offset, sr.when_target);
+#ifdef UNW_DEBUG
+	UNW_DEBUG_PRINT(1, "unwind.%s: state record for func 0x%lx, t=%u:\n",
+		__FUNCTION__, table->segment_base + e->start_offset, sr.when_target);
 	for (r = sr.curr.reg; r < sr.curr.reg + UNW_NUM_REGS; ++r) {
 		if (r->where != UNW_WHERE_NONE || r->when != UNW_WHEN_NEVER) {
-			printk("  %s <- ", unw.preg_name[r - sr.curr.reg]);
+			UNW_DEBUG_PRINT(1, "  %s <- ", unw.preg_name[r - sr.curr.reg]);
 			switch (r->where) {
-			      case UNW_WHERE_GR:     printk("r%lu", r->val); break;
-			      case UNW_WHERE_FR:     printk("f%lu", r->val); break;
-			      case UNW_WHERE_BR:     printk("b%lu", r->val); break;
-			      case UNW_WHERE_SPREL:  printk("[sp+0x%lx]", r->val); break;
-			      case UNW_WHERE_PSPREL: printk("[psp+0x%lx]", r->val); break;
+			      case UNW_WHERE_GR:     UNW_DEBUG_PRINT(1, "r%lu", r->val); break;
+			      case UNW_WHERE_FR:     UNW_DEBUG_PRINT(1, "f%lu", r->val); break;
+			      case UNW_WHERE_BR:     UNW_DEBUG_PRINT(1, "b%lu", r->val); break;
+			      case UNW_WHERE_SPREL:  UNW_DEBUG_PRINT(1, "[sp+0x%lx]", r->val); break;
+			      case UNW_WHERE_PSPREL: UNW_DEBUG_PRINT(1, "[psp+0x%lx]", r->val); break;
 			      case UNW_WHERE_NONE:
-				printk("%s+0x%lx", unw.preg_name[r - sr.curr.reg], r->val);
+				UNW_DEBUG_PRINT(1, "%s+0x%lx", unw.preg_name[r - sr.curr.reg], r->val);
 				break;
-			      default:		     printk("BADWHERE(%d)", r->where); break;
+			      default:		     UNW_DEBUG_PRINT(1, "BADWHERE(%d)", r->where); break;
 			}
-			printk("\t\t%d\n", r->when);
+			UNW_DEBUG_PRINT(1, "\t\t%d\n", r->when);
 		}
 	}
 #endif
@@ -1641,6 +1658,18 @@
 			s[dst] = s[val];
 			break;
 
+		      case UNW_INSN_MOVE_SCRATCH:
+			if (state->pt) {
+				dump_info_pt(state,  __FUNCTION__);
+				UNW_DEBUG_PRINT(6, "unwind.%s: dst %ld val %ld\n", __FUNCTION__, dst, val);
+				s[dst] = state->pt+val;
+			}
+			else {
+				s[dst] = 0;
+				UNW_DEBUG_PRINT(0, "unwind.%s: no state->pt, dst=%ld, val=%ld\n", __FUNCTION__, dst, val);
+			}
+			break;
+
 		      case UNW_INSN_MOVE_STACKED:
 			s[dst] = (unsigned long) ia64_rse_skip_regs((unsigned long *)state->bsp,
 								    val);
@@ -1666,11 +1695,11 @@
 			break;
 
 		      case UNW_INSN_LOAD:
-#if UNW_DEBUG
+#ifdef UNW_DEBUG
 			if ((s[val] & (local_cpu_data->unimpl_va_mask | 0x7)) != 0
 			    || s[val] < TASK_SIZE)
 			{
-				debug(1, "unwind: rejecting bad psp=0x%lx\n", s[val]);
+				UNW_DEBUG_PRINT(0, "unwind.%s: rejecting bad psp=0x%lx\n", __FUNCTION__, s[val]);
 				break;
 			}
 #endif
@@ -1703,7 +1732,8 @@
 
 	if ((info->ip & (local_cpu_data->unimpl_va_mask | 0xf)) || info->ip < TASK_SIZE) {
 		/* don't let obviously bad addresses pollute the cache */
-		debug(1, "unwind: rejecting bad ip=0x%lx\n", info->ip);
+		/* FIXME: should really be level 0 but it occurs too often. KAO */
+		UNW_DEBUG_PRINT(1, "unwind.%s: rejecting bad ip=0x%lx\n", __FUNCTION__, info->ip);
 		info->rp_loc = 0;
 		return -1;
 	}
@@ -1712,8 +1742,8 @@
 	if (!scr) {
 		scr = build_script(info);
 		if (!scr) {
-			dprintk("unwind: failed to locate/build unwind script for ip %lx\n",
-				info->ip);
+			UNW_DEBUG_PRINT(0, "unwind.%s: failed to locate/build unwind script for ip %lx\n",
+				__FUNCTION__, info->ip);
 			return -1;
 		}
 		have_write_lock = 1;
@@ -1746,7 +1776,8 @@
 
 	/* restore the ip */
 	if (!info->rp_loc) {
-		debug(1, "unwind: failed to locate return link (ip=0x%lx)!\n", info->ip);
+		/* FIXME: should really be level 0 but it occurs too often. KAO */
+		UNW_DEBUG_PRINT(1, "unwind.%s: failed to locate return link (ip=0x%lx)!\n",  __FUNCTION__, info->ip);
 		STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));
 		return -1;
 	}
@@ -1756,14 +1787,14 @@
 		 * We don't have unwind info for the gate page, so we consider that part
 		 * of user-space for the purpose of unwinding.
 		 */
-		debug(1, "unwind: reached user-space (ip=0x%lx)\n", ip);
+		UNW_DEBUG_PRINT(2, "unwind.%s: reached user-space (ip=0x%lx)\n", __FUNCTION__, ip);
 		STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));
 		return -1;
 	}
 
 	/* restore the cfm: */
 	if (!info->pfs_loc) {
-		dprintk("unwind: failed to locate ar.pfs!\n");
+		UNW_DEBUG_PRINT(0, "unwind.%s: failed to locate ar.pfs!\n", __FUNCTION__);
 		STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));
 		return -1;
 	}
@@ -1773,16 +1804,18 @@
 	pr = info->pr;
 	num_regs = 0;
 	if ((info->flags & UNW_FLAG_INTERRUPT_FRAME)) {
+		info->pt = info->sp + 16;
 		if ((pr & (1UL << pNonSys)) != 0)
 			num_regs = *info->cfm_loc & 0x7f;		/* size of frame */
 		info->pfs_loc -			(unsigned long *) (info->sp + 16 + struct_offset(struct pt_regs, ar_pfs));
+			(unsigned long *) (info->pt + struct_offset(struct pt_regs, ar_pfs));
+		UNW_DEBUG_PRINT(3, "unwind.%s: interrupt_frame pt 0x%lx\n", __FUNCTION__, info->pt);
 	} else
 		num_regs = (*info->cfm_loc >> 7) & 0x7f;	/* size of locals */
 	info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->bsp, -num_regs);
 	if (info->bsp < info->regstk.limit || info->bsp > info->regstk.top) {
-		dprintk("unwind: bsp (0x%lx) out of range [0x%lx-0x%lx]\n",
-			info->bsp, info->regstk.limit, info->regstk.top);
+		UNW_DEBUG_PRINT(0, "unwind.%s: bsp (0x%lx) out of range [0x%lx-0x%lx]\n",
+			__FUNCTION__, info->bsp, info->regstk.limit, info->regstk.top);
 		STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));
 		return -1;
 	}
@@ -1790,14 +1823,14 @@
 	/* restore the sp: */
 	info->sp = info->psp;
 	if (info->sp < info->memstk.top || info->sp > info->memstk.limit) {
-		dprintk("unwind: sp (0x%lx) out of range [0x%lx-0x%lx]\n",
-			info->sp, info->memstk.top, info->memstk.limit);
+		UNW_DEBUG_PRINT(0, "unwind.%s: sp (0x%lx) out of range [0x%lx-0x%lx]\n",
+			__FUNCTION__, info->sp, info->memstk.top, info->memstk.limit);
 		STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));
 		return -1;
 	}
 
 	if (info->ip = prev_ip && info->sp = prev_sp && info->bsp = prev_bsp) {
-		dprintk("unwind: ip, sp, bsp remain unchanged; stopping here (ip=0x%lx)\n", ip);
+		UNW_DEBUG_PRINT(0, "unwind.%s: ip, sp, bsp remain unchanged; stopping here (ip=0x%lx)\n", __FUNCTION__, ip);
 		STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));
 		return -1;
 	}
@@ -1821,7 +1854,7 @@
 	while (unw_unwind(info) >= 0) {
 		if (unw_get_rp(info, &ip) < 0) {
 			unw_get_ip(info, &ip);
-			dprintk("unwind: failed to read return pointer (ip=0x%lx)\n", ip);
+			UNW_DEBUG_PRINT(0, "unwind.%s: failed to read return pointer (ip=0x%lx)\n", __FUNCTION__, ip);
 			return -1;
 		}
 		/*
@@ -1832,7 +1865,7 @@
 			return 0;
 	}
 	unw_get_ip(info, &ip);
-	dprintk("unwind: failed to unwind to user-level (ip=0x%lx)\n", ip);
+	UNW_DEBUG_PRINT(0, "unwind.%s: failed to unwind to user-level (ip=0x%lx)\n", __FUNCTION__, ip);
 	return -1;
 }
 
@@ -1873,11 +1906,30 @@
 	info->task = t;
 	info->sw  = sw;
 	info->sp = info->psp = (unsigned long) (sw + 1) - 16;
+	info->pt = 0;
 	info->cfm_loc = &sw->ar_pfs;
 	sol = (*info->cfm_loc >> 7) & 0x7f;
 	info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sol);
 	info->ip = sw->b0;
 	info->pr = sw->pr;
+	UNW_DEBUG_PRINT(3,
+			"unwind.%s\n"
+			"  rbslimit 0x%lx\n"
+			"  rbstop   0x%lx\n"
+			"  stklimit 0x%lx\n"
+			"  stktop   0x%lx\n"
+			"  task     0x%lx\n"
+			"  sw       0x%lx\n",
+			__FUNCTION__, rbslimit, rbstop, stklimit, stktop,
+			(unsigned long)(info->task),
+			(unsigned long)(info->sw));
+	UNW_DEBUG_PRINT(3,
+			"  sp/psp   0x%lx\n"
+			"  sol      0x%lx\n"
+			"  bsp      0x%lx\n"
+			"  ip       0x%lx\n"
+			"  pr       0x%lx\n",
+			info->sp, sol, info->bsp, info->ip, info->pr);
 
 	find_save_locs(info);
 	STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags));
@@ -1888,6 +1940,7 @@
 {
 	struct switch_stack *sw = (struct switch_stack *) (t->thread.ksp + 16);
 
+	UNW_DEBUG_PRINT(1, "unwind.%s\n", __FUNCTION__);
 	unw_init_frame_info(info, t, sw);
 }
 
@@ -1915,7 +1968,7 @@
 	unsigned long flags;
 
 	if (end - start <= 0) {
-		dprintk("unwind: ignoring attempt to insert empty unwind table\n");
+		UNW_DEBUG_PRINT(0, "unwind.%s: ignoring attempt to insert empty unwind table\n", __FUNCTION__);
 		return 0;
 	}
 
@@ -1945,13 +1998,13 @@
 	long index;
 
 	if (!handle) {
-		dprintk("unwind: ignoring attempt to remove non-existent unwind table\n");
+		UNW_DEBUG_PRINT(0, "unwind.%s: ignoring attempt to remove non-existent unwind table\n", __FUNCTION__);
 		return;
 	}
 
 	table = handle;
 	if (table = &unw.kernel_table) {
-		dprintk("unwind: sorry, freeing the kernel's unwind table is a no-can-do!\n");
+		UNW_DEBUG_PRINT(0, "unwind.%s: sorry, freeing the kernel's unwind table is a no-can-do!\n", __FUNCTION__);
 		return;
 	}
 
@@ -1963,7 +2016,7 @@
 			if (prev->next = table)
 				break;
 		if (!prev) {
-			dprintk("unwind: failed to find unwind table %p\n", (void *) table);
+			UNW_DEBUG_PRINT(0, "unwind.%s: failed to find unwind table %p\n", __FUNCTION__, (void *) table);
 			spin_unlock_irqrestore(&unw.lock, flags);
 			return;
 		}
@@ -2013,7 +2066,7 @@
 	unw.gate_table = alloc_bootmem(size);
 	if (!unw.gate_table) {
 		unw.gate_table_size = 0;
-		printk("unwind: unable to create unwind data for gate page!\n");
+		UNW_DEBUG_PRINT(0, "unwind.%s: unable to create unwind data for gate page!\n", __FUNCTION__);
 		return;
 	}
 	unw.gate_table_size = size;



^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [Linux-ia64] [patch] 2.4.20 unwind.c to handle multiple struct pt_regs
  2003-02-17  6:16 [Linux-ia64] [patch] 2.4.20 unwind.c to handle multiple struct pt_regs Keith Owens
@ 2003-02-19 19:21 ` David Mosberger
  0 siblings, 0 replies; 2+ messages in thread
From: David Mosberger @ 2003-02-19 19:21 UTC (permalink / raw)
  To: linux-ia64

Hi Keith,

  Keith> This patch has been running inside SGI for 2 months.  It
  Keith> handles kernel stacks with multiple struct pt_regs, as found
  Keith> while debugging the kernel.  The debugging statements in the
  Keith> unwind code were awkward to use and inconsistent in what was
  Keith> being dumped and when, I ended up changing almost all the
  Keith> unwind debugging code while tracking down this problem.

The patch basically looks fine to me, except that I'd really like to
prefer to have it split up into one patch that does the pt_regs fixes
and one that does the debug enhancements.  And while you're at it,
please use something a bit more concise than UNW_DEBUG_PRINT
(something like DPRINT or UNW_DPRINT should be sufficient).

Thanks,

	--david


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2003-02-19 19:21 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-02-17  6:16 [Linux-ia64] [patch] 2.4.20 unwind.c to handle multiple struct pt_regs Keith Owens
2003-02-19 19:21 ` David Mosberger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox