#include "unwind_i.h"
#include <signal.h>
static int
s390x_handle_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret, i;
unw_word_t sc_addr, sp, *gprs, *fprs, *psw;
ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_S390X_R15], &sp);
if (ret < 0)
return ret;
c->sigcontext_sp = sp;
c->sigcontext_pc = c->dwarf.ip;
switch (c->sigcontext_format)
{
case S390X_SCF_LINUX_SIGFRAME:
sc_addr = sp + 160;
gprs = ((struct sigcontext*)sc_addr)->sregs->regs.gprs;
fprs = (unw_word_t*)((struct sigcontext*)sc_addr)->sregs->fpregs.fprs;
psw = &((struct sigcontext*)sc_addr)->sregs->regs.psw.addr;
break;
case S390X_SCF_LINUX_RT_SIGFRAME:
sc_addr = sp + sizeof(siginfo_t) + 8 + 160;
gprs = ((ucontext_t*)sc_addr)->uc_mcontext.gregs;
fprs = (unw_word_t*)((ucontext_t*)sc_addr)->uc_mcontext.fpregs.fprs;
psw = &((ucontext_t*)sc_addr)->uc_mcontext.psw.addr;
break;
default:
return -UNW_EUNSPEC;
}
c->sigcontext_addr = sc_addr;
for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
c->dwarf.loc[i] = DWARF_NULL_LOC;
for (i = UNW_S390X_R0; i <= UNW_S390X_R15; ++i)
c->dwarf.loc[i] = DWARF_MEM_LOC (c, (unw_word_t) &gprs[i-UNW_S390X_R0]);
for (i = UNW_S390X_F0; i <= UNW_S390X_F15; ++i)
c->dwarf.loc[i] = DWARF_MEM_LOC (c, (unw_word_t) &fprs[i-UNW_S390X_F0]);
c->dwarf.loc[UNW_S390X_IP] = DWARF_MEM_LOC (c, (unw_word_t) psw);
dwarf_get (&c->dwarf, c->dwarf.loc[UNW_S390X_R15], &c->dwarf.cfa);
dwarf_get (&c->dwarf, c->dwarf.loc[UNW_S390X_IP], &c->dwarf.ip);
c->dwarf.pi_valid = 0;
c->dwarf.use_prev_instr = 0;
return 1;
}
int
unw_step (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret = 0, val = c->validate, sig;
#if CONSERVATIVE_CHECKS
c->validate = 1;
#endif
Debug (1, "(cursor=%p, ip=0x%016lx, cfa=0x%016lx)\n",
c, c->dwarf.ip, c->dwarf.cfa);
c->sigcontext_format = S390X_SCF_NONE;
ret = dwarf_step (&c->dwarf);
#if CONSERVATIVE_CHECKS
c->validate = val;
#endif
if (unlikely (ret == -UNW_ENOINFO))
{
c->validate = 1;
sig = unw_is_signal_frame (cursor);
if (sig > 0)
{
c->sigcontext_format = sig;
ret = s390x_handle_signal_frame (cursor);
}
else
{
c->dwarf.ip = 0;
ret = 0;
}
c->validate = val;
return ret;
}
if (unlikely (ret > 0 && c->dwarf.ip == 0))
return 0;
return ret;
}