1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-05-17 10:45:18 +02: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:
Arun Sharma 2010-05-26 19:28:44 -07:00
parent 46e10c5abe
commit 00aed9631b
5 changed files with 99 additions and 8 deletions

View file

@ -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 */

View file

@ -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 ();

View file

@ -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;
}

View file

@ -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

View file

@ -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