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