Make UEFI boot-platform build again
[haiku.git] / src / libs / libunwind / x86 / Gos-freebsd.c
blobcf05f0789d441d61748fe2d5e4145b7762ec0000
1 /* libunwind - a platform-independent unwind library
2 Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
4 This file is part of libunwind.
6 Permission is hereby granted, free of charge, to any person obtaining
7 a copy of this software and associated documentation files (the
8 "Software"), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sublicense, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
14 The above copyright notice and this permission notice shall be
15 included in all copies or substantial portions of the Software.
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
29 #include <sys/types.h>
30 #include <signal.h>
31 #include <stddef.h>
32 #include <ucontext.h>
33 #include <machine/sigframe.h>
35 #include "unwind_i.h"
36 #include "offsets.h"
38 PROTECTED int
39 unw_is_signal_frame (unw_cursor_t *cursor)
41 struct cursor *c = (struct cursor *) cursor;
42 unw_word_t w0, w1, w2, w3, w4, w5, ip;
43 unw_addr_space_t as;
44 unw_accessors_t *a;
45 void *arg;
46 int ret;
48 as = c->dwarf.as;
49 a = unw_get_accessors (as);
50 arg = c->dwarf.as_arg;
52 /* Check if EIP points at sigreturn() sequence. It can be:
53 sigcode+4: from amd64 freebsd32 environment
54 8d 44 24 20 lea 0x20(%esp),%eax
55 50 push %eax
56 b8 a1 01 00 00 mov $0x1a1,%eax
57 50 push %eax
58 cd 80 int $0x80
60 sigcode+4: from real i386
61 8d 44 24 20 lea 0x20(%esp),%eax
62 50 push %eax
63 f7 40 54 00 02 00 testl $0x20000,0x54(%eax)
64 75 03 jne sigcode+21
65 8e 68 14 mov 0x14(%eax),%gs
66 b8 a1 01 00 00 mov $0x1a1,%eax
67 50 push %eax
68 cd 80 int $0x80
70 freebsd4_sigcode+4:
71 XXX
72 osigcode:
73 XXX
75 ip = c->dwarf.ip;
76 ret = X86_SCF_NONE;
77 c->sigcontext_format = ret;
78 if ((*a->access_mem) (as, ip, &w0, 0, arg) < 0 ||
79 (*a->access_mem) (as, ip + 4, &w1, 0, arg) < 0 ||
80 (*a->access_mem) (as, ip + 8, &w2, 0, arg) < 0 ||
81 (*a->access_mem) (as, ip + 12, &w3, 0, arg) < 0)
82 return ret;
83 if (w0 == 0x2024448d && w1 == 0x01a1b850 && w2 == 0xcd500000 &&
84 (w3 & 0xff) == 0x80)
85 ret = X86_SCF_FREEBSD_SIGFRAME;
86 else {
87 if ((*a->access_mem) (as, ip + 16, &w4, 0, arg) < 0 ||
88 (*a->access_mem) (as, ip + 20, &w5, 0, arg) < 0)
89 return ret;
90 if (w0 == 0x2024448d && w1 == 0x5440f750 && w2 == 0x75000200 &&
91 w3 == 0x14688e03 && w4 == 0x0001a1b8 && w5 == 0x80cd5000)
92 ret = X86_SCF_FREEBSD_SIGFRAME;
95 /* Check for syscall */
96 if (ret == X86_SCF_NONE && (*a->access_mem) (as, ip - 2, &w0, 0, arg) >= 0 &&
97 (w0 & 0xffff) == 0x80cd)
98 ret = X86_SCF_FREEBSD_SYSCALL;
99 Debug (16, "returning %d\n", ret);
100 c->sigcontext_format = ret;
101 return (ret);
104 PROTECTED int
105 unw_handle_signal_frame (unw_cursor_t *cursor)
107 struct cursor *c = (struct cursor *) cursor;
108 int ret;
110 if (c->sigcontext_format == X86_SCF_FREEBSD_SIGFRAME) {
111 struct sigframe *sf;
112 uintptr_t uc_addr;
113 struct dwarf_loc esp_loc;
115 sf = (struct sigframe *)c->dwarf.cfa;
116 uc_addr = (uintptr_t)&(sf->sf_uc);
117 c->sigcontext_addr = c->dwarf.cfa;
119 esp_loc = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_ESP_OFF, 0);
120 ret = dwarf_get (&c->dwarf, esp_loc, &c->dwarf.cfa);
121 if (ret < 0)
123 Debug (2, "returning 0\n");
124 return 0;
127 c->dwarf.loc[EIP] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EIP_OFF, 0);
128 c->dwarf.loc[ESP] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_ESP_OFF, 0);
129 c->dwarf.loc[EAX] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EAX_OFF, 0);
130 c->dwarf.loc[ECX] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_ECX_OFF, 0);
131 c->dwarf.loc[EDX] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EDX_OFF, 0);
132 c->dwarf.loc[EBX] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EBX_OFF, 0);
133 c->dwarf.loc[EBP] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EBP_OFF, 0);
134 c->dwarf.loc[ESI] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_ESI_OFF, 0);
135 c->dwarf.loc[EDI] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EDI_OFF, 0);
136 c->dwarf.loc[EFLAGS] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EFLAGS_OFF, 0);
137 c->dwarf.loc[TRAPNO] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_TRAPNO_OFF, 0);
138 c->dwarf.loc[ST0] = DWARF_NULL_LOC;
139 } else if (c->sigcontext_format == X86_SCF_FREEBSD_SYSCALL) {
140 c->dwarf.loc[EIP] = DWARF_LOC (c->dwarf.cfa, 0);
141 c->dwarf.loc[EAX] = DWARF_NULL_LOC;
142 c->dwarf.cfa += 4;
143 c->dwarf.use_prev_instr = 1;
144 } else {
145 Debug (8, "Gstep: not handling frame format %d\n", c->sigcontext_format);
146 abort();
148 return 0;
151 HIDDEN dwarf_loc_t
152 x86_get_scratch_loc (struct cursor *c, unw_regnum_t reg)
154 unw_word_t addr = c->sigcontext_addr, off, xmm_off;
155 unw_word_t fpstate, fpformat;
156 int ret, is_fpstate = 0, is_xmmstate = 0;
158 switch (c->sigcontext_format)
160 case X86_SCF_NONE:
161 return DWARF_REG_LOC (&c->dwarf, reg);
163 case X86_SCF_FREEBSD_SIGFRAME:
164 addr += offsetof(struct sigframe, sf_uc) + FREEBSD_UC_MCONTEXT_OFF;
165 break;
167 case X86_SCF_FREEBSD_SIGFRAME4:
168 abort();
169 break;
171 case X86_SCF_FREEBSD_OSIGFRAME:
172 /* XXXKIB */
173 abort();
174 break;
176 case X86_SCF_FREEBSD_SYSCALL:
177 /* XXXKIB */
178 abort();
179 break;
181 default:
182 /* XXXKIB */
183 abort();
184 break;
187 off = 0; /* shut gcc warning */
188 switch (reg)
190 case UNW_X86_GS: off = FREEBSD_UC_MCONTEXT_GS_OFF; break;
191 case UNW_X86_FS: off = FREEBSD_UC_MCONTEXT_FS_OFF; break;
192 case UNW_X86_ES: off = FREEBSD_UC_MCONTEXT_ES_OFF; break;
193 case UNW_X86_DS: off = FREEBSD_UC_MCONTEXT_SS_OFF; break;
194 case UNW_X86_EDI: off = FREEBSD_UC_MCONTEXT_EDI_OFF; break;
195 case UNW_X86_ESI: off = FREEBSD_UC_MCONTEXT_ESI_OFF; break;
196 case UNW_X86_EBP: off = FREEBSD_UC_MCONTEXT_EBP_OFF; break;
197 case UNW_X86_ESP: off = FREEBSD_UC_MCONTEXT_ESP_OFF; break;
198 case UNW_X86_EBX: off = FREEBSD_UC_MCONTEXT_EBX_OFF; break;
199 case UNW_X86_EDX: off = FREEBSD_UC_MCONTEXT_EDX_OFF; break;
200 case UNW_X86_ECX: off = FREEBSD_UC_MCONTEXT_ECX_OFF; break;
201 case UNW_X86_EAX: off = FREEBSD_UC_MCONTEXT_EAX_OFF; break;
202 case UNW_X86_TRAPNO: off = FREEBSD_UC_MCONTEXT_TRAPNO_OFF; break;
203 case UNW_X86_EIP: off = FREEBSD_UC_MCONTEXT_EIP_OFF; break;
204 case UNW_X86_CS: off = FREEBSD_UC_MCONTEXT_CS_OFF; break;
205 case UNW_X86_EFLAGS: off = FREEBSD_UC_MCONTEXT_EFLAGS_OFF; break;
206 case UNW_X86_SS: off = FREEBSD_UC_MCONTEXT_SS_OFF; break;
208 case UNW_X86_FCW:
209 is_fpstate = 1;
210 off = FREEBSD_UC_MCONTEXT_CW_OFF;
211 xmm_off = FREEBSD_UC_MCONTEXT_CW_XMM_OFF;
212 break;
213 case UNW_X86_FSW:
214 is_fpstate = 1;
215 off = FREEBSD_UC_MCONTEXT_SW_OFF;
216 xmm_off = FREEBSD_UC_MCONTEXT_SW_XMM_OFF;
217 break;
218 case UNW_X86_FTW:
219 is_fpstate = 1;
220 xmm_off = FREEBSD_UC_MCONTEXT_TAG_XMM_OFF;
221 off = FREEBSD_UC_MCONTEXT_TAG_OFF;
222 break;
223 case UNW_X86_FCS:
224 is_fpstate = 1;
225 off = FREEBSD_UC_MCONTEXT_CSSEL_OFF;
226 xmm_off = FREEBSD_UC_MCONTEXT_CSSEL_XMM_OFF;
227 break;
228 case UNW_X86_FIP:
229 is_fpstate = 1;
230 off = FREEBSD_UC_MCONTEXT_IPOFF_OFF;
231 xmm_off = FREEBSD_UC_MCONTEXT_IPOFF_XMM_OFF;
232 break;
233 case UNW_X86_FEA:
234 is_fpstate = 1;
235 off = FREEBSD_UC_MCONTEXT_DATAOFF_OFF;
236 xmm_off = FREEBSD_UC_MCONTEXT_DATAOFF_XMM_OFF;
237 break;
238 case UNW_X86_FDS:
239 is_fpstate = 1;
240 off = FREEBSD_US_MCONTEXT_DATASEL_OFF;
241 xmm_off = FREEBSD_US_MCONTEXT_DATASEL_XMM_OFF;
242 break;
243 case UNW_X86_MXCSR:
244 is_fpstate = 1;
245 is_xmmstate = 1;
246 xmm_off = FREEBSD_UC_MCONTEXT_MXCSR_XMM_OFF;
247 break;
249 /* stacked fp registers */
250 case UNW_X86_ST0: case UNW_X86_ST1: case UNW_X86_ST2: case UNW_X86_ST3:
251 case UNW_X86_ST4: case UNW_X86_ST5: case UNW_X86_ST6: case UNW_X86_ST7:
252 is_fpstate = 1;
253 off = FREEBSD_UC_MCONTEXT_ST0_OFF + 10*(reg - UNW_X86_ST0);
254 xmm_off = FREEBSD_UC_MCONTEXT_ST0_XMM_OFF + 10*(reg - UNW_X86_ST0);
255 break;
257 /* SSE fp registers */
258 case UNW_X86_XMM0_lo: case UNW_X86_XMM0_hi:
259 case UNW_X86_XMM1_lo: case UNW_X86_XMM1_hi:
260 case UNW_X86_XMM2_lo: case UNW_X86_XMM2_hi:
261 case UNW_X86_XMM3_lo: case UNW_X86_XMM3_hi:
262 case UNW_X86_XMM4_lo: case UNW_X86_XMM4_hi:
263 case UNW_X86_XMM5_lo: case UNW_X86_XMM5_hi:
264 case UNW_X86_XMM6_lo: case UNW_X86_XMM6_hi:
265 case UNW_X86_XMM7_lo: case UNW_X86_XMM7_hi:
266 is_fpstate = 1;
267 is_xmmstate = 1;
268 xmm_off = FREEBSD_UC_MCONTEXT_XMM0_OFF + 8*(reg - UNW_X86_XMM0_lo);
269 break;
270 case UNW_X86_XMM0:
271 case UNW_X86_XMM1:
272 case UNW_X86_XMM2:
273 case UNW_X86_XMM3:
274 case UNW_X86_XMM4:
275 case UNW_X86_XMM5:
276 case UNW_X86_XMM6:
277 case UNW_X86_XMM7:
278 is_fpstate = 1;
279 is_xmmstate = 1;
280 xmm_off = FREEBSD_UC_MCONTEXT_XMM0_OFF + 16*(reg - UNW_X86_XMM0);
281 break;
283 case UNW_X86_FOP:
284 case UNW_X86_TSS:
285 case UNW_X86_LDT:
286 default:
287 return DWARF_REG_LOC (&c->dwarf, reg);
290 if (is_fpstate)
292 if ((ret = dwarf_get (&c->dwarf,
293 DWARF_MEM_LOC (&c->dwarf, addr + FREEBSD_UC_MCONTEXT_FPSTATE_OFF),
294 &fpstate)) < 0)
295 return DWARF_NULL_LOC;
296 if (fpstate == FREEBSD_UC_MCONTEXT_FPOWNED_NONE)
297 return DWARF_NULL_LOC;
298 if ((ret = dwarf_get (&c->dwarf,
299 DWARF_MEM_LOC (&c->dwarf, addr + FREEBSD_UC_MCONTEXT_FPFORMAT_OFF),
300 &fpformat)) < 0)
301 return DWARF_NULL_LOC;
302 if (fpformat == FREEBSD_UC_MCONTEXT_FPFMT_NODEV ||
303 (is_xmmstate && fpformat != FREEBSD_UC_MCONTEXT_FPFMT_XMM))
304 return DWARF_NULL_LOC;
305 if (is_xmmstate)
306 off = xmm_off;
309 return DWARF_MEM_LOC (c, addr + off);
312 #ifndef UNW_REMOTE_ONLY
313 HIDDEN void *
314 x86_r_uc_addr (ucontext_t *uc, int reg)
316 void *addr;
318 switch (reg)
320 case UNW_X86_GS: addr = &uc->uc_mcontext.mc_gs; break;
321 case UNW_X86_FS: addr = &uc->uc_mcontext.mc_fs; break;
322 case UNW_X86_ES: addr = &uc->uc_mcontext.mc_es; break;
323 case UNW_X86_DS: addr = &uc->uc_mcontext.mc_ds; break;
324 case UNW_X86_EAX: addr = &uc->uc_mcontext.mc_eax; break;
325 case UNW_X86_EBX: addr = &uc->uc_mcontext.mc_ebx; break;
326 case UNW_X86_ECX: addr = &uc->uc_mcontext.mc_ecx; break;
327 case UNW_X86_EDX: addr = &uc->uc_mcontext.mc_edx; break;
328 case UNW_X86_ESI: addr = &uc->uc_mcontext.mc_esi; break;
329 case UNW_X86_EDI: addr = &uc->uc_mcontext.mc_edi; break;
330 case UNW_X86_EBP: addr = &uc->uc_mcontext.mc_ebp; break;
331 case UNW_X86_EIP: addr = &uc->uc_mcontext.mc_eip; break;
332 case UNW_X86_ESP: addr = &uc->uc_mcontext.mc_esp; break;
333 case UNW_X86_TRAPNO: addr = &uc->uc_mcontext.mc_trapno; break;
334 case UNW_X86_CS: addr = &uc->uc_mcontext.mc_cs; break;
335 case UNW_X86_EFLAGS: addr = &uc->uc_mcontext.mc_eflags; break;
336 case UNW_X86_SS: addr = &uc->uc_mcontext.mc_ss; break;
338 default:
339 addr = NULL;
341 return addr;
344 HIDDEN int
345 x86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
347 struct cursor *c = (struct cursor *) cursor;
348 ucontext_t *uc = c->uc;
350 /* Ensure c->pi is up-to-date. On x86, it's relatively common to be
351 missing DWARF unwind info. We don't want to fail in that case,
352 because the frame-chain still would let us do a backtrace at
353 least. */
354 dwarf_make_proc_info (&c->dwarf);
356 if (c->sigcontext_format == X86_SCF_NONE) {
357 Debug (8, "resuming at ip=%x via setcontext()\n", c->dwarf.ip);
358 setcontext (uc);
359 abort();
360 } else if (c->sigcontext_format == X86_SCF_FREEBSD_SIGFRAME) {
361 struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr;
363 Debug (8, "resuming at ip=%x via sigreturn(%p)\n", c->dwarf.ip, sc);
364 sigreturn((ucontext_t *)((const char *)sc + FREEBSD_SC_UCONTEXT_OFF));
365 abort();
366 } else {
367 Debug (8, "resuming at ip=%x for sigcontext format %d not implemented\n",
368 c->dwarf.ip, c->sigcontext_format);
369 abort();
371 return -UNW_EINVAL;
374 #endif