Gos-freebsd.c revision 69001646fa81d4692ee4b3a5ce942aa2d957bbe0
1/* libunwind - a platform-independent unwind library
2   Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
3
4This file is part of libunwind.
5
6Permission is hereby granted, free of charge, to any person obtaining
7a copy of this software and associated documentation files (the
8"Software"), to deal in the Software without restriction, including
9without limitation the rights to use, copy, modify, merge, publish,
10distribute, sublicense, and/or sell copies of the Software, and to
11permit persons to whom the Software is furnished to do so, subject to
12the following conditions:
13
14The above copyright notice and this permission notice shall be
15included in all copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include <sys/ucontext.h>
30#include <machine/sigframe.h>
31#include <signal.h>
32#include <stddef.h>
33#include "unwind_i.h"
34#include "ucontext_i.h"
35
36PROTECTED int
37unw_is_signal_frame (unw_cursor_t *cursor)
38{
39  /* XXXKIB */
40  struct cursor *c = (struct cursor *) cursor;
41  unw_word_t w0, w1, w2, b0, ip;
42  unw_addr_space_t as;
43  unw_accessors_t *a;
44  void *arg;
45  int ret;
46
47  as = c->dwarf.as;
48  a = unw_get_accessors (as);
49  arg = c->dwarf.as_arg;
50
51  /* Check if RIP points at sigreturn sequence.
5248 8d 7c 24 10		lea	SIGF_UC(%rsp),%rdi
536a 00			pushq	$0
5448 c7 c0 a1 01 00 00	movq	$SYS_sigreturn,%rax
550f 05			syscall
56f4		0:	hlt
57eb fd			jmp	0b
58  */
59
60  ip = c->dwarf.ip;
61  c->sigcontext_format = X86_64_SCF_NONE;
62  if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0
63      || (ret = (*a->access_mem) (as, ip + 8, &w1, 0, arg)) < 0
64      || (ret = (*a->access_mem) (as, ip + 16, &w2, 0, arg)) < 0)
65    return 0;
66  w2 &= 0xffffff;
67  if (w0 == 0x48006a10247c8d48 &&
68      w1 == 0x050f000001a1c0c7 &&
69      w2 == 0x0000000000fdebf4)
70   {
71     c->sigcontext_format = X86_64_SCF_FREEBSD_SIGFRAME;
72     return (c->sigcontext_format);
73   }
74  /* Check if RIP points at standard syscall sequence.
7549 89 ca	mov    %rcx,%r10
760f 05		syscall
77  */
78  if ((ret = (*a->access_mem) (as, ip - 5, &b0, 0, arg)) < 0)
79    return (0);
80  b0 &= 0xffffffffff;
81  if (b0 == 0x000000050fca8949)
82   {
83    c->sigcontext_format = X86_64_SCF_FREEBSD_SYSCALL;
84    return (c->sigcontext_format);
85   }
86  return (X86_64_SCF_NONE);
87}
88
89PROTECTED int
90unw_handle_signal_frame (unw_cursor_t *cursor)
91{
92  struct cursor *c = (struct cursor *) cursor;
93  unw_word_t ucontext;
94  int ret;
95
96  if (c->sigcontext_format == X86_64_SCF_FREEBSD_SIGFRAME)
97   {
98    ucontext = c->dwarf.cfa + offsetof(struct sigframe, sf_uc);
99    c->uc = (ucontext_t *)ucontext;
100    Debug(1, "signal frame, skip over trampoline\n");
101
102    struct dwarf_loc rsp_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSP, 0);
103    ret = dwarf_get (&c->dwarf, rsp_loc, &c->dwarf.cfa);
104    if (ret < 0)
105     {
106       Debug (2, "returning %d\n", ret);
107       return ret;
108     }
109
110    c->dwarf.loc[RAX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RAX, 0);
111    c->dwarf.loc[RDX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDX, 0);
112    c->dwarf.loc[RCX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RCX, 0);
113    c->dwarf.loc[RBX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBX, 0);
114    c->dwarf.loc[RSI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSI, 0);
115    c->dwarf.loc[RDI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDI, 0);
116    c->dwarf.loc[RBP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBP, 0);
117    c->dwarf.loc[RSP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSP, 0);
118    c->dwarf.loc[ R8] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R8, 0);
119    c->dwarf.loc[ R9] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R9, 0);
120    c->dwarf.loc[R10] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R10, 0);
121    c->dwarf.loc[R11] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R11, 0);
122    c->dwarf.loc[R12] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R12, 0);
123    c->dwarf.loc[R13] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R13, 0);
124    c->dwarf.loc[R14] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R14, 0);
125    c->dwarf.loc[R15] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R15, 0);
126    c->dwarf.loc[RIP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RIP, 0);
127
128    return 0;
129   }
130  else if (c->sigcontext_format == X86_64_SCF_FREEBSD_SYSCALL)
131   {
132    c->dwarf.loc[RCX] = c->dwarf.loc[R10];
133    /*  rsp_loc = DWARF_LOC(c->dwarf.cfa - 8, 0);	*/
134    /*	rbp_loc = c->dwarf.loc[RBP];			*/
135    c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0);
136    ret = dwarf_get (&c->dwarf, c->dwarf.loc[RIP], &c->dwarf.ip);
137    Debug (1, "Frame Chain [RIP=0x%Lx] = 0x%Lx\n",
138	   (unsigned long long) DWARF_GET_LOC (c->dwarf.loc[RIP]),
139	   (unsigned long long) c->dwarf.ip);
140    if (ret < 0)
141     {
142       Debug (2, "returning %d\n", ret);
143       return ret;
144     }
145    c->dwarf.cfa += 8;
146    return 1;
147   }
148  else
149    return -UNW_EBADFRAME;
150
151}
152
153#ifndef UNW_REMOTE_ONLY
154HIDDEN void *
155x86_64_r_uc_addr (ucontext_t *uc, int reg)
156{
157  void *addr;
158
159  switch (reg)
160    {
161    case UNW_X86_64_R8: addr = &uc->uc_mcontext.mc_r8; break;
162    case UNW_X86_64_R9: addr = &uc->uc_mcontext.mc_r9; break;
163    case UNW_X86_64_R10: addr = &uc->uc_mcontext.mc_r10; break;
164    case UNW_X86_64_R11: addr = &uc->uc_mcontext.mc_r11; break;
165    case UNW_X86_64_R12: addr = &uc->uc_mcontext.mc_r12; break;
166    case UNW_X86_64_R13: addr = &uc->uc_mcontext.mc_r13; break;
167    case UNW_X86_64_R14: addr = &uc->uc_mcontext.mc_r14; break;
168    case UNW_X86_64_R15: addr = &uc->uc_mcontext.mc_r15; break;
169    case UNW_X86_64_RDI: addr = &uc->uc_mcontext.mc_rdi; break;
170    case UNW_X86_64_RSI: addr = &uc->uc_mcontext.mc_rsi; break;
171    case UNW_X86_64_RBP: addr = &uc->uc_mcontext.mc_rbp; break;
172    case UNW_X86_64_RBX: addr = &uc->uc_mcontext.mc_rbx; break;
173    case UNW_X86_64_RDX: addr = &uc->uc_mcontext.mc_rdx; break;
174    case UNW_X86_64_RAX: addr = &uc->uc_mcontext.mc_rax; break;
175    case UNW_X86_64_RCX: addr = &uc->uc_mcontext.mc_rcx; break;
176    case UNW_X86_64_RSP: addr = &uc->uc_mcontext.mc_rsp; break;
177    case UNW_X86_64_RIP: addr = &uc->uc_mcontext.mc_rip; break;
178
179    default:
180      addr = NULL;
181    }
182  return addr;
183}
184
185HIDDEN NORETURN void
186x86_64_sigreturn (unw_cursor_t *cursor)
187{
188  struct cursor *c = (struct cursor *) cursor;
189  ucontext_t *uc = c->uc;
190
191  Debug (8, "resuming at ip=%llx via sigreturn(%p)\n",
192	     (unsigned long long) c->dwarf.ip, uc);
193  sigreturn(uc);
194  abort();
195}
196#endif
197