* defs.h (strlen_paddr, paddr, paddr_nz): Remove.
[deliverable/binutils-gdb.git] / gdb / amd64obsd-tdep.c
CommitLineData
e2879ccb
MK
1/* Target-dependent code for OpenBSD/amd64.
2
0fb0cc75
JB
3 Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009
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{
254 CORE_ADDR sp_addr = addr + AMD64OBSD_UTHREAD_RSP_OFFSET;
255 CORE_ADDR sp = 0;
256 gdb_byte buf[8];
257 int i;
258
259 gdb_assert (regnum >= -1);
260
261 if (regnum == -1 || regnum == AMD64_RSP_REGNUM)
262 {
263 int offset;
264
265 /* Fetch stack pointer from thread structure. */
266 sp = read_memory_unsigned_integer (sp_addr, 8);
267
268 /* Adjust the stack pointer such that it looks as if we just
269 returned from _thread_machdep_switch. */
270 offset = amd64obsd_uthread_reg_offset[AMD64_RIP_REGNUM] + 8;
271 store_unsigned_integer (buf, 8, sp + offset);
272 regcache_raw_supply (regcache, AMD64_RSP_REGNUM, buf);
273 }
274
275 for (i = 0; i < ARRAY_SIZE (amd64obsd_uthread_reg_offset); i++)
276 {
277 if (amd64obsd_uthread_reg_offset[i] != -1
278 && (regnum == -1 || regnum == i))
279 {
280 /* Fetch stack pointer from thread structure (if we didn't
281 do so already). */
282 if (sp == 0)
283 sp = read_memory_unsigned_integer (sp_addr, 8);
284
285 /* Read the saved register from the stack frame. */
286 read_memory (sp + amd64obsd_uthread_reg_offset[i], buf, 8);
287 regcache_raw_supply (regcache, i, buf);
288 }
289 }
290}
291
292static void
293amd64obsd_collect_uthread (const struct regcache *regcache,
294 int regnum, CORE_ADDR addr)
295{
296 CORE_ADDR sp_addr = addr + AMD64OBSD_UTHREAD_RSP_OFFSET;
297 CORE_ADDR sp = 0;
298 gdb_byte buf[8];
299 int i;
300
301 gdb_assert (regnum >= -1);
302
303 if (regnum == -1 || regnum == AMD64_RSP_REGNUM)
304 {
305 int offset;
306
307 /* Calculate the stack pointer (frame pointer) that will be
308 stored into the thread structure. */
309 offset = amd64obsd_uthread_reg_offset[AMD64_RIP_REGNUM] + 8;
310 regcache_raw_collect (regcache, AMD64_RSP_REGNUM, buf);
311 sp = extract_unsigned_integer (buf, 8) - offset;
312
313 /* Store the stack pointer. */
314 write_memory_unsigned_integer (sp_addr, 8, sp);
315
316 /* The stack pointer was (potentially) modified. Make sure we
317 build a proper stack frame. */
318 regnum = -1;
319 }
320
321 for (i = 0; i < ARRAY_SIZE (amd64obsd_uthread_reg_offset); i++)
322 {
323 if (amd64obsd_uthread_reg_offset[i] != -1
324 && (regnum == -1 || regnum == i))
325 {
326 /* Fetch stack pointer from thread structure (if we didn't
327 calculate it already). */
328 if (sp == 0)
329 sp = read_memory_unsigned_integer (sp_addr, 8);
330
331 /* Write the register into the stack frame. */
332 regcache_raw_collect (regcache, i, buf);
333 write_memory (sp + amd64obsd_uthread_reg_offset[i], buf, 8);
334 }
335 }
336}
f6acec62
MK
337/* Kernel debugging support. */
338
339/* From <machine/frame.h>. Easy since `struct trapframe' matches
340 `struct sigcontext'. */
341#define amd64obsd_tf_reg_offset amd64obsd_sc_reg_offset
342
343static struct trad_frame_cache *
10458914 344amd64obsd_trapframe_cache (struct frame_info *this_frame, void **this_cache)
f6acec62
MK
345{
346 struct trad_frame_cache *cache;
347 CORE_ADDR func, sp, addr;
348 ULONGEST cs;
349 char *name;
350 int i;
351
352 if (*this_cache)
353 return *this_cache;
354
10458914 355 cache = trad_frame_cache_zalloc (this_frame);
f6acec62
MK
356 *this_cache = cache;
357
10458914
DJ
358 func = get_frame_func (this_frame);
359 sp = get_frame_register_unsigned (this_frame, AMD64_RSP_REGNUM);
f6acec62
MK
360
361 find_pc_partial_function (func, &name, NULL, NULL);
6d566cff 362 if (name && strncmp (name, "Xintr", 5) == 0)
f6acec62
MK
363 addr = sp + 8; /* It's an interrupt frame. */
364 else
365 addr = sp;
366
367 for (i = 0; i < ARRAY_SIZE (amd64obsd_tf_reg_offset); i++)
368 if (amd64obsd_tf_reg_offset[i] != -1)
369 trad_frame_set_reg_addr (cache, i, addr + amd64obsd_tf_reg_offset[i]);
370
371 /* Read %cs from trap frame. */
7238f002 372 addr += amd64obsd_tf_reg_offset[AMD64_CS_REGNUM];
f6acec62
MK
373 cs = read_memory_unsigned_integer (addr, 8);
374 if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
375 {
6d566cff 376 /* Trap from user space; terminate backtrace. */
f6acec62
MK
377 trad_frame_set_id (cache, null_frame_id);
378 }
379 else
380 {
381 /* Construct the frame ID using the function start. */
382 trad_frame_set_id (cache, frame_id_build (sp + 16, func));
383 }
384
385 return cache;
386}
387
388static void
10458914 389amd64obsd_trapframe_this_id (struct frame_info *this_frame,
f6acec62
MK
390 void **this_cache, struct frame_id *this_id)
391{
392 struct trad_frame_cache *cache =
10458914 393 amd64obsd_trapframe_cache (this_frame, this_cache);
f6acec62
MK
394
395 trad_frame_get_id (cache, this_id);
396}
397
10458914
DJ
398static struct value *
399amd64obsd_trapframe_prev_register (struct frame_info *this_frame,
400 void **this_cache, int regnum)
f6acec62
MK
401{
402 struct trad_frame_cache *cache =
10458914 403 amd64obsd_trapframe_cache (this_frame, this_cache);
f6acec62 404
10458914 405 return trad_frame_get_register (cache, this_frame, regnum);
f6acec62
MK
406}
407
408static int
409amd64obsd_trapframe_sniffer (const struct frame_unwind *self,
10458914 410 struct frame_info *this_frame,
f6acec62
MK
411 void **this_prologue_cache)
412{
413 ULONGEST cs;
414 char *name;
415
e5cc6d11 416 /* Check Current Privilege Level and bail out if we're not executing
6d566cff 417 in kernel space. */
10458914 418 cs = get_frame_register_unsigned (this_frame, AMD64_CS_REGNUM);
f6acec62
MK
419 if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
420 return 0;
421
10458914 422 find_pc_partial_function (get_frame_pc (this_frame), &name, NULL, NULL);
f6acec62
MK
423 return (name && ((strcmp (name, "calltrap") == 0)
424 || (strcmp (name, "osyscall1") == 0)
425 || (strcmp (name, "Xsyscall") == 0)
426 || (strncmp (name, "Xintr", 5) == 0)));
427}
428
429static const struct frame_unwind amd64obsd_trapframe_unwind = {
430 /* FIXME: kettenis/20051219: This really is more like an interrupt
431 frame, but SIGTRAMP_FRAME would print <signal handler called>,
432 which really is not what we want here. */
433 NORMAL_FRAME,
434 amd64obsd_trapframe_this_id,
435 amd64obsd_trapframe_prev_register,
436 NULL,
437 amd64obsd_trapframe_sniffer
438};
439\f
d78749b4 440
e2879ccb
MK
441static void
442amd64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
443{
444 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
445
90f90721 446 amd64_init_abi (info, gdbarch);
e2879ccb 447
30b344b1
MK
448 /* Initialize general-purpose register set details. */
449 tdep->gregset_reg_offset = amd64obsd_r_reg_offset;
450 tdep->gregset_num_regs = ARRAY_SIZE (amd64obsd_r_reg_offset);
451 tdep->sizeof_gregset = 24 * 8;
452
453 set_gdbarch_regset_from_core_section (gdbarch,
454 amd64obsd_regset_from_core_section);
455
e2879ccb
MK
456 tdep->jb_pc_offset = 7 * 8;
457
911bc6ee 458 tdep->sigtramp_p = amd64obsd_sigtramp_p;
e2879ccb
MK
459 tdep->sigcontext_addr = amd64obsd_sigcontext_addr;
460 tdep->sc_reg_offset = amd64obsd_sc_reg_offset;
461 tdep->sc_num_regs = ARRAY_SIZE (amd64obsd_sc_reg_offset);
7e654c37 462
d78749b4
MK
463 /* OpenBSD provides a user-level threads implementation. */
464 bsd_uthread_set_supply_uthread (gdbarch, amd64obsd_supply_uthread);
465 bsd_uthread_set_collect_uthread (gdbarch, amd64obsd_collect_uthread);
466
7e654c37
MK
467 /* OpenBSD uses SVR4-style shared libraries. */
468 set_solib_svr4_fetch_link_map_offsets
469 (gdbarch, svr4_lp64_fetch_link_map_offsets);
f6acec62
MK
470
471 /* Unwind kernel trap frames correctly. */
472 frame_unwind_prepend_unwinder (gdbarch, &amd64obsd_trapframe_unwind);
e2879ccb
MK
473}
474\f
475
476/* Provide a prototype to silence -Wmissing-prototypes. */
477void _initialize_amd64obsd_tdep (void);
478
479void
30b344b1 480_initialize_amd64obsd_tdep (void)
e2879ccb
MK
481{
482 /* The OpenBSD/amd64 native dependent code makes this assumption. */
90f90721 483 gdb_assert (ARRAY_SIZE (amd64obsd_r_reg_offset) == AMD64_NUM_GREGS);
e2879ccb
MK
484
485 gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
486 GDB_OSABI_OPENBSD_ELF, amd64obsd_init_abi);
30b344b1
MK
487
488 /* OpenBSD uses traditional (a.out) NetBSD-style core dumps. */
489 gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
490 GDB_OSABI_NETBSD_AOUT, amd64obsd_init_abi);
e2879ccb 491}
This page took 0.358916 seconds and 4 git commands to generate.