Multi-target support
[deliverable/binutils-gdb.git] / gdb / i386-fbsd-tdep.c
CommitLineData
8a96bc77
MK
1/* Target-dependent code for FreeBSD/i386.
2
b811d2c2 3 Copyright (C) 2003-2020 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"
268a13a5 27#include "gdbsupport/x86-xstate.h"
fa565c2b 28
8a96bc77
MK
29#include "i386-tdep.h"
30#include "i387-tdep.h"
490496c3 31#include "fbsd-tdep.h"
7e654c37 32#include "solib-svr4.h"
5b6d1e4f 33#include "inferior.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
97de3545
JB
227/* Get XSAVE extended state xcr0 from core dump. */
228
229uint64_t
230i386fbsd_core_read_xcr0 (bfd *abfd)
231{
232 asection *xstate = bfd_get_section_by_name (abfd, ".reg-xstate");
233 uint64_t xcr0;
234
235 if (xstate)
236 {
fd361982 237 size_t size = bfd_section_size (xstate);
97de3545
JB
238
239 /* Check extended state size. */
240 if (size < X86_XSTATE_AVX_SIZE)
241 xcr0 = X86_XSTATE_SSE_MASK;
242 else
243 {
244 char contents[8];
245
246 if (! bfd_get_section_contents (abfd, xstate, contents,
247 I386_FBSD_XSAVE_XCR0_OFFSET,
248 8))
249 {
250 warning (_("Couldn't read `xcr0' bytes from "
251 "`.reg-xstate' section in core file."));
d78bdb54 252 return X86_XSTATE_SSE_MASK;
97de3545
JB
253 }
254
255 xcr0 = bfd_get_64 (abfd, contents);
256 }
257 }
258 else
d78bdb54 259 xcr0 = X86_XSTATE_SSE_MASK;
97de3545
JB
260
261 return xcr0;
262}
263
264/* Implement the core_read_description gdbarch method. */
265
266static const struct target_desc *
267i386fbsd_core_read_description (struct gdbarch *gdbarch,
268 struct target_ops *target,
269 bfd *abfd)
270{
dd6876c9 271 return i386_target_description (i386fbsd_core_read_xcr0 (abfd), true);
97de3545
JB
272}
273
274/* Similar to i386_supply_fpregset, but use XSAVE extended state. */
275
276static void
277i386fbsd_supply_xstateregset (const struct regset *regset,
278 struct regcache *regcache, int regnum,
279 const void *xstateregs, size_t len)
280{
281 i387_supply_xsave (regcache, regnum, xstateregs);
282}
283
284/* Similar to i386_collect_fpregset, but use XSAVE extended state. */
285
286static void
287i386fbsd_collect_xstateregset (const struct regset *regset,
288 const struct regcache *regcache,
289 int regnum, void *xstateregs, size_t len)
290{
291 i387_collect_xsave (regcache, regnum, xstateregs, 1);
292}
293
294/* Register set definitions. */
295
296static const struct regset i386fbsd_xstateregset =
297 {
298 NULL,
299 i386fbsd_supply_xstateregset,
300 i386fbsd_collect_xstateregset
301 };
302
303/* Iterate over core file register note sections. */
304
305static void
306i386fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
307 iterate_over_regset_sections_cb *cb,
308 void *cb_data,
309 const struct regcache *regcache)
310{
311 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
312
a616bb94
AH
313 cb (".reg", tdep->sizeof_gregset, tdep->sizeof_gregset, &i386_gregset, NULL,
314 cb_data);
315 cb (".reg2", tdep->sizeof_fpregset, tdep->sizeof_fpregset, &i386_fpregset,
316 NULL, cb_data);
97de3545
JB
317
318 if (tdep->xcr0 & X86_XSTATE_AVX)
a616bb94
AH
319 cb (".reg-xstate", X86_XSTATE_SIZE (tdep->xcr0),
320 X86_XSTATE_SIZE (tdep->xcr0), &i386fbsd_xstateregset,
321 "XSAVE extended state", cb_data);
97de3545
JB
322}
323
ce25aa57
JB
324/* Implement the get_thread_local_address gdbarch method. */
325
326static CORE_ADDR
327i386fbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid,
328 CORE_ADDR lm_addr, CORE_ADDR offset)
329{
330 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
331 struct regcache *regcache;
332
333 if (tdep->fsbase_regnum == -1)
334 error (_("Unable to fetch %%gsbase"));
335
5b6d1e4f
PA
336 regcache = get_thread_arch_regcache (current_inferior ()->process_target (),
337 ptid, gdbarch);
ce25aa57
JB
338
339 target_fetch_registers (regcache, tdep->fsbase_regnum + 1);
340
341 ULONGEST gsbase;
342 if (regcache->cooked_read (tdep->fsbase_regnum + 1, &gsbase) != REG_VALID)
343 error (_("Unable to fetch %%gsbase"));
344
345 CORE_ADDR dtv_addr = gsbase + gdbarch_ptr_bit (gdbarch) / 8;
346 return fbsd_get_thread_local_address (gdbarch, dtv_addr, lm_addr, offset);
347}
348
8a96bc77 349static void
1736a7bd 350i386fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
8a96bc77
MK
351{
352 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
353
354 /* Obviously FreeBSD is BSD-based. */
355 i386bsd_init_abi (info, gdbarch);
356
357 /* FreeBSD has a different `struct reg', and reserves some space for
358 its FPU emulator in `struct fpreg'. */
359 tdep->gregset_reg_offset = i386fbsd_r_reg_offset;
360 tdep->gregset_num_regs = ARRAY_SIZE (i386fbsd_r_reg_offset);
361 tdep->sizeof_gregset = 18 * 4;
362 tdep->sizeof_fpregset = 176;
363
364 /* FreeBSD uses -freg-struct-return by default. */
365 tdep->struct_return = reg_struct_return;
366
cf424aef
JB
367 tdep->sigtramp_p = i386fbsd_sigtramp_p;
368
8a96bc77 369 /* FreeBSD uses a different memory layout. */
5d93ae8c
MK
370 tdep->sigtramp_start = i386fbsd_sigtramp_start_addr;
371 tdep->sigtramp_end = i386fbsd_sigtramp_end_addr;
8a96bc77
MK
372
373 /* FreeBSD has a more complete `struct sigcontext'. */
374 tdep->sc_reg_offset = i386fbsd_sc_reg_offset;
375 tdep->sc_num_regs = ARRAY_SIZE (i386fbsd_sc_reg_offset);
fa565c2b 376
8a96bc77
MK
377 i386_elf_init_abi (info, gdbarch);
378
1736a7bd 379 /* FreeBSD uses SVR4-style shared libraries. */
7e654c37
MK
380 set_solib_svr4_fetch_link_map_offsets
381 (gdbarch, svr4_ilp32_fetch_link_map_offsets);
8a96bc77
MK
382}
383
384/* FreeBSD 4.0-RELEASE or later. */
385
386/* From <machine/reg.h>. */
387static int i386fbsd4_r_reg_offset[] =
388{
389 10 * 4, 9 * 4, 8 * 4, 7 * 4, /* %eax, %ecx, %edx, %ebx */
390 16 * 4, 5 * 4, /* %esp, %ebp */
391 4 * 4, 3 * 4, /* %esi, %edi */
392 13 * 4, 15 * 4, /* %eip, %eflags */
393 14 * 4, 17 * 4, /* %cs, %ss */
394 2 * 4, 1 * 4, 0 * 4, 18 * 4 /* %ds, %es, %fs, %gs */
395};
396
397/* From <machine/signal.h>. */
398int i386fbsd4_sc_reg_offset[] =
399{
400 20 + 11 * 4, /* %eax */
401 20 + 10 * 4, /* %ecx */
402 20 + 9 * 4, /* %edx */
403 20 + 8 * 4, /* %ebx */
404 20 + 17 * 4, /* %esp */
405 20 + 6 * 4, /* %ebp */
406 20 + 5 * 4, /* %esi */
407 20 + 4 * 4, /* %edi */
408 20 + 14 * 4, /* %eip */
409 20 + 16 * 4, /* %eflags */
410 20 + 15 * 4, /* %cs */
411 20 + 18 * 4, /* %ss */
412 20 + 3 * 4, /* %ds */
413 20 + 2 * 4, /* %es */
414 20 + 1 * 4, /* %fs */
415 20 + 0 * 4 /* %gs */
416};
417
418static void
419i386fbsd4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
420{
421 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
422
490496c3
AA
423 /* Generic FreeBSD support. */
424 fbsd_init_abi (info, gdbarch);
425
8a96bc77
MK
426 /* Inherit stuff from older releases. We assume that FreeBSD
427 4.0-RELEASE always uses ELF. */
428 i386fbsd_init_abi (info, gdbarch);
429
430 /* FreeBSD 4.0 introduced a new `struct reg'. */
431 tdep->gregset_reg_offset = i386fbsd4_r_reg_offset;
432 tdep->gregset_num_regs = ARRAY_SIZE (i386fbsd4_r_reg_offset);
433 tdep->sizeof_gregset = 19 * 4;
434
435 /* FreeBSD 4.0 introduced a new `struct sigcontext'. */
436 tdep->sc_reg_offset = i386fbsd4_sc_reg_offset;
437 tdep->sc_num_regs = ARRAY_SIZE (i386fbsd4_sc_reg_offset);
97de3545
JB
438
439 tdep->xsave_xcr0_offset = I386_FBSD_XSAVE_XCR0_OFFSET;
440
441 /* Iterate over core file register note sections. */
442 set_gdbarch_iterate_over_regset_sections
443 (gdbarch, i386fbsd_iterate_over_regset_sections);
444
445 set_gdbarch_core_read_description (gdbarch,
446 i386fbsd_core_read_description);
ce25aa57
JB
447
448 set_gdbarch_fetch_tls_load_module_address (gdbarch,
449 svr4_fetch_objfile_link_map);
450 set_gdbarch_get_thread_local_address (gdbarch,
451 i386fbsd_get_thread_local_address);
8a96bc77
MK
452}
453
8a96bc77
MK
454void
455_initialize_i386fbsd_tdep (void)
456{
1736a7bd 457 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_FREEBSD,
8a96bc77
MK
458 i386fbsd4_init_abi);
459}
This page took 1.244887 seconds and 4 git commands to generate.