#include <stdlib.h>
#include "unwind_i.h"
#ifndef UNW_REMOTE_ONLY
HIDDEN inline int
s390x_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
{
struct cursor *c = (struct cursor *) cursor;
ucontext_t uc = *c->uc;
ucontext_t *rt = NULL;
struct sigcontext *sc = NULL;
int i;
unw_word_t sp, ip;
uc.uc_mcontext.psw.addr = c->dwarf.ip;
dwarf_make_proc_info (&c->dwarf);
switch (c->sigcontext_format)
{
case S390X_SCF_NONE:
Debug (8, "resuming at ip=%llx via setcontext()\n",
(unsigned long long) c->dwarf.ip);
setcontext (&uc);
abort();
case S390X_SCF_LINUX_SIGFRAME:
Debug (8, "resuming at ip=%llx via signal trampoline\n",
(unsigned long long) c->dwarf.ip);
sc = (struct sigcontext*)c->sigcontext_addr;
for (i = UNW_S390X_R0; i <= UNW_S390X_R15; ++i)
sc->sregs->regs.gprs[i-UNW_S390X_R0] = uc.uc_mcontext.gregs[i-UNW_S390X_R0];
for (i = UNW_S390X_F0; i <= UNW_S390X_F15; ++i)
sc->sregs->fpregs.fprs[i-UNW_S390X_F0] = uc.uc_mcontext.fpregs.fprs[i-UNW_S390X_F0].d;
sc->sregs->regs.psw.addr = uc.uc_mcontext.psw.addr;
sp = c->sigcontext_sp;
ip = c->sigcontext_pc;
__asm__ __volatile__ (
"lgr %%r15, %[sp]\n"
"br %[ip]\n"
: : [sp] "r" (sp), [ip] "r" (ip)
);
abort();
case S390X_SCF_LINUX_RT_SIGFRAME:
Debug (8, "resuming at ip=%llx via signal trampoline\n",
(unsigned long long) c->dwarf.ip);
rt = (ucontext_t*)c->sigcontext_addr;
for (i = UNW_S390X_R0; i <= UNW_S390X_R15; ++i)
rt->uc_mcontext.gregs[i-UNW_S390X_R0] = uc.uc_mcontext.gregs[i-UNW_S390X_R0];
for (i = UNW_S390X_F0; i <= UNW_S390X_F15; ++i)
rt->uc_mcontext.fpregs.fprs[i-UNW_S390X_F0] = uc.uc_mcontext.fpregs.fprs[i-UNW_S390X_F0];
rt->uc_mcontext.psw.addr = uc.uc_mcontext.psw.addr;
sp = c->sigcontext_sp;
ip = c->sigcontext_pc;
__asm__ __volatile__ (
"lgr %%r15, %[sp]\n"
"br %[ip]\n"
: : [sp] "r" (sp), [ip] "r" (ip)
);
abort();
}
return -UNW_EINVAL;
}
#endif
static inline int
establish_machine_state (struct cursor *c)
{
int (*access_reg) (unw_addr_space_t, unw_regnum_t, unw_word_t *,
int write, void *);
int (*access_fpreg) (unw_addr_space_t, unw_regnum_t, unw_fpreg_t *,
int write, void *);
unw_addr_space_t as = c->dwarf.as;
void *arg = c->dwarf.as_arg;
unw_fpreg_t fpval;
unw_word_t val;
int reg;
access_reg = as->acc.access_reg;
access_fpreg = as->acc.access_fpreg;
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)
(*access_fpreg) (as, reg, &fpval, 1, arg);
}
else
{
if (tdep_access_reg (c, reg, &val, 0) >= 0)
(*access_reg) (as, reg, &val, 1, arg);
}
}
if (c->dwarf.args_size)
{
if (tdep_access_reg (c, UNW_S390X_R15, &val, 0) >= 0)
{
val += c->dwarf.args_size;
(*access_reg) (as, UNW_S390X_R15, &val, 1, arg);
}
}
return 0;
}
int
unw_resume (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret;
Debug (1, "(cursor=%p)\n", c);
if ((ret = establish_machine_state (c)) < 0)
return ret;
return (*c->dwarf.as->acc.resume) (c->dwarf.as, (unw_cursor_t *) c,
c->dwarf.as_arg);
}