1 /* GNU/Linux/MIPS specific low level interface, for the remote server for GDB. 2 Copyright (C) 2022-2023 Free Software Foundation, Inc. 3 4 This file is part of GDB. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18 19 #include "server.h" 20 #include "tdesc.h" 21 #include "linux-low.h" 22 #include <sys/ptrace.h> 23 #include "gdb_proc_service.h" 24 #include <asm/ptrace.h> 25 #include <elf.h> 26 #include "arch/csky.h" 27 28 /* Linux target op definitions for the CSKY architecture. */ 29 30 class csky_target : public linux_process_target 31 { 32 public: 33 34 const regs_info *get_regs_info () override; 35 36 const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override; 37 38 bool supports_z_point_type (char z_type) override; 39 40 bool supports_hardware_single_step () override; 41 42 protected: 43 44 void low_arch_setup () override; 45 46 bool low_cannot_fetch_register (int regno) override; 47 48 bool low_cannot_store_register (int regno) override; 49 50 CORE_ADDR low_get_pc (regcache *regcache) override; 51 52 void low_set_pc (regcache *regcache, CORE_ADDR newpc) override; 53 54 bool low_breakpoint_at (CORE_ADDR pc) override; 55 }; 56 57 /* The singleton target ops object. */ 58 59 static csky_target the_csky_target; 60 61 /* Return the ptrace "address" of register REGNO. */ 62 static int csky_regmap[] = { 63 0*4, 1*4, 2*4, 3*4, 4*4, 5*4, 6*4, 7*4, 64 8*4, 9*4, 10*4, 11*4, 12*4, 13*4, 14*4, 15*4, 65 16*4, 17*4, 18*4, 19*4, 20*4, 21*4, 22*4, 23*4, 66 24*4, 25*4, 26*4, 27*4, 28*4, 29*4, 30*4, 31*4, 67 -1, -1, -1, -1, 34*4, 35*4, -1, -1, 68 40*4, 42*4, 44*4, 46*4, 48*4, 50*4, 52*4, 54*4, /* fr0 ~ fr15, 64bit */ 69 56*4, 58*4, 60*4, 62*4, 64*4, 66*4, 68*4, 70*4, 70 72*4, 76*4, 80*4, 84*4, 88*4, 92*4, 96*4,100*4, /* vr0 ~ vr15, 128bit */ 71 104*4,108*4,112*4,116*4,120*4,124*4,128*4,132*4, 72 33*4, /* pc */ 73 -1, -1, -1, -1, -1, -1, -1, -1, 74 -1, -1, -1, -1, -1, -1, -1, -1, 75 32*4, -1, -1, -1, -1, -1, -1, -1, /* psr */ 76 -1, -1, -1, -1, -1, -1, -1, -1, 77 -1, -1, -1, -1, -1, -1, -1, -1, 78 -1, -1, -1, -1, -1, -1, -1, -1, 79 73*4, 72*4, 74*4, -1, -1, -1, 14*4, /* fcr, fid, fesr, usp */ 80 }; 81 82 /* CSKY software breakpoint instruction code. */ 83 84 /* When the kernel code version is behind v4.x, 85 illegal insn 0x1464 will be a software bkpt trigger. 86 When an illegal insn exception happens, the case 87 that insn at EPC is 0x1464 will be recognized as SIGTRAP. */ 88 static unsigned short csky_breakpoint_illegal_2_v2 = 0x1464; 89 static unsigned int csky_breakpoint_illegal_4_v2 = 0x14641464; 90 91 bool 92 csky_target::low_cannot_fetch_register (int regno) 93 { 94 if (csky_regmap[regno] == -1) 95 return true; 96 97 return false; 98 } 99 100 bool 101 csky_target::low_cannot_store_register (int regno) 102 { 103 if (csky_regmap[regno] == -1) 104 return true; 105 106 return false; 107 } 108 109 /* Get the value of pc register. */ 110 111 CORE_ADDR 112 csky_target::low_get_pc (struct regcache *regcache) 113 { 114 unsigned long pc; 115 collect_register_by_name (regcache, "pc", &pc); 116 return pc; 117 } 118 119 /* Set pc register. */ 120 121 void 122 csky_target::low_set_pc (struct regcache *regcache, CORE_ADDR pc) 123 { 124 unsigned long new_pc = pc; 125 supply_register_by_name (regcache, "pc", &new_pc); 126 } 127 128 129 void 130 csky_target::low_arch_setup () 131 { 132 static const char *expedite_regs[] = { "r14", "pc", NULL }; 133 target_desc_up tdesc = csky_create_target_description (); 134 135 if (!tdesc->expedite_regs) 136 init_target_desc (tdesc.get (), expedite_regs); 137 138 current_process ()->tdesc = tdesc.release (); 139 140 return; 141 } 142 143 /* Fetch the thread-local storage pointer for libthread_db. */ 144 145 ps_err_e 146 ps_get_thread_area (struct ps_prochandle *ph, 147 lwpid_t lwpid, int idx, void **base) 148 { 149 struct pt_regs regset; 150 if (ptrace (PTRACE_GETREGSET, lwpid, 151 (PTRACE_TYPE_ARG3) (long) NT_PRSTATUS, ®set) != 0) 152 return PS_ERR; 153 154 *base = (void *) regset.tls; 155 156 /* IDX is the bias from the thread pointer to the beginning of the 157 thread descriptor. It has to be subtracted due to implementation 158 quirks in libthread_db. */ 159 *base = (void *) ((char *)*base - idx); 160 161 return PS_OK; 162 } 163 164 /* Gdbserver uses PTRACE_GET/SET_RGESET. */ 165 166 static void 167 csky_fill_pt_gregset (struct regcache *regcache, void *buf) 168 { 169 int i, base; 170 struct pt_regs *regset = (struct pt_regs *)buf; 171 172 collect_register_by_name (regcache, "r15", ®set->lr); 173 collect_register_by_name (regcache, "pc", ®set->pc); 174 collect_register_by_name (regcache, "psr", ®set->sr); 175 collect_register_by_name (regcache, "r14", ®set->usp); 176 177 collect_register_by_name (regcache, "r0", ®set->a0); 178 collect_register_by_name (regcache, "r1", ®set->a1); 179 collect_register_by_name (regcache, "r2", ®set->a2); 180 collect_register_by_name (regcache, "r3", ®set->a3); 181 182 base = find_regno (regcache->tdesc, "r4"); 183 184 for (i = 0; i < 10; i++) 185 collect_register (regcache, base + i, ®set->regs[i]); 186 187 base = find_regno (regcache->tdesc, "r16"); 188 for (i = 0; i < 16; i++) 189 collect_register (regcache, base + i, ®set->exregs[i]); 190 191 collect_register_by_name (regcache, "hi", ®set->rhi); 192 collect_register_by_name (regcache, "lo", ®set->rlo); 193 } 194 195 static void 196 csky_store_pt_gregset (struct regcache *regcache, const void *buf) 197 { 198 int i, base; 199 const struct pt_regs *regset = (const struct pt_regs *) buf; 200 201 supply_register_by_name (regcache, "r15", ®set->lr); 202 supply_register_by_name (regcache, "pc", ®set->pc); 203 supply_register_by_name (regcache, "psr", ®set->sr); 204 supply_register_by_name (regcache, "r14", ®set->usp); 205 206 supply_register_by_name (regcache, "r0", ®set->a0); 207 supply_register_by_name (regcache, "r1", ®set->a1); 208 supply_register_by_name (regcache, "r2", ®set->a2); 209 supply_register_by_name (regcache, "r3", ®set->a3); 210 211 base = find_regno (regcache->tdesc, "r4"); 212 213 for (i = 0; i < 10; i++) 214 supply_register (regcache, base + i, ®set->regs[i]); 215 216 base = find_regno (regcache->tdesc, "r16"); 217 for (i = 0; i < 16; i++) 218 supply_register (regcache, base + i, ®set->exregs[i]); 219 220 supply_register_by_name (regcache, "hi", ®set->rhi); 221 supply_register_by_name (regcache, "lo", ®set->rlo); 222 } 223 224 static void 225 csky_fill_pt_vrregset (struct regcache *regcache, void *buf) 226 { 227 int i, base; 228 struct user_fp *regset = (struct user_fp *)buf; 229 230 base = find_regno (regcache->tdesc, "vr0"); 231 232 for (i = 0; i < 16; i++) 233 collect_register (regcache, base + i, ®set->vr[i * 4]); 234 collect_register_by_name (regcache, "fcr", ®set->fcr); 235 collect_register_by_name (regcache, "fesr", ®set->fesr); 236 collect_register_by_name (regcache, "fid", ®set->fid); 237 } 238 239 240 static void 241 csky_store_pt_vrregset (struct regcache *regcache, const void *buf) 242 { 243 int i, base; 244 const struct user_fp *regset = (const struct user_fp *)buf; 245 246 base = find_regno (regcache->tdesc, "vr0"); 247 248 for (i = 0; i < 16; i++) 249 supply_register (regcache, base + i, ®set->vr[i * 4]); 250 251 base = find_regno (regcache->tdesc, "fr0"); 252 253 for (i = 0; i < 16; i++) 254 supply_register (regcache, base + i, ®set->vr[i * 4]); 255 supply_register_by_name (regcache, "fcr", ®set->fcr); 256 supply_register_by_name (regcache, "fesr", ®set->fesr); 257 supply_register_by_name (regcache, "fid", ®set->fid); 258 } 259 260 struct regset_info csky_regsets[] = { 261 { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, sizeof(struct pt_regs), 262 GENERAL_REGS, csky_fill_pt_gregset, csky_store_pt_gregset}, 263 264 { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET, sizeof(struct user_fp), 265 FP_REGS, csky_fill_pt_vrregset, csky_store_pt_vrregset}, 266 NULL_REGSET 267 }; 268 269 270 static struct regsets_info csky_regsets_info = 271 { 272 csky_regsets, /* Regsets */ 273 0, /* Num_regsets */ 274 NULL, /* Disabled_regsets */ 275 }; 276 277 278 static struct regs_info csky_regs_info = 279 { 280 NULL, /* FIXME: what's this */ 281 NULL, /* PEEKUSER/PORKUSR isn't supported by kernel > 4.x */ 282 &csky_regsets_info 283 }; 284 285 286 const regs_info * 287 csky_target::get_regs_info () 288 { 289 return &csky_regs_info; 290 } 291 292 /* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ 293 294 const gdb_byte * 295 csky_target::sw_breakpoint_from_kind (int kind, int *size) 296 { 297 if (kind == 4) 298 { 299 *size = 4; 300 return (const gdb_byte *) &csky_breakpoint_illegal_4_v2; 301 } 302 else 303 { 304 *size = 2; 305 return (const gdb_byte *) &csky_breakpoint_illegal_2_v2; 306 } 307 } 308 309 bool 310 csky_target::supports_z_point_type (char z_type) 311 { 312 /* FIXME: hardware breakpoint support ?? */ 313 if (z_type == Z_PACKET_SW_BP) 314 return true; 315 316 return false; 317 } 318 319 bool 320 csky_target::low_breakpoint_at (CORE_ADDR where) 321 { 322 unsigned int insn; 323 324 /* Here just read 2 bytes, as csky_breakpoint_illegal_4_v2 325 is double of csky_breakpoint_illegal_2_v2, csky_breakpoint_bkpt_4 326 is double of csky_breakpoint_bkpt_2. Others are 2 bytes bkpt. */ 327 read_memory (where, (unsigned char *) &insn, 2); 328 329 if (insn == csky_breakpoint_illegal_2_v2) 330 return true; 331 332 return false; 333 } 334 335 /* Support for hardware single step. */ 336 337 bool 338 csky_target::supports_hardware_single_step () 339 { 340 return true; 341 } 342 343 /* The linux target ops object. */ 344 345 linux_process_target *the_linux_target = &the_csky_target; 346 347 void 348 initialize_low_arch (void) 349 { 350 initialize_regsets_info (&csky_regsets_info); 351 } 352