18e53e62db913470952b8eb541834b876f7a6882cArun Sharma/* libunwind - a platform-independent unwind library
28e53e62db913470952b8eb541834b876f7a6882cArun Sharma   Copyright (C) 2002-2003 Hewlett-Packard Co
38e53e62db913470952b8eb541834b876f7a6882cArun Sharma	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
48e53e62db913470952b8eb541834b876f7a6882cArun Sharma
58e53e62db913470952b8eb541834b876f7a6882cArun Sharma   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
68e53e62db913470952b8eb541834b876f7a6882cArun Sharma
78e53e62db913470952b8eb541834b876f7a6882cArun SharmaThis file is part of libunwind.
88e53e62db913470952b8eb541834b876f7a6882cArun Sharma
98e53e62db913470952b8eb541834b876f7a6882cArun SharmaPermission is hereby granted, free of charge, to any person obtaining
108e53e62db913470952b8eb541834b876f7a6882cArun Sharmaa copy of this software and associated documentation files (the
118e53e62db913470952b8eb541834b876f7a6882cArun Sharma"Software"), to deal in the Software without restriction, including
128e53e62db913470952b8eb541834b876f7a6882cArun Sharmawithout limitation the rights to use, copy, modify, merge, publish,
138e53e62db913470952b8eb541834b876f7a6882cArun Sharmadistribute, sublicense, and/or sell copies of the Software, and to
148e53e62db913470952b8eb541834b876f7a6882cArun Sharmapermit persons to whom the Software is furnished to do so, subject to
158e53e62db913470952b8eb541834b876f7a6882cArun Sharmathe following conditions:
168e53e62db913470952b8eb541834b876f7a6882cArun Sharma
178e53e62db913470952b8eb541834b876f7a6882cArun SharmaThe above copyright notice and this permission notice shall be
188e53e62db913470952b8eb541834b876f7a6882cArun Sharmaincluded in all copies or substantial portions of the Software.
198e53e62db913470952b8eb541834b876f7a6882cArun Sharma
208e53e62db913470952b8eb541834b876f7a6882cArun SharmaTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
218e53e62db913470952b8eb541834b876f7a6882cArun SharmaEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
228e53e62db913470952b8eb541834b876f7a6882cArun SharmaMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
238e53e62db913470952b8eb541834b876f7a6882cArun SharmaNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
248e53e62db913470952b8eb541834b876f7a6882cArun SharmaLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
258e53e62db913470952b8eb541834b876f7a6882cArun SharmaOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
268e53e62db913470952b8eb541834b876f7a6882cArun SharmaWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
278e53e62db913470952b8eb541834b876f7a6882cArun Sharma
288e53e62db913470952b8eb541834b876f7a6882cArun Sharma#include "unwind_i.h"
298e53e62db913470952b8eb541834b876f7a6882cArun Sharma#include "ucontext_i.h"
308e53e62db913470952b8eb541834b876f7a6882cArun Sharma
31979af4502fe19b0d98459633731d004a4a010a0eKonstantin Belousov#include <sys/syscall.h>
32979af4502fe19b0d98459633731d004a4a010a0eKonstantin Belousov
33dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi TuuraHIDDEN void
34dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuuratdep_fetch_frame (struct dwarf_cursor *dw, unw_word_t ip, int need_unwind_info)
35dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura{
36dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura  struct cursor *c = (struct cursor *) dw;
37dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura  assert(! need_unwind_info || dw->pi_valid);
38dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura  assert(! need_unwind_info || dw->pi.unwind_info);
39dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura  if (dw->pi_valid
40dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura      && dw->pi.unwind_info
41dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura      && ((struct dwarf_cie_info *) dw->pi.unwind_info)->signal_frame)
42dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura    c->sigcontext_format = X86_64_SCF_LINUX_RT_SIGFRAME;
43dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura  else
44dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura    c->sigcontext_format = X86_64_SCF_NONE;
45dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura
469e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura  Debug(5, "fetch frame ip=0x%lx cfa=0x%lx format=%d\n",
479e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura        dw->ip, dw->cfa, c->sigcontext_format);
48dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura}
49dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura
50dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi TuuraHIDDEN void
51dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuuratdep_cache_frame (struct dwarf_cursor *dw, struct dwarf_reg_state *rs)
52dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura{
53dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura  struct cursor *c = (struct cursor *) dw;
54dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura  rs->signal_frame = c->sigcontext_format;
55dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura
569e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura  Debug(5, "cache frame ip=0x%lx cfa=0x%lx format=%d\n",
579e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura        dw->ip, dw->cfa, c->sigcontext_format);
58dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura}
59dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura
60dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi TuuraHIDDEN void
61dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuuratdep_reuse_frame (struct dwarf_cursor *dw, struct dwarf_reg_state *rs)
62dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura{
63dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura  struct cursor *c = (struct cursor *) dw;
64dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura  c->sigcontext_format = rs->signal_frame;
65dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura  if (c->sigcontext_format == X86_64_SCF_LINUX_RT_SIGFRAME)
669e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura  {
679e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura    c->frame_info.frame_type = UNW_X86_64_FRAME_SIGRETURN;
681010880548589685a27b8f63ef54a3ea78e052fcArun Sharma    /* Offset from cfa to ucontext_t in signal frame.  */
691010880548589685a27b8f63ef54a3ea78e052fcArun Sharma    c->frame_info.cfa_reg_offset = 0;
70dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura    c->sigcontext_addr = dw->cfa;
719e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura  }
72dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura  else
73dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura    c->sigcontext_addr = 0;
74dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura
759e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura  Debug(5, "reuse frame ip=0x%lx cfa=0x%lx format=%d addr=0x%lx offset=%+d\n",
769e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura        dw->ip, dw->cfa, c->sigcontext_format, c->sigcontext_addr,
779e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura	(c->sigcontext_format == X86_64_SCF_LINUX_RT_SIGFRAME
789e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura	 ? c->frame_info.cfa_reg_offset : 0));
79dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura}
80dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura
818e53e62db913470952b8eb541834b876f7a6882cArun SharmaPROTECTED int
828e53e62db913470952b8eb541834b876f7a6882cArun Sharmaunw_is_signal_frame (unw_cursor_t *cursor)
838e53e62db913470952b8eb541834b876f7a6882cArun Sharma{
848e53e62db913470952b8eb541834b876f7a6882cArun Sharma  struct cursor *c = (struct cursor *) cursor;
85dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura  return c->sigcontext_format != X86_64_SCF_NONE;
868e53e62db913470952b8eb541834b876f7a6882cArun Sharma}
878e53e62db913470952b8eb541834b876f7a6882cArun Sharma
888e53e62db913470952b8eb541834b876f7a6882cArun SharmaPROTECTED int
898e53e62db913470952b8eb541834b876f7a6882cArun Sharmaunw_handle_signal_frame (unw_cursor_t *cursor)
908e53e62db913470952b8eb541834b876f7a6882cArun Sharma{
91fdc534ccb05d1e6c0438345d292203343a811701Arun Sharma#if UNW_DEBUG /* To silence compiler warnings */
92dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura  /* Should not get here because we now use kernel-provided dwarf
93dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura     information for the signal trampoline and dwarf_step() works.
949e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura     Hence unw_step() should never call this function. Maybe
95dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura     restore old non-dwarf signal handling here, but then the
96dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura     gating on unw_is_signal_frame() needs to be removed. */
97aa3bb307a30a5b78bf1ae4ac843ae53e354736f5Arun Sharma  struct cursor *c = (struct cursor *) cursor;
98dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura  Debug(1, "old format signal frame? format=%d addr=0x%lx cfa=0x%lx\n",
99dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura	c->sigcontext_format, c->sigcontext_addr, c->dwarf.cfa);
100fdc534ccb05d1e6c0438345d292203343a811701Arun Sharma#endif
1019e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura  return -UNW_EBADFRAME;
1028e53e62db913470952b8eb541834b876f7a6882cArun Sharma}
1030dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov
1040dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov#ifndef UNW_REMOTE_ONLY
105caa6095aec43541bdbca1ad58d6f65b3de53a1efArun SharmaHIDDEN void *
1060dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousovx86_64_r_uc_addr (ucontext_t *uc, int reg)
1070dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov{
108ae5c1f2adf4da04235d87d024d4d942c01b2b447Lassi Tuura  /* NOTE: common_init() in init.h inlines these for fast path access. */
1090dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov  void *addr;
1100dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov
1110dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov  switch (reg)
1120dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov    {
1130dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov    case UNW_X86_64_R8: addr = &uc->uc_mcontext.gregs[REG_R8]; break;
1140dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov    case UNW_X86_64_R9: addr = &uc->uc_mcontext.gregs[REG_R9]; break;
1150dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov    case UNW_X86_64_R10: addr = &uc->uc_mcontext.gregs[REG_R10]; break;
1160dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov    case UNW_X86_64_R11: addr = &uc->uc_mcontext.gregs[REG_R11]; break;
1170dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov    case UNW_X86_64_R12: addr = &uc->uc_mcontext.gregs[REG_R12]; break;
1180dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov    case UNW_X86_64_R13: addr = &uc->uc_mcontext.gregs[REG_R13]; break;
1190dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov    case UNW_X86_64_R14: addr = &uc->uc_mcontext.gregs[REG_R14]; break;
1200dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov    case UNW_X86_64_R15: addr = &uc->uc_mcontext.gregs[REG_R15]; break;
1210dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov    case UNW_X86_64_RDI: addr = &uc->uc_mcontext.gregs[REG_RDI]; break;
1220dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov    case UNW_X86_64_RSI: addr = &uc->uc_mcontext.gregs[REG_RSI]; break;
1230dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov    case UNW_X86_64_RBP: addr = &uc->uc_mcontext.gregs[REG_RBP]; break;
1240dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov    case UNW_X86_64_RBX: addr = &uc->uc_mcontext.gregs[REG_RBX]; break;
1250dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov    case UNW_X86_64_RDX: addr = &uc->uc_mcontext.gregs[REG_RDX]; break;
1260dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov    case UNW_X86_64_RAX: addr = &uc->uc_mcontext.gregs[REG_RAX]; break;
1270dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov    case UNW_X86_64_RCX: addr = &uc->uc_mcontext.gregs[REG_RCX]; break;
1280dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov    case UNW_X86_64_RSP: addr = &uc->uc_mcontext.gregs[REG_RSP]; break;
1290dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov    case UNW_X86_64_RIP: addr = &uc->uc_mcontext.gregs[REG_RIP]; break;
1300dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov
1310dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov    default:
1320dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov      addr = NULL;
1330dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov    }
1340dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov  return addr;
1350dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov}
136979af4502fe19b0d98459633731d004a4a010a0eKonstantin Belousov
137979af4502fe19b0d98459633731d004a4a010a0eKonstantin Belousov/* sigreturn() is a no-op on x86_64 glibc.  */
138979af4502fe19b0d98459633731d004a4a010a0eKonstantin BelousovHIDDEN NORETURN void
139979af4502fe19b0d98459633731d004a4a010a0eKonstantin Belousovx86_64_sigreturn (unw_cursor_t *cursor)
140979af4502fe19b0d98459633731d004a4a010a0eKonstantin Belousov{
141979af4502fe19b0d98459633731d004a4a010a0eKonstantin Belousov  struct cursor *c = (struct cursor *) cursor;
142979af4502fe19b0d98459633731d004a4a010a0eKonstantin Belousov  struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr;
143979af4502fe19b0d98459633731d004a4a010a0eKonstantin Belousov
144979af4502fe19b0d98459633731d004a4a010a0eKonstantin Belousov  Debug (8, "resuming at ip=%llx via sigreturn(%p)\n",
145979af4502fe19b0d98459633731d004a4a010a0eKonstantin Belousov	     (unsigned long long) c->dwarf.ip, sc);
146979af4502fe19b0d98459633731d004a4a010a0eKonstantin Belousov  __asm__ __volatile__ ("mov %0, %%rsp;"
147979af4502fe19b0d98459633731d004a4a010a0eKonstantin Belousov			"mov %1, %%rax;"
148979af4502fe19b0d98459633731d004a4a010a0eKonstantin Belousov			"syscall"
149979af4502fe19b0d98459633731d004a4a010a0eKonstantin Belousov			:: "r"(sc), "i"(SYS_rt_sigreturn)
150979af4502fe19b0d98459633731d004a4a010a0eKonstantin Belousov			: "memory");
1511d9c5a356d72993d8e9f5ac70811a723ea156403Arun Sharma  abort();
152979af4502fe19b0d98459633731d004a4a010a0eKonstantin Belousov}
153979af4502fe19b0d98459633731d004a4a010a0eKonstantin Belousov
1540dbeeeb08dc9a7e46281954e9225a84d4629a3dbKonstantin Belousov#endif
155