1 /* Target-dependent code for NetBSD/arm. 2 3 Copyright (C) 2002-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 23 #include "arch/arm.h" 24 #include "arm-netbsd-tdep.h" 25 #include "netbsd-tdep.h" 26 #include "arm-tdep.h" 27 #include "regset.h" 28 #include "solib-svr4.h" 29 30 /* Description of the longjmp buffer. */ 31 #define ARM_NBSD_JB_PC 24 32 #define ARM_NBSD_JB_ELEMENT_SIZE ARM_INT_REGISTER_SIZE 33 34 /* For compatibility with previous implementations of GDB on arm/NetBSD, 35 override the default little-endian breakpoint. */ 36 static const gdb_byte arm_nbsd_arm_le_breakpoint[] = {0x11, 0x00, 0x00, 0xe6}; 37 static const gdb_byte arm_nbsd_arm_be_breakpoint[] = {0xe6, 0x00, 0x00, 0x11}; 38 static const gdb_byte arm_nbsd_thumb_le_breakpoint[] = {0xfe, 0xde}; 39 static const gdb_byte arm_nbsd_thumb_be_breakpoint[] = {0xde, 0xfe}; 40 41 /* This matches struct reg from NetBSD's sys/arch/arm/include/reg.h: 42 https://github.com/NetBSD/src/blob/7c13e6e6773bb171f4ed3ed53013e9d24b3c1eac/sys/arch/arm/include/reg.h#L39 43 */ 44 struct arm_nbsd_reg 45 { 46 uint32_t reg[13]; 47 uint32_t sp; 48 uint32_t lr; 49 uint32_t pc; 50 uint32_t cpsr; 51 }; 52 53 void 54 arm_nbsd_supply_gregset (const struct regset *regset, struct regcache *regcache, 55 int regnum, const void *gregs, size_t len) 56 { 57 const arm_nbsd_reg *gregset = static_cast<const arm_nbsd_reg *>(gregs); 58 gdb_assert (len >= sizeof (arm_nbsd_reg)); 59 60 /* Integer registers. */ 61 for (int i = ARM_A1_REGNUM; i < ARM_SP_REGNUM; i++) 62 if (regnum == -1 || regnum == i) 63 regcache->raw_supply (i, (char *) &gregset->reg[i]); 64 65 if (regnum == -1 || regnum == ARM_SP_REGNUM) 66 regcache->raw_supply (ARM_SP_REGNUM, (char *) &gregset->sp); 67 68 if (regnum == -1 || regnum == ARM_LR_REGNUM) 69 regcache->raw_supply (ARM_LR_REGNUM, (char *) &gregset->lr); 70 71 if (regnum == -1 || regnum == ARM_PC_REGNUM) 72 { 73 /* XXX Use uint32_t instead of CORE_ADDR (aka uint64_t; see 74 gdbsupport/common-types.h). Otherwise, zero-filled word 75 will be stored for big-endian targets. */ 76 uint32_t r_pc = gdbarch_addr_bits_remove (regcache->arch (), gregset->pc); 77 regcache->raw_supply (ARM_PC_REGNUM, (char *) &r_pc); 78 } 79 80 if (regnum == -1 || regnum == ARM_PS_REGNUM) 81 { 82 if (arm_apcs_32) 83 regcache->raw_supply (ARM_PS_REGNUM, (char *) &gregset->cpsr); 84 else 85 regcache->raw_supply (ARM_PS_REGNUM, (char *) &gregset->pc); 86 } 87 } 88 89 static const struct regset arm_nbsd_regset = { 90 nullptr, 91 arm_nbsd_supply_gregset, 92 /* We don't need a collect function because we only use this reading registers 93 (via iterate_over_regset_sections and fetch_regs/fetch_register). */ 94 nullptr, 95 0 96 }; 97 98 static void 99 arm_nbsd_iterate_over_regset_sections (struct gdbarch *gdbarch, 100 iterate_over_regset_sections_cb *cb, 101 void *cb_data, 102 const struct regcache *regcache) 103 { 104 cb (".reg", sizeof (arm_nbsd_reg), sizeof (arm_nbsd_reg), &arm_nbsd_regset, 105 NULL, cb_data); 106 /* cbiesinger/2020-02-12 -- as far as I can tell, ARM/NetBSD does 107 not write any floating point registers into the core file (tested 108 with NetBSD 9.1_RC1). When it does, this function will need to read them, 109 and the arm-netbsd gdbarch will need a core_read_description function 110 to return the right description for them. */ 111 } 112 113 static void 114 arm_netbsd_init_abi_common (struct gdbarch_info info, 115 struct gdbarch *gdbarch) 116 { 117 arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (gdbarch); 118 119 tdep->lowest_pc = 0x8000; 120 /* For armv[67]eb (BE8), insns are encoded in little-endian. 121 Therefore, we cannot use info.byte_order here. */ 122 switch (info.byte_order_for_code) 123 { 124 case BFD_ENDIAN_LITTLE: 125 tdep->arm_breakpoint = arm_nbsd_arm_le_breakpoint; 126 tdep->thumb_breakpoint = arm_nbsd_thumb_le_breakpoint; 127 tdep->arm_breakpoint_size = sizeof (arm_nbsd_arm_le_breakpoint); 128 tdep->thumb_breakpoint_size = sizeof (arm_nbsd_thumb_le_breakpoint); 129 break; 130 131 case BFD_ENDIAN_BIG: 132 tdep->arm_breakpoint = arm_nbsd_arm_be_breakpoint; 133 tdep->thumb_breakpoint = arm_nbsd_thumb_be_breakpoint; 134 tdep->arm_breakpoint_size = sizeof (arm_nbsd_arm_be_breakpoint); 135 tdep->thumb_breakpoint_size = sizeof (arm_nbsd_thumb_be_breakpoint); 136 break; 137 138 default: 139 internal_error (_("arm_gdbarch_init: bad byte order for float format")); 140 } 141 142 tdep->jb_pc = ARM_NBSD_JB_PC; 143 tdep->jb_elt_size = ARM_NBSD_JB_ELEMENT_SIZE; 144 145 set_gdbarch_iterate_over_regset_sections 146 (gdbarch, arm_nbsd_iterate_over_regset_sections); 147 /* Single stepping. */ 148 set_gdbarch_software_single_step (gdbarch, arm_software_single_step); 149 } 150 151 static void 152 arm_netbsd_elf_init_abi (struct gdbarch_info info, 153 struct gdbarch *gdbarch) 154 { 155 arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (gdbarch); 156 157 arm_netbsd_init_abi_common (info, gdbarch); 158 159 nbsd_init_abi (info, gdbarch); 160 161 if (tdep->fp_model == ARM_FLOAT_AUTO) 162 tdep->fp_model = ARM_FLOAT_SOFT_VFP; 163 164 /* NetBSD ELF uses SVR4-style shared libraries. */ 165 set_solib_svr4_fetch_link_map_offsets 166 (gdbarch, svr4_ilp32_fetch_link_map_offsets); 167 } 168 169 void _initialize_arm_netbsd_tdep (); 170 void 171 _initialize_arm_netbsd_tdep () 172 { 173 gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_NETBSD, 174 arm_netbsd_elf_init_abi); 175 } 176