]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/i386fbsd-tdep.c
GDB copyright headers update after running GDB's copyright.py script.
[thirdparty/binutils-gdb.git] / gdb / i386fbsd-tdep.c
CommitLineData
8a96bc77
MK
1/* Target-dependent code for FreeBSD/i386.
2
618f726f 3 Copyright (C) 2003-2016 Free Software Foundation, Inc.
8a96bc77
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
8a96bc77
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/>. */
8a96bc77
MK
19
20#include "defs.h"
21#include "arch-utils.h"
fa565c2b 22#include "gdbcore.h"
8a96bc77 23#include "osabi.h"
fa565c2b 24#include "regcache.h"
97de3545
JB
25#include "regset.h"
26#include "i386fbsd-tdep.h"
27#include "x86-xstate.h"
fa565c2b 28
8a96bc77
MK
29#include "i386-tdep.h"
30#include "i387-tdep.h"
fa565c2b 31#include "bsd-uthread.h"
490496c3 32#include "fbsd-tdep.h"
7e654c37 33#include "solib-svr4.h"
8a96bc77 34
cf424aef
JB
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
47static const gdb_byte i386fbsd_sigtramp_start[] =
48{
49 0x8d, 0x44, 0x24, 0x20, /* lea SIGF_UC(%esp),%eax */
50 0x50 /* pushl %eax */
51};
52
53static 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
61static 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
68static const gdb_byte i386fbsd_freebsd4_sigtramp_start[] =
69{
70 0x8d, 0x44, 0x24, 0x14, /* lea SIGF_UC4(%esp),%eax */
71 0x50 /* pushl %eax */
72};
73
74static 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
82static 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
89static const gdb_byte i386fbsd_osigtramp_start[] =
90{
91 0x8d, 0x44, 0x24, 0x14, /* lea SIGF_SC(%esp),%eax */
92 0x50 /* pushl %eax */
93};
94
95static 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
103static 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. */
773eacf5
JB
111gdb_static_assert (sizeof i386fbsd_sigtramp_start
112 == sizeof i386fbsd_freebsd4_sigtramp_start);
113gdb_static_assert (sizeof i386fbsd_sigtramp_start
114 == sizeof i386fbsd_osigtramp_start);
115gdb_static_assert (sizeof i386fbsd_sigtramp_middle
116 == sizeof i386fbsd_freebsd4_sigtramp_middle);
117gdb_static_assert (sizeof i386fbsd_sigtramp_middle
118 == sizeof i386fbsd_osigtramp_middle);
119gdb_static_assert (sizeof i386fbsd_sigtramp_end
120 == sizeof i386fbsd_freebsd4_sigtramp_end);
121gdb_static_assert (sizeof i386fbsd_sigtramp_end
122 == sizeof i386fbsd_osigtramp_end);
cf424aef
JB
123
124/* We assume that the middle is the largest chunk below. */
773eacf5
JB
125gdb_static_assert (sizeof i386fbsd_sigtramp_middle
126 > sizeof i386fbsd_sigtramp_start);
127gdb_static_assert (sizeof i386fbsd_sigtramp_middle
128 > sizeof i386fbsd_sigtramp_end);
cf424aef
JB
129
130static int
131i386fbsd_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;
773eacf5
JB
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
cf424aef
JB
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
8a96bc77
MK
189/* FreeBSD 3.0-RELEASE or later. */
190
191/* From <machine/reg.h>. */
192static 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
5d93ae8c 202/* Sigtramp routine location. */
cf424aef
JB
203CORE_ADDR i386fbsd_sigtramp_start_addr;
204CORE_ADDR i386fbsd_sigtramp_end_addr;
8a96bc77
MK
205
206/* From <machine/signal.h>. */
abfcdd21 207int i386fbsd_sc_reg_offset[] =
8a96bc77
MK
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
1c02b2a5 227/* From /usr/src/lib/libc/i386/gen/_setjmp.S. */
fa565c2b
MK
228static 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
97de3545
JB
241/* Get XSAVE extended state xcr0 from core dump. */
242
243uint64_t
244i386fbsd_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
280static const struct target_desc *
281i386fbsd_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
290static void
291i386fbsd_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
300static void
301i386fbsd_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
310static 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
319static void
320i386fbsd_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
fa565c2b
MK
335static void
336i386fbsd_supply_uthread (struct regcache *regcache,
337 int regnum, CORE_ADDR addr)
338{
e362b510 339 gdb_byte buf[4];
fa565c2b
MK
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
355static void
356i386fbsd_collect_uthread (const struct regcache *regcache,
357 int regnum, CORE_ADDR addr)
358{
e362b510 359 gdb_byte buf[4];
fa565c2b
MK
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
8a96bc77
MK
375static void
376i386fbsdaout_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
cf424aef
JB
393 tdep->sigtramp_p = i386fbsd_sigtramp_p;
394
8a96bc77 395 /* FreeBSD uses a different memory layout. */
5d93ae8c
MK
396 tdep->sigtramp_start = i386fbsd_sigtramp_start_addr;
397 tdep->sigtramp_end = i386fbsd_sigtramp_end_addr;
8a96bc77
MK
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);
fa565c2b
MK
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);
8a96bc77
MK
406}
407
408static void
409i386fbsd_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. */
7e654c37
MK
418 set_solib_svr4_fetch_link_map_offsets
419 (gdbarch, svr4_ilp32_fetch_link_map_offsets);
8a96bc77
MK
420}
421
422/* FreeBSD 4.0-RELEASE or later. */
423
424/* From <machine/reg.h>. */
425static 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>. */
436int 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
456static void
457i386fbsd4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
458{
459 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
460
490496c3
AA
461 /* Generic FreeBSD support. */
462 fbsd_init_abi (info, gdbarch);
463
8a96bc77
MK
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);
97de3545
JB
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);
8a96bc77
MK
485}
486
487\f
488/* Provide a prototype to silence -Wmissing-prototypes. */
489void _initialize_i386fbsd_tdep (void);
490
491void
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}