This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] 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 <mjw@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@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>
 
 	* 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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]