GDB (xrefs)
/tmp/gdb-7.10/gdb/i386fbsd-tdep.c
Go to the documentation of this file.
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 
48 {
49  0x8d, 0x44, 0x24, 0x20, /* lea SIGF_UC(%esp),%eax */
50  0x50 /* pushl %eax */
51 };
52 
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 
62 {
63  0xb8, 0xa1, 0x01, 0x00, 0x00, /* movl $SYS_sigreturn,%eax */
64  0x50, /* pushl %eax */
65  0xcd, 0x80 /* int $0x80 */
66 };
67 
69 {
70  0x8d, 0x44, 0x24, 0x14, /* lea SIGF_UC4(%esp),%eax */
71  0x50 /* pushl %eax */
72 };
73 
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 
83 {
84  0xb8, 0x58, 0x01, 0x00, 0x00, /* movl $344,%eax */
85  0x50, /* pushl %eax */
86  0xcd, 0x80 /* int $0x80 */
87 };
88 
90 {
91  0x8d, 0x44, 0x24, 0x14, /* lea SIGF_SC(%esp),%eax */
92  0x50 /* pushl %eax */
93 };
94 
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 
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. */
114  == sizeof i386fbsd_osigtramp_start);
118  == sizeof i386fbsd_osigtramp_middle);
122  == sizeof i386fbsd_osigtramp_end);
123 
124 /* We assume that the middle is the largest chunk below. */
126  > sizeof i386fbsd_sigtramp_start);
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);
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,
149  {
152  }
153  else if (memcmp (buf, i386fbsd_osigtramp_start,
154  sizeof i386fbsd_osigtramp_start) == 0)
155  {
156  middle = i386fbsd_osigtramp_middle;
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. */
205 
206 /* From <machine/signal.h>. */
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. */
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
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,
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 *
282  struct target_ops *target,
283  bfd *abfd)
284 {
286 }
287 
288 /* Similar to i386_supply_fpregset, but use XSAVE extended state. */
289 
290 static void
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
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,
315  };
316 
317 /* Iterate over core file register note sections. */
318 
319 static void
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
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
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
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'. */
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. */
392 
394 
395  /* FreeBSD uses a different memory layout. */
398 
399  /* FreeBSD has a more complete `struct sigcontext'. */
401  tdep->sc_num_regs = ARRAY_SIZE (i386fbsd_sc_reg_offset);
402 
403  /* FreeBSD provides a user-level threads implementation. */
406 }
407 
408 static void
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. */
420 }
421 
422 /* FreeBSD 4.0-RELEASE or later. */
423 
424 /* From <machine/reg.h>. */
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>. */
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 static void
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'. */
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'. */
475  tdep->sc_num_regs = ARRAY_SIZE (i386fbsd4_sc_reg_offset);
476 
478 
479  /* Iterate over core file register note sections. */
482 
485 }
486 
487 
488 /* Provide a prototype to silence -Wmissing-prototypes. */
489 void _initialize_i386fbsd_tdep (void);
490 
491 void
493 {
498 }
int i386fbsd_sc_reg_offset[]
static int i386fbsd_jmp_buf_reg_offset[]
int xsave_xcr0_offset
Definition: i386-tdep.h:142
static void i386fbsd4_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch)
CORE_ADDR get_frame_pc(struct frame_info *frame)
Definition: frame.c:2217
CORE_ADDR i386fbsd_sigtramp_end_addr
void i386bsd_init_abi(struct gdbarch_info, struct gdbarch *)
Definition: i386bsd-tdep.c:75
#define X86_XSTATE_SSE_MASK
Definition: x86-xstate.h:40
bfd_vma CORE_ADDR
Definition: common-types.h:41
int sc_num_regs
Definition: i386-tdep.h:216
CORE_ADDR sigtramp_start
Definition: i386-tdep.h:205
void warning(const char *fmt,...)
Definition: errors.c:26
static const gdb_byte i386fbsd_freebsd4_sigtramp_middle[]
Definition: i386fbsd-tdep.c:74
static void i386fbsdaout_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch)
void _initialize_i386fbsd_tdep(void)
const struct regset i386_fpregset
Definition: i386-tdep.c:3824
CORE_ADDR sigtramp_end
Definition: i386-tdep.h:206
static const gdb_byte i386fbsd_freebsd4_sigtramp_end[]
Definition: i386fbsd-tdep.c:82
struct m32c_reg * pc
Definition: m32c-tdep.c:111
static void i386fbsd_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch)
static void i386fbsd_collect_xstateregset(const struct regset *regset, const struct regcache *regcache, int regnum, void *xstateregs, size_t len)
struct link_map_offsets * svr4_ilp32_fetch_link_map_offsets(void)
Definition: solib-svr4.c:3149
static const gdb_byte i386fbsd_sigtramp_start[]
Definition: i386fbsd-tdep.c:47
static void i386fbsd_supply_xstateregset(const struct regset *regset, struct regcache *regcache, int regnum, const void *xstateregs, size_t len)
void bsd_uthread_set_collect_uthread(struct gdbarch *gdbarch, void(*collect_uthread)(const struct regcache *, int, CORE_ADDR))
Definition: bsd-uthread.c:79
uint64_t i386fbsd_core_read_xcr0(bfd *abfd)
#define _(String)
Definition: gdb_locale.h:40
size_t sizeof_fpregset
Definition: i386-tdep.h:64
int i386fbsd4_sc_reg_offset[]
struct gdbarch_tdep * gdbarch_tdep(struct gdbarch *gdbarch)
Definition: gdbarch.c:1402
#define X86_XSTATE_SIZE(XCR0)
Definition: x86-xstate.h:62
Definition: regset.h:34
static int i386fbsd_sigtramp_p(struct frame_info *this_frame)
static const struct target_desc * i386fbsd_core_read_description(struct gdbarch *gdbarch, struct target_ops *target, bfd *abfd)
static const gdb_byte i386fbsd_osigtramp_start[]
Definition: i386fbsd-tdep.c:89
enum struct_return struct_return
Definition: arm-tdep.h:197
static const gdb_byte i386fbsd_osigtramp_end[]
int safe_frame_unwind_memory(struct frame_info *this_frame, CORE_ADDR addr, gdb_byte *buf, int len)
Definition: frame.c:2525
CORE_ADDR i386fbsd_sigtramp_start_addr
void set_solib_svr4_fetch_link_map_offsets(struct gdbarch *gdbarch, struct link_map_offsets *(*flmo)(void))
Definition: solib-svr4.c:3108
void fbsd_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch)
Definition: fbsd-tdep.c:132
static void i386fbsd_collect_uthread(const struct regcache *regcache, int regnum, CORE_ADDR addr)
static int i386fbsd4_r_reg_offset[]
#define gdb_assert(expr)
Definition: gdb_assert.h:33
const struct regset i386_gregset
Definition: i386-tdep.c:3819
static const gdb_byte i386fbsd_freebsd4_sigtramp_start[]
Definition: i386fbsd-tdep.c:68
int regnum
Definition: aarch64-tdep.c:69
void read_memory(CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len)
Definition: corefile.c:244
void( iterate_over_regset_sections_cb)(const char *sect_name, int size, const struct regset *regset, const char *human_name, void *cb_data)
Definition: gdbarch.h:98
void i387_collect_xsave(const struct regcache *regcache, int regnum, void *xsave, int gcore)
Definition: i387-tdep.c:1267
int * gregset_reg_offset
Definition: i386-tdep.h:59
gdb_static_assert(sizeof i386fbsd_sigtramp_start==sizeof i386fbsd_freebsd4_sigtramp_start)
bfd_byte gdb_byte
Definition: common-types.h:38
static void i386fbsd_iterate_over_regset_sections(struct gdbarch *gdbarch, iterate_over_regset_sections_cb *cb, void *cb_data, const struct regcache *regcache)
int(* sigtramp_p)(struct frame_info *)
Definition: i386-tdep.h:209
uint64_t xcr0
Definition: i386-tdep.h:139
#define X86_XSTATE_AVX_SIZE
Definition: x86-xstate.h:49
static void i386fbsd_supply_uthread(struct regcache *regcache, int regnum, CORE_ADDR addr)
void i386_elf_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch)
Definition: i386-tdep.c:4332
size_t sizeof_gregset
Definition: i386-tdep.h:61
static const gdb_byte i386fbsd_sigtramp_end[]
Definition: i386fbsd-tdep.c:61
#define I386_FBSD_XSAVE_XCR0_OFFSET
Definition: i386fbsd-tdep.h:29
void regcache_raw_supply(struct regcache *regcache, int regnum, const void *buf)
Definition: regcache.c:1041
int * sc_reg_offset
Definition: i386-tdep.h:215
void regcache_raw_collect(const struct regcache *regcache, int regnum, void *buf)
Definition: regcache.c:1071
static int i386fbsd_r_reg_offset[]
static const gdb_byte i386fbsd_osigtramp_middle[]
Definition: i386fbsd-tdep.c:95
void set_gdbarch_iterate_over_regset_sections(struct gdbarch *gdbarch, gdbarch_iterate_over_regset_sections_ftype iterate_over_regset_sections)
Definition: gdbarch.c:3398
void write_memory(CORE_ADDR memaddr, const bfd_byte *myaddr, ssize_t len)
Definition: corefile.c:389
void i387_supply_xsave(struct regcache *regcache, int regnum, const void *xsave)
Definition: i387-tdep.c:894
void bsd_uthread_set_supply_uthread(struct gdbarch *gdbarch, void(*supply_uthread)(struct regcache *, int, CORE_ADDR))
Definition: bsd-uthread.c:67
int gregset_num_regs
Definition: i386-tdep.h:60
#define X86_XSTATE_AVX
Definition: x86-xstate.h:26
void set_gdbarch_core_read_description(struct gdbarch *gdbarch, gdbarch_core_read_description_ftype core_read_description)
Definition: gdbarch.c:3816
void gdbarch_register_osabi(enum bfd_architecture arch, unsigned long machine, enum gdb_osabi osabi, void(*init_osabi)(struct gdbarch_info, struct gdbarch *))
Definition: osabi.c:148
size_t size
Definition: go32-nat.c:242
const struct target_desc * i386_target_description(uint64_t xcr0)
Definition: i386-tdep.c:8604
static const gdb_byte i386fbsd_sigtramp_middle[]
Definition: i386fbsd-tdep.c:53
const ULONGEST const LONGEST len
Definition: target.h:309