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