From: Mark Wielaard Date: Sat, 21 Dec 2013 20:56:35 +0000 (+0100) Subject: libdwfl: Make sure to set the CFI return register only once (for ppc64). X-Git-Tag: elfutils-0.158~22 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3e98ab73f31ed35fcd83e0e1a01147a559d1858b;p=thirdparty%2Felfutils.git libdwfl: Make sure to set the CFI return register only once (for ppc64). On PPC64 there are two DWARF registers numbers that can represent the same register. If that register is the CIE return register then we only want to set it once. The second setting will confuse the unwinder. Signed-off-by: Mark Wielaard --- diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index d8ca9eb36..13a4ff9db 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,3 +1,8 @@ +2013-12-21 Mark Wielaard + + * frame_unwind.c (handle_cfi): Track whether the return register + has been set and only allow it to be set once. + 2013-12-20 Mark Wielaard * dwfl_frame.c (one_arg): New struct. diff --git a/libdwfl/frame_unwind.c b/libdwfl/frame_unwind.c index 671c6d111..3ce45479b 100644 --- a/libdwfl/frame_unwind.c +++ b/libdwfl/frame_unwind.c @@ -536,6 +536,12 @@ handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias) Ebl *ebl = process->ebl; size_t nregs = ebl_frame_nregs (ebl); assert (nregs > 0); + + /* The return register is special for setting the unwound->pc_state. */ + unsigned ra = frame->fde->cie->return_address_register; + bool ra_set = false; + ebl_dwarf_to_regno (ebl, &ra); + for (unsigned regno = 0; regno < nregs; regno++) { Dwarf_Op reg_ops_mem[3], *reg_ops; @@ -552,8 +558,7 @@ handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias) if (reg_ops == reg_ops_mem) { /* REGNO is undefined. */ - unsigned ra = frame->fde->cie->return_address_register; - if (ebl_dwarf_to_regno (ebl, &ra) && regno == ra) + if (regno == ra) unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED; continue; } @@ -576,11 +581,29 @@ handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias) But PPC32 does not use such registers. */ continue; } + + /* This is another strange PPC[64] case. There are two + registers numbers that can represent the same DWARF return + register number. We only want one to actually set the return + register value. */ + if (ra_set) + { + unsigned r = regno; + if (ebl_dwarf_to_regno (ebl, &r) && r == ra) + continue; + } + if (! __libdwfl_frame_reg_set (unwound, regno, regval)) { __libdwfl_seterrno (DWFL_E_INVALID_REGISTER); continue; } + else if (! ra_set) + { + unsigned r = regno; + if (ebl_dwarf_to_regno (ebl, &r) && r == ra) + ra_set = true; + } } if (unwound->pc_state == DWFL_FRAME_STATE_ERROR && __libdwfl_frame_reg_get (unwound,