1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-12-23 12:03:41 +01:00

Add initial support for local unw_resume on ARM Linux.

Provides basic support for resuming execution at a certain stack frame.

Signed-off-by: Ken Werner <ken.werner@linaro.org>
This commit is contained in:
Ken Werner 2011-04-21 15:52:51 +02:00
parent 288f18f7ae
commit 1e10c2931d
3 changed files with 74 additions and 6 deletions

View file

@ -199,7 +199,7 @@ arm_local_addr_space_init (void)
local_addr_space.acc.access_mem = access_mem; local_addr_space.acc.access_mem = access_mem;
local_addr_space.acc.access_reg = access_reg; local_addr_space.acc.access_reg = access_reg;
local_addr_space.acc.access_fpreg = access_fpreg; local_addr_space.acc.access_fpreg = access_fpreg;
local_addr_space.acc.resume = 0; /* arm_local_resume? FIXME! */ local_addr_space.acc.resume = arm_local_resume;
local_addr_space.acc.get_proc_name = get_static_proc_name; local_addr_space.acc.get_proc_name = get_static_proc_name;
unw_flush_cache (&local_addr_space, 0, 0); unw_flush_cache (&local_addr_space, 0, 0);
} }

View file

@ -1,5 +1,6 @@
/* libunwind - a platform-independent unwind library /* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery Copyright (C) 2008 CodeSourcery
Copyright 2011 Linaro Limited
This file is part of libunwind. This file is part of libunwind.
@ -22,10 +23,6 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/* FIXME for ARM. */
#include <stdlib.h>
#include "unwind_i.h" #include "unwind_i.h"
#ifndef UNW_REMOTE_ONLY #ifndef UNW_REMOTE_ONLY
@ -33,13 +30,82 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
HIDDEN inline int HIDDEN inline int
arm_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) arm_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
{ {
#ifdef __linux__
struct cursor *c = (struct cursor *) cursor;
ucontext_t *uc = c->dwarf.as_arg;
unsigned long regs[10];
/* Copy the register contents to be restored. */
regs[0] = uc->uc_mcontext.arm_r4;
regs[1] = uc->uc_mcontext.arm_r5;
regs[2] = uc->uc_mcontext.arm_r6;
regs[3] = uc->uc_mcontext.arm_r7;
regs[4] = uc->uc_mcontext.arm_r8;
regs[5] = uc->uc_mcontext.arm_r9;
regs[6] = uc->uc_mcontext.arm_r10;
regs[7] = uc->uc_mcontext.arm_fp;
regs[8] = uc->uc_mcontext.arm_sp;
regs[9] = uc->uc_mcontext.arm_lr;
/* Restore the registers. */
asm __volatile__ (
"ldmia %0, {r4-r12, lr}\n"
"mov sp, r12\n"
"bx lr\n"
: : "r" (regs) :
);
#else
printf ("%s: implement me\n", __FUNCTION__);
#endif
return -UNW_EINVAL; return -UNW_EINVAL;
} }
#endif /* !UNW_REMOTE_ONLY */ #endif /* !UNW_REMOTE_ONLY */
static inline void
establish_machine_state (struct cursor *c)
{
unw_addr_space_t as = c->dwarf.as;
void *arg = c->dwarf.as_arg;
unw_fpreg_t fpval;
unw_word_t val;
int reg;
Debug (8, "copying out cursor state\n");
for (reg = 0; reg <= UNW_REG_LAST; ++reg)
{
Debug (16, "copying %s %d\n", unw_regname (reg), reg);
if (unw_is_fpreg (reg))
{
if (tdep_access_fpreg (c, reg, &fpval, 0) >= 0)
as->acc.access_fpreg (as, reg, &fpval, 1, arg);
}
else
{
if (tdep_access_reg (c, reg, &val, 0) >= 0)
as->acc.access_reg (as, reg, &val, 1, arg);
}
}
}
PROTECTED int PROTECTED int
unw_resume (unw_cursor_t *cursor) unw_resume (unw_cursor_t *cursor)
{ {
return -UNW_EINVAL; struct cursor *c = (struct cursor *) cursor;
Debug (1, "(cursor=%p)\n", c);
if (!c->dwarf.ip)
{
/* This can happen easily when the frame-chain gets truncated
due to bad or missing unwind-info. */
Debug (1, "refusing to resume execution at address 0\n");
return -UNW_EINVAL;
}
establish_machine_state (c);
return (*c->dwarf.as->acc.resume) (c->dwarf.as, (unw_cursor_t *) c,
c->dwarf.as_arg);
} }

View file

@ -37,5 +37,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#define arm_local_addr_space_init UNW_OBJ(local_addr_space_init) #define arm_local_addr_space_init UNW_OBJ(local_addr_space_init)
extern void arm_local_addr_space_init (void); extern void arm_local_addr_space_init (void);
extern int arm_local_resume (unw_addr_space_t as, unw_cursor_t *cursor,
void *arg);
#endif /* unwind_i_h */ #endif /* unwind_i_h */