xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/i386-fbsd-tdep.c (revision 6881a4007f077b54e5f51159c52b9b25f57deb0d)
1 /* Target-dependent code for FreeBSD/i386.
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 "regcache.h"
23 #include "regset.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 "i386-tdep.h"
30 #include "i387-tdep.h"
31 #include "fbsd-tdep.h"
32 #include "solib-svr4.h"
33 #include "inferior.h"
34 
35 /* The general-purpose regset consists of 19 32-bit slots.  */
36 #define I386_FBSD_SIZEOF_GREGSET	(19 * 4)
37 
38 /* The segment base register set consists of 2 32-bit registers.  */
39 #define I386_FBSD_SIZEOF_SEGBASES_REGSET	(2 * 4)
40 
41 /* Register maps.  */
42 
43 static const struct regcache_map_entry i386_fbsd_gregmap[] =
44 {
45   { 1, I386_FS_REGNUM, 4 },
46   { 1, I386_ES_REGNUM, 4 },
47   { 1, I386_DS_REGNUM, 4 },
48   { 1, I386_EDI_REGNUM, 0 },
49   { 1, I386_ESI_REGNUM, 0 },
50   { 1, I386_EBP_REGNUM, 0 },
51   { 1, REGCACHE_MAP_SKIP, 4 },	/* isp */
52   { 1, I386_EBX_REGNUM, 0 },
53   { 1, I386_EDX_REGNUM, 0 },
54   { 1, I386_ECX_REGNUM, 0 },
55   { 1, I386_EAX_REGNUM, 0 },
56   { 1, REGCACHE_MAP_SKIP, 4 },	/* trapno */
57   { 1, REGCACHE_MAP_SKIP, 4 },	/* err */
58   { 1, I386_EIP_REGNUM, 0 },
59   { 1, I386_CS_REGNUM, 4 },
60   { 1, I386_EFLAGS_REGNUM, 0 },
61   { 1, I386_ESP_REGNUM, 0 },
62   { 1, I386_SS_REGNUM, 4 },
63   { 1, I386_GS_REGNUM, 4 },
64   { 0 }
65 };
66 
67 static const struct regcache_map_entry i386_fbsd_segbases_regmap[] =
68 {
69   { 1, I386_FSBASE_REGNUM, 0 },
70   { 1, I386_GSBASE_REGNUM, 0 },
71   { 0 }
72 };
73 
74 /* This layout including fsbase and gsbase was adopted in FreeBSD
75    8.0.  */
76 
77 static const struct regcache_map_entry i386_fbsd_mcregmap[] =
78 {
79   { 1, REGCACHE_MAP_SKIP, 4 },	/* mc_onstack */
80   { 1, I386_GS_REGNUM, 4 },
81   { 1, I386_FS_REGNUM, 4 },
82   { 1, I386_ES_REGNUM, 4 },
83   { 1, I386_DS_REGNUM, 4 },
84   { 1, I386_EDI_REGNUM, 0 },
85   { 1, I386_ESI_REGNUM, 0 },
86   { 1, I386_EBP_REGNUM, 0 },
87   { 1, REGCACHE_MAP_SKIP, 4 },	/* isp */
88   { 1, I386_EBX_REGNUM, 0 },
89   { 1, I386_EDX_REGNUM, 0 },
90   { 1, I386_ECX_REGNUM, 0 },
91   { 1, I386_EAX_REGNUM, 0 },
92   { 1, REGCACHE_MAP_SKIP, 4 },	/* mc_trapno */
93   { 1, REGCACHE_MAP_SKIP, 4 },	/* mc_err */
94   { 1, I386_EIP_REGNUM, 0 },
95   { 1, I386_CS_REGNUM, 4 },
96   { 1, I386_EFLAGS_REGNUM, 0 },
97   { 1, I386_ESP_REGNUM, 0 },
98   { 1, I386_SS_REGNUM, 4 },
99   { 1, REGCACHE_MAP_SKIP, 4 },	/* mc_len */
100   { 1, REGCACHE_MAP_SKIP, 4 },	/* mc_fpformat */
101   { 1, REGCACHE_MAP_SKIP, 4 },	/* mc_ownedfp */
102   { 1, REGCACHE_MAP_SKIP, 4 },	/* mc_flags */
103   { 128, REGCACHE_MAP_SKIP, 4 },/* mc_fpstate */
104   { 1, I386_FSBASE_REGNUM, 0 },
105   { 1, I386_GSBASE_REGNUM, 0 },
106   { 0 }
107 };
108 
109 /* Register set definitions.  */
110 
111 const struct regset i386_fbsd_gregset =
112 {
113   i386_fbsd_gregmap, regcache_supply_regset, regcache_collect_regset
114 };
115 
116 const struct regset i386_fbsd_segbases_regset =
117 {
118   i386_fbsd_segbases_regmap, regcache_supply_regset, regcache_collect_regset
119 };
120 
121 /* Support for signal handlers.  */
122 
123 /* In a signal frame, esp points to a 'struct sigframe' which is
124    defined as:
125 
126    struct sigframe {
127 	register_t	sf_signum;
128 	register_t	sf_siginfo;
129 	register_t	sf_ucontext;
130 	register_t	sf_addr;
131 	union {
132 		__siginfohandler_t	*sf_action;
133 		__sighandler_t		*sf_handler;
134 	} sf_ahu;
135 	ucontext_t	sf_uc;
136         ...
137    }
138 
139    ucontext_t is defined as:
140 
141    struct __ucontext {
142 	   sigset_t	uc_sigmask;
143 	   mcontext_t	uc_mcontext;
144 	   ...
145    };
146 
147    The mcontext_t contains the general purpose register set as well
148    as the floating point or XSAVE state.  */
149 
150 /* NB: There is a 12 byte padding hole between sf_ahu and sf_uc. */
151 #define I386_SIGFRAME_UCONTEXT_OFFSET 		32
152 #define I386_UCONTEXT_MCONTEXT_OFFSET		16
153 #define I386_SIZEOF_MCONTEXT_T			640
154 
155 /* Implement the "init" method of struct tramp_frame.  */
156 
157 static void
158 i386_fbsd_sigframe_init (const struct tramp_frame *self,
159 			 frame_info_ptr this_frame,
160 			 struct trad_frame_cache *this_cache,
161 			 CORE_ADDR func)
162 {
163   CORE_ADDR sp = get_frame_register_unsigned (this_frame, I386_ESP_REGNUM);
164   CORE_ADDR mcontext_addr
165     = (sp
166        + I386_SIGFRAME_UCONTEXT_OFFSET
167        + I386_UCONTEXT_MCONTEXT_OFFSET);
168 
169   trad_frame_set_reg_regmap (this_cache, i386_fbsd_mcregmap, mcontext_addr,
170 			     I386_SIZEOF_MCONTEXT_T);
171 
172   /* Don't bother with floating point or XSAVE state for now.  The
173      current helper routines for parsing FXSAVE and XSAVE state only
174      work with regcaches.  This could perhaps create a temporary
175      regcache, collect the register values from mc_fpstate and
176      mc_xfpustate, and then set register values in the trad_frame.  */
177 
178   trad_frame_set_id (this_cache, frame_id_build (sp, func));
179 }
180 
181 static const struct tramp_frame i386_fbsd_sigframe =
182 {
183   SIGTRAMP_FRAME,
184   1,
185   {
186     {0x8d, ULONGEST_MAX},		/* lea     SIGF_UC(%esp),%eax */
187     {0x44, ULONGEST_MAX},
188     {0x24, ULONGEST_MAX},
189     {0x20, ULONGEST_MAX},
190     {0x50, ULONGEST_MAX},		/* pushl   %eax */
191     {0xf7, ULONGEST_MAX},		/* testl   $PSL_VM,UC_EFLAGS(%eax) */
192     {0x40, ULONGEST_MAX},
193     {0x54, ULONGEST_MAX},
194     {0x00, ULONGEST_MAX},
195     {0x00, ULONGEST_MAX},
196     {0x02, ULONGEST_MAX},
197     {0x00, ULONGEST_MAX},
198     {0x75, ULONGEST_MAX},		/* jne	   +3 */
199     {0x03, ULONGEST_MAX},
200     {0x8e, ULONGEST_MAX},		/* mov	   UC_GS(%eax),%gs */
201     {0x68, ULONGEST_MAX},
202     {0x14, ULONGEST_MAX},
203     {0xb8, ULONGEST_MAX},		/* movl   $SYS_sigreturn,%eax */
204     {0xa1, ULONGEST_MAX},
205     {0x01, ULONGEST_MAX},
206     {0x00, ULONGEST_MAX},
207     {0x00, ULONGEST_MAX},
208     {0x50, ULONGEST_MAX},		/* pushl   %eax */
209     {0xcd, ULONGEST_MAX},		/* int	   $0x80 */
210     {0x80, ULONGEST_MAX},
211     {TRAMP_SENTINEL_INSN, ULONGEST_MAX}
212   },
213   i386_fbsd_sigframe_init
214 };
215 
216 /* FreeBSD/i386 binaries running under an amd64 kernel use a different
217    trampoline.  This trampoline differs from the i386 kernel trampoline
218    in that it omits a middle section that conditionally restores
219    %gs.  */
220 
221 static const struct tramp_frame i386_fbsd64_sigframe =
222 {
223   SIGTRAMP_FRAME,
224   1,
225   {
226     {0x8d, ULONGEST_MAX},		/* lea     SIGF_UC(%esp),%eax */
227     {0x44, ULONGEST_MAX},
228     {0x24, ULONGEST_MAX},
229     {0x20, ULONGEST_MAX},
230     {0x50, ULONGEST_MAX},		/* pushl   %eax */
231     {0xb8, ULONGEST_MAX},		/* movl   $SYS_sigreturn,%eax */
232     {0xa1, ULONGEST_MAX},
233     {0x01, ULONGEST_MAX},
234     {0x00, ULONGEST_MAX},
235     {0x00, ULONGEST_MAX},
236     {0x50, ULONGEST_MAX},		/* pushl   %eax */
237     {0xcd, ULONGEST_MAX},		/* int	   $0x80 */
238     {0x80, ULONGEST_MAX},
239     {TRAMP_SENTINEL_INSN, ULONGEST_MAX}
240   },
241   i386_fbsd_sigframe_init
242 };
243 
244 /* Get XSAVE extended state xcr0 from core dump.  */
245 
246 uint64_t
247 i386fbsd_core_read_xcr0 (bfd *abfd)
248 {
249   asection *xstate = bfd_get_section_by_name (abfd, ".reg-xstate");
250   uint64_t xcr0;
251 
252   if (xstate)
253     {
254       size_t size = bfd_section_size (xstate);
255 
256       /* Check extended state size.  */
257       if (size < X86_XSTATE_AVX_SIZE)
258 	xcr0 = X86_XSTATE_SSE_MASK;
259       else
260 	{
261 	  char contents[8];
262 
263 	  if (! bfd_get_section_contents (abfd, xstate, contents,
264 					  I386_FBSD_XSAVE_XCR0_OFFSET,
265 					  8))
266 	    {
267 	      warning (_("Couldn't read `xcr0' bytes from "
268 			 "`.reg-xstate' section in core file."));
269 	      return X86_XSTATE_SSE_MASK;
270 	    }
271 
272 	  xcr0 = bfd_get_64 (abfd, contents);
273 	}
274     }
275   else
276     xcr0 = X86_XSTATE_SSE_MASK;
277 
278   return xcr0;
279 }
280 
281 /* Implement the core_read_description gdbarch method.  */
282 
283 static const struct target_desc *
284 i386fbsd_core_read_description (struct gdbarch *gdbarch,
285 				struct target_ops *target,
286 				bfd *abfd)
287 {
288   return i386_target_description (i386fbsd_core_read_xcr0 (abfd), true);
289 }
290 
291 /* Similar to i386_supply_fpregset, but use XSAVE extended state.  */
292 
293 static void
294 i386fbsd_supply_xstateregset (const struct regset *regset,
295 			      struct regcache *regcache, int regnum,
296 			      const void *xstateregs, size_t len)
297 {
298   i387_supply_xsave (regcache, regnum, xstateregs);
299 }
300 
301 /* Similar to i386_collect_fpregset, but use XSAVE extended state.  */
302 
303 static void
304 i386fbsd_collect_xstateregset (const struct regset *regset,
305 			       const struct regcache *regcache,
306 			       int regnum, void *xstateregs, size_t len)
307 {
308   i387_collect_xsave (regcache, regnum, xstateregs, 1);
309 }
310 
311 /* Register set definitions.  */
312 
313 static const struct regset i386fbsd_xstateregset =
314   {
315     NULL,
316     i386fbsd_supply_xstateregset,
317     i386fbsd_collect_xstateregset
318   };
319 
320 /* Iterate over core file register note sections.  */
321 
322 static void
323 i386fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
324 				       iterate_over_regset_sections_cb *cb,
325 				       void *cb_data,
326 				       const struct regcache *regcache)
327 {
328   i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
329 
330   cb (".reg", I386_FBSD_SIZEOF_GREGSET, I386_FBSD_SIZEOF_GREGSET,
331       &i386_fbsd_gregset, NULL, cb_data);
332   cb (".reg2", tdep->sizeof_fpregset, tdep->sizeof_fpregset, &i386_fpregset,
333       NULL, cb_data);
334   cb (".reg-x86-segbases", I386_FBSD_SIZEOF_SEGBASES_REGSET,
335       I386_FBSD_SIZEOF_SEGBASES_REGSET, &i386_fbsd_segbases_regset,
336       "segment bases", cb_data);
337 
338   if (tdep->xcr0 & X86_XSTATE_AVX)
339     cb (".reg-xstate", X86_XSTATE_SIZE (tdep->xcr0),
340 	X86_XSTATE_SIZE (tdep->xcr0), &i386fbsd_xstateregset,
341 	"XSAVE extended state", cb_data);
342 }
343 
344 /* Implement the get_thread_local_address gdbarch method.  */
345 
346 static CORE_ADDR
347 i386fbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid,
348 				   CORE_ADDR lm_addr, CORE_ADDR offset)
349 {
350   struct regcache *regcache;
351 
352   regcache = get_thread_arch_regcache (current_inferior ()->process_target (),
353 				       ptid, gdbarch);
354 
355   target_fetch_registers (regcache, I386_GSBASE_REGNUM);
356 
357   ULONGEST gsbase;
358   if (regcache->cooked_read (I386_GSBASE_REGNUM, &gsbase) != REG_VALID)
359     error (_("Unable to fetch %%gsbase"));
360 
361   CORE_ADDR dtv_addr = gsbase + gdbarch_ptr_bit (gdbarch) / 8;
362   return fbsd_get_thread_local_address (gdbarch, dtv_addr, lm_addr, offset);
363 }
364 
365 static void
366 i386fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
367 {
368   i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
369 
370   /* Generic FreeBSD support. */
371   fbsd_init_abi (info, gdbarch);
372 
373   /* Obviously FreeBSD is BSD-based.  */
374   i386bsd_init_abi (info, gdbarch);
375 
376   /* FreeBSD reserves some space for its FPU emulator in
377      `struct fpreg'.  */
378   tdep->sizeof_fpregset = 176;
379 
380   /* FreeBSD uses -freg-struct-return by default.  */
381   tdep->struct_return = reg_struct_return;
382 
383   tramp_frame_prepend_unwinder (gdbarch, &i386_fbsd_sigframe);
384   tramp_frame_prepend_unwinder (gdbarch, &i386_fbsd64_sigframe);
385 
386   i386_elf_init_abi (info, gdbarch);
387 
388   tdep->xsave_xcr0_offset = I386_FBSD_XSAVE_XCR0_OFFSET;
389 
390   /* Iterate over core file register note sections.  */
391   set_gdbarch_iterate_over_regset_sections
392     (gdbarch, i386fbsd_iterate_over_regset_sections);
393 
394   set_gdbarch_core_read_description (gdbarch,
395 				     i386fbsd_core_read_description);
396 
397   /* FreeBSD uses SVR4-style shared libraries.  */
398   set_solib_svr4_fetch_link_map_offsets
399     (gdbarch, svr4_ilp32_fetch_link_map_offsets);
400 
401   set_gdbarch_fetch_tls_load_module_address (gdbarch,
402 					     svr4_fetch_objfile_link_map);
403   set_gdbarch_get_thread_local_address (gdbarch,
404 					i386fbsd_get_thread_local_address);
405 }
406 
407 void _initialize_i386fbsd_tdep ();
408 void
409 _initialize_i386fbsd_tdep ()
410 {
411   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_FREEBSD,
412 			  i386fbsd_init_abi);
413 }
414