diff options
author | Keith Owens <kaos@sgi.com> | 2005-07-22 02:41:00 -0400 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2005-07-27 17:18:08 -0400 |
commit | b833961bd30eec201b9a94eec36aa7ac96f9c9c0 (patch) | |
tree | 2ae8efad5995f7f23564304fd5027bea026ac65e /arch/ia64/kernel | |
parent | d108919b2b5c064946c9bd30cbd4761d491cddb0 (diff) |
[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>
Diffstat (limited to 'arch/ia64/kernel')
-rw-r--r-- | arch/ia64/kernel/unwind.c | 12 |
1 files changed, 6 insertions, 6 deletions
diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c index 2776a074c6f..3288be47bc7 100644 --- a/arch/ia64/kernel/unwind.c +++ b/arch/ia64/kernel/unwind.c | |||
@@ -362,7 +362,7 @@ unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char | |||
362 | if (info->pri_unat_loc) | 362 | if (info->pri_unat_loc) |
363 | nat_addr = info->pri_unat_loc; | 363 | nat_addr = info->pri_unat_loc; |
364 | else | 364 | else |
365 | nat_addr = &info->sw->ar_unat; | 365 | nat_addr = &info->sw->caller_unat; |
366 | nat_mask = (1UL << ((long) addr & 0x1f8)/8); | 366 | nat_mask = (1UL << ((long) addr & 0x1f8)/8); |
367 | } | 367 | } |
368 | } else { | 368 | } else { |
@@ -524,7 +524,7 @@ unw_access_ar (struct unw_frame_info *info, int regnum, unsigned long *val, int | |||
524 | case UNW_AR_UNAT: | 524 | case UNW_AR_UNAT: |
525 | addr = info->unat_loc; | 525 | addr = info->unat_loc; |
526 | if (!addr) | 526 | if (!addr) |
527 | addr = &info->sw->ar_unat; | 527 | addr = &info->sw->caller_unat; |
528 | break; | 528 | break; |
529 | 529 | ||
530 | case UNW_AR_LC: | 530 | case UNW_AR_LC: |
@@ -1775,7 +1775,7 @@ run_script (struct unw_script *script, struct unw_frame_info *state) | |||
1775 | 1775 | ||
1776 | case UNW_INSN_SETNAT_MEMSTK: | 1776 | case UNW_INSN_SETNAT_MEMSTK: |
1777 | if (!state->pri_unat_loc) | 1777 | if (!state->pri_unat_loc) |
1778 | state->pri_unat_loc = &state->sw->ar_unat; | 1778 | state->pri_unat_loc = &state->sw->caller_unat; |
1779 | /* register off. is a multiple of 8, so the least 3 bits (type) are 0 */ | 1779 | /* register off. is a multiple of 8, so the least 3 bits (type) are 0 */ |
1780 | s[dst+1] = ((unsigned long) state->pri_unat_loc - s[dst]) | UNW_NAT_MEMSTK; | 1780 | s[dst+1] = ((unsigned long) state->pri_unat_loc - s[dst]) | UNW_NAT_MEMSTK; |
1781 | break; | 1781 | break; |
@@ -2243,11 +2243,11 @@ unw_init (void) | |||
2243 | if (8*sizeof(unw_hash_index_t) < UNW_LOG_HASH_SIZE) | 2243 | if (8*sizeof(unw_hash_index_t) < UNW_LOG_HASH_SIZE) |
2244 | unw_hash_index_t_is_too_narrow(); | 2244 | unw_hash_index_t_is_too_narrow(); |
2245 | 2245 | ||
2246 | unw.sw_off[unw.preg_index[UNW_REG_PRI_UNAT_GR]] = SW(AR_UNAT); | 2246 | unw.sw_off[unw.preg_index[UNW_REG_PRI_UNAT_GR]] = SW(CALLER_UNAT); |
2247 | unw.sw_off[unw.preg_index[UNW_REG_BSPSTORE]] = SW(AR_BSPSTORE); | 2247 | unw.sw_off[unw.preg_index[UNW_REG_BSPSTORE]] = SW(AR_BSPSTORE); |
2248 | unw.sw_off[unw.preg_index[UNW_REG_PFS]] = SW(AR_UNAT); | 2248 | unw.sw_off[unw.preg_index[UNW_REG_PFS]] = SW(AR_PFS); |
2249 | unw.sw_off[unw.preg_index[UNW_REG_RP]] = SW(B0); | 2249 | unw.sw_off[unw.preg_index[UNW_REG_RP]] = SW(B0); |
2250 | unw.sw_off[unw.preg_index[UNW_REG_UNAT]] = SW(AR_UNAT); | 2250 | unw.sw_off[unw.preg_index[UNW_REG_UNAT]] = SW(CALLER_UNAT); |
2251 | unw.sw_off[unw.preg_index[UNW_REG_PR]] = SW(PR); | 2251 | unw.sw_off[unw.preg_index[UNW_REG_PR]] = SW(PR); |
2252 | unw.sw_off[unw.preg_index[UNW_REG_LC]] = SW(AR_LC); | 2252 | unw.sw_off[unw.preg_index[UNW_REG_LC]] = SW(AR_LC); |
2253 | unw.sw_off[unw.preg_index[UNW_REG_FPSR]] = SW(AR_FPSR); | 2253 | unw.sw_off[unw.preg_index[UNW_REG_FPSR]] = SW(AR_FPSR); |