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