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