]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdwfl: Make sure to set the CFI return register only once (for ppc64).
authorMark Wielaard <mjw@redhat.com>
Sat, 21 Dec 2013 20:56:35 +0000 (21:56 +0100)
committerMark Wielaard <mjw@redhat.com>
Wed, 25 Dec 2013 20:19:35 +0000 (21:19 +0100)
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 <mjw@redhat.com>
libdwfl/ChangeLog
libdwfl/frame_unwind.c

index d8ca9eb367a45f5bf9fd641bd83a0e8607acef6a..13a4ff9dbb695a749ae718f0dc31f696176672ed 100644 (file)
@@ -1,3 +1,8 @@
+2013-12-21  Mark Wielaard  <mjw@redhat.com>
+
+       * 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  <mjw@redhat.com>
 
        * dwfl_frame.c (one_arg): New struct.
index 671c6d111e8e2085b346631c1c39f8c972375514..3ce45479b8c7a964f7ee514f12b1a2e4cfa31a4a 100644 (file)
@@ -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,