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