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