Skip to contentSkip to conversation

Unwind can load wrong data from pt_regs

Linux-ia64 Keith Owens 2 participants 4 messages Dec 9, 2002

lore
Share & tools
lore
#0 lore raw

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.

#1 lore raw
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
#2 lore raw
In reply to Keith Owens
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->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.

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.

#3 lore raw
In reply to Keith Owens
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