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