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