Another ARM oddity. A return value address in an unwind will contain an
extra bit to indicate whether to return to a regular ARM or THUMB function.
Add a new ebl function to return a mask to use to get the actual return
address during an unwind ebl_unwind_ret_mask.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
backends/ChangeLog | 4 ++++
backends/arm_init.c | 3 +++
libdwfl/ChangeLog | 4 ++++
libdwfl/frame_unwind.c | 6 +++++-
libebl/ChangeLog | 6 ++++++
libebl/eblinitreg.c | 9 ++++++++-
libebl/libebl.h | 4 ++++
libebl/libeblP.h | 8 +++++++-
8 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/backends/ChangeLog b/backends/ChangeLog
index 64b669e..11538b0 100644
--- a/backends/ChangeLog
+++ b/backends/ChangeLog
@@ -1,3 +1,7 @@
+2014-06-15 Mark Wielaard <mjw(a)redhat.com>
+
+ * arm_init.c (arm_init): Set unwind_ret_mask.
+
2014-06-14 Mark Wielaard <mjw(a)redhat.com>
* arm_init.c (arm_init): Hook sym_func_value.
diff --git a/backends/arm_init.c b/backends/arm_init.c
index e2e20e4..f95949d 100644
--- a/backends/arm_init.c
+++ b/backends/arm_init.c
@@ -70,5 +70,8 @@ arm_init (elf, machine, eh, ehlen)
eh->frame_nregs = 16;
HOOK (eh, set_initial_registers_tid);
+ /* Bit zero encodes whether to return to a THUMB or ARM function. */
+ eh->unwind_ret_mask = ~(GElf_Addr)1;
+
return MODVERSION;
}
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 888b400..195f5a0 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,7 @@
+2014-06-15 Mark Wielaard <mjw(a)redhat.com>
+
+ * frame_unwind.c (handle_cfi): Use ebl_unwind_ret_mask.
+
2014-06-14 Mark Wielaard <mjw(a)redhat.com>
* dwfl_module_getsym.c (__libdwfl_getsym): Call ebl_sym_func_value.
diff --git a/libdwfl/frame_unwind.c b/libdwfl/frame_unwind.c
index 18c808b..f93348f 100644
--- a/libdwfl/frame_unwind.c
+++ b/libdwfl/frame_unwind.c
@@ -1,5 +1,5 @@
/* Get previous frame state for an existing frame state.
- Copyright (C) 2013 Red Hat, Inc.
+ Copyright (C) 2013, 2014 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -582,6 +582,10 @@ handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi,
Dwarf_Addr bias)
continue;
}
+ /* Some architectures encode some extra info in the return address. */
+ if (regno == frame->fde->cie->return_address_register)
+ regval &= ebl_unwind_ret_mask (ebl);
+
/* 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
diff --git a/libebl/ChangeLog b/libebl/ChangeLog
index 1c7a2ba..d5fac1d 100644
--- a/libebl/ChangeLog
+++ b/libebl/ChangeLog
@@ -1,3 +1,9 @@
+2014-06-15 Mark Wielaard <mjw(a)redhat.com>
+
+ * eblinitreg.c (ebl_unwind_ret_mask): New function.
+ * libebl.h (ebl_unwind_ret_mask): Define.
+ * libeblP.h (struct ebl): Add unwind_ret_mask.
+
2014-06-14 Mark Wielaard <mjw(a)redhat.com>
* Makefile.am (gen_SOURCES): Add eblsymfuncval.c.
diff --git a/libebl/eblinitreg.c b/libebl/eblinitreg.c
index 8909c50..a6bb00c 100644
--- a/libebl/eblinitreg.c
+++ b/libebl/eblinitreg.c
@@ -1,5 +1,5 @@
/* Fetch live process Dwfl_Frame from PID.
- Copyright (C) 2013 Red Hat, Inc.
+ Copyright (C) 2013, 2014 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -49,3 +49,10 @@ ebl_frame_nregs (Ebl *ebl)
{
return ebl == NULL ? 0 : ebl->frame_nregs;
}
+
+GElf_Addr
+ebl_unwind_ret_mask (Ebl *ebl)
+{
+ return ((ebl == NULL || ebl->unwind_ret_mask == 0)
+ ? ~(GElf_Addr)0 : ebl->unwind_ret_mask);
+}
diff --git a/libebl/libebl.h b/libebl/libebl.h
index bc1f491..768dab4 100644
--- a/libebl/libebl.h
+++ b/libebl/libebl.h
@@ -409,6 +409,10 @@ extern bool ebl_set_initial_registers_tid (Ebl *ebl,
extern size_t ebl_frame_nregs (Ebl *ebl)
__nonnull_attribute__ (1);
+/* Mask to use for unwind return address in case the architecture adds
+ some extra non-address bits to it. */
+extern GElf_Addr ebl_unwind_ret_mask (Ebl *ebl);
+
/* Convert *REGNO as is in DWARF to a lower range suitable for
Dwarf_Frame->REGS indexing. */
extern bool ebl_dwarf_to_regno (Ebl *ebl, unsigned *regno)
diff --git a/libebl/libeblP.h b/libebl/libeblP.h
index f91c2a0..ac38258 100644
--- a/libebl/libeblP.h
+++ b/libebl/libeblP.h
@@ -1,5 +1,5 @@
/* Internal definitions for interface for libebl.
- Copyright (C) 2000-2009, 2013 Red Hat, Inc.
+ Copyright (C) 2000-2009, 2013, 2014 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -64,6 +64,12 @@ struct ebl
Ebl architecture can unwind iff FRAME_NREGS > 0. */
size_t frame_nregs;
+ /* Mask to use to get the return address from an unwind in case the
+ architecture adds some extra non-address bits to it. When not
+ initialized (0) then ebl_unwind_ret_mask will return ~0, otherwise
+ it should be the actual mask to use. */
+ GElf_Addr unwind_ret_mask;
+
/* Function descriptor load address and table as used by
ebl_resolve_sym_value if available for this arch. */
GElf_Addr fd_addr;
--
1.9.3