gdb - Local mods (compile)
[dragonfly.git] / contrib / gdb-7 / gdb / i386fbsd-tdep.c
1 /* Target-dependent code for FreeBSD/i386.
2
3    Copyright (C) 2003-2015 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 "arch-utils.h"
22 #include "gdbcore.h"
23 #include "osabi.h"
24 #include "regcache.h"
25 #include "regset.h"
26 #include "i386fbsd-tdep.h"
27 #include "x86-xstate.h"
28
29 #include "i386-tdep.h"
30 #include "i387-tdep.h"
31 #include "bsd-uthread.h"
32 #include "fbsd-tdep.h"
33 #include "solib-svr4.h"
34
35 /* Support for signal handlers.  */
36
37 /* Return whether THIS_FRAME corresponds to a FreeBSD sigtramp
38    routine.  */
39
40 /* FreeBSD/i386 supports three different signal trampolines, one for
41    versions before 4.0, a second for 4.x, and a third for 5.0 and
42    later.  To complicate matters, FreeBSD/i386 binaries running under
43    an amd64 kernel use a different set of trampolines.  These
44    trampolines differ from the i386 kernel trampolines in that they
45    omit a middle section that conditionally restores %gs.  */
46
47 static const gdb_byte i386fbsd_sigtramp_start[] =
48 {
49   0x8d, 0x44, 0x24, 0x20,       /* lea     SIGF_UC(%esp),%eax */
50   0x50                          /* pushl   %eax */
51 };
52
53 static const gdb_byte i386fbsd_sigtramp_middle[] =
54 {
55   0xf7, 0x40, 0x54, 0x00, 0x00, 0x02, 0x00,
56                                 /* testl   $PSL_VM,UC_EFLAGS(%eax) */
57   0x75, 0x03,                   /* jne     +3 */
58   0x8e, 0x68, 0x14              /* mov     UC_GS(%eax),%gs */
59 };
60
61 static const gdb_byte i386fbsd_sigtramp_end[] =
62 {
63   0xb8, 0xa1, 0x01, 0x00, 0x00, /* movl   $SYS_sigreturn,%eax */
64   0x50,                 /* pushl   %eax */
65   0xcd, 0x80                    /* int     $0x80 */
66 };
67
68 static const gdb_byte i386fbsd_freebsd4_sigtramp_start[] =
69 {
70   0x8d, 0x44, 0x24, 0x14,       /* lea     SIGF_UC4(%esp),%eax */
71   0x50                          /* pushl   %eax */
72 };
73
74 static const gdb_byte i386fbsd_freebsd4_sigtramp_middle[] =
75 {
76   0xf7, 0x40, 0x54, 0x00, 0x00, 0x02, 0x00,
77                                 /* testl   $PSL_VM,UC4_EFLAGS(%eax) */
78   0x75, 0x03,                   /* jne     +3 */
79   0x8e, 0x68, 0x14              /* mov     UC4_GS(%eax),%gs */
80 };
81
82 static const gdb_byte i386fbsd_freebsd4_sigtramp_end[] =
83 {
84   0xb8, 0x58, 0x01, 0x00, 0x00, /* movl    $344,%eax */
85   0x50,                 /* pushl   %eax */
86   0xcd, 0x80                    /* int     $0x80 */
87 };
88
89 static const gdb_byte i386fbsd_osigtramp_start[] =
90 {
91   0x8d, 0x44, 0x24, 0x14,       /* lea     SIGF_SC(%esp),%eax */
92   0x50                          /* pushl   %eax */
93 };
94
95 static const gdb_byte i386fbsd_osigtramp_middle[] =
96 {
97   0xf7, 0x40, 0x18, 0x00, 0x00, 0x02, 0x00,
98                                 /* testl   $PSL_VM,SC_PS(%eax) */
99   0x75, 0x03,                   /* jne     +3 */
100   0x8e, 0x68, 0x44              /* mov     SC_GS(%eax),%gs */
101 };
102
103 static const gdb_byte i386fbsd_osigtramp_end[] =
104 {
105   0xb8, 0x67, 0x00, 0x00, 0x00, /* movl    $103,%eax */
106   0x50,                 /* pushl   %eax */
107   0xcd, 0x80                    /* int     $0x80 */
108 };
109
110 /* The three different trampolines are all the same size.  */
111 gdb_static_assert (sizeof i386fbsd_sigtramp_start
112                    == sizeof i386fbsd_freebsd4_sigtramp_start);
113 gdb_static_assert (sizeof i386fbsd_sigtramp_start
114                    == sizeof i386fbsd_osigtramp_start);
115 gdb_static_assert (sizeof i386fbsd_sigtramp_middle
116                    == sizeof i386fbsd_freebsd4_sigtramp_middle);
117 gdb_static_assert (sizeof i386fbsd_sigtramp_middle
118                    == sizeof i386fbsd_osigtramp_middle);
119 gdb_static_assert (sizeof i386fbsd_sigtramp_end
120                    == sizeof i386fbsd_freebsd4_sigtramp_end);
121 gdb_static_assert (sizeof i386fbsd_sigtramp_end
122                    == sizeof i386fbsd_osigtramp_end);
123
124 /* We assume that the middle is the largest chunk below.  */
125 gdb_static_assert (sizeof i386fbsd_sigtramp_middle
126                    > sizeof i386fbsd_sigtramp_start);
127 gdb_static_assert (sizeof i386fbsd_sigtramp_middle
128                    > sizeof i386fbsd_sigtramp_end);
129
130 static int
131 i386fbsd_sigtramp_p (struct frame_info *this_frame)
132 {
133   CORE_ADDR pc = get_frame_pc (this_frame);
134   gdb_byte buf[sizeof i386fbsd_sigtramp_middle];
135   const gdb_byte *middle, *end;
136
137   /* Look for a matching start.  */
138   if (!safe_frame_unwind_memory (this_frame, pc, buf,
139                                  sizeof i386fbsd_sigtramp_start))
140     return 0;
141   if (memcmp (buf, i386fbsd_sigtramp_start, sizeof i386fbsd_sigtramp_start)
142       == 0)
143     {
144       middle = i386fbsd_sigtramp_middle;
145       end = i386fbsd_sigtramp_end;
146     }
147   else if (memcmp (buf, i386fbsd_freebsd4_sigtramp_start,
148                    sizeof i386fbsd_freebsd4_sigtramp_start) == 0)
149     {
150       middle = i386fbsd_freebsd4_sigtramp_middle;
151       end = i386fbsd_freebsd4_sigtramp_end;
152     }
153   else if (memcmp (buf, i386fbsd_osigtramp_start,
154                    sizeof i386fbsd_osigtramp_start) == 0)
155     {
156       middle = i386fbsd_osigtramp_middle;
157       end = i386fbsd_osigtramp_end;
158     }
159   else
160     return 0;
161
162   /* Since the end is shorter than the middle, check for a matching end
163      next.  */
164   pc += sizeof i386fbsd_sigtramp_start;
165   if (!safe_frame_unwind_memory (this_frame, pc, buf,
166                                  sizeof i386fbsd_sigtramp_end))
167     return 0;
168   if (memcmp (buf, end, sizeof i386fbsd_sigtramp_end) == 0)
169     return 1;
170
171   /* If the end didn't match, check for a matching middle.  */
172   if (!safe_frame_unwind_memory (this_frame, pc, buf,
173                                  sizeof i386fbsd_sigtramp_middle))
174     return 0;
175   if (memcmp (buf, middle, sizeof i386fbsd_sigtramp_middle) != 0)
176     return 0;
177
178   /* The middle matched, check for a matching end.  */
179   pc += sizeof i386fbsd_sigtramp_middle;
180   if (!safe_frame_unwind_memory (this_frame, pc, buf,
181                                  sizeof i386fbsd_sigtramp_end))
182     return 0;
183   if (memcmp (buf, end, sizeof i386fbsd_sigtramp_end) != 0)
184     return 0;
185
186   return 1;
187 }
188
189 /* FreeBSD 3.0-RELEASE or later.  */
190
191 /* From <machine/reg.h>.  */
192 static int i386fbsd_r_reg_offset[] =
193 {
194   9 * 4, 8 * 4, 7 * 4, 6 * 4,   /* %eax, %ecx, %edx, %ebx */
195   15 * 4, 4 * 4,                /* %esp, %ebp */
196   3 * 4, 2 * 4,                 /* %esi, %edi */
197   12 * 4, 14 * 4,               /* %eip, %eflags */
198   13 * 4, 16 * 4,               /* %cs, %ss */
199   1 * 4, 0 * 4, -1, -1          /* %ds, %es, %fs, %gs */
200 };
201
202 /* Sigtramp routine location.  */
203 CORE_ADDR i386fbsd_sigtramp_start_addr;
204 CORE_ADDR i386fbsd_sigtramp_end_addr;
205
206 /* From <machine/signal.h>.  */
207 int i386fbsd_sc_reg_offset[] =
208 {
209   8 + 14 * 4,                   /* %eax */
210   8 + 13 * 4,                   /* %ecx */
211   8 + 12 * 4,                   /* %edx */
212   8 + 11 * 4,                   /* %ebx */
213   8 + 0 * 4,                    /* %esp */
214   8 + 1 * 4,                    /* %ebp */
215   8 + 10 * 4,                   /* %esi */
216   8 + 9 * 4,                    /* %edi */
217   8 + 3 * 4,                    /* %eip */
218   8 + 4 * 4,                    /* %eflags */
219   8 + 7 * 4,                    /* %cs */
220   8 + 8 * 4,                    /* %ss */
221   8 + 6 * 4,                    /* %ds */
222   8 + 5 * 4,                    /* %es */
223   8 + 15 * 4,                   /* %fs */
224   8 + 16 * 4                    /* %gs */
225 };
226
227 /* From /usr/src/lib/libc/i386/gen/_setjmp.S.  */
228 static int i386fbsd_jmp_buf_reg_offset[] =
229 {
230   -1,                           /* %eax */
231   -1,                           /* %ecx */
232   -1,                           /* %edx */
233   1 * 4,                        /* %ebx */
234   2 * 4,                        /* %esp */
235   3 * 4,                        /* %ebp */
236   4 * 4,                        /* %esi */
237   5 * 4,                        /* %edi */
238   0 * 4                         /* %eip */
239 };
240
241 /* Get XSAVE extended state xcr0 from core dump.  */
242
243 uint64_t
244 i386fbsd_core_read_xcr0 (bfd *abfd)
245 {
246   asection *xstate = bfd_get_section_by_name (abfd, ".reg-xstate");
247   uint64_t xcr0;
248
249   if (xstate)
250     {
251       size_t size = bfd_section_size (abfd, xstate);
252
253       /* Check extended state size.  */
254       if (size < X86_XSTATE_AVX_SIZE)
255         xcr0 = X86_XSTATE_SSE_MASK;
256       else
257         {
258           char contents[8];
259
260           if (! bfd_get_section_contents (abfd, xstate, contents,
261                                           I386_FBSD_XSAVE_XCR0_OFFSET,
262                                           8))
263             {
264               warning (_("Couldn't read `xcr0' bytes from "
265                          "`.reg-xstate' section in core file."));
266               return 0;
267             }
268
269           xcr0 = bfd_get_64 (abfd, contents);
270         }
271     }
272   else
273     xcr0 = 0;
274
275   return xcr0;
276 }
277
278 /* Implement the core_read_description gdbarch method.  */
279
280 static const struct target_desc *
281 i386fbsd_core_read_description (struct gdbarch *gdbarch,
282                                 struct target_ops *target,
283                                 bfd *abfd)
284 {
285   return i386_target_description (i386fbsd_core_read_xcr0 (abfd));
286 }
287
288 /* Similar to i386_supply_fpregset, but use XSAVE extended state.  */
289
290 static void
291 i386fbsd_supply_xstateregset (const struct regset *regset,
292                               struct regcache *regcache, int regnum,
293                               const void *xstateregs, size_t len)
294 {
295   i387_supply_xsave (regcache, regnum, xstateregs);
296 }
297
298 /* Similar to i386_collect_fpregset, but use XSAVE extended state.  */
299
300 static void
301 i386fbsd_collect_xstateregset (const struct regset *regset,
302                                const struct regcache *regcache,
303                                int regnum, void *xstateregs, size_t len)
304 {
305   i387_collect_xsave (regcache, regnum, xstateregs, 1);
306 }
307
308 /* Register set definitions.  */
309
310 static const struct regset i386fbsd_xstateregset =
311   {
312     NULL,
313     i386fbsd_supply_xstateregset,
314     i386fbsd_collect_xstateregset
315   };
316
317 /* Iterate over core file register note sections.  */
318
319 static void
320 i386fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
321                                        iterate_over_regset_sections_cb *cb,
322                                        void *cb_data,
323                                        const struct regcache *regcache)
324 {
325   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
326
327   cb (".reg", tdep->sizeof_gregset, &i386_gregset, NULL, cb_data);
328   cb (".reg2", tdep->sizeof_fpregset, &i386_fpregset, NULL, cb_data);
329
330   if (tdep->xcr0 & X86_XSTATE_AVX)
331     cb (".reg-xstate", X86_XSTATE_SIZE(tdep->xcr0),
332         &i386fbsd_xstateregset, "XSAVE extended state", cb_data);
333 }
334
335 static void
336 i386fbsd_supply_uthread (struct regcache *regcache,
337                          int regnum, CORE_ADDR addr)
338 {
339   gdb_byte buf[4];
340   int i;
341
342   gdb_assert (regnum >= -1);
343
344   for (i = 0; i < ARRAY_SIZE (i386fbsd_jmp_buf_reg_offset); i++)
345     {
346       if (i386fbsd_jmp_buf_reg_offset[i] != -1
347           && (regnum == -1 || regnum == i))
348         {
349           read_memory (addr + i386fbsd_jmp_buf_reg_offset[i], buf, 4);
350           regcache_raw_supply (regcache, i, buf);
351         }
352     }
353 }
354
355 static void
356 i386fbsd_collect_uthread (const struct regcache *regcache,
357                           int regnum, CORE_ADDR addr)
358 {
359   gdb_byte buf[4];
360   int i;
361
362   gdb_assert (regnum >= -1);
363
364   for (i = 0; i < ARRAY_SIZE (i386fbsd_jmp_buf_reg_offset); i++)
365     {
366       if (i386fbsd_jmp_buf_reg_offset[i] != -1
367           && (regnum == -1 || regnum == i))
368         {
369           regcache_raw_collect (regcache, i, buf);
370           write_memory (addr + i386fbsd_jmp_buf_reg_offset[i], buf, 4);
371         }
372     }
373 }
374
375 static void
376 i386fbsdaout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
377 {
378   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
379
380   /* Obviously FreeBSD is BSD-based.  */
381   i386bsd_init_abi (info, gdbarch);
382
383   /* FreeBSD has a different `struct reg', and reserves some space for
384      its FPU emulator in `struct fpreg'.  */
385   tdep->gregset_reg_offset = i386fbsd_r_reg_offset;
386   tdep->gregset_num_regs = ARRAY_SIZE (i386fbsd_r_reg_offset);
387   tdep->sizeof_gregset = 18 * 4;
388   tdep->sizeof_fpregset = 176;
389
390   /* FreeBSD uses -freg-struct-return by default.  */
391   tdep->struct_return = reg_struct_return;
392
393   tdep->sigtramp_p = i386fbsd_sigtramp_p;
394
395   /* FreeBSD uses a different memory layout.  */
396   tdep->sigtramp_start = i386fbsd_sigtramp_start_addr;
397   tdep->sigtramp_end = i386fbsd_sigtramp_end_addr;
398
399   /* FreeBSD has a more complete `struct sigcontext'.  */
400   tdep->sc_reg_offset = i386fbsd_sc_reg_offset;
401   tdep->sc_num_regs = ARRAY_SIZE (i386fbsd_sc_reg_offset);
402
403   /* FreeBSD provides a user-level threads implementation.  */
404   bsd_uthread_set_supply_uthread (gdbarch, i386fbsd_supply_uthread);
405   bsd_uthread_set_collect_uthread (gdbarch, i386fbsd_collect_uthread);
406 }
407
408 static void
409 i386fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
410 {
411   /* It's almost identical to FreeBSD a.out.  */
412   i386fbsdaout_init_abi (info, gdbarch);
413
414   /* Except that it uses ELF.  */
415   i386_elf_init_abi (info, gdbarch);
416
417   /* FreeBSD ELF uses SVR4-style shared libraries.  */
418   set_solib_svr4_fetch_link_map_offsets
419     (gdbarch, svr4_ilp32_fetch_link_map_offsets);
420 }
421
422 /* FreeBSD 4.0-RELEASE or later.  */
423
424 /* From <machine/reg.h>.  */
425 static int i386fbsd4_r_reg_offset[] =
426 {
427   10 * 4, 9 * 4, 8 * 4, 7 * 4,  /* %eax, %ecx, %edx, %ebx */
428   16 * 4, 5 * 4,                /* %esp, %ebp */
429   4 * 4, 3 * 4,                 /* %esi, %edi */
430   13 * 4, 15 * 4,               /* %eip, %eflags */
431   14 * 4, 17 * 4,               /* %cs, %ss */
432   2 * 4, 1 * 4, 0 * 4, 18 * 4   /* %ds, %es, %fs, %gs */
433 };
434
435 /* From <machine/signal.h>.  */
436 int i386fbsd4_sc_reg_offset[] =
437 {
438   20 + 11 * 4,                  /* %eax */
439   20 + 10 * 4,                  /* %ecx */
440   20 + 9 * 4,                   /* %edx */
441   20 + 8 * 4,                   /* %ebx */
442   20 + 17 * 4,                  /* %esp */
443   20 + 6 * 4,                   /* %ebp */
444   20 + 5 * 4,                   /* %esi */
445   20 + 4 * 4,                   /* %edi */
446   20 + 14 * 4,                  /* %eip */
447   20 + 16 * 4,                  /* %eflags */
448   20 + 15 * 4,                  /* %cs */
449   20 + 18 * 4,                  /* %ss */
450   20 + 3 * 4,                   /* %ds */
451   20 + 2 * 4,                   /* %es */
452   20 + 1 * 4,                   /* %fs */
453   20 + 0 * 4                    /* %gs */
454 };
455
456 void
457 i386fbsd4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
458 {
459   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
460
461   /* Generic FreeBSD support. */
462   fbsd_init_abi (info, gdbarch);
463
464   /* Inherit stuff from older releases.  We assume that FreeBSD
465      4.0-RELEASE always uses ELF.  */
466   i386fbsd_init_abi (info, gdbarch);
467
468   /* FreeBSD 4.0 introduced a new `struct reg'.  */
469   tdep->gregset_reg_offset = i386fbsd4_r_reg_offset;
470   tdep->gregset_num_regs = ARRAY_SIZE (i386fbsd4_r_reg_offset);
471   tdep->sizeof_gregset = 19 * 4;
472
473   /* FreeBSD 4.0 introduced a new `struct sigcontext'.  */
474   tdep->sc_reg_offset = i386fbsd4_sc_reg_offset;
475   tdep->sc_num_regs = ARRAY_SIZE (i386fbsd4_sc_reg_offset);
476
477   tdep->xsave_xcr0_offset = I386_FBSD_XSAVE_XCR0_OFFSET;
478
479   /* Iterate over core file register note sections.  */
480   set_gdbarch_iterate_over_regset_sections
481     (gdbarch, i386fbsd_iterate_over_regset_sections);
482
483   set_gdbarch_core_read_description (gdbarch,
484                                      i386fbsd_core_read_description);
485 }
486
487 \f
488 /* Provide a prototype to silence -Wmissing-prototypes.  */
489 void _initialize_i386fbsd_tdep (void);
490
491 void
492 _initialize_i386fbsd_tdep (void)
493 {
494   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_FREEBSD_AOUT,
495                           i386fbsdaout_init_abi);
496   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_FREEBSD_ELF,
497                           i386fbsd4_init_abi);
498 }