Automatic date update in version.in
[deliverable/binutils-gdb.git] / gdb / i386-fbsd-tdep.c
CommitLineData
8a96bc77
MK
1/* Target-dependent code for FreeBSD/i386.
2
61baf725 3 Copyright (C) 2003-2017 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 25#include "regset.h"
03b62bbb 26#include "i386-fbsd-tdep.h"
97de3545 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 375static void
1736a7bd 376i386fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
8a96bc77
MK
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 406
8a96bc77
MK
407 i386_elf_init_abi (info, gdbarch);
408
1736a7bd 409 /* FreeBSD uses SVR4-style shared libraries. */
7e654c37
MK
410 set_solib_svr4_fetch_link_map_offsets
411 (gdbarch, svr4_ilp32_fetch_link_map_offsets);
8a96bc77
MK
412}
413
414/* FreeBSD 4.0-RELEASE or later. */
415
416/* From <machine/reg.h>. */
417static int i386fbsd4_r_reg_offset[] =
418{
419 10 * 4, 9 * 4, 8 * 4, 7 * 4, /* %eax, %ecx, %edx, %ebx */
420 16 * 4, 5 * 4, /* %esp, %ebp */
421 4 * 4, 3 * 4, /* %esi, %edi */
422 13 * 4, 15 * 4, /* %eip, %eflags */
423 14 * 4, 17 * 4, /* %cs, %ss */
424 2 * 4, 1 * 4, 0 * 4, 18 * 4 /* %ds, %es, %fs, %gs */
425};
426
427/* From <machine/signal.h>. */
428int i386fbsd4_sc_reg_offset[] =
429{
430 20 + 11 * 4, /* %eax */
431 20 + 10 * 4, /* %ecx */
432 20 + 9 * 4, /* %edx */
433 20 + 8 * 4, /* %ebx */
434 20 + 17 * 4, /* %esp */
435 20 + 6 * 4, /* %ebp */
436 20 + 5 * 4, /* %esi */
437 20 + 4 * 4, /* %edi */
438 20 + 14 * 4, /* %eip */
439 20 + 16 * 4, /* %eflags */
440 20 + 15 * 4, /* %cs */
441 20 + 18 * 4, /* %ss */
442 20 + 3 * 4, /* %ds */
443 20 + 2 * 4, /* %es */
444 20 + 1 * 4, /* %fs */
445 20 + 0 * 4 /* %gs */
446};
447
448static void
449i386fbsd4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
450{
451 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
452
490496c3
AA
453 /* Generic FreeBSD support. */
454 fbsd_init_abi (info, gdbarch);
455
8a96bc77
MK
456 /* Inherit stuff from older releases. We assume that FreeBSD
457 4.0-RELEASE always uses ELF. */
458 i386fbsd_init_abi (info, gdbarch);
459
460 /* FreeBSD 4.0 introduced a new `struct reg'. */
461 tdep->gregset_reg_offset = i386fbsd4_r_reg_offset;
462 tdep->gregset_num_regs = ARRAY_SIZE (i386fbsd4_r_reg_offset);
463 tdep->sizeof_gregset = 19 * 4;
464
465 /* FreeBSD 4.0 introduced a new `struct sigcontext'. */
466 tdep->sc_reg_offset = i386fbsd4_sc_reg_offset;
467 tdep->sc_num_regs = ARRAY_SIZE (i386fbsd4_sc_reg_offset);
97de3545
JB
468
469 tdep->xsave_xcr0_offset = I386_FBSD_XSAVE_XCR0_OFFSET;
470
471 /* Iterate over core file register note sections. */
472 set_gdbarch_iterate_over_regset_sections
473 (gdbarch, i386fbsd_iterate_over_regset_sections);
474
475 set_gdbarch_core_read_description (gdbarch,
476 i386fbsd_core_read_description);
8a96bc77
MK
477}
478
479\f
480/* Provide a prototype to silence -Wmissing-prototypes. */
481void _initialize_i386fbsd_tdep (void);
482
483void
484_initialize_i386fbsd_tdep (void)
485{
1736a7bd 486 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_FREEBSD,
8a96bc77
MK
487 i386fbsd4_init_abi);
488}
This page took 1.067008 seconds and 4 git commands to generate.