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 --- 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 + + * arm_init.c (arm_init): Set unwind_ret_mask. + 2014-06-14 Mark Wielaard * 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 + + * frame_unwind.c (handle_cfi): Use ebl_unwind_ret_mask. + 2014-06-14 Mark Wielaard * 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 + + * 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 * 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