1 1.1 christos /* GNU/Linux/Microblaze specific low level interface, for the remote server for 2 1.1 christos GDB. 3 1.1 christos Copyright (C) 1995-2025 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 #include "server.h" 21 1.1 christos #include "linux-low.h" 22 1.1 christos 23 1.1 christos #include "elf/common.h" 24 1.1 christos #include "nat/gdb_ptrace.h" 25 1.1 christos #include <endian.h> 26 1.1 christos 27 1.1 christos #include <asm/ptrace.h> 28 1.1 christos #include <sys/procfs.h> 29 1.1 christos #include <sys/ptrace.h> 30 1.1 christos 31 1.1 christos #include "gdb_proc_service.h" 32 1.1 christos 33 1.1 christos 34 1.1 christos static int microblaze_regmap[] = 35 1.1 christos {PT_GPR(0), PT_GPR(1), PT_GPR(2), PT_GPR(3), 36 1.1 christos PT_GPR(4), PT_GPR(5), PT_GPR(6), PT_GPR(7), 37 1.1 christos PT_GPR(8), PT_GPR(9), PT_GPR(10), PT_GPR(11), 38 1.1 christos PT_GPR(12), PT_GPR(13), PT_GPR(14), PT_GPR(15), 39 1.1 christos PT_GPR(16), PT_GPR(17), PT_GPR(18), PT_GPR(19), 40 1.1 christos PT_GPR(20), PT_GPR(21), PT_GPR(22), PT_GPR(23), 41 1.1 christos PT_GPR(24), PT_GPR(25), PT_GPR(26), PT_GPR(27), 42 1.1 christos PT_GPR(28), PT_GPR(29), PT_GPR(30), PT_GPR(31), 43 1.1 christos PT_PC, PT_MSR, PT_EAR, PT_ESR, 44 1.1 christos PT_FSR 45 1.1 christos }; 46 1.1 christos 47 1.1 christos 48 1.1 christos 49 1.1 christos class microblaze_target : public linux_process_target 50 1.1 christos { 51 1.1 christos public: 52 1.1 christos 53 1.1 christos const regs_info *get_regs_info () override; 54 1.1 christos 55 1.1 christos const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override; 56 1.1 christos 57 1.1 christos protected: 58 1.1 christos 59 1.1 christos void low_arch_setup () override; 60 1.1 christos 61 1.1 christos bool low_cannot_fetch_register (int regno) override; 62 1.1 christos 63 1.1 christos bool low_cannot_store_register (int regno) override; 64 1.1 christos 65 1.1 christos bool low_supports_breakpoints () override; 66 1.1 christos 67 1.1 christos CORE_ADDR low_get_pc (regcache *regcache) override; 68 1.1 christos 69 1.1 christos void low_set_pc (regcache *regcache, CORE_ADDR newpc) override; 70 1.1 christos 71 1.1 christos bool low_breakpoint_at (CORE_ADDR pc) override; 72 1.1 christos }; 73 1.1 christos 74 1.1 christos /* The singleton target ops object. */ 75 1.1 christos 76 1.1 christos static microblaze_target the_microblaze_target; 77 1.1 christos 78 1.1 christos constexpr auto microblaze_num_regs 79 1.1 christos = sizeof (microblaze_regmap) / sizeof (microblaze_regmap[0]); 80 1.1 christos 81 1.1 christos /* Defined in auto-generated file microblaze-linux-generated.c. */ 82 1.1 christos void init_registers_microblaze_linux (); 83 1.1 christos extern const target_desc *tdesc_microblaze_linux; 84 1.1 christos 85 1.1 christos bool 86 1.1 christos microblaze_target::low_supports_breakpoints () 87 1.1 christos { 88 1.1 christos return true; 89 1.1 christos } 90 1.1 christos 91 1.1 christos bool 92 1.1 christos microblaze_target::low_cannot_store_register (int regno) 93 1.1 christos { 94 1.1 christos if (microblaze_regmap[regno] == -1 || regno == 0) 95 1.1 christos return 1; 96 1.1 christos 97 1.1 christos return 0; 98 1.1 christos } 99 1.1 christos 100 1.1 christos bool 101 1.1 christos microblaze_target::low_cannot_fetch_register (int regno) 102 1.1 christos { 103 1.1 christos return 0; 104 1.1 christos } 105 1.1 christos 106 1.1 christos CORE_ADDR 107 1.1 christos microblaze_target::low_get_pc (regcache *regcache) 108 1.1 christos { 109 1.1 christos unsigned long pc; 110 1.1 christos 111 1.1 christos collect_register_by_name (regcache, "rpc", &pc); 112 1.1 christos return pc; 113 1.1 christos } 114 1.1 christos 115 1.1 christos void 116 1.1 christos microblaze_target::low_set_pc (regcache *regcache, CORE_ADDR pc) 117 1.1 christos { 118 1.1 christos unsigned long newpc = pc; 119 1.1 christos 120 1.1 christos supply_register_by_name (regcache, "rpc", &newpc); 121 1.1 christos } 122 1.1 christos 123 1.1 christos /* dbtrap insn */ 124 1.1 christos /* brki r16, 0x18; */ 125 1.1 christos static const uint32_t microblaze_breakpoint = 0xba0c0018; 126 1.1 christos #define microblaze_breakpoint_len 4 127 1.1 christos 128 1.1 christos const gdb_byte * 129 1.1 christos microblaze_target::sw_breakpoint_from_kind (int kind, int *size) 130 1.1 christos { 131 1.1 christos *size = microblaze_breakpoint_len; 132 1.1 christos return reinterpret_cast<const gdb_byte *> (µblaze_breakpoint); 133 1.1 christos } 134 1.1 christos 135 1.1 christos bool 136 1.1 christos microblaze_target::low_breakpoint_at (CORE_ADDR where) 137 1.1 christos { 138 1.1 christos uint32_t insn; 139 1.1 christos 140 1.1 christos read_memory (where, (unsigned char *) &insn, 4); 141 1.1 christos /* If necessary, recognize more trap instructions here. GDB only uses the 142 1.1 christos one. */ 143 1.1 christos return insn == microblaze_breakpoint; 144 1.1 christos } 145 1.1 christos 146 1.1 christos #ifdef HAVE_PTRACE_GETREGS 147 1.1 christos 148 1.1 christos static void 149 1.1 christos microblaze_collect_ptrace_register (struct regcache *regcache, int regno, 150 1.1 christos char *buf) 151 1.1 christos { 152 1.1 christos memset (buf, 0, sizeof (long)); 153 1.1 christos 154 1.1 christos if (__BYTE_ORDER == __LITTLE_ENDIAN) 155 1.1 christos { 156 1.1 christos collect_register (regcache, regno, buf); 157 1.1 christos } 158 1.1 christos else if (__BYTE_ORDER == __BIG_ENDIAN) 159 1.1 christos { 160 1.1 christos int size = register_size (regcache->tdesc, regno); 161 1.1 christos 162 1.1 christos if (size < sizeof (long)) 163 1.1 christos collect_register (regcache, regno, buf + sizeof (long) - size); 164 1.1 christos else 165 1.1 christos collect_register (regcache, regno, buf); 166 1.1 christos } 167 1.1 christos } 168 1.1 christos 169 1.1 christos /* Collect GPRs from REGCACHE into BUF. */ 170 1.1 christos 171 1.1 christos static void microblaze_fill_gregset (struct regcache *regcache, void *buf) 172 1.1 christos { 173 1.1 christos int i; 174 1.1 christos 175 1.1 christos for (i = 0; i < microblaze_num_regs; i++) 176 1.1 christos microblaze_collect_ptrace_register (regcache, i, 177 1.1 christos (char *) buf + microblaze_regmap[i]); 178 1.1 christos } 179 1.1 christos 180 1.1 christos /* Supply GPRs from BUF into REGCACHE. */ 181 1.1 christos 182 1.1 christos static void 183 1.1 christos microblaze_store_gregset (struct regcache *regcache, const void *buf) 184 1.1 christos { 185 1.1 christos int i; 186 1.1 christos 187 1.1 christos for (i = 0; i < microblaze_num_regs; i++) 188 1.1 christos supply_register (regcache, i, (char *) buf + microblaze_regmap[i]); 189 1.1 christos } 190 1.1 christos 191 1.1 christos static struct regset_info microblaze_regsets[] = { 192 1.1 christos { PTRACE_GETREGS, PTRACE_SETREGS, NT_PRSTATUS, 193 1.1 christos sizeof (elf_gregset_t), GENERAL_REGS, 194 1.1 christos microblaze_fill_gregset, microblaze_store_gregset 195 1.1 christos }, 196 1.1 christos NULL_REGSET 197 1.1 christos }; 198 1.1 christos #endif /* HAVE_PTRACE_GETREGS */ 199 1.1 christos 200 1.1 christos static struct usrregs_info microblaze_usrregs_info = 201 1.1 christos { 202 1.1 christos microblaze_num_regs, 203 1.1 christos microblaze_regmap, 204 1.1 christos }; 205 1.1 christos 206 1.1 christos #ifdef HAVE_PTRACE_GETREGS 207 1.1 christos static struct regsets_info microblaze_regsets_info = 208 1.1 christos { 209 1.1 christos microblaze_regsets, /* regsets */ 210 1.1 christos 0, /* num_regsets */ 211 1.1 christos nullptr /* disabled_regsets */ 212 1.1 christos }; 213 1.1 christos #endif /* HAVE_PTRACE_GETREGS */ 214 1.1 christos 215 1.1 christos static struct regs_info microblaze_regs_info = 216 1.1 christos { 217 1.1 christos nullptr, /* regset_bitmap */ 218 1.1 christos µblaze_usrregs_info, 219 1.1 christos #ifdef HAVE_PTRACE_GETREGS 220 1.1 christos µblaze_regsets_info 221 1.1 christos #endif /* HAVE_PTRACE_GETREGS */ 222 1.1 christos }; 223 1.1 christos 224 1.1 christos const regs_info * 225 1.1 christos microblaze_target::get_regs_info () 226 1.1 christos { 227 1.1 christos return µblaze_regs_info; 228 1.1 christos } 229 1.1 christos 230 1.1 christos void 231 1.1 christos microblaze_target::low_arch_setup () 232 1.1 christos { 233 1.1 christos current_process ()->tdesc = tdesc_microblaze_linux; 234 1.1 christos } 235 1.1 christos 236 1.1 christos linux_process_target *the_linux_target = &the_microblaze_target; 237 1.1 christos 238 1.1 christos void 239 1.1 christos initialize_low_arch () 240 1.1 christos { 241 1.1 christos init_registers_microblaze_linux (); 242 1.1 christos #ifdef HAVE_PTRACE_GETREGS 243 1.1 christos initialize_regsets_info (µblaze_regsets_info); 244 1.1 christos #endif /* HAVE_PTRACE_GETREGS */ 245 1.1 christos } 246