patch-2.4.22 linux-2.4.22/arch/ia64/kernel/unwind.c
Next file: linux-2.4.22/arch/ia64/kernel/unwind_i.h
Previous file: linux-2.4.22/arch/ia64/kernel/traps.c
Back to the patch index
Back to the overall index
- Lines: 823
- Date:
2003-08-25 04:44:39.000000000 -0700
- Orig file:
linux-2.4.21/arch/ia64/kernel/unwind.c
- Orig date:
2003-06-13 07:51:29.000000000 -0700
diff -urN linux-2.4.21/arch/ia64/kernel/unwind.c linux-2.4.22/arch/ia64/kernel/unwind.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1999-2002 Hewlett-Packard Co
+ * Copyright (C) 1999-2003 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com>
*/
/*
@@ -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_DPRINT(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_DPRINT(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_DPRINT(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
@@ -140,13 +146,13 @@
} stat;
# endif
} unw = {
- tables: &unw.kernel_table,
- lock: SPIN_LOCK_UNLOCKED,
- save_order: {
+ .tables = &unw.kernel_table,
+ .lock = SPIN_LOCK_UNLOCKED,
+ .save_order = {
UNW_REG_RP, UNW_REG_PFS, UNW_REG_PSP, UNW_REG_PR,
UNW_REG_UNAT, UNW_REG_LC, UNW_REG_FPSR, UNW_REG_PRI_UNAT_GR
},
- preg_index: {
+ .preg_index = {
struct_offset(struct unw_frame_info, pri_unat_loc)/8, /* PRI_UNAT_GR */
struct_offset(struct unw_frame_info, pri_unat_loc)/8, /* PRI_UNAT_MEM */
struct_offset(struct unw_frame_info, bsp_loc)/8,
@@ -189,9 +195,9 @@
struct_offset(struct unw_frame_info, fr_loc[30 - 16])/8,
struct_offset(struct unw_frame_info, fr_loc[31 - 16])/8,
},
- hash : { [0 ... UNW_HASH_SIZE - 1] = -1 },
-#if UNW_DEBUG
- preg_name: {
+ .hash = { [0 ... UNW_HASH_SIZE - 1] = -1 },
+#ifdef UNW_DEBUG
+ .preg_name = {
"pri_unat_gr", "pri_unat_mem", "bsp", "bspstore", "ar.pfs", "ar.rnat", "psp", "rp",
"r4", "r5", "r6", "r7",
"ar.unat", "pr", "ar.lc", "ar.fpsr",
@@ -223,10 +229,25 @@
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_DPRINT(0, "unwind.%s: bad scratch reg r%lu\n", __FUNCTION__, reg);
return off;
}
+static inline struct pt_regs *
+get_scratch_regs (struct unw_frame_info *info)
+{
+ if (!info->pt) {
+ /* This should not happen with valid unwind info. */
+ UNW_DPRINT(0, "unwind.%s: bad unwind info: resetting info->pt\n", __FUNCTION__);
+ if (info->flags & UNW_FLAG_INTERRUPT_FRAME)
+ info->pt = (unsigned long) ((struct pt_regs *) info->psp - 1);
+ else
+ info->pt = info->sp - 16;
+ }
+ UNW_DPRINT(3, "unwind.%s: sp 0x%lx pt 0x%lx\n", __FUNCTION__, info->sp, info->pt);
+ return (struct pt_regs *) info->pt;
+}
+
int
unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char *nat, int write)
{
@@ -235,7 +256,13 @@
struct pt_regs *pt;
if ((unsigned) regnum - 1 >= 127) {
- dprintk("unwind: trying to access non-existent r%u\n", regnum);
+ if (regnum == 0 && !write) {
+ *val = 0; /* read r0 always returns 0 */
+ *nat = 0;
+ return 0;
+ }
+ UNW_DPRINT(0, "unwind.%s: trying to access non-existent r%u\n",
+ __FUNCTION__, regnum);
return -1;
}
@@ -280,8 +307,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_DPRINT(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 +326,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));
+ pt = get_scratch_regs(info);
+ addr = (unsigned long *) ((unsigned long)pt + pt_regs_off(regnum));
if (info->pri_unat_loc)
nat_addr = info->pri_unat_loc;
else
@@ -316,7 +341,8 @@
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_DPRINT(0, "unwind.%s: ignoring attempt to access register outside "
+ "of rbs\n", __FUNCTION__);
return -1;
}
if ((unsigned long) nat_addr >= info->regstk.top)
@@ -348,15 +374,11 @@
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;
switch (regnum) {
/* scratch: */
- case 0: addr = &pt->b0; break;
- case 6: addr = &pt->b6; break;
- case 7: addr = &pt->b7; break;
+ case 0: pt = get_scratch_regs(info); addr = &pt->b0; break;
+ case 6: pt = get_scratch_regs(info); addr = &pt->b6; break;
+ case 7: pt = get_scratch_regs(info); addr = &pt->b7; break;
/* preserved: */
case 1: case 2: case 3: case 4: case 5:
@@ -366,7 +388,8 @@
break;
default:
- dprintk("unwind: trying to access non-existent b%u\n", regnum);
+ UNW_DPRINT(0, "unwind.%s: trying to access non-existent b%u\n",
+ __FUNCTION__, regnum);
return -1;
}
if (write)
@@ -383,22 +406,20 @@
struct pt_regs *pt;
if ((unsigned) (regnum - 2) >= 126) {
- dprintk("unwind: trying to access non-existent f%u\n", regnum);
+ UNW_DPRINT(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;
-
if (regnum <= 5) {
addr = *(&info->f2_loc + (regnum - 2));
if (!addr)
addr = &info->sw->f2 + (regnum - 2);
} else if (regnum <= 15) {
- if (regnum <= 9)
+ if (regnum <= 9) {
+ pt = get_scratch_regs(info);
addr = &pt->f6 + (regnum - 6);
+ }
else
addr = &info->sw->f10 + (regnum - 10);
} else if (regnum <= 31) {
@@ -428,11 +449,6 @@
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;
-
switch (regnum) {
case UNW_AR_BSP:
addr = info->bsp_loc;
@@ -487,15 +503,18 @@
break;
case UNW_AR_RSC:
+ pt = get_scratch_regs(info);
addr = &pt->ar_rsc;
break;
case UNW_AR_CCV:
+ pt = get_scratch_regs(info);
addr = &pt->ar_ccv;
break;
default:
- dprintk("unwind: trying to access non-existent ar%u\n", regnum);
+ UNW_DPRINT(0, "unwind.%s: trying to access non-existent ar%u\n",
+ __FUNCTION__, regnum);
return -1;
}
@@ -532,7 +551,7 @@
rs = alloc_reg_state();
if (!rs) {
- printk("unwind: cannot stack reg state!\n");
+ printk(KERN_ERR "unwind: cannot stack reg state!\n");
return;
}
memcpy(rs, &sr->curr, sizeof(*rs));
@@ -545,7 +564,7 @@
struct unw_reg_state *rs = sr->curr.next;
if (!rs) {
- printk("unwind: stack underflow!\n");
+ printk(KERN_ERR "unwind: stack underflow!\n");
return;
}
memcpy(&sr->curr, rs, sizeof(*rs));
@@ -561,7 +580,7 @@
while (rs) {
copy = alloc_reg_state();
if (!copy) {
- printk ("unwind.dup_state_stack: out of memory\n");
+ printk(KERN_ERR "unwind.dup_state_stack: out of memory\n");
return NULL;
}
memcpy(copy, rs, sizeof(*copy));
@@ -612,7 +631,7 @@
default:
break;
}
- dprintk("unwind: bad abreg=0x%x\n", abreg);
+ UNW_DPRINT(0, "unwind.%s: bad abreg=0x%x\n", __FUNCTION__, abreg);
return UNW_REG_LC;
}
@@ -652,7 +671,7 @@
return;
}
}
- dprintk("unwind: excess spill!\n");
+ UNW_DPRINT(0, "unwind.%s: excess spill!\n", __FUNCTION__);
}
static inline void
@@ -720,7 +739,7 @@
desc_prologue (int body, unw_word rlen, unsigned char mask, unsigned char grsave,
struct unw_state_record *sr)
{
- int i;
+ int i, region_start;
if (!(sr->in_body || sr->first_region))
finish_prologue(sr);
@@ -732,19 +751,20 @@
return;
}
+ region_start = sr->region_start + sr->region_len;
+
for (i = 0; i < sr->epilogue_count; ++i)
pop(sr);
sr->epilogue_count = 0;
sr->epilogue_start = UNW_WHEN_NEVER;
- if (!body)
- push(sr);
-
- sr->region_start += sr->region_len;
+ sr->region_start = region_start;
sr->region_len = rlen;
sr->in_body = body;
if (!body) {
+ push(sr);
+
for (i = 0; i < 4; ++i) {
if (mask & 0x8)
set_reg(sr->curr.reg + unw.save_order[i], UNW_WHERE_GR,
@@ -765,10 +785,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_DPRINT(3, "unwind.%s: interrupt frame\n", __FUNCTION__);
+ }
else
- dprintk("unwind: ignoring unwabi(abi=0x%x,context=0x%x)\n", abi, context);
+ UNW_DPRINT(0, "unwind%s: ignoring unwabi(abi=0x%x,context=0x%x)\n",
+ __FUNCTION__, abi, context);
}
static inline void
@@ -951,7 +974,7 @@
return;
}
}
- printk("unwind: failed to find state labeled 0x%lx\n", label);
+ printk(KERN_ERR "unwind: failed to find state labeled 0x%lx\n", label);
}
static inline void
@@ -961,7 +984,7 @@
ls = alloc_labeled_state();
if (!ls) {
- printk("unwind.desc_label_state(): out of memory\n");
+ printk(KERN_ERR "unwind.desc_label_state(): out of memory\n");
return;
}
ls->label = label;
@@ -1055,7 +1078,8 @@
r->val = 4*spoff;
}
-#define UNW_DEC_BAD_CODE(code) printk("unwind: unknown code 0x%02x\n", code);
+#define UNW_DEC_BAD_CODE(code) printk(KERN_ERR "unwind: unknown code 0x%02x\n", \
+ code);
/*
* region headers:
@@ -1135,6 +1159,9 @@
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);
ip = info->ip;
@@ -1259,8 +1286,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_DPRINT(0, "unwind.%s: script exceeds maximum size of %u instructions!\n",
+ __FUNCTION__, UNW_MAX_SCRIPT_LEN);
return;
}
script->insn[script->count++] = insn;
@@ -1301,7 +1328,8 @@
break;
default:
- dprintk("unwind: don't know how to emit nat info for where = %u\n", r->where);
+ UNW_DPRINT(0, "unwind.%s: don't know how to emit nat info for where = %u\n",
+ __FUNCTION__, r->where);
return;
}
insn.opc = opc;
@@ -1338,8 +1366,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 +1378,12 @@
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_DPRINT(0, "unwind.%s: kernel may not touch f%lu\n",
+ __FUNCTION__, rval);
}
break;
@@ -1362,14 +1391,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 +1410,8 @@
break;
default:
- dprintk("unwind: register %u has unexpected `where' value of %u\n", i, r->where);
+ UNW_DPRINT(0, "unwind%s: register %u has unexpected `where' value of %u\n",
+ __FUNCTION__, i, r->where);
break;
}
insn.opc = opc;
@@ -1455,9 +1484,10 @@
r->when = UNW_WHEN_NEVER;
sr.pr_val = info->pr;
+ UNW_DPRINT(3, "unwind.%s: ip 0x%lx\n", __FUNCTION__, ip);
script = script_new(ip);
if (!script) {
- dprintk("unwind: failed to create unwind script\n");
+ UNW_DPRINT(0, "unwind.%s: failed to create unwind script\n", __FUNCTION__);
STAT(unw.stat.script.build_time += ia64_get_itc() - start);
return 0;
}
@@ -1475,8 +1505,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_DPRINT(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 +1554,32 @@
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_DPRINT(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_DPRINT(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_DPRINT(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_DPRINT(1, "r%lu", r->val); break;
+ case UNW_WHERE_FR: UNW_DPRINT(1, "f%lu", r->val); break;
+ case UNW_WHERE_BR: UNW_DPRINT(1, "b%lu", r->val); break;
+ case UNW_WHERE_SPREL: UNW_DPRINT(1, "[sp+0x%lx]", r->val); break;
+ case UNW_WHERE_PSPREL: UNW_DPRINT(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_DPRINT(1, "%s+0x%lx", unw.preg_name[r - sr.curr.reg], r->val);
+ break;
+
+ default:
+ UNW_DPRINT(1, "BADWHERE(%d)", r->where);
break;
- default: printk("BADWHERE(%d)", r->where); break;
}
- printk("\t\t%d\n", r->when);
+ UNW_DPRINT(1, "\t\t%d\n", r->when);
}
}
#endif
@@ -1641,6 +1677,16 @@
s[dst] = s[val];
break;
+ case UNW_INSN_MOVE_SCRATCH:
+ if (state->pt) {
+ s[dst] = (unsigned long) get_scratch_regs(state) + val;
+ } else {
+ s[dst] = 0;
+ UNW_DPRINT(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 +1712,12 @@
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_DPRINT(0, "unwind.%s: rejecting bad psp=0x%lx\n",
+ __FUNCTION__, s[val]);
break;
}
#endif
@@ -1703,7 +1750,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_DPRINT(1, "unwind.%s: rejecting bad ip=0x%lx\n", __FUNCTION__, info->ip);
info->rp_loc = 0;
return -1;
}
@@ -1712,8 +1760,9 @@
if (!scr) {
scr = build_script(info);
if (!scr) {
- dprintk("unwind: failed to locate/build unwind script for ip %lx\n",
- info->ip);
+ UNW_DPRINT(0,
+ "unwind.%s: failed to locate/build unwind script for ip %lx\n",
+ __FUNCTION__, info->ip);
return -1;
}
have_write_lock = 1;
@@ -1746,7 +1795,9 @@
/* 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_DPRINT(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 +1807,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_DPRINT(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_DPRINT(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 +1824,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_DPRINT(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_DPRINT(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 +1843,15 @@
/* 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_DPRINT(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_DPRINT(0, "unwind.%s: ip, sp, bsp 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 +1875,8 @@
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_DPRINT(0, "unwind.%s: failed to read return pointer (ip=0x%lx)\n",
+ __FUNCTION__, ip);
return -1;
}
/*
@@ -1832,26 +1887,25 @@
return 0;
}
unw_get_ip(info, &ip);
- dprintk("unwind: failed to unwind to user-level (ip=0x%lx)\n", ip);
+ UNW_DPRINT(0, "unwind.%s: failed to unwind to user-level (ip=0x%lx)\n", __FUNCTION__, ip);
return -1;
}
-void
-unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t, struct switch_stack *sw)
+static void
+init_frame_info (struct unw_frame_info *info, struct task_struct *t,
+ struct switch_stack *sw, unsigned long stktop)
{
- unsigned long rbslimit, rbstop, stklimit, stktop, sol;
+ unsigned long rbslimit, rbstop, stklimit;
STAT(unsigned long start, flags;)
STAT(local_irq_save(flags); ++unw.stat.api.inits; start = ia64_get_itc());
/*
- * Subtle stuff here: we _could_ unwind through the
- * switch_stack frame but we don't want to do that because it
- * would be slow as each preserved register would have to be
- * processed. Instead, what we do here is zero out the frame
- * info and start the unwind process at the function that
- * created the switch_stack frame. When a preserved value in
- * switch_stack needs to be accessed, run_script() will
+ * Subtle stuff here: we _could_ unwind through the switch_stack frame but we
+ * don't want to do that because it would be slow as each preserved register would
+ * have to be processed. Instead, what we do here is zero out the frame info and
+ * start the unwind process at the function that created the switch_stack frame.
+ * When a preserved value in switch_stack needs to be accessed, run_script() will
* initialize the appropriate pointer on demand.
*/
memset(info, 0, sizeof(*info));
@@ -1862,7 +1916,6 @@
rbstop = rbslimit;
stklimit = (unsigned long) t + IA64_STK_OFFSET;
- stktop = (unsigned long) sw - 16;
if (stktop <= rbstop)
stktop = rbstop;
@@ -1872,15 +1925,56 @@
info->memstk.top = stktop;
info->task = t;
info->sw = sw;
- info->sp = info->psp = (unsigned long) (sw + 1) - 16;
+ info->sp = info->psp = stktop;
+ info->pr = sw->pr;
+ UNW_DPRINT(3, "unwind.%s:\n"
+ " task 0x%lx\n"
+ " rbs = [0x%lx-0x%lx)\n"
+ " stk = [0x%lx-0x%lx)\n"
+ " pr 0x%lx\n"
+ " sw 0x%lx\n"
+ " sp 0x%lx\n",
+ __FUNCTION__, (unsigned long) task, rbslimit, rbstop, stktop, stklimit,
+ info->pr, (unsigned long) info->sw, info->sp);
+ STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags));
+}
+
+void
+unw_init_from_interruption (struct unw_frame_info *info, struct task_struct *t,
+ struct pt_regs *pt, struct switch_stack *sw)
+{
+ unsigned long sof;
+
+ init_frame_info(info, t, sw, pt->r12);
+ info->cfm_loc = &pt->cr_ifs;
+ sof = *info->cfm_loc & 0x7f;
+ info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sof);
+ info->ip = pt->cr_iip + ia64_psr(pt)->ri;
+ info->pt = (unsigned long) pt;
+ UNW_DPRINT(3, "unwind.%s:\n"
+ " bsp 0x%lx\n"
+ " sof 0x%lx\n"
+ " ip 0x%lx\n",
+ info->bsp, sof, info->ip);
+ find_save_locs(info);
+}
+
+void
+unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t, struct switch_stack *sw)
+{
+ unsigned long sol;
+
+ init_frame_info(info, t, sw, (unsigned long) (sw + 1) - 16);
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_DPRINT(3, "unwind.%s:\n"
+ " bsp 0x%lx\n"
+ " sol 0x%lx\n"
+ " ip 0x%lx\n",
+ info->bsp, sol, info->ip);
find_save_locs(info);
- STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags));
}
void
@@ -1888,6 +1982,7 @@
{
struct switch_stack *sw = (struct switch_stack *) (t->thread.ksp + 16);
+ UNW_DPRINT(1, "unwind.%s\n", __FUNCTION__);
unw_init_frame_info(info, t, sw);
}
@@ -1915,7 +2010,8 @@
unsigned long flags;
if (end - start <= 0) {
- dprintk("unwind: ignoring attempt to insert empty unwind table\n");
+ UNW_DPRINT(0, "unwind.%s: ignoring attempt to insert empty unwind table\n",
+ __FUNCTION__);
return 0;
}
@@ -1945,13 +2041,15 @@
long index;
if (!handle) {
- dprintk("unwind: ignoring attempt to remove non-existent unwind table\n");
+ UNW_DPRINT(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_DPRINT(0, "unwind.%s: sorry, freeing the kernel's unwind table is a "
+ "no-can-do!\n", __FUNCTION__);
return;
}
@@ -1963,7 +2061,8 @@
if (prev->next == table)
break;
if (!prev) {
- dprintk("unwind: failed to find unwind table %p\n", (void *) table);
+ UNW_DPRINT(0, "unwind.%s: failed to find unwind table %p\n",
+ __FUNCTION__, (void *) table);
spin_unlock_irqrestore(&unw.lock, flags);
return;
}
@@ -2015,7 +2114,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");
+ printk(KERN_ERR "unwind: unable to create unwind data for gate page!\n");
return;
}
unw.gate_table_size = size;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)