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:
parent
288f18f7ae
commit
1e10c2931d
3 changed files with 74 additions and 6 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
Loading…
Reference in a new issue