Unwind can load wrong data from pt_regs
2.4.19-ia64-020821/arch/ia64/kernel/unwind.c, compile_reg() contains
case UNW_WHERE_FR:
if (rval <= 5)
val = unw.preg_index[UNW_REG_F2 + (rval - 1)];
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);
if (rval <= 9)
val += struct_offset(struct pt_regs, f6) + 16*(rval - 6);
else
dprintk("unwind: kernel may not touch f%lu\n", rval);
}
break;
case UNW_WHERE_BR:
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);
if (rval = 0)
val += struct_offset(struct pt_regs, b0);
else if (rval = 6)
val += struct_offset(struct pt_regs, b6);
else
val += struct_offset(struct pt_regs, b7);
}
break;This implicitly assumes that when a fr or br register is required from pt_regs, info->sp is pointing to pt_regs. But info->sp is modified as the code unwinds through each function. The above code only gives correct results for register lookups from the failing function. Unwinding and accessing a fr or br register from earlier functions loads incorrect values for those registers.
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Keith Owens
Keith> This implicitly assumes that when a fr or br register is Keith> required from pt_regs, info->sp is pointing to pt_regs. But Keith> info->sp is modified as the code unwinds through each Keith> function. The above code only gives correct results for Keith> register lookups from the failing function. Unwinding and Keith> accessing a fr or br register from earlier functions loads Keith> incorrect values for those registers.
Yes, this is something that has been fixed already in the user-level libunwind. It's not hard to fix, just someone needs to get around to do it. I don't think it's a critical issue, since it only happens for nested traps. I assume you saw this with kdb?
--david
Quoted 10 lines · David Mosberger
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Keith Owens
Keith> This implicitly assumes that when a fr or br register is Keith> required from
pt_regs,info->spis pointing topt_regs. But Keith>info->spis modified as the code unwinds through each Keith> function. The above code only gives correct results for Keith> register lookups from the failing function. Unwinding and Keith> accessing a fr or br register from earlier functions loads Keith> incorrect values for those registers.
Quoted 4 lines
Yes, this is something that has been fixed already in the user-level libunwind. It's not hard to fix, just someone needs to get around to do it. I don't think it's a critical issue, since it only happens for nested traps. I assume you saw this with kdb?
How did you guess :). I will look at libunwind and do a kernel fix.
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Keith Owens
Keith> How did you guess :). I will look at libunwind and do a Keith> kernel fix.
The basic idea for the fix is to add a new variable (pt_regs_addr) to unw_frame_info to track the sp of the latest UNW_FLAG_INTERRUPT_FRAME encountered.
--david