#ifdef HAVE_ASM_VSYSCALL_H
#include <asm/vsyscall.h>
#endif
#include "libunwind_i.h"
#include "unwind_i.h"
#include "ucontext_i.h"
#include <sys/syscall.h>
HIDDEN void
tdep_fetch_frame (struct dwarf_cursor *dw, unw_word_t ip UNUSED, int need_unwind_info UNUSED)
{
struct cursor *c = (struct cursor *) dw;
assert(! need_unwind_info || dw->pi_valid);
assert(! need_unwind_info || dw->pi.unwind_info);
if (dw->pi_valid
&& dw->pi.unwind_info
&& ((struct dwarf_cie_info *) dw->pi.unwind_info)->signal_frame)
c->sigcontext_format = X86_64_SCF_LINUX_RT_SIGFRAME;
else
c->sigcontext_format = X86_64_SCF_NONE;
Debug(5, "fetch frame ip=0x%lx cfa=0x%lx format=%d\n",
dw->ip, dw->cfa, c->sigcontext_format);
}
HIDDEN int
tdep_cache_frame (struct dwarf_cursor *dw)
{
struct cursor *c = (struct cursor *) dw;
Debug(5, "cache frame ip=0x%lx cfa=0x%lx format=%d\n",
dw->ip, dw->cfa, c->sigcontext_format);
return c->sigcontext_format;
}
HIDDEN void
tdep_reuse_frame (struct dwarf_cursor *dw, int frame)
{
struct cursor *c = (struct cursor *) dw;
c->sigcontext_format = frame;
if (c->sigcontext_format == X86_64_SCF_LINUX_RT_SIGFRAME)
{
c->frame_info.frame_type = UNW_X86_64_FRAME_SIGRETURN;
c->frame_info.cfa_reg_offset = 0;
c->sigcontext_addr = dw->cfa;
}
Debug(5, "reuse frame ip=0x%lx cfa=0x%lx format=%d addr=0x%lx offset=%+d\n",
dw->ip, dw->cfa, c->sigcontext_format, c->sigcontext_addr,
(c->sigcontext_format == X86_64_SCF_LINUX_RT_SIGFRAME
? c->frame_info.cfa_reg_offset : 0));
}
int
unw_is_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
return c->sigcontext_format != X86_64_SCF_NONE;
}
HIDDEN int
x86_64_handle_signal_frame (unw_cursor_t *cursor UNUSED)
{
#if UNW_DEBUG
struct cursor *c = (struct cursor *) cursor;
Debug(1, "old format signal frame? format=%d addr=0x%lx cfa=0x%lx\n",
c->sigcontext_format, c->sigcontext_addr, c->dwarf.cfa);
#endif
return -UNW_EBADFRAME;
}
#ifndef UNW_REMOTE_ONLY
HIDDEN void *
x86_64_r_uc_addr (ucontext_t *uc, int reg)
{
void *addr;
switch (reg)
{
case UNW_X86_64_R8: addr = &uc->uc_mcontext.gregs[REG_R8]; break;
case UNW_X86_64_R9: addr = &uc->uc_mcontext.gregs[REG_R9]; break;
case UNW_X86_64_R10: addr = &uc->uc_mcontext.gregs[REG_R10]; break;
case UNW_X86_64_R11: addr = &uc->uc_mcontext.gregs[REG_R11]; break;
case UNW_X86_64_R12: addr = &uc->uc_mcontext.gregs[REG_R12]; break;
case UNW_X86_64_R13: addr = &uc->uc_mcontext.gregs[REG_R13]; break;
case UNW_X86_64_R14: addr = &uc->uc_mcontext.gregs[REG_R14]; break;
case UNW_X86_64_R15: addr = &uc->uc_mcontext.gregs[REG_R15]; break;
case UNW_X86_64_RDI: addr = &uc->uc_mcontext.gregs[REG_RDI]; break;
case UNW_X86_64_RSI: addr = &uc->uc_mcontext.gregs[REG_RSI]; break;
case UNW_X86_64_RBP: addr = &uc->uc_mcontext.gregs[REG_RBP]; break;
case UNW_X86_64_RBX: addr = &uc->uc_mcontext.gregs[REG_RBX]; break;
case UNW_X86_64_RDX: addr = &uc->uc_mcontext.gregs[REG_RDX]; break;
case UNW_X86_64_RAX: addr = &uc->uc_mcontext.gregs[REG_RAX]; break;
case UNW_X86_64_RCX: addr = &uc->uc_mcontext.gregs[REG_RCX]; break;
case UNW_X86_64_RSP: addr = &uc->uc_mcontext.gregs[REG_RSP]; break;
case UNW_X86_64_RIP: addr = &uc->uc_mcontext.gregs[REG_RIP]; break;
default:
addr = NULL;
}
return addr;
}
HIDDEN NORETURN void
x86_64_sigreturn (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr;
mcontext_t *sc_mcontext = &((ucontext_t*)sc)->uc_mcontext;
memcpy(sc_mcontext, &dwarf_get_uc(&c->dwarf)->uc_mcontext,
DWARF_NUM_PRESERVED_REGS * sizeof(unw_word_t));
Debug (8, "resuming at ip=%llx via sigreturn(%p)\n",
(unsigned long long) c->dwarf.ip, sc);
__asm__ __volatile__ ("mov %0, %%rsp;"
"mov %1, %%rax;"
"syscall"
:: "r"((uint64_t)sc), "i"(SYS_rt_sigreturn)
: "memory");
abort();
}
#endif
static int
is_vsyscall (struct dwarf_cursor *c UNUSED)
{
#if defined(VSYSCALL_START) && defined(VSYSCALL_END)
return c->ip >= VSYSCALL_START && c->ip < VSYSCALL_END;
#elif defined(VSYSCALL_ADDR)
return c->ip >= VSYSCALL_ADDR && c->ip < VSYSCALL_ADDR + unw_page_size;
#else
return 0;
#endif
}
HIDDEN int
x86_64_os_step(struct cursor *c)
{
if (is_vsyscall (&c->dwarf))
{
Debug (2, "in vsyscall region\n");
c->frame_info.cfa_reg_offset = 8;
c->frame_info.cfa_reg_rsp = -1;
c->frame_info.frame_type = UNW_X86_64_FRAME_GUESSED;
c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0);
c->dwarf.cfa += 8;
return (1);
}
return (0);
}