]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/amd64-fbsd-tdep.c
Fix regression on aarch64-linux gdbserver
[thirdparty/binutils-gdb.git] / gdb / amd64-fbsd-tdep.c
CommitLineData
68cc0bfb 1/* Target-dependent code for FreeBSD/amd64.
477f40d1 2
1d506c26 3 Copyright (C) 2003-2024 Free Software Foundation, Inc.
68cc0bfb
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
68cc0bfb
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/>. */
68cc0bfb 19
4de283e4 20#include "osabi.h"
97de3545 21#include "regset.h"
7384826e
JB
22#include "target.h"
23#include "trad-frame.h"
24#include "tramp-frame.h"
4de283e4 25#include "i386-fbsd-tdep.h"
268a13a5 26#include "gdbsupport/x86-xstate.h"
4de283e4
TT
27
28#include "amd64-tdep.h"
00d7af04 29#include "amd64-fbsd-tdep.h"
4de283e4 30#include "fbsd-tdep.h"
7e654c37 31#include "solib-svr4.h"
5b6d1e4f 32#include "inferior.h"
68cc0bfb 33
a423c9f3
JB
34/* The general-purpose regset consists of 22 64-bit slots, most of
35 which contain individual registers, but a few contain multiple
36 16-bit segment registers. */
37#define AMD64_FBSD_SIZEOF_GREGSET (22 * 8)
38
f3215e15
JB
39/* The segment base register set consists of 2 64-bit registers. */
40#define AMD64_FBSD_SIZEOF_SEGBASES_REGSET (2 * 8)
41
a423c9f3
JB
42/* Register maps. */
43
44static const struct regcache_map_entry amd64_fbsd_gregmap[] =
45{
46 { 1, AMD64_R15_REGNUM, 0 },
47 { 1, AMD64_R14_REGNUM, 0 },
48 { 1, AMD64_R13_REGNUM, 0 },
49 { 1, AMD64_R12_REGNUM, 0 },
50 { 1, AMD64_R11_REGNUM, 0 },
51 { 1, AMD64_R10_REGNUM, 0 },
52 { 1, AMD64_R9_REGNUM, 0 },
53 { 1, AMD64_R8_REGNUM, 0 },
54 { 1, AMD64_RDI_REGNUM, 0 },
55 { 1, AMD64_RSI_REGNUM, 0 },
56 { 1, AMD64_RBP_REGNUM, 0 },
57 { 1, AMD64_RBX_REGNUM, 0 },
58 { 1, AMD64_RDX_REGNUM, 0 },
59 { 1, AMD64_RCX_REGNUM, 0 },
60 { 1, AMD64_RAX_REGNUM, 0 },
61 { 1, REGCACHE_MAP_SKIP, 4 }, /* trapno */
62 { 1, AMD64_FS_REGNUM, 2 },
63 { 1, AMD64_GS_REGNUM, 2 },
64 { 1, REGCACHE_MAP_SKIP, 4 }, /* err */
65 { 1, AMD64_ES_REGNUM, 2 },
66 { 1, AMD64_DS_REGNUM, 2 },
67 { 1, AMD64_RIP_REGNUM, 0 },
68 { 1, AMD64_CS_REGNUM, 8 },
69 { 1, AMD64_EFLAGS_REGNUM, 8 },
70 { 1, AMD64_RSP_REGNUM, 0 },
71 { 1, AMD64_SS_REGNUM, 8 },
72 { 0 }
73};
74
f3215e15
JB
75static const struct regcache_map_entry amd64_fbsd_segbases_regmap[] =
76{
77 { 1, AMD64_FSBASE_REGNUM, 0 },
78 { 1, AMD64_GSBASE_REGNUM, 0 },
79 { 0 }
80};
81
7384826e
JB
82/* This layout including fsbase and gsbase was adopted in FreeBSD
83 8.0. */
84
85static const struct regcache_map_entry amd64_fbsd_mcregmap[] =
86{
87 { 1, REGCACHE_MAP_SKIP, 8 }, /* mc_onstack */
88 { 1, AMD64_RDI_REGNUM, 0 },
89 { 1, AMD64_RSI_REGNUM, 0 },
90 { 1, AMD64_RDX_REGNUM, 0 },
91 { 1, AMD64_RCX_REGNUM, 0 },
92 { 1, AMD64_R8_REGNUM, 0 },
93 { 1, AMD64_R9_REGNUM, 0 },
94 { 1, AMD64_RAX_REGNUM, 0 },
95 { 1, AMD64_RBX_REGNUM, 0 },
96 { 1, AMD64_RBP_REGNUM, 0 },
97 { 1, AMD64_R10_REGNUM, 0 },
98 { 1, AMD64_R11_REGNUM, 0 },
99 { 1, AMD64_R12_REGNUM, 0 },
100 { 1, AMD64_R13_REGNUM, 0 },
101 { 1, AMD64_R14_REGNUM, 0 },
102 { 1, AMD64_R15_REGNUM, 0 },
103 { 1, REGCACHE_MAP_SKIP, 4 }, /* mc_trapno */
104 { 1, AMD64_FS_REGNUM, 2 },
105 { 1, AMD64_GS_REGNUM, 2 },
106 { 1, REGCACHE_MAP_SKIP, 8 }, /* mc_addr */
107 { 1, REGCACHE_MAP_SKIP, 4 }, /* mc_flags */
108 { 1, AMD64_ES_REGNUM, 2 },
109 { 1, AMD64_DS_REGNUM, 2 },
110 { 1, REGCACHE_MAP_SKIP, 8 }, /* mc_err */
111 { 1, AMD64_RIP_REGNUM, 0 },
112 { 1, AMD64_CS_REGNUM, 8 },
113 { 1, AMD64_EFLAGS_REGNUM, 8 },
114 { 1, AMD64_RSP_REGNUM, 0 },
115 { 1, AMD64_SS_REGNUM, 8 },
116 { 1, REGCACHE_MAP_SKIP, 8 }, /* mc_len */
117 { 1, REGCACHE_MAP_SKIP, 8 }, /* mc_fpformat */
118 { 1, REGCACHE_MAP_SKIP, 8 }, /* mc_ownedfp */
119 { 64, REGCACHE_MAP_SKIP, 8 }, /* mc_fpstate */
120 { 1, AMD64_FSBASE_REGNUM, 0 },
121 { 1, AMD64_GSBASE_REGNUM, 0 },
122 { 0 }
123};
124
a423c9f3
JB
125/* Register set definitions. */
126
127const struct regset amd64_fbsd_gregset =
128{
129 amd64_fbsd_gregmap, regcache_supply_regset, regcache_collect_regset
130};
131
f3215e15
JB
132const struct regset amd64_fbsd_segbases_regset =
133{
134 amd64_fbsd_segbases_regmap, regcache_supply_regset, regcache_collect_regset
135};
136
68cc0bfb
MK
137/* Support for signal handlers. */
138
7384826e
JB
139/* In a signal frame, rsp points to a 'struct sigframe' which is
140 defined as:
cf424aef 141
7384826e
JB
142 struct sigframe {
143 union {
144 __siginfohandler_t *sf_action;
145 __sighandler_t *sf_handler;
146 } sf_ahu;
147 ucontext_t sf_uc;
287de656 148 ...
7384826e 149 }
cf424aef 150
7384826e 151 ucontext_t is defined as:
cf424aef 152
7384826e
JB
153 struct __ucontext {
154 sigset_t uc_sigmask;
155 mcontext_t uc_mcontext;
156 ...
157 };
cf424aef 158
7384826e
JB
159 The mcontext_t contains the general purpose register set as well
160 as the floating point or XSAVE state. */
cf424aef 161
7384826e
JB
162/* NB: There is an 8 byte padding hole between sf_ahu and sf_uc. */
163#define AMD64_SIGFRAME_UCONTEXT_OFFSET 16
164#define AMD64_UCONTEXT_MCONTEXT_OFFSET 16
165#define AMD64_SIZEOF_MCONTEXT_T 800
68cc0bfb 166
7384826e
JB
167/* Implement the "init" method of struct tramp_frame. */
168
169static void
170amd64_fbsd_sigframe_init (const struct tramp_frame *self,
8480a37e 171 const frame_info_ptr &this_frame,
7384826e
JB
172 struct trad_frame_cache *this_cache,
173 CORE_ADDR func)
68cc0bfb 174{
7384826e
JB
175 CORE_ADDR sp = get_frame_register_unsigned (this_frame, AMD64_RSP_REGNUM);
176 CORE_ADDR mcontext_addr
177 = (sp
178 + AMD64_SIGFRAME_UCONTEXT_OFFSET
179 + AMD64_UCONTEXT_MCONTEXT_OFFSET);
180
181 trad_frame_set_reg_regmap (this_cache, amd64_fbsd_mcregmap, mcontext_addr,
182 AMD64_SIZEOF_MCONTEXT_T);
183
184 /* Don't bother with floating point or XSAVE state for now. The
185 current helper routines for parsing FXSAVE and XSAVE state only
186 work with regcaches. This could perhaps create a temporary
187 regcache, collect the register values from mc_fpstate and
188 mc_xfpustate, and then set register values in the trad_frame. */
189
190 trad_frame_set_id (this_cache, frame_id_build (sp, func));
68cc0bfb 191}
477f40d1 192
7384826e 193static const struct tramp_frame amd64_fbsd_sigframe =
68cc0bfb 194{
7384826e
JB
195 SIGTRAMP_FRAME,
196 1,
197 {
198 {0x48, ULONGEST_MAX}, /* lea SIGF_UC(%rsp),%rdi */
199 {0x8d, ULONGEST_MAX},
200 {0x7c, ULONGEST_MAX},
201 {0x24, ULONGEST_MAX},
202 {0x10, ULONGEST_MAX},
203 {0x6a, ULONGEST_MAX}, /* pushq $0 */
204 {0x00, ULONGEST_MAX},
205 {0x48, ULONGEST_MAX}, /* movq $SYS_sigreturn,%rax */
206 {0xc7, ULONGEST_MAX},
207 {0xc0, ULONGEST_MAX},
208 {0xa1, ULONGEST_MAX},
209 {0x01, ULONGEST_MAX},
210 {0x00, ULONGEST_MAX},
211 {0x00, ULONGEST_MAX},
212 {0x0f, ULONGEST_MAX}, /* syscall */
213 {0x05, ULONGEST_MAX},
214 {TRAMP_SENTINEL_INSN, ULONGEST_MAX}
215 },
216 amd64_fbsd_sigframe_init
68cc0bfb
MK
217};
218
97de3545
JB
219/* Implement the core_read_description gdbarch method. */
220
221static const struct target_desc *
222amd64fbsd_core_read_description (struct gdbarch *gdbarch,
223 struct target_ops *target,
224 bfd *abfd)
225{
22ca5c10
JB
226 x86_xsave_layout layout;
227 uint64_t xcr0 = i386_fbsd_core_read_xsave_info (abfd, layout);
228 if (xcr0 == 0)
229 xcr0 = X86_XSTATE_SSE_MASK;
230
231 return amd64_target_description (xcr0, true);
97de3545
JB
232}
233
234/* Similar to amd64_supply_fpregset, but use XSAVE extended state. */
235
236static void
237amd64fbsd_supply_xstateregset (const struct regset *regset,
238 struct regcache *regcache, int regnum,
239 const void *xstateregs, size_t len)
240{
241 amd64_supply_xsave (regcache, regnum, xstateregs);
242}
243
244/* Similar to amd64_collect_fpregset, but use XSAVE extended state. */
245
246static void
247amd64fbsd_collect_xstateregset (const struct regset *regset,
248 const struct regcache *regcache,
249 int regnum, void *xstateregs, size_t len)
250{
251 amd64_collect_xsave (regcache, regnum, xstateregs, 1);
252}
253
254static const struct regset amd64fbsd_xstateregset =
255 {
256 NULL,
257 amd64fbsd_supply_xstateregset,
258 amd64fbsd_collect_xstateregset
259 };
260
261/* Iterate over core file register note sections. */
262
263static void
264amd64fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
265 iterate_over_regset_sections_cb *cb,
266 void *cb_data,
267 const struct regcache *regcache)
268{
08106042 269 i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
97de3545 270
a423c9f3
JB
271 cb (".reg", AMD64_FBSD_SIZEOF_GREGSET, AMD64_FBSD_SIZEOF_GREGSET,
272 &amd64_fbsd_gregset, NULL, cb_data);
a616bb94
AH
273 cb (".reg2", tdep->sizeof_fpregset, tdep->sizeof_fpregset, &amd64_fpregset,
274 NULL, cb_data);
f3215e15
JB
275 cb (".reg-x86-segbases", AMD64_FBSD_SIZEOF_SEGBASES_REGSET,
276 AMD64_FBSD_SIZEOF_SEGBASES_REGSET, &amd64_fbsd_segbases_regset,
277 "segment bases", cb_data);
22ca5c10
JB
278 if (tdep->xsave_layout.sizeof_xsave != 0)
279 cb (".reg-xstate", tdep->xsave_layout.sizeof_xsave,
280 tdep->xsave_layout.sizeof_xsave, &amd64fbsd_xstateregset,
281 "XSAVE extended state", cb_data);
97de3545
JB
282}
283
f5424cfa
JB
284/* Implement the get_thread_local_address gdbarch method. */
285
286static CORE_ADDR
287amd64fbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid,
288 CORE_ADDR lm_addr, CORE_ADDR offset)
289{
74387712
SM
290 regcache *regcache
291 = get_thread_arch_regcache (current_inferior (), ptid, gdbarch);
f5424cfa
JB
292
293 target_fetch_registers (regcache, AMD64_FSBASE_REGNUM);
294
295 ULONGEST fsbase;
296 if (regcache->cooked_read (AMD64_FSBASE_REGNUM, &fsbase) != REG_VALID)
297 error (_("Unable to fetch %%fsbase"));
298
299 CORE_ADDR dtv_addr = fsbase + gdbarch_ptr_bit (gdbarch) / 8;
300 return fbsd_get_thread_local_address (gdbarch, dtv_addr, lm_addr, offset);
301}
302
63807e1d 303static void
68cc0bfb
MK
304amd64fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
305{
08106042 306 i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
68cc0bfb 307
490496c3
AA
308 /* Generic FreeBSD support. */
309 fbsd_init_abi (info, gdbarch);
310
68cc0bfb
MK
311 /* Obviously FreeBSD is BSD-based. */
312 i386bsd_init_abi (info, gdbarch);
313
2434b019 314 amd64_init_abi (info, gdbarch,
41206e32 315 amd64_target_description (X86_XSTATE_SSE_MASK, true));
68cc0bfb 316
7384826e 317 tramp_frame_prepend_unwinder (gdbarch, &amd64_fbsd_sigframe);
7e654c37 318
97de3545 319 tdep->xsave_xcr0_offset = I386_FBSD_XSAVE_XCR0_OFFSET;
22ca5c10
JB
320 set_gdbarch_core_read_x86_xsave_layout
321 (gdbarch, i386_fbsd_core_read_x86_xsave_layout);
97de3545
JB
322
323 /* Iterate over core file register note sections. */
324 set_gdbarch_iterate_over_regset_sections
325 (gdbarch, amd64fbsd_iterate_over_regset_sections);
326
327 set_gdbarch_core_read_description (gdbarch,
328 amd64fbsd_core_read_description);
329
7e654c37
MK
330 /* FreeBSD uses SVR4-style shared libraries. */
331 set_solib_svr4_fetch_link_map_offsets
332 (gdbarch, svr4_lp64_fetch_link_map_offsets);
f5424cfa
JB
333
334 set_gdbarch_fetch_tls_load_module_address (gdbarch,
335 svr4_fetch_objfile_link_map);
336 set_gdbarch_get_thread_local_address (gdbarch,
337 amd64fbsd_get_thread_local_address);
68cc0bfb 338}
68cc0bfb 339
6c265988 340void _initialize_amd64fbsd_tdep ();
68cc0bfb 341void
6c265988 342_initialize_amd64fbsd_tdep ()
68cc0bfb
MK
343{
344 gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
1736a7bd 345 GDB_OSABI_FREEBSD, amd64fbsd_init_abi);
68cc0bfb 346}