]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/amd64obsd-tdep.c
* elfxx-tilegx.c (tilegx_elf_relocate_section): Silence bogus warning.
[thirdparty/binutils-gdb.git] / gdb / amd64obsd-tdep.c
CommitLineData
e2879ccb
MK
1/* Target-dependent code for OpenBSD/amd64.
2
0b302171 3 Copyright (C) 2003-2005, 2007-2012 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));
0dcddd84 90 const gdb_byte osigreturn[] =
e2879ccb
MK
91 {
92 0x48, 0xc7, 0xc0,
93 0x67, 0x00, 0x00, 0x00, /* movq $SYS_sigreturn, %rax */
84d04465 94 0xcd, 0x80 /* int $0x80 */
e2879ccb 95 };
0dcddd84
MK
96 const gdb_byte sigreturn[] =
97 {
98 0x48, 0xc7, 0xc0,
99 0x67, 0x00, 0x00, 0x00, /* movq $SYS_sigreturn, %rax */
100 0x0f, 0x05 /* syscall */
101 };
1c5bf419 102 size_t buflen = (sizeof sigreturn) + 1;
d8de1ef7 103 gdb_byte *buf;
2c02bd72 104 const char *name;
911bc6ee
MK
105
106 /* If the function has a valid symbol name, it isn't a
107 trampoline. */
108 find_pc_partial_function (pc, &name, NULL, NULL);
109 if (name != NULL)
110 return 0;
e2879ccb 111
911bc6ee
MK
112 /* If the function lives in a valid section (even without a starting
113 point) it isn't a trampoline. */
114 if (find_pc_section (pc) != NULL)
e2879ccb
MK
115 return 0;
116
117 /* If we can't read the instructions at START_PC, return zero. */
4cd28409 118 buf = alloca ((sizeof sigreturn) + 1);
10458914 119 if (!safe_frame_unwind_memory (this_frame, start_pc + 6, buf, buflen))
e2879ccb
MK
120 return 0;
121
4cd28409
MK
122 /* Check for sigreturn(2). Depending on how the assembler encoded
123 the `movq %rsp, %rdi' instruction, the code starts at offset 6 or
0dcddd84
MK
124 7. OpenBSD 5.0 and later use the `syscall' instruction. Older
125 versions use `int $0x80'. Check for both. */
4cd28409 126 if (memcmp (buf, sigreturn, sizeof sigreturn)
0dcddd84
MK
127 && memcmp (buf + 1, sigreturn, sizeof sigreturn)
128 && memcmp (buf, osigreturn, sizeof osigreturn)
129 && memcmp (buf + 1, osigreturn, sizeof osigreturn))
e2879ccb
MK
130 return 0;
131
132 return 1;
133}
134
10458914
DJ
135/* Assuming THIS_FRAME is for a BSD sigtramp routine, return the
136 address of the associated sigcontext structure. */
e2879ccb
MK
137
138static CORE_ADDR
10458914 139amd64obsd_sigcontext_addr (struct frame_info *this_frame)
e2879ccb 140{
10458914 141 CORE_ADDR pc = get_frame_pc (this_frame);
0fe85704
MK
142 ULONGEST offset = (pc & (amd64obsd_page_size - 1));
143
e2879ccb 144 /* The %rsp register points at `struct sigcontext' upon entry of a
0fe85704
MK
145 signal trampoline. The relevant part of the trampoline is
146
147 call *%rax
148 movq %rsp, %rdi
149 pushq %rdi
150 movq $SYS_sigreturn,%rax
151 int $0x80
152
153 (see /usr/src/sys/arch/amd64/amd64/locore.S). The `pushq'
154 instruction clobbers %rsp, but its value is saved in `%rdi'. */
155
4cd28409 156 if (offset > 5)
10458914 157 return get_frame_register_unsigned (this_frame, AMD64_RDI_REGNUM);
0fe85704 158 else
10458914 159 return get_frame_register_unsigned (this_frame, AMD64_RSP_REGNUM);
e2879ccb
MK
160}
161\f
162/* OpenBSD 3.5 or later. */
163
164/* Mapping between the general-purpose registers in `struct reg'
165 format and GDB's register cache layout. */
166
30b344b1 167/* From <machine/reg.h>. */
e2879ccb
MK
168int amd64obsd_r_reg_offset[] =
169{
170 14 * 8, /* %rax */
171 13 * 8, /* %rbx */
172 3 * 8, /* %rcx */
173 2 * 8, /* %rdx */
174 1 * 8, /* %rsi */
175 0 * 8, /* %rdi */
176 12 * 8, /* %rbp */
177 15 * 8, /* %rsp */
0963b4bd 178 4 * 8, /* %r8 .. */
e2879ccb
MK
179 5 * 8,
180 6 * 8,
181 7 * 8,
182 8 * 8,
183 9 * 8,
184 10 * 8,
185 11 * 8, /* ... %r15 */
186 16 * 8, /* %rip */
187 17 * 8, /* %eflags */
188 18 * 8, /* %cs */
189 19 * 8, /* %ss */
190 20 * 8, /* %ds */
191 21 * 8, /* %es */
192 22 * 8, /* %fs */
193 23 * 8 /* %gs */
194};
195
30b344b1 196/* From <machine/signal.h>. */
e2879ccb
MK
197static int amd64obsd_sc_reg_offset[] =
198{
199 14 * 8, /* %rax */
200 13 * 8, /* %rbx */
201 3 * 8, /* %rcx */
202 2 * 8, /* %rdx */
203 1 * 8, /* %rsi */
204 0 * 8, /* %rdi */
205 12 * 8, /* %rbp */
206 24 * 8, /* %rsp */
0963b4bd 207 4 * 8, /* %r8 ... */
e2879ccb
MK
208 5 * 8,
209 6 * 8,
210 7 * 8,
211 8 * 8,
212 9 * 8,
213 10 * 8,
214 11 * 8, /* ... %r15 */
215 21 * 8, /* %rip */
216 23 * 8, /* %eflags */
217 22 * 8, /* %cs */
218 25 * 8, /* %ss */
219 18 * 8, /* %ds */
220 17 * 8, /* %es */
221 16 * 8, /* %fs */
222 15 * 8 /* %gs */
223};
224
d78749b4
MK
225/* From /usr/src/lib/libpthread/arch/amd64/uthread_machdep.c. */
226static int amd64obsd_uthread_reg_offset[] =
227{
228 19 * 8, /* %rax */
229 16 * 8, /* %rbx */
230 18 * 8, /* %rcx */
231 17 * 8, /* %rdx */
232 14 * 8, /* %rsi */
233 13 * 8, /* %rdi */
234 15 * 8, /* %rbp */
235 -1, /* %rsp */
0963b4bd 236 12 * 8, /* %r8 ... */
d78749b4
MK
237 11 * 8,
238 10 * 8,
239 9 * 8,
240 8 * 8,
241 7 * 8,
242 6 * 8,
243 5 * 8, /* ... %r15 */
244 20 * 8, /* %rip */
245 4 * 8, /* %eflags */
246 21 * 8, /* %cs */
247 -1, /* %ss */
248 3 * 8, /* %ds */
249 2 * 8, /* %es */
250 1 * 8, /* %fs */
251 0 * 8 /* %gs */
252};
253
254/* Offset within the thread structure where we can find the saved
255 stack pointer (%esp). */
256#define AMD64OBSD_UTHREAD_RSP_OFFSET 400
257
258static void
259amd64obsd_supply_uthread (struct regcache *regcache,
260 int regnum, CORE_ADDR addr)
261{
e17a4113
UW
262 struct gdbarch *gdbarch = get_regcache_arch (regcache);
263 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
d78749b4
MK
264 CORE_ADDR sp_addr = addr + AMD64OBSD_UTHREAD_RSP_OFFSET;
265 CORE_ADDR sp = 0;
266 gdb_byte buf[8];
267 int i;
268
269 gdb_assert (regnum >= -1);
270
271 if (regnum == -1 || regnum == AMD64_RSP_REGNUM)
272 {
273 int offset;
274
275 /* Fetch stack pointer from thread structure. */
e17a4113 276 sp = read_memory_unsigned_integer (sp_addr, 8, byte_order);
d78749b4
MK
277
278 /* Adjust the stack pointer such that it looks as if we just
279 returned from _thread_machdep_switch. */
280 offset = amd64obsd_uthread_reg_offset[AMD64_RIP_REGNUM] + 8;
e17a4113 281 store_unsigned_integer (buf, 8, byte_order, sp + offset);
d78749b4
MK
282 regcache_raw_supply (regcache, AMD64_RSP_REGNUM, buf);
283 }
284
285 for (i = 0; i < ARRAY_SIZE (amd64obsd_uthread_reg_offset); i++)
286 {
287 if (amd64obsd_uthread_reg_offset[i] != -1
288 && (regnum == -1 || regnum == i))
289 {
290 /* Fetch stack pointer from thread structure (if we didn't
291 do so already). */
292 if (sp == 0)
e17a4113 293 sp = read_memory_unsigned_integer (sp_addr, 8, byte_order);
d78749b4
MK
294
295 /* Read the saved register from the stack frame. */
296 read_memory (sp + amd64obsd_uthread_reg_offset[i], buf, 8);
297 regcache_raw_supply (regcache, i, buf);
298 }
299 }
300}
301
302static void
303amd64obsd_collect_uthread (const struct regcache *regcache,
304 int regnum, CORE_ADDR addr)
305{
e17a4113
UW
306 struct gdbarch *gdbarch = get_regcache_arch (regcache);
307 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
d78749b4
MK
308 CORE_ADDR sp_addr = addr + AMD64OBSD_UTHREAD_RSP_OFFSET;
309 CORE_ADDR sp = 0;
310 gdb_byte buf[8];
311 int i;
312
313 gdb_assert (regnum >= -1);
314
315 if (regnum == -1 || regnum == AMD64_RSP_REGNUM)
316 {
317 int offset;
318
319 /* Calculate the stack pointer (frame pointer) that will be
320 stored into the thread structure. */
321 offset = amd64obsd_uthread_reg_offset[AMD64_RIP_REGNUM] + 8;
322 regcache_raw_collect (regcache, AMD64_RSP_REGNUM, buf);
e17a4113 323 sp = extract_unsigned_integer (buf, 8, byte_order) - offset;
d78749b4
MK
324
325 /* Store the stack pointer. */
e17a4113 326 write_memory_unsigned_integer (sp_addr, 8, byte_order, sp);
d78749b4
MK
327
328 /* The stack pointer was (potentially) modified. Make sure we
329 build a proper stack frame. */
330 regnum = -1;
331 }
332
333 for (i = 0; i < ARRAY_SIZE (amd64obsd_uthread_reg_offset); i++)
334 {
335 if (amd64obsd_uthread_reg_offset[i] != -1
336 && (regnum == -1 || regnum == i))
337 {
338 /* Fetch stack pointer from thread structure (if we didn't
339 calculate it already). */
340 if (sp == 0)
e17a4113 341 sp = read_memory_unsigned_integer (sp_addr, 8, byte_order);
d78749b4
MK
342
343 /* Write the register into the stack frame. */
344 regcache_raw_collect (regcache, i, buf);
345 write_memory (sp + amd64obsd_uthread_reg_offset[i], buf, 8);
346 }
347 }
348}
f6acec62
MK
349/* Kernel debugging support. */
350
351/* From <machine/frame.h>. Easy since `struct trapframe' matches
352 `struct sigcontext'. */
353#define amd64obsd_tf_reg_offset amd64obsd_sc_reg_offset
354
355static struct trad_frame_cache *
10458914 356amd64obsd_trapframe_cache (struct frame_info *this_frame, void **this_cache)
f6acec62 357{
e17a4113
UW
358 struct gdbarch *gdbarch = get_frame_arch (this_frame);
359 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
f6acec62
MK
360 struct trad_frame_cache *cache;
361 CORE_ADDR func, sp, addr;
362 ULONGEST cs;
2c02bd72 363 const char *name;
f6acec62
MK
364 int i;
365
366 if (*this_cache)
367 return *this_cache;
368
10458914 369 cache = trad_frame_cache_zalloc (this_frame);
f6acec62
MK
370 *this_cache = cache;
371
10458914
DJ
372 func = get_frame_func (this_frame);
373 sp = get_frame_register_unsigned (this_frame, AMD64_RSP_REGNUM);
f6acec62
MK
374
375 find_pc_partial_function (func, &name, NULL, NULL);
6d566cff 376 if (name && strncmp (name, "Xintr", 5) == 0)
f6acec62
MK
377 addr = sp + 8; /* It's an interrupt frame. */
378 else
379 addr = sp;
380
381 for (i = 0; i < ARRAY_SIZE (amd64obsd_tf_reg_offset); i++)
382 if (amd64obsd_tf_reg_offset[i] != -1)
383 trad_frame_set_reg_addr (cache, i, addr + amd64obsd_tf_reg_offset[i]);
384
385 /* Read %cs from trap frame. */
7238f002 386 addr += amd64obsd_tf_reg_offset[AMD64_CS_REGNUM];
e17a4113 387 cs = read_memory_unsigned_integer (addr, 8, byte_order);
f6acec62
MK
388 if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
389 {
6d566cff 390 /* Trap from user space; terminate backtrace. */
005ca36a 391 trad_frame_set_id (cache, outer_frame_id);
f6acec62
MK
392 }
393 else
394 {
395 /* Construct the frame ID using the function start. */
396 trad_frame_set_id (cache, frame_id_build (sp + 16, func));
397 }
398
399 return cache;
400}
401
402static void
10458914 403amd64obsd_trapframe_this_id (struct frame_info *this_frame,
f6acec62
MK
404 void **this_cache, struct frame_id *this_id)
405{
406 struct trad_frame_cache *cache =
10458914 407 amd64obsd_trapframe_cache (this_frame, this_cache);
f6acec62
MK
408
409 trad_frame_get_id (cache, this_id);
410}
411
10458914
DJ
412static struct value *
413amd64obsd_trapframe_prev_register (struct frame_info *this_frame,
414 void **this_cache, int regnum)
f6acec62
MK
415{
416 struct trad_frame_cache *cache =
10458914 417 amd64obsd_trapframe_cache (this_frame, this_cache);
f6acec62 418
10458914 419 return trad_frame_get_register (cache, this_frame, regnum);
f6acec62
MK
420}
421
422static int
423amd64obsd_trapframe_sniffer (const struct frame_unwind *self,
10458914 424 struct frame_info *this_frame,
f6acec62
MK
425 void **this_prologue_cache)
426{
427 ULONGEST cs;
2c02bd72 428 const char *name;
f6acec62 429
e5cc6d11 430 /* Check Current Privilege Level and bail out if we're not executing
6d566cff 431 in kernel space. */
10458914 432 cs = get_frame_register_unsigned (this_frame, AMD64_CS_REGNUM);
f6acec62
MK
433 if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
434 return 0;
435
10458914 436 find_pc_partial_function (get_frame_pc (this_frame), &name, NULL, NULL);
f6acec62
MK
437 return (name && ((strcmp (name, "calltrap") == 0)
438 || (strcmp (name, "osyscall1") == 0)
439 || (strcmp (name, "Xsyscall") == 0)
440 || (strncmp (name, "Xintr", 5) == 0)));
441}
442
443static const struct frame_unwind amd64obsd_trapframe_unwind = {
444 /* FIXME: kettenis/20051219: This really is more like an interrupt
445 frame, but SIGTRAMP_FRAME would print <signal handler called>,
446 which really is not what we want here. */
447 NORMAL_FRAME,
8fbca658 448 default_frame_unwind_stop_reason,
f6acec62
MK
449 amd64obsd_trapframe_this_id,
450 amd64obsd_trapframe_prev_register,
451 NULL,
452 amd64obsd_trapframe_sniffer
453};
454\f
d78749b4 455
e2879ccb
MK
456static void
457amd64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
458{
459 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
460
90f90721 461 amd64_init_abi (info, gdbarch);
e2879ccb 462
30b344b1
MK
463 /* Initialize general-purpose register set details. */
464 tdep->gregset_reg_offset = amd64obsd_r_reg_offset;
465 tdep->gregset_num_regs = ARRAY_SIZE (amd64obsd_r_reg_offset);
466 tdep->sizeof_gregset = 24 * 8;
467
e2879ccb
MK
468 tdep->jb_pc_offset = 7 * 8;
469
911bc6ee 470 tdep->sigtramp_p = amd64obsd_sigtramp_p;
e2879ccb
MK
471 tdep->sigcontext_addr = amd64obsd_sigcontext_addr;
472 tdep->sc_reg_offset = amd64obsd_sc_reg_offset;
473 tdep->sc_num_regs = ARRAY_SIZE (amd64obsd_sc_reg_offset);
7e654c37 474
d78749b4
MK
475 /* OpenBSD provides a user-level threads implementation. */
476 bsd_uthread_set_supply_uthread (gdbarch, amd64obsd_supply_uthread);
477 bsd_uthread_set_collect_uthread (gdbarch, amd64obsd_collect_uthread);
478
7e654c37
MK
479 /* OpenBSD uses SVR4-style shared libraries. */
480 set_solib_svr4_fetch_link_map_offsets
481 (gdbarch, svr4_lp64_fetch_link_map_offsets);
f6acec62
MK
482
483 /* Unwind kernel trap frames correctly. */
484 frame_unwind_prepend_unwinder (gdbarch, &amd64obsd_trapframe_unwind);
e2879ccb 485}
a3e3e961
MK
486
487/* Traditional (a.out) NetBSD-style core dumps. */
488
489static void
490amd64obsd_core_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
491{
492 amd64obsd_init_abi (info, gdbarch);
493
494 set_gdbarch_regset_from_core_section
495 (gdbarch, amd64obsd_regset_from_core_section);
496}
e2879ccb
MK
497\f
498
499/* Provide a prototype to silence -Wmissing-prototypes. */
500void _initialize_amd64obsd_tdep (void);
501
502void
30b344b1 503_initialize_amd64obsd_tdep (void)
e2879ccb
MK
504{
505 /* The OpenBSD/amd64 native dependent code makes this assumption. */
90f90721 506 gdb_assert (ARRAY_SIZE (amd64obsd_r_reg_offset) == AMD64_NUM_GREGS);
e2879ccb
MK
507
508 gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
509 GDB_OSABI_OPENBSD_ELF, amd64obsd_init_abi);
30b344b1
MK
510
511 /* OpenBSD uses traditional (a.out) NetBSD-style core dumps. */
512 gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
a3e3e961 513 GDB_OSABI_NETBSD_AOUT, amd64obsd_core_init_abi);
e2879ccb 514}