1 /* Target-dependent code for FreeBSD/arm. 2 3 Copyright (C) 2017-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 21 #include "elf/common.h" 22 #include "target-descriptions.h" 23 #include "aarch32-tdep.h" 24 #include "arm-tdep.h" 25 #include "arm-fbsd-tdep.h" 26 #include "auxv.h" 27 #include "fbsd-tdep.h" 28 #include "gdbcore.h" 29 #include "inferior.h" 30 #include "osabi.h" 31 #include "solib-svr4.h" 32 #include "trad-frame.h" 33 #include "tramp-frame.h" 34 35 /* Register maps. */ 36 37 static const struct regcache_map_entry arm_fbsd_gregmap[] = 38 { 39 { 13, ARM_A1_REGNUM, 4 }, /* r0 ... r12 */ 40 { 1, ARM_SP_REGNUM, 4 }, 41 { 1, ARM_LR_REGNUM, 4 }, 42 { 1, ARM_PC_REGNUM, 4 }, 43 { 1, ARM_PS_REGNUM, 4 }, 44 { 0 } 45 }; 46 47 static const struct regcache_map_entry arm_fbsd_vfpregmap[] = 48 { 49 { 32, ARM_D0_REGNUM, 8 }, /* d0 ... d31 */ 50 { 1, ARM_FPSCR_REGNUM, 4 }, 51 { 0 } 52 }; 53 54 /* Register numbers are relative to tdep->tls_regnum. */ 55 56 static const struct regcache_map_entry arm_fbsd_tls_regmap[] = 57 { 58 { 1, 0, 4 }, /* tpidruro */ 59 { 0 } 60 }; 61 62 /* In a signal frame, sp points to a 'struct sigframe' which is 63 defined as: 64 65 struct sigframe { 66 siginfo_t sf_si; 67 ucontext_t sf_uc; 68 mcontext_vfp_t sf_vfp; 69 }; 70 71 ucontext_t is defined as: 72 73 struct __ucontext { 74 sigset_t uc_sigmask; 75 mcontext_t uc_mcontext; 76 ... 77 }; 78 79 mcontext_t is defined as: 80 81 struct { 82 unsigned int __gregs[17]; 83 size_t mc_vfp_size; 84 void *mc_vfp_ptr; 85 ... 86 }; 87 88 mcontext_vfp_t is defined as: 89 90 struct { 91 uint64_t mcv_reg[32]; 92 uint32_t mcv_fpscr; 93 }; 94 95 If the VFP state is valid, then mc_vfp_ptr will point to sf_vfp in 96 the sigframe, otherwise it is NULL. There is no non-VFP floating 97 point register state saved in the signal frame. */ 98 99 #define ARM_SIGFRAME_UCONTEXT_OFFSET 64 100 #define ARM_UCONTEXT_MCONTEXT_OFFSET 16 101 #define ARM_MCONTEXT_VFP_PTR_OFFSET 72 102 103 /* Implement the "init" method of struct tramp_frame. */ 104 105 static void 106 arm_fbsd_sigframe_init (const struct tramp_frame *self, 107 const frame_info_ptr &this_frame, 108 struct trad_frame_cache *this_cache, 109 CORE_ADDR func) 110 { 111 struct gdbarch *gdbarch = get_frame_arch (this_frame); 112 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); 113 CORE_ADDR sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM); 114 CORE_ADDR mcontext_addr = (sp 115 + ARM_SIGFRAME_UCONTEXT_OFFSET 116 + ARM_UCONTEXT_MCONTEXT_OFFSET); 117 ULONGEST mcontext_vfp_addr; 118 119 trad_frame_set_reg_regmap (this_cache, arm_fbsd_gregmap, mcontext_addr, 120 regcache_map_entry_size (arm_fbsd_gregmap)); 121 122 if (safe_read_memory_unsigned_integer (mcontext_addr 123 + ARM_MCONTEXT_VFP_PTR_OFFSET, 4, 124 byte_order, 125 &mcontext_vfp_addr) 126 && mcontext_vfp_addr != 0) 127 trad_frame_set_reg_regmap (this_cache, arm_fbsd_vfpregmap, mcontext_vfp_addr, 128 regcache_map_entry_size (arm_fbsd_vfpregmap)); 129 130 trad_frame_set_id (this_cache, frame_id_build (sp, func)); 131 } 132 133 static const struct tramp_frame arm_fbsd_sigframe = 134 { 135 SIGTRAMP_FRAME, 136 4, 137 { 138 {0xe1a0000d, ULONGEST_MAX}, /* mov r0, sp */ 139 {0xe2800040, ULONGEST_MAX}, /* add r0, r0, #SIGF_UC */ 140 {0xe59f700c, ULONGEST_MAX}, /* ldr r7, [pc, #12] */ 141 {0xef0001a1, ULONGEST_MAX}, /* swi SYS_sigreturn */ 142 {TRAMP_SENTINEL_INSN, ULONGEST_MAX} 143 }, 144 arm_fbsd_sigframe_init 145 }; 146 147 /* Register set definitions. */ 148 149 const struct regset arm_fbsd_gregset = 150 { 151 arm_fbsd_gregmap, 152 regcache_supply_regset, regcache_collect_regset 153 }; 154 155 const struct regset arm_fbsd_vfpregset = 156 { 157 arm_fbsd_vfpregmap, 158 regcache_supply_regset, regcache_collect_regset 159 }; 160 161 static void 162 arm_fbsd_supply_tls_regset (const struct regset *regset, 163 struct regcache *regcache, 164 int regnum, const void *buf, size_t size) 165 { 166 struct gdbarch *gdbarch = regcache->arch (); 167 arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (gdbarch); 168 169 regcache->supply_regset (regset, tdep->tls_regnum, regnum, buf, size); 170 } 171 172 static void 173 arm_fbsd_collect_tls_regset (const struct regset *regset, 174 const struct regcache *regcache, 175 int regnum, void *buf, size_t size) 176 { 177 struct gdbarch *gdbarch = regcache->arch (); 178 arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (gdbarch); 179 180 regcache->collect_regset (regset, tdep->tls_regnum, regnum, buf, size); 181 } 182 183 const struct regset arm_fbsd_tls_regset = 184 { 185 arm_fbsd_tls_regmap, 186 arm_fbsd_supply_tls_regset, arm_fbsd_collect_tls_regset 187 }; 188 189 /* Implement the "iterate_over_regset_sections" gdbarch method. */ 190 191 static void 192 arm_fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch, 193 iterate_over_regset_sections_cb *cb, 194 void *cb_data, 195 const struct regcache *regcache) 196 { 197 arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (gdbarch); 198 199 cb (".reg", ARM_FBSD_SIZEOF_GREGSET, ARM_FBSD_SIZEOF_GREGSET, 200 &arm_fbsd_gregset, NULL, cb_data); 201 202 if (tdep->tls_regnum > 0) 203 cb (".reg-aarch-tls", ARM_FBSD_SIZEOF_TLSREGSET, ARM_FBSD_SIZEOF_TLSREGSET, 204 &arm_fbsd_tls_regset, NULL, cb_data); 205 206 /* While FreeBSD/arm cores do contain a NT_FPREGSET / ".reg2" 207 register set, it is not populated with register values by the 208 kernel but just contains all zeroes. */ 209 if (tdep->vfp_register_count > 0) 210 cb (".reg-arm-vfp", ARM_FBSD_SIZEOF_VFPREGSET, ARM_FBSD_SIZEOF_VFPREGSET, 211 &arm_fbsd_vfpregset, "VFP floating-point", cb_data); 212 } 213 214 /* See arm-fbsd-tdep.h. */ 215 216 const struct target_desc * 217 arm_fbsd_read_description_auxv (const std::optional<gdb::byte_vector> &auxv, 218 target_ops *target, gdbarch *gdbarch, bool tls) 219 { 220 CORE_ADDR arm_hwcap = 0; 221 222 if (!auxv.has_value () 223 || target_auxv_search (*auxv, target, gdbarch, AT_FREEBSD_HWCAP, 224 &arm_hwcap) != 1) 225 return arm_read_description (ARM_FP_TYPE_NONE, tls); 226 227 if (arm_hwcap & HWCAP_VFP) 228 { 229 if (arm_hwcap & HWCAP_NEON) 230 return aarch32_read_description (tls); 231 else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPD32)) 232 == (HWCAP_VFPv3 | HWCAP_VFPD32)) 233 return arm_read_description (ARM_FP_TYPE_VFPV3, tls); 234 else 235 return arm_read_description (ARM_FP_TYPE_VFPV2, tls); 236 } 237 238 return arm_read_description (ARM_FP_TYPE_NONE, tls); 239 } 240 241 /* See arm-fbsd-tdep.h. */ 242 243 const struct target_desc * 244 arm_fbsd_read_description_auxv (bool tls) 245 { 246 const std::optional<gdb::byte_vector> &auxv = target_read_auxv (); 247 return arm_fbsd_read_description_auxv (auxv, 248 current_inferior ()->top_target (), 249 current_inferior ()->arch (), 250 tls); 251 } 252 253 /* Implement the "core_read_description" gdbarch method. */ 254 255 static const struct target_desc * 256 arm_fbsd_core_read_description (struct gdbarch *gdbarch, 257 struct target_ops *target, 258 bfd *abfd) 259 { 260 asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls"); 261 262 std::optional<gdb::byte_vector> auxv = target_read_auxv_raw (target); 263 return arm_fbsd_read_description_auxv (auxv, target, gdbarch, tls != nullptr); 264 } 265 266 /* Implement the get_thread_local_address gdbarch method. */ 267 268 static CORE_ADDR 269 arm_fbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid, 270 CORE_ADDR lm_addr, CORE_ADDR offset) 271 { 272 arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (gdbarch); 273 regcache *regcache 274 = get_thread_arch_regcache (current_inferior (), ptid, gdbarch); 275 276 target_fetch_registers (regcache, tdep->tls_regnum); 277 278 ULONGEST tpidruro; 279 if (regcache->cooked_read (tdep->tls_regnum, &tpidruro) != REG_VALID) 280 error (_("Unable to fetch %%tpidruro")); 281 282 /* %tpidruro points to the TCB whose first member is the dtv 283 pointer. */ 284 CORE_ADDR dtv_addr = tpidruro; 285 return fbsd_get_thread_local_address (gdbarch, dtv_addr, lm_addr, offset); 286 } 287 288 /* Implement the 'init_osabi' method of struct gdb_osabi_handler. */ 289 290 static void 291 arm_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 292 { 293 arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (gdbarch); 294 295 /* Generic FreeBSD support. */ 296 fbsd_init_abi (info, gdbarch); 297 298 if (tdep->fp_model == ARM_FLOAT_AUTO) 299 tdep->fp_model = ARM_FLOAT_SOFT_VFP; 300 301 tramp_frame_prepend_unwinder (gdbarch, &arm_fbsd_sigframe); 302 303 set_solib_svr4_fetch_link_map_offsets 304 (gdbarch, svr4_ilp32_fetch_link_map_offsets); 305 306 tdep->jb_pc = 24; 307 tdep->jb_elt_size = 4; 308 309 set_gdbarch_iterate_over_regset_sections 310 (gdbarch, arm_fbsd_iterate_over_regset_sections); 311 set_gdbarch_core_read_description (gdbarch, arm_fbsd_core_read_description); 312 313 if (tdep->tls_regnum > 0) 314 { 315 set_gdbarch_fetch_tls_load_module_address (gdbarch, 316 svr4_fetch_objfile_link_map); 317 set_gdbarch_get_thread_local_address (gdbarch, 318 arm_fbsd_get_thread_local_address); 319 } 320 321 /* Single stepping. */ 322 set_gdbarch_software_single_step (gdbarch, arm_software_single_step); 323 } 324 325 void _initialize_arm_fbsd_tdep (); 326 void 327 _initialize_arm_fbsd_tdep () 328 { 329 gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_FREEBSD, 330 arm_fbsd_init_abi); 331 } 332