mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2025-02-16 18:21:41 +01:00
Add an experimental and optional frame chain unwinding for ARM
The environment variable UNW_ARM_UNWIND_METHOD controls the unwind method. 1 - debug_frame unwinding 2 - frame chain unwinding, 3 - 1 & 2 (default)) Signed-off-by: Andris Zeila <andris.zeila@accenture.com>
This commit is contained in:
parent
46e10c5abe
commit
00aed9631b
5 changed files with 99 additions and 8 deletions
|
@ -255,4 +255,14 @@ extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
|
|||
extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
|
||||
unw_fpreg_t *valp, int write);
|
||||
|
||||
/* unwinding method selection support */
|
||||
#define UNW_ARM_METHOD_ALL 0xFF
|
||||
#define UNW_ARM_METHOD_DWARF 0x01
|
||||
#define UNW_ARM_METHOD_FRAME 0x02
|
||||
|
||||
#define unwi_unwind_method UNWI_ARCH_OBJ(unwind_method)
|
||||
extern int unwi_unwind_method;
|
||||
|
||||
#define UNW_TRY_METHOD(x) (unwi_unwind_method & x)
|
||||
|
||||
#endif /* ARM_LIBUNWIND_I_H */
|
||||
|
|
|
@ -29,6 +29,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|||
HIDDEN pthread_mutex_t arm_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
HIDDEN int tdep_needs_initialization = 1;
|
||||
|
||||
/* Unwinding methods to use. See UNW_METHOD_ enums */
|
||||
HIDDEN int unwi_unwind_method = UNW_ARM_METHOD_ALL;
|
||||
|
||||
/* FIXME: I'm pretty sure we don't need this at all for ARM, but "generic"
|
||||
code (include/dwarf_i.h) seems to expect it to be here at present. */
|
||||
|
||||
|
@ -50,6 +53,13 @@ tdep_init (void)
|
|||
/* another thread else beat us to it... */
|
||||
goto out;
|
||||
|
||||
/* read ARM unwind method setting */
|
||||
const char* str = getenv ("UNW_ARM_UNWIND_METHOD");
|
||||
if (str)
|
||||
{
|
||||
unwi_unwind_method = atoi (str);
|
||||
}
|
||||
|
||||
mi_init ();
|
||||
|
||||
dwarf_init ();
|
||||
|
|
|
@ -29,20 +29,83 @@ PROTECTED int
|
|||
unw_step (unw_cursor_t *cursor)
|
||||
{
|
||||
struct cursor *c = (struct cursor *) cursor;
|
||||
int ret;
|
||||
int ret = -UNW_EUNSPEC;
|
||||
|
||||
Debug (1, "(cursor=%p)\n", c);
|
||||
|
||||
/* Try DWARF-based unwinding... this is the only method likely to work for
|
||||
ARM. */
|
||||
ret = dwarf_step (&c->dwarf);
|
||||
if (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF))
|
||||
{
|
||||
ret = dwarf_step (&c->dwarf);
|
||||
Debug(1, "dwarf_step()=%d\n", ret);
|
||||
|
||||
if (unlikely (ret == -UNW_ESTOPUNWIND))
|
||||
return ret;
|
||||
if (unlikely (ret == -UNW_ESTOPUNWIND))
|
||||
return ret;
|
||||
|
||||
if (ret < 0 && ret != -UNW_ENOINFO)
|
||||
{
|
||||
Debug (2, "returning %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dwarf unwinding didn't work, stop. */
|
||||
if (unlikely (ret < 0))
|
||||
return 0;
|
||||
|
||||
return (c->dwarf.ip == 0) ? 0 : 1;
|
||||
{
|
||||
if (UNW_TRY_METHOD(UNW_ARM_METHOD_FRAME))
|
||||
{
|
||||
ret = UNW_ESUCCESS;
|
||||
/* DWARF unwinding failed, try to follow APCS/optimized APCS frame chain */
|
||||
unw_word_t instr, i;
|
||||
Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
|
||||
dwarf_loc_t ip_loc, fp_loc;
|
||||
unw_word_t frame;
|
||||
/* Mark all registers unsaved, since we don't know where
|
||||
they are saved (if at all), except for the EBP and
|
||||
EIP. */
|
||||
if (dwarf_get(&c->dwarf, c->dwarf.loc[UNW_ARM_R11], &frame) < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) {
|
||||
c->dwarf.loc[i] = DWARF_NULL_LOC;
|
||||
}
|
||||
if (frame)
|
||||
{
|
||||
if (dwarf_get(&c->dwarf, DWARF_LOC(frame, 0), &instr) < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
instr -= 8;
|
||||
if (dwarf_get(&c->dwarf, DWARF_LOC(instr, 0), &instr) < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if ((instr & 0xFFFFD800) == 0xE92DD800)
|
||||
{
|
||||
/* Standard APCS frame. */
|
||||
ip_loc = DWARF_LOC(frame - 4, 0);
|
||||
fp_loc = DWARF_LOC(frame - 12, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Codesourcery optimized normal frame. */
|
||||
ip_loc = DWARF_LOC(frame, 0);
|
||||
fp_loc = DWARF_LOC(frame - 4, 0);
|
||||
}
|
||||
if (dwarf_get(&c->dwarf, ip_loc, &c->dwarf.ip) < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
c->dwarf.loc[UNW_ARM_R12] = ip_loc;
|
||||
c->dwarf.loc[UNW_ARM_R11] = fp_loc;
|
||||
Debug(15, "ip=%lx\n", c->dwarf.ip);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -UNW_ENOINFO;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret == -UNW_ENOINFO ? 0 : 1;
|
||||
}
|
||||
|
|
|
@ -50,3 +50,7 @@ _Uarm_getcontext:
|
|||
str r1, [r0, #15 * 4]
|
||||
ldmfd sp!, {r0, r1}
|
||||
bx lr
|
||||
#ifdef __linux__
|
||||
/* We do not need executable stack. */
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
#endif
|
||||
|
|
|
@ -6,3 +6,7 @@
|
|||
_UI_siglongjmp_cont:
|
||||
_UI_longjmp_cont:
|
||||
bx lr
|
||||
#ifdef __linux__
|
||||
/* We do not need executable stack. */
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue