[PATCH] libdwfl: Make sure to set the CFI return register only once (for ppc64).

Mark Wielaard mjw at redhat.com
Sat Dec 21 20:56:35 UTC 2013


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 at redhat.com>
---
 libdwfl/ChangeLog      |  5 +++++
 libdwfl/frame_unwind.c | 27 +++++++++++++++++++++++++--
 2 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index fa605bd..e83b124 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,8 @@
+2013-12-21  Mark Wielaard  <mjw at 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 at redhat.com>
 
 	* linux-kernel-modules.c (report_kernel_archive): Correct nested
diff --git a/libdwfl/frame_unwind.c b/libdwfl/frame_unwind.c
index 671c6d1..3ce4547 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,
-- 
1.8.4.2



More information about the elfutils-devel mailing list