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