[IA64] unwind.c uses wrong unat from switch_stack
unwind.c can read the wrong unat bits from switch_stack. sw->caller_unat is the value of ar.unat when the task was blocked. sw->ar_unat is the value of ar.unat after doing st8.spill for r4-7. IOW, ar_unat is caller_unat with 4 bits changed. unw_access_gr() uses sw->ar_unat for r4-7 (correct), but it also uses sw->ar_unat for other scratch registers (incorrect). sw->ar_unat should only be used for r4-7, everything else should use sw->caller_unat, unless modified by unwind info. Using sw->ar_unat risks picking up the 4 bits that were overwritten when r4-7 were saved. Also this line is wrong unw.sw_off[unw.preg_index[UNW_REG_PFS]] = SW(AR_UNAT); and should be unw.sw_off[unw.preg_index[UNW_REG_PFS]] = SW(AR_PFS); Signed-off-by: Keith Owens <kaos@sgi.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
This commit is contained in:
parent
d108919b2b
commit
b833961bd3
@ -362,7 +362,7 @@ unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char
|
|||||||
if (info->pri_unat_loc)
|
if (info->pri_unat_loc)
|
||||||
nat_addr = info->pri_unat_loc;
|
nat_addr = info->pri_unat_loc;
|
||||||
else
|
else
|
||||||
nat_addr = &info->sw->ar_unat;
|
nat_addr = &info->sw->caller_unat;
|
||||||
nat_mask = (1UL << ((long) addr & 0x1f8)/8);
|
nat_mask = (1UL << ((long) addr & 0x1f8)/8);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -524,7 +524,7 @@ unw_access_ar (struct unw_frame_info *info, int regnum, unsigned long *val, int
|
|||||||
case UNW_AR_UNAT:
|
case UNW_AR_UNAT:
|
||||||
addr = info->unat_loc;
|
addr = info->unat_loc;
|
||||||
if (!addr)
|
if (!addr)
|
||||||
addr = &info->sw->ar_unat;
|
addr = &info->sw->caller_unat;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UNW_AR_LC:
|
case UNW_AR_LC:
|
||||||
@ -1775,7 +1775,7 @@ run_script (struct unw_script *script, struct unw_frame_info *state)
|
|||||||
|
|
||||||
case UNW_INSN_SETNAT_MEMSTK:
|
case UNW_INSN_SETNAT_MEMSTK:
|
||||||
if (!state->pri_unat_loc)
|
if (!state->pri_unat_loc)
|
||||||
state->pri_unat_loc = &state->sw->ar_unat;
|
state->pri_unat_loc = &state->sw->caller_unat;
|
||||||
/* register off. is a multiple of 8, so the least 3 bits (type) are 0 */
|
/* register off. is a multiple of 8, so the least 3 bits (type) are 0 */
|
||||||
s[dst+1] = ((unsigned long) state->pri_unat_loc - s[dst]) | UNW_NAT_MEMSTK;
|
s[dst+1] = ((unsigned long) state->pri_unat_loc - s[dst]) | UNW_NAT_MEMSTK;
|
||||||
break;
|
break;
|
||||||
@ -2243,11 +2243,11 @@ unw_init (void)
|
|||||||
if (8*sizeof(unw_hash_index_t) < UNW_LOG_HASH_SIZE)
|
if (8*sizeof(unw_hash_index_t) < UNW_LOG_HASH_SIZE)
|
||||||
unw_hash_index_t_is_too_narrow();
|
unw_hash_index_t_is_too_narrow();
|
||||||
|
|
||||||
unw.sw_off[unw.preg_index[UNW_REG_PRI_UNAT_GR]] = SW(AR_UNAT);
|
unw.sw_off[unw.preg_index[UNW_REG_PRI_UNAT_GR]] = SW(CALLER_UNAT);
|
||||||
unw.sw_off[unw.preg_index[UNW_REG_BSPSTORE]] = SW(AR_BSPSTORE);
|
unw.sw_off[unw.preg_index[UNW_REG_BSPSTORE]] = SW(AR_BSPSTORE);
|
||||||
unw.sw_off[unw.preg_index[UNW_REG_PFS]] = SW(AR_UNAT);
|
unw.sw_off[unw.preg_index[UNW_REG_PFS]] = SW(AR_PFS);
|
||||||
unw.sw_off[unw.preg_index[UNW_REG_RP]] = SW(B0);
|
unw.sw_off[unw.preg_index[UNW_REG_RP]] = SW(B0);
|
||||||
unw.sw_off[unw.preg_index[UNW_REG_UNAT]] = SW(AR_UNAT);
|
unw.sw_off[unw.preg_index[UNW_REG_UNAT]] = SW(CALLER_UNAT);
|
||||||
unw.sw_off[unw.preg_index[UNW_REG_PR]] = SW(PR);
|
unw.sw_off[unw.preg_index[UNW_REG_PR]] = SW(PR);
|
||||||
unw.sw_off[unw.preg_index[UNW_REG_LC]] = SW(AR_LC);
|
unw.sw_off[unw.preg_index[UNW_REG_LC]] = SW(AR_LC);
|
||||||
unw.sw_off[unw.preg_index[UNW_REG_FPSR]] = SW(AR_FPSR);
|
unw.sw_off[unw.preg_index[UNW_REG_FPSR]] = SW(AR_FPSR);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user