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