]>
Commit | Line | Data |
---|---|---|
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 | ||
44 | static 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 |
75 | static 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 | ||
85 | static 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 | ||
127 | const struct regset amd64_fbsd_gregset = | |
128 | { | |
129 | amd64_fbsd_gregmap, regcache_supply_regset, regcache_collect_regset | |
130 | }; | |
131 | ||
f3215e15 JB |
132 | const 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 | ||
169 | static void | |
170 | amd64_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 | 193 | static 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 | ||
221 | static const struct target_desc * | |
222 | amd64fbsd_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 | ||
236 | static void | |
237 | amd64fbsd_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 | ||
246 | static void | |
247 | amd64fbsd_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 | ||
254 | static 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 | ||
263 | static void | |
264 | amd64fbsd_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 | ||
286 | static CORE_ADDR | |
287 | amd64fbsd_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 | 303 | static void |
68cc0bfb MK |
304 | amd64fbsd_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 | 340 | void _initialize_amd64fbsd_tdep (); |
68cc0bfb | 341 | void |
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 | } |