Commit c9b85512 authored by David Mosberger's avatar David Mosberger

ia64: Add support to the kernel unwinder for the ".save rp, r0" idiom.

Based on patch by Keith Owens.
parent 69aeca90
...@@ -56,8 +56,7 @@ halt_msg: ...@@ -56,8 +56,7 @@ halt_msg:
GLOBAL_ENTRY(_start) GLOBAL_ENTRY(_start)
start_ap: start_ap:
.prologue .prologue
.save rp, r4 // terminate unwind chain with a NULL rp .save rp, r0 // terminate unwind chain with a NULL rp
mov r4=r0
.body .body
rsm psr.i | psr.ic rsm psr.i | psr.ic
...@@ -818,8 +817,7 @@ END(ia64_delay_loop) ...@@ -818,8 +817,7 @@ END(ia64_delay_loop)
GLOBAL_ENTRY(start_kernel_thread) GLOBAL_ENTRY(start_kernel_thread)
.prologue .prologue
.save rp, r4 // this is the end of the call-chain .save rp, r0 // this is the end of the call-chain
mov r4=r0
.body .body
alloc r2 = ar.pfs, 0, 0, 2, 0 alloc r2 = ar.pfs, 0, 0, 2, 0
mov out0 = r9 mov out0 = r9
......
...@@ -89,6 +89,8 @@ static struct { ...@@ -89,6 +89,8 @@ static struct {
/* list of unwind tables (one per load-module) */ /* list of unwind tables (one per load-module) */
struct unw_table *tables; struct unw_table *tables;
unsigned long r0; /* constant 0 for r0 */
/* table of registers that prologues can save (and order in which they're saved): */ /* table of registers that prologues can save (and order in which they're saved): */
const unsigned char save_order[8]; const unsigned char save_order[8];
...@@ -239,7 +241,11 @@ static struct { ...@@ -239,7 +241,11 @@ static struct {
#endif #endif
}; };
/* Unwind accessors. */ static inline int
read_only (unsigned long *addr)
{
return (addr == &unw.r0);
}
/* /*
* Returns offset of rREG in struct pt_regs. * Returns offset of rREG in struct pt_regs.
...@@ -274,6 +280,8 @@ get_scratch_regs (struct unw_frame_info *info) ...@@ -274,6 +280,8 @@ get_scratch_regs (struct unw_frame_info *info)
return (struct pt_regs *) info->pt; return (struct pt_regs *) info->pt;
} }
/* Unwind accessors. */
int int
unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char *nat, int write) unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char *nat, int write)
{ {
...@@ -377,11 +385,15 @@ unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char ...@@ -377,11 +385,15 @@ unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char
} }
if (write) { if (write) {
*addr = *val; if (read_only(addr))
if (*nat) UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n");
*nat_addr |= nat_mask; else {
else *addr = *val;
*nat_addr &= ~nat_mask; if (*nat)
*nat_addr |= nat_mask;
else
*nat_addr &= ~nat_mask;
}
} else { } else {
if ((*nat_addr & nat_mask) == 0) { if ((*nat_addr & nat_mask) == 0) {
*val = *addr; *val = *addr;
...@@ -420,7 +432,10 @@ unw_access_br (struct unw_frame_info *info, int regnum, unsigned long *val, int ...@@ -420,7 +432,10 @@ unw_access_br (struct unw_frame_info *info, int regnum, unsigned long *val, int
return -1; return -1;
} }
if (write) if (write)
*addr = *val; if (read_only(addr))
UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n");
else
*addr = *val;
else else
*val = *addr; *val = *addr;
return 0; return 0;
...@@ -465,7 +480,10 @@ unw_access_fr (struct unw_frame_info *info, int regnum, struct ia64_fpreg *val, ...@@ -465,7 +480,10 @@ unw_access_fr (struct unw_frame_info *info, int regnum, struct ia64_fpreg *val,
} }
if (write) if (write)
*addr = *val; if (read_only(addr))
UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n");
else
*addr = *val;
else else
*val = *addr; *val = *addr;
return 0; return 0;
...@@ -557,9 +575,12 @@ unw_access_ar (struct unw_frame_info *info, int regnum, unsigned long *val, int ...@@ -557,9 +575,12 @@ unw_access_ar (struct unw_frame_info *info, int regnum, unsigned long *val, int
return -1; return -1;
} }
if (write) if (write) {
*addr = *val; if (read_only(addr))
else UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n");
else
*addr = *val;
} else
*val = *addr; *val = *addr;
return 0; return 0;
} }
...@@ -574,9 +595,12 @@ unw_access_pr (struct unw_frame_info *info, unsigned long *val, int write) ...@@ -574,9 +595,12 @@ unw_access_pr (struct unw_frame_info *info, unsigned long *val, int write)
if (!addr) if (!addr)
addr = &info->sw->pr; addr = &info->sw->pr;
if (write) if (write) {
*addr = *val; if (read_only(addr))
else UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n");
else
*addr = *val;
} else
*val = *addr; *val = *addr;
return 0; return 0;
} }
...@@ -1407,6 +1431,9 @@ compile_reg (struct unw_state_record *sr, int i, struct unw_script *script) ...@@ -1407,6 +1431,9 @@ compile_reg (struct unw_state_record *sr, int i, struct unw_script *script)
need_nat_info = 0; need_nat_info = 0;
} }
val = unw.preg_index[UNW_REG_R4 + (rval - 4)]; val = unw.preg_index[UNW_REG_R4 + (rval - 4)];
} else if (rval == 0) {
opc = UNW_INSN_MOVE_CONST;
val = 0;
} else { } else {
/* register got spilled to a scratch register */ /* register got spilled to a scratch register */
opc = UNW_INSN_MOVE_SCRATCH; opc = UNW_INSN_MOVE_SCRATCH;
...@@ -1729,6 +1756,17 @@ run_script (struct unw_script *script, struct unw_frame_info *state) ...@@ -1729,6 +1756,17 @@ run_script (struct unw_script *script, struct unw_frame_info *state)
} }
break; break;
case UNW_INSN_MOVE_CONST:
if (val == 0)
s[dst] = (unsigned long) &unw.r0;
else {
s[dst] = 0;
UNW_DPRINT(0, "unwind.%s: UNW_INSN_MOVE_CONST bad val=%ld\n",
__FUNCTION__, val);
}
break;
case UNW_INSN_MOVE_STACKED: case UNW_INSN_MOVE_STACKED:
s[dst] = (unsigned long) ia64_rse_skip_regs((unsigned long *)state->bsp, s[dst] = (unsigned long) ia64_rse_skip_regs((unsigned long *)state->bsp,
val); val);
......
...@@ -133,6 +133,7 @@ enum unw_insn_opcode { ...@@ -133,6 +133,7 @@ enum unw_insn_opcode {
UNW_INSN_SETNAT_TYPE, /* s[dst+1].nat.type = val */ 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" */ UNW_INSN_MOVE_SCRATCH, /* s[dst] = scratch reg "val" */
UNW_INSN_MOVE_CONST, /* s[dst] = constant reg "val" */
}; };
struct unw_insn { struct unw_insn {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment