Update i386 and amd64 ports for unwinder changes.
[deliverable/binutils-gdb.git] / gdb / amd64obsd-tdep.c
CommitLineData
e2879ccb
MK
1/* Target-dependent code for OpenBSD/amd64.
2
9b254dd1 3 Copyright (C) 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
e2879ccb
MK
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
a9762ec7 9 the Free Software Foundation; either version 3 of the License, or
e2879ccb
MK
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
a9762ec7 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
e2879ccb
MK
19
20#include "defs.h"
21#include "frame.h"
f6acec62 22#include "frame-unwind.h"
e2879ccb 23#include "gdbcore.h"
911bc6ee
MK
24#include "symtab.h"
25#include "objfiles.h"
e2879ccb 26#include "osabi.h"
d78749b4 27#include "regcache.h"
30b344b1 28#include "regset.h"
e2879ccb 29#include "target.h"
f6acec62 30#include "trad-frame.h"
e2879ccb
MK
31
32#include "gdb_assert.h"
33#include "gdb_string.h"
34
85be1ca6 35#include "amd64-tdep.h"
30b344b1 36#include "i387-tdep.h"
7e654c37 37#include "solib-svr4.h"
d78749b4 38#include "bsd-uthread.h"
30b344b1
MK
39
40/* Support for core dumps. */
41
42static void
43amd64obsd_supply_regset (const struct regset *regset,
44 struct regcache *regcache, int regnum,
45 const void *regs, size_t len)
46{
9ea75c57 47 const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
30b344b1
MK
48
49 gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FXSAVE);
50
51 i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset);
d8de1ef7
MK
52 amd64_supply_fxsave (regcache, regnum,
53 ((const gdb_byte *)regs) + tdep->sizeof_gregset);
30b344b1
MK
54}
55
56static const struct regset *
57amd64obsd_regset_from_core_section (struct gdbarch *gdbarch,
58 const char *sect_name, size_t sect_size)
59{
60 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
61
62 /* OpenBSD core dumps don't use seperate register sets for the
63 general-purpose and floating-point registers. */
64
65 if (strcmp (sect_name, ".reg") == 0
66 && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FXSAVE)
67 {
68 if (tdep->gregset == NULL)
9ea75c57 69 tdep->gregset = regset_alloc (gdbarch, amd64obsd_supply_regset, NULL);
30b344b1
MK
70 return tdep->gregset;
71 }
72
73 return NULL;
74}
75\f
e2879ccb
MK
76
77/* Support for signal handlers. */
78
911bc6ee 79/* Default page size. */
e2879ccb
MK
80static const int amd64obsd_page_size = 4096;
81
10458914
DJ
82/* Return whether THIS_FRAME corresponds to an OpenBSD sigtramp
83 routine. */
911bc6ee 84
e2879ccb 85static int
10458914 86amd64obsd_sigtramp_p (struct frame_info *this_frame)
e2879ccb 87{
10458914 88 CORE_ADDR pc = get_frame_pc (this_frame);
e2879ccb 89 CORE_ADDR start_pc = (pc & ~(amd64obsd_page_size - 1));
d8de1ef7 90 const gdb_byte sigreturn[] =
e2879ccb
MK
91 {
92 0x48, 0xc7, 0xc0,
93 0x67, 0x00, 0x00, 0x00, /* movq $SYS_sigreturn, %rax */
84d04465 94 0xcd, 0x80 /* int $0x80 */
e2879ccb 95 };
1c5bf419 96 size_t buflen = (sizeof sigreturn) + 1;
d8de1ef7
MK
97 gdb_byte *buf;
98 char *name;
911bc6ee
MK
99
100 /* If the function has a valid symbol name, it isn't a
101 trampoline. */
102 find_pc_partial_function (pc, &name, NULL, NULL);
103 if (name != NULL)
104 return 0;
e2879ccb 105
911bc6ee
MK
106 /* If the function lives in a valid section (even without a starting
107 point) it isn't a trampoline. */
108 if (find_pc_section (pc) != NULL)
e2879ccb
MK
109 return 0;
110
111 /* If we can't read the instructions at START_PC, return zero. */
4cd28409 112 buf = alloca ((sizeof sigreturn) + 1);
10458914 113 if (!safe_frame_unwind_memory (this_frame, start_pc + 6, buf, buflen))
e2879ccb
MK
114 return 0;
115
4cd28409
MK
116 /* Check for sigreturn(2). Depending on how the assembler encoded
117 the `movq %rsp, %rdi' instruction, the code starts at offset 6 or
118 7. */
119 if (memcmp (buf, sigreturn, sizeof sigreturn)
120 && memcpy (buf + 1, sigreturn, sizeof sigreturn))
e2879ccb
MK
121 return 0;
122
123 return 1;
124}
125
10458914
DJ
126/* Assuming THIS_FRAME is for a BSD sigtramp routine, return the
127 address of the associated sigcontext structure. */
e2879ccb
MK
128
129static CORE_ADDR
10458914 130amd64obsd_sigcontext_addr (struct frame_info *this_frame)
e2879ccb 131{
10458914 132 CORE_ADDR pc = get_frame_pc (this_frame);
0fe85704
MK
133 ULONGEST offset = (pc & (amd64obsd_page_size - 1));
134
e2879ccb 135 /* The %rsp register points at `struct sigcontext' upon entry of a
0fe85704
MK
136 signal trampoline. The relevant part of the trampoline is
137
138 call *%rax
139 movq %rsp, %rdi
140 pushq %rdi
141 movq $SYS_sigreturn,%rax
142 int $0x80
143
144 (see /usr/src/sys/arch/amd64/amd64/locore.S). The `pushq'
145 instruction clobbers %rsp, but its value is saved in `%rdi'. */
146
4cd28409 147 if (offset > 5)
10458914 148 return get_frame_register_unsigned (this_frame, AMD64_RDI_REGNUM);
0fe85704 149 else
10458914 150 return get_frame_register_unsigned (this_frame, AMD64_RSP_REGNUM);
e2879ccb
MK
151}
152\f
153/* OpenBSD 3.5 or later. */
154
155/* Mapping between the general-purpose registers in `struct reg'
156 format and GDB's register cache layout. */
157
30b344b1 158/* From <machine/reg.h>. */
e2879ccb
MK
159int amd64obsd_r_reg_offset[] =
160{
161 14 * 8, /* %rax */
162 13 * 8, /* %rbx */
163 3 * 8, /* %rcx */
164 2 * 8, /* %rdx */
165 1 * 8, /* %rsi */
166 0 * 8, /* %rdi */
167 12 * 8, /* %rbp */
168 15 * 8, /* %rsp */
169 4 * 8, /* %r8 .. */
170 5 * 8,
171 6 * 8,
172 7 * 8,
173 8 * 8,
174 9 * 8,
175 10 * 8,
176 11 * 8, /* ... %r15 */
177 16 * 8, /* %rip */
178 17 * 8, /* %eflags */
179 18 * 8, /* %cs */
180 19 * 8, /* %ss */
181 20 * 8, /* %ds */
182 21 * 8, /* %es */
183 22 * 8, /* %fs */
184 23 * 8 /* %gs */
185};
186
30b344b1 187/* From <machine/signal.h>. */
e2879ccb
MK
188static int amd64obsd_sc_reg_offset[] =
189{
190 14 * 8, /* %rax */
191 13 * 8, /* %rbx */
192 3 * 8, /* %rcx */
193 2 * 8, /* %rdx */
194 1 * 8, /* %rsi */
195 0 * 8, /* %rdi */
196 12 * 8, /* %rbp */
197 24 * 8, /* %rsp */
198 4 * 8, /* %r8 ... */
199 5 * 8,
200 6 * 8,
201 7 * 8,
202 8 * 8,
203 9 * 8,
204 10 * 8,
205 11 * 8, /* ... %r15 */
206 21 * 8, /* %rip */
207 23 * 8, /* %eflags */
208 22 * 8, /* %cs */
209 25 * 8, /* %ss */
210 18 * 8, /* %ds */
211 17 * 8, /* %es */
212 16 * 8, /* %fs */
213 15 * 8 /* %gs */
214};
215
d78749b4
MK
216/* From /usr/src/lib/libpthread/arch/amd64/uthread_machdep.c. */
217static int amd64obsd_uthread_reg_offset[] =
218{
219 19 * 8, /* %rax */
220 16 * 8, /* %rbx */
221 18 * 8, /* %rcx */
222 17 * 8, /* %rdx */
223 14 * 8, /* %rsi */
224 13 * 8, /* %rdi */
225 15 * 8, /* %rbp */
226 -1, /* %rsp */
227 12 * 8, /* %r8 ... */
228 11 * 8,
229 10 * 8,
230 9 * 8,
231 8 * 8,
232 7 * 8,
233 6 * 8,
234 5 * 8, /* ... %r15 */
235 20 * 8, /* %rip */
236 4 * 8, /* %eflags */
237 21 * 8, /* %cs */
238 -1, /* %ss */
239 3 * 8, /* %ds */
240 2 * 8, /* %es */
241 1 * 8, /* %fs */
242 0 * 8 /* %gs */
243};
244
245/* Offset within the thread structure where we can find the saved
246 stack pointer (%esp). */
247#define AMD64OBSD_UTHREAD_RSP_OFFSET 400
248
249static void
250amd64obsd_supply_uthread (struct regcache *regcache,
251 int regnum, CORE_ADDR addr)
252{
253 CORE_ADDR sp_addr = addr + AMD64OBSD_UTHREAD_RSP_OFFSET;
254 CORE_ADDR sp = 0;
255 gdb_byte buf[8];
256 int i;
257
258 gdb_assert (regnum >= -1);
259
260 if (regnum == -1 || regnum == AMD64_RSP_REGNUM)
261 {
262 int offset;
263
264 /* Fetch stack pointer from thread structure. */
265 sp = read_memory_unsigned_integer (sp_addr, 8);
266
267 /* Adjust the stack pointer such that it looks as if we just
268 returned from _thread_machdep_switch. */
269 offset = amd64obsd_uthread_reg_offset[AMD64_RIP_REGNUM] + 8;
270 store_unsigned_integer (buf, 8, sp + offset);
271 regcache_raw_supply (regcache, AMD64_RSP_REGNUM, buf);
272 }
273
274 for (i = 0; i < ARRAY_SIZE (amd64obsd_uthread_reg_offset); i++)
275 {
276 if (amd64obsd_uthread_reg_offset[i] != -1
277 && (regnum == -1 || regnum == i))
278 {
279 /* Fetch stack pointer from thread structure (if we didn't
280 do so already). */
281 if (sp == 0)
282 sp = read_memory_unsigned_integer (sp_addr, 8);
283
284 /* Read the saved register from the stack frame. */
285 read_memory (sp + amd64obsd_uthread_reg_offset[i], buf, 8);
286 regcache_raw_supply (regcache, i, buf);
287 }
288 }
289}
290
291static void
292amd64obsd_collect_uthread (const struct regcache *regcache,
293 int regnum, CORE_ADDR addr)
294{
295 CORE_ADDR sp_addr = addr + AMD64OBSD_UTHREAD_RSP_OFFSET;
296 CORE_ADDR sp = 0;
297 gdb_byte buf[8];
298 int i;
299
300 gdb_assert (regnum >= -1);
301
302 if (regnum == -1 || regnum == AMD64_RSP_REGNUM)
303 {
304 int offset;
305
306 /* Calculate the stack pointer (frame pointer) that will be
307 stored into the thread structure. */
308 offset = amd64obsd_uthread_reg_offset[AMD64_RIP_REGNUM] + 8;
309 regcache_raw_collect (regcache, AMD64_RSP_REGNUM, buf);
310 sp = extract_unsigned_integer (buf, 8) - offset;
311
312 /* Store the stack pointer. */
313 write_memory_unsigned_integer (sp_addr, 8, sp);
314
315 /* The stack pointer was (potentially) modified. Make sure we
316 build a proper stack frame. */
317 regnum = -1;
318 }
319
320 for (i = 0; i < ARRAY_SIZE (amd64obsd_uthread_reg_offset); i++)
321 {
322 if (amd64obsd_uthread_reg_offset[i] != -1
323 && (regnum == -1 || regnum == i))
324 {
325 /* Fetch stack pointer from thread structure (if we didn't
326 calculate it already). */
327 if (sp == 0)
328 sp = read_memory_unsigned_integer (sp_addr, 8);
329
330 /* Write the register into the stack frame. */
331 regcache_raw_collect (regcache, i, buf);
332 write_memory (sp + amd64obsd_uthread_reg_offset[i], buf, 8);
333 }
334 }
335}
f6acec62
MK
336/* Kernel debugging support. */
337
338/* From <machine/frame.h>. Easy since `struct trapframe' matches
339 `struct sigcontext'. */
340#define amd64obsd_tf_reg_offset amd64obsd_sc_reg_offset
341
342static struct trad_frame_cache *
10458914 343amd64obsd_trapframe_cache (struct frame_info *this_frame, void **this_cache)
f6acec62
MK
344{
345 struct trad_frame_cache *cache;
346 CORE_ADDR func, sp, addr;
347 ULONGEST cs;
348 char *name;
349 int i;
350
351 if (*this_cache)
352 return *this_cache;
353
10458914 354 cache = trad_frame_cache_zalloc (this_frame);
f6acec62
MK
355 *this_cache = cache;
356
10458914
DJ
357 func = get_frame_func (this_frame);
358 sp = get_frame_register_unsigned (this_frame, AMD64_RSP_REGNUM);
f6acec62
MK
359
360 find_pc_partial_function (func, &name, NULL, NULL);
6d566cff 361 if (name && strncmp (name, "Xintr", 5) == 0)
f6acec62
MK
362 addr = sp + 8; /* It's an interrupt frame. */
363 else
364 addr = sp;
365
366 for (i = 0; i < ARRAY_SIZE (amd64obsd_tf_reg_offset); i++)
367 if (amd64obsd_tf_reg_offset[i] != -1)
368 trad_frame_set_reg_addr (cache, i, addr + amd64obsd_tf_reg_offset[i]);
369
370 /* Read %cs from trap frame. */
7238f002 371 addr += amd64obsd_tf_reg_offset[AMD64_CS_REGNUM];
f6acec62
MK
372 cs = read_memory_unsigned_integer (addr, 8);
373 if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
374 {
6d566cff 375 /* Trap from user space; terminate backtrace. */
f6acec62
MK
376 trad_frame_set_id (cache, null_frame_id);
377 }
378 else
379 {
380 /* Construct the frame ID using the function start. */
381 trad_frame_set_id (cache, frame_id_build (sp + 16, func));
382 }
383
384 return cache;
385}
386
387static void
10458914 388amd64obsd_trapframe_this_id (struct frame_info *this_frame,
f6acec62
MK
389 void **this_cache, struct frame_id *this_id)
390{
391 struct trad_frame_cache *cache =
10458914 392 amd64obsd_trapframe_cache (this_frame, this_cache);
f6acec62
MK
393
394 trad_frame_get_id (cache, this_id);
395}
396
10458914
DJ
397static struct value *
398amd64obsd_trapframe_prev_register (struct frame_info *this_frame,
399 void **this_cache, int regnum)
f6acec62
MK
400{
401 struct trad_frame_cache *cache =
10458914 402 amd64obsd_trapframe_cache (this_frame, this_cache);
f6acec62 403
10458914 404 return trad_frame_get_register (cache, this_frame, regnum);
f6acec62
MK
405}
406
407static int
408amd64obsd_trapframe_sniffer (const struct frame_unwind *self,
10458914 409 struct frame_info *this_frame,
f6acec62
MK
410 void **this_prologue_cache)
411{
412 ULONGEST cs;
413 char *name;
414
e5cc6d11 415 /* Check Current Privilege Level and bail out if we're not executing
6d566cff 416 in kernel space. */
10458914 417 cs = get_frame_register_unsigned (this_frame, AMD64_CS_REGNUM);
f6acec62
MK
418 if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
419 return 0;
420
10458914 421 find_pc_partial_function (get_frame_pc (this_frame), &name, NULL, NULL);
f6acec62
MK
422 return (name && ((strcmp (name, "calltrap") == 0)
423 || (strcmp (name, "osyscall1") == 0)
424 || (strcmp (name, "Xsyscall") == 0)
425 || (strncmp (name, "Xintr", 5) == 0)));
426}
427
428static const struct frame_unwind amd64obsd_trapframe_unwind = {
429 /* FIXME: kettenis/20051219: This really is more like an interrupt
430 frame, but SIGTRAMP_FRAME would print <signal handler called>,
431 which really is not what we want here. */
432 NORMAL_FRAME,
433 amd64obsd_trapframe_this_id,
434 amd64obsd_trapframe_prev_register,
435 NULL,
436 amd64obsd_trapframe_sniffer
437};
438\f
d78749b4 439
e2879ccb
MK
440static void
441amd64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
442{
443 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
444
90f90721 445 amd64_init_abi (info, gdbarch);
e2879ccb 446
30b344b1
MK
447 /* Initialize general-purpose register set details. */
448 tdep->gregset_reg_offset = amd64obsd_r_reg_offset;
449 tdep->gregset_num_regs = ARRAY_SIZE (amd64obsd_r_reg_offset);
450 tdep->sizeof_gregset = 24 * 8;
451
452 set_gdbarch_regset_from_core_section (gdbarch,
453 amd64obsd_regset_from_core_section);
454
e2879ccb
MK
455 tdep->jb_pc_offset = 7 * 8;
456
911bc6ee 457 tdep->sigtramp_p = amd64obsd_sigtramp_p;
e2879ccb
MK
458 tdep->sigcontext_addr = amd64obsd_sigcontext_addr;
459 tdep->sc_reg_offset = amd64obsd_sc_reg_offset;
460 tdep->sc_num_regs = ARRAY_SIZE (amd64obsd_sc_reg_offset);
7e654c37 461
d78749b4
MK
462 /* OpenBSD provides a user-level threads implementation. */
463 bsd_uthread_set_supply_uthread (gdbarch, amd64obsd_supply_uthread);
464 bsd_uthread_set_collect_uthread (gdbarch, amd64obsd_collect_uthread);
465
7e654c37
MK
466 /* OpenBSD uses SVR4-style shared libraries. */
467 set_solib_svr4_fetch_link_map_offsets
468 (gdbarch, svr4_lp64_fetch_link_map_offsets);
f6acec62
MK
469
470 /* Unwind kernel trap frames correctly. */
471 frame_unwind_prepend_unwinder (gdbarch, &amd64obsd_trapframe_unwind);
e2879ccb
MK
472}
473\f
474
475/* Provide a prototype to silence -Wmissing-prototypes. */
476void _initialize_amd64obsd_tdep (void);
477
478void
30b344b1 479_initialize_amd64obsd_tdep (void)
e2879ccb
MK
480{
481 /* The OpenBSD/amd64 native dependent code makes this assumption. */
90f90721 482 gdb_assert (ARRAY_SIZE (amd64obsd_r_reg_offset) == AMD64_NUM_GREGS);
e2879ccb
MK
483
484 gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
485 GDB_OSABI_OPENBSD_ELF, amd64obsd_init_abi);
30b344b1
MK
486
487 /* OpenBSD uses traditional (a.out) NetBSD-style core dumps. */
488 gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
489 GDB_OSABI_NETBSD_AOUT, amd64obsd_init_abi);
e2879ccb 490}
This page took 0.367648 seconds and 4 git commands to generate.