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