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