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