Remove support for pre-5.0 FreeBSD/i386 signal trampolines.
[binutils-gdb.git] / gdb / i386-fbsd-tdep.c
1 /* Target-dependent code for FreeBSD/i386.
2
3 Copyright (C) 2003-2022 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 "i386-fbsd-tdep.h"
27 #include "gdbsupport/x86-xstate.h"
28
29 #include "i386-tdep.h"
30 #include "i387-tdep.h"
31 #include "fbsd-tdep.h"
32 #include "solib-svr4.h"
33 #include "inferior.h"
34
35 /* Support for signal handlers. */
36
37 /* Return whether THIS_FRAME corresponds to a FreeBSD sigtramp
38 routine. */
39
40 /* FreeBSD/i386 binaries running under an amd64 kernel use a different
41 trampoline This trampoline differs from the i386 kernel trampoline
42 in that it omits a middle section that conditionally restores
43 %gs. */
44
45 static const gdb_byte i386fbsd_sigtramp_start[] =
46 {
47 0x8d, 0x44, 0x24, 0x20, /* lea SIGF_UC(%esp),%eax */
48 0x50 /* pushl %eax */
49 };
50
51 static const gdb_byte i386fbsd_sigtramp_middle[] =
52 {
53 0xf7, 0x40, 0x54, 0x00, 0x00, 0x02, 0x00,
54 /* testl $PSL_VM,UC_EFLAGS(%eax) */
55 0x75, 0x03, /* jne +3 */
56 0x8e, 0x68, 0x14 /* mov UC_GS(%eax),%gs */
57 };
58
59 static const gdb_byte i386fbsd_sigtramp_end[] =
60 {
61 0xb8, 0xa1, 0x01, 0x00, 0x00, /* movl $SYS_sigreturn,%eax */
62 0x50, /* pushl %eax */
63 0xcd, 0x80 /* int $0x80 */
64 };
65
66 /* We assume that the middle is the largest chunk below. */
67 gdb_static_assert (sizeof i386fbsd_sigtramp_middle
68 > sizeof i386fbsd_sigtramp_start);
69 gdb_static_assert (sizeof i386fbsd_sigtramp_middle
70 > sizeof i386fbsd_sigtramp_end);
71
72 static int
73 i386fbsd_sigtramp_p (struct frame_info *this_frame)
74 {
75 CORE_ADDR pc = get_frame_pc (this_frame);
76 gdb_byte buf[sizeof i386fbsd_sigtramp_middle];
77
78 /* Look for a matching start. */
79 if (!safe_frame_unwind_memory (this_frame, pc,
80 {buf, sizeof i386fbsd_sigtramp_start}))
81 return 0;
82 if (memcmp (buf, i386fbsd_sigtramp_start, sizeof i386fbsd_sigtramp_start)
83 != 0)
84 return 0;
85
86 /* Since the end is shorter than the middle, check for a matching end
87 next. */
88 pc += sizeof i386fbsd_sigtramp_start;
89 if (!safe_frame_unwind_memory (this_frame, pc,
90 {buf, sizeof i386fbsd_sigtramp_end}))
91 return 0;
92 if (memcmp (buf, i386fbsd_sigtramp_end, sizeof i386fbsd_sigtramp_end) == 0)
93 return 1;
94
95 /* If the end didn't match, check for a matching middle. */
96 if (!safe_frame_unwind_memory (this_frame, pc,
97 {buf, sizeof i386fbsd_sigtramp_middle}))
98 return 0;
99 if (memcmp (buf, i386fbsd_sigtramp_middle, sizeof i386fbsd_sigtramp_middle)
100 != 0)
101 return 0;
102
103 /* The middle matched, check for a matching end. */
104 pc += sizeof i386fbsd_sigtramp_middle;
105 if (!safe_frame_unwind_memory (this_frame, pc,
106 {buf, sizeof i386fbsd_sigtramp_end}))
107 return 0;
108 if (memcmp (buf, i386fbsd_sigtramp_end, sizeof i386fbsd_sigtramp_end) != 0)
109 return 0;
110
111 return 1;
112 }
113
114 /* From <machine/reg.h>. */
115 static int i386fbsd_r_reg_offset[] =
116 {
117 10 * 4, 9 * 4, 8 * 4, 7 * 4, /* %eax, %ecx, %edx, %ebx */
118 16 * 4, 5 * 4, /* %esp, %ebp */
119 4 * 4, 3 * 4, /* %esi, %edi */
120 13 * 4, 15 * 4, /* %eip, %eflags */
121 14 * 4, 17 * 4, /* %cs, %ss */
122 2 * 4, 1 * 4, 0 * 4, 18 * 4 /* %ds, %es, %fs, %gs */
123 };
124
125 /* Sigtramp routine location. */
126 CORE_ADDR i386fbsd_sigtramp_start_addr;
127 CORE_ADDR i386fbsd_sigtramp_end_addr;
128
129 /* From <machine/signal.h>. */
130 int i386fbsd_sc_reg_offset[] =
131 {
132 20 + 11 * 4, /* %eax */
133 20 + 10 * 4, /* %ecx */
134 20 + 9 * 4, /* %edx */
135 20 + 8 * 4, /* %ebx */
136 20 + 17 * 4, /* %esp */
137 20 + 6 * 4, /* %ebp */
138 20 + 5 * 4, /* %esi */
139 20 + 4 * 4, /* %edi */
140 20 + 14 * 4, /* %eip */
141 20 + 16 * 4, /* %eflags */
142 20 + 15 * 4, /* %cs */
143 20 + 18 * 4, /* %ss */
144 20 + 3 * 4, /* %ds */
145 20 + 2 * 4, /* %es */
146 20 + 1 * 4, /* %fs */
147 20 + 0 * 4 /* %gs */
148 };
149
150 /* Get XSAVE extended state xcr0 from core dump. */
151
152 uint64_t
153 i386fbsd_core_read_xcr0 (bfd *abfd)
154 {
155 asection *xstate = bfd_get_section_by_name (abfd, ".reg-xstate");
156 uint64_t xcr0;
157
158 if (xstate)
159 {
160 size_t size = bfd_section_size (xstate);
161
162 /* Check extended state size. */
163 if (size < X86_XSTATE_AVX_SIZE)
164 xcr0 = X86_XSTATE_SSE_MASK;
165 else
166 {
167 char contents[8];
168
169 if (! bfd_get_section_contents (abfd, xstate, contents,
170 I386_FBSD_XSAVE_XCR0_OFFSET,
171 8))
172 {
173 warning (_("Couldn't read `xcr0' bytes from "
174 "`.reg-xstate' section in core file."));
175 return X86_XSTATE_SSE_MASK;
176 }
177
178 xcr0 = bfd_get_64 (abfd, contents);
179 }
180 }
181 else
182 xcr0 = X86_XSTATE_SSE_MASK;
183
184 return xcr0;
185 }
186
187 /* Implement the core_read_description gdbarch method. */
188
189 static const struct target_desc *
190 i386fbsd_core_read_description (struct gdbarch *gdbarch,
191 struct target_ops *target,
192 bfd *abfd)
193 {
194 return i386_target_description (i386fbsd_core_read_xcr0 (abfd), true);
195 }
196
197 /* Similar to i386_supply_fpregset, but use XSAVE extended state. */
198
199 static void
200 i386fbsd_supply_xstateregset (const struct regset *regset,
201 struct regcache *regcache, int regnum,
202 const void *xstateregs, size_t len)
203 {
204 i387_supply_xsave (regcache, regnum, xstateregs);
205 }
206
207 /* Similar to i386_collect_fpregset, but use XSAVE extended state. */
208
209 static void
210 i386fbsd_collect_xstateregset (const struct regset *regset,
211 const struct regcache *regcache,
212 int regnum, void *xstateregs, size_t len)
213 {
214 i387_collect_xsave (regcache, regnum, xstateregs, 1);
215 }
216
217 /* Register set definitions. */
218
219 static const struct regset i386fbsd_xstateregset =
220 {
221 NULL,
222 i386fbsd_supply_xstateregset,
223 i386fbsd_collect_xstateregset
224 };
225
226 /* Iterate over core file register note sections. */
227
228 static void
229 i386fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
230 iterate_over_regset_sections_cb *cb,
231 void *cb_data,
232 const struct regcache *regcache)
233 {
234 i386_gdbarch_tdep *tdep = (i386_gdbarch_tdep *) gdbarch_tdep (gdbarch);
235
236 cb (".reg", tdep->sizeof_gregset, tdep->sizeof_gregset, &i386_gregset, NULL,
237 cb_data);
238 cb (".reg2", tdep->sizeof_fpregset, tdep->sizeof_fpregset, &i386_fpregset,
239 NULL, cb_data);
240
241 if (tdep->xcr0 & X86_XSTATE_AVX)
242 cb (".reg-xstate", X86_XSTATE_SIZE (tdep->xcr0),
243 X86_XSTATE_SIZE (tdep->xcr0), &i386fbsd_xstateregset,
244 "XSAVE extended state", cb_data);
245 }
246
247 /* Implement the get_thread_local_address gdbarch method. */
248
249 static CORE_ADDR
250 i386fbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid,
251 CORE_ADDR lm_addr, CORE_ADDR offset)
252 {
253 i386_gdbarch_tdep *tdep = (i386_gdbarch_tdep *) gdbarch_tdep (gdbarch);
254 struct regcache *regcache;
255
256 if (tdep->fsbase_regnum == -1)
257 error (_("Unable to fetch %%gsbase"));
258
259 regcache = get_thread_arch_regcache (current_inferior ()->process_target (),
260 ptid, gdbarch);
261
262 target_fetch_registers (regcache, tdep->fsbase_regnum + 1);
263
264 ULONGEST gsbase;
265 if (regcache->cooked_read (tdep->fsbase_regnum + 1, &gsbase) != REG_VALID)
266 error (_("Unable to fetch %%gsbase"));
267
268 CORE_ADDR dtv_addr = gsbase + gdbarch_ptr_bit (gdbarch) / 8;
269 return fbsd_get_thread_local_address (gdbarch, dtv_addr, lm_addr, offset);
270 }
271
272 static void
273 i386fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
274 {
275 i386_gdbarch_tdep *tdep = (i386_gdbarch_tdep *) gdbarch_tdep (gdbarch);
276
277 /* Generic FreeBSD support. */
278 fbsd_init_abi (info, gdbarch);
279
280 /* Obviously FreeBSD is BSD-based. */
281 i386bsd_init_abi (info, gdbarch);
282
283 /* FreeBSD has a different `struct reg', and reserves some space for
284 its FPU emulator in `struct fpreg'. */
285 tdep->gregset_reg_offset = i386fbsd_r_reg_offset;
286 tdep->gregset_num_regs = ARRAY_SIZE (i386fbsd_r_reg_offset);
287 tdep->sizeof_gregset = 19 * 4;
288 tdep->sizeof_fpregset = 176;
289
290 /* FreeBSD uses -freg-struct-return by default. */
291 tdep->struct_return = reg_struct_return;
292
293 tdep->sigtramp_p = i386fbsd_sigtramp_p;
294
295 /* FreeBSD uses a different memory layout. */
296 tdep->sigtramp_start = i386fbsd_sigtramp_start_addr;
297 tdep->sigtramp_end = i386fbsd_sigtramp_end_addr;
298
299 /* FreeBSD has a more complete `struct sigcontext'. */
300 tdep->sc_reg_offset = i386fbsd_sc_reg_offset;
301 tdep->sc_num_regs = ARRAY_SIZE (i386fbsd_sc_reg_offset);
302
303 i386_elf_init_abi (info, gdbarch);
304
305 tdep->xsave_xcr0_offset = I386_FBSD_XSAVE_XCR0_OFFSET;
306
307 /* Iterate over core file register note sections. */
308 set_gdbarch_iterate_over_regset_sections
309 (gdbarch, i386fbsd_iterate_over_regset_sections);
310
311 set_gdbarch_core_read_description (gdbarch,
312 i386fbsd_core_read_description);
313
314 /* FreeBSD uses SVR4-style shared libraries. */
315 set_solib_svr4_fetch_link_map_offsets
316 (gdbarch, svr4_ilp32_fetch_link_map_offsets);
317
318 set_gdbarch_fetch_tls_load_module_address (gdbarch,
319 svr4_fetch_objfile_link_map);
320 set_gdbarch_get_thread_local_address (gdbarch,
321 i386fbsd_get_thread_local_address);
322 }
323
324 void _initialize_i386fbsd_tdep ();
325 void
326 _initialize_i386fbsd_tdep ()
327 {
328 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_FREEBSD,
329 i386fbsd_init_abi);
330 }