1 1.1 christos /* Target dependent code for GDB on TI C6x systems. 2 1.1 christos 3 1.1.1.4 christos Copyright (C) 2010-2025 Free Software Foundation, Inc. 4 1.1 christos Contributed by Andrew Jenner <andrew (at) codesourcery.com> 5 1.1 christos Contributed by Yao Qi <yao (at) codesourcery.com> 6 1.1 christos 7 1.1 christos This file is part of GDB. 8 1.1 christos 9 1.1 christos This program is free software; you can redistribute it and/or modify 10 1.1 christos it under the terms of the GNU General Public License as published by 11 1.1 christos the Free Software Foundation; either version 3 of the License, or 12 1.1 christos (at your option) any later version. 13 1.1 christos 14 1.1 christos This program is distributed in the hope that it will be useful, 15 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 16 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 1.1 christos GNU General Public License for more details. 18 1.1 christos 19 1.1 christos You should have received a copy of the GNU General Public License 20 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 21 1.1 christos 22 1.1 christos #include "linux-low.h" 23 1.1 christos #include "arch/tic6x.h" 24 1.1 christos #include "tdesc.h" 25 1.1 christos 26 1.1 christos #include "nat/gdb_ptrace.h" 27 1.1 christos #include <endian.h> 28 1.1 christos 29 1.1 christos #include "gdb_proc_service.h" 30 1.1 christos 31 1.1 christos #ifndef PTRACE_GET_THREAD_AREA 32 1.1 christos #define PTRACE_GET_THREAD_AREA 25 33 1.1 christos #endif 34 1.1 christos 35 1.1 christos /* There are at most 69 registers accessible in ptrace. */ 36 1.1 christos #define TIC6X_NUM_REGS 69 37 1.1 christos 38 1.1 christos #include <asm/ptrace.h> 39 1.1 christos 40 1.1 christos /* Linux target op definitions for the TI C6x architecture. */ 41 1.1 christos 42 1.1 christos class tic6x_target : public linux_process_target 43 1.1 christos { 44 1.1 christos public: 45 1.1 christos 46 1.1 christos const regs_info *get_regs_info () override; 47 1.1 christos 48 1.1 christos const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override; 49 1.1 christos 50 1.1 christos protected: 51 1.1 christos 52 1.1 christos void low_arch_setup () override; 53 1.1 christos 54 1.1 christos bool low_cannot_fetch_register (int regno) override; 55 1.1 christos 56 1.1 christos bool low_cannot_store_register (int regno) override; 57 1.1 christos 58 1.1 christos bool low_supports_breakpoints () override; 59 1.1 christos 60 1.1 christos CORE_ADDR low_get_pc (regcache *regcache) override; 61 1.1 christos 62 1.1 christos void low_set_pc (regcache *regcache, CORE_ADDR newpc) override; 63 1.1 christos 64 1.1 christos bool low_breakpoint_at (CORE_ADDR pc) override; 65 1.1 christos }; 66 1.1 christos 67 1.1 christos /* The singleton target ops object. */ 68 1.1 christos 69 1.1 christos static tic6x_target the_tic6x_target; 70 1.1 christos 71 1.1 christos /* Defined in auto-generated file tic6x-c64xp-linux.c. */ 72 1.1 christos void init_registers_tic6x_c64xp_linux (void); 73 1.1 christos extern const struct target_desc *tdesc_tic6x_c64xp_linux; 74 1.1 christos 75 1.1 christos /* Defined in auto-generated file tic6x-c64x-linux.c. */ 76 1.1 christos void init_registers_tic6x_c64x_linux (void); 77 1.1 christos extern const struct target_desc *tdesc_tic6x_c64x_linux; 78 1.1 christos 79 1.1 christos /* Defined in auto-generated file tic62x-c6xp-linux.c. */ 80 1.1 christos void init_registers_tic6x_c62x_linux (void); 81 1.1 christos extern const struct target_desc *tdesc_tic6x_c62x_linux; 82 1.1 christos 83 1.1 christos union tic6x_register 84 1.1 christos { 85 1.1 christos unsigned char buf[4]; 86 1.1 christos 87 1.1 christos int reg32; 88 1.1 christos }; 89 1.1 christos 90 1.1 christos /* Return the ptrace ``address'' of register REGNO. */ 91 1.1 christos 92 1.1 christos #if __BYTE_ORDER == __BIG_ENDIAN 93 1.1 christos static int tic6x_regmap_c64xp[] = { 94 1.1 christos /* A0 - A15 */ 95 1.1 christos 53, 52, 55, 54, 57, 56, 59, 58, 96 1.1 christos 61, 60, 63, 62, 65, 64, 67, 66, 97 1.1 christos /* B0 - B15 */ 98 1.1 christos 23, 22, 25, 24, 27, 26, 29, 28, 99 1.1 christos 31, 30, 33, 32, 35, 34, 69, 68, 100 1.1 christos /* CSR PC */ 101 1.1 christos 5, 4, 102 1.1 christos /* A16 - A31 */ 103 1.1 christos 37, 36, 39, 38, 41, 40, 43, 42, 104 1.1 christos 45, 44, 47, 46, 49, 48, 51, 50, 105 1.1 christos /* B16 - B31 */ 106 1.1 christos 7, 6, 9, 8, 11, 10, 13, 12, 107 1.1 christos 15, 14, 17, 16, 19, 18, 21, 20, 108 1.1 christos /* TSR, ILC, RILC */ 109 1.1 christos 1, 2, 3 110 1.1 christos }; 111 1.1 christos 112 1.1 christos static int tic6x_regmap_c64x[] = { 113 1.1 christos /* A0 - A15 */ 114 1.1 christos 51, 50, 53, 52, 55, 54, 57, 56, 115 1.1 christos 59, 58, 61, 60, 63, 62, 65, 64, 116 1.1 christos /* B0 - B15 */ 117 1.1 christos 21, 20, 23, 22, 25, 24, 27, 26, 118 1.1 christos 29, 28, 31, 30, 33, 32, 67, 66, 119 1.1 christos /* CSR PC */ 120 1.1 christos 3, 2, 121 1.1 christos /* A16 - A31 */ 122 1.1 christos 35, 34, 37, 36, 39, 38, 41, 40, 123 1.1 christos 43, 42, 45, 44, 47, 46, 49, 48, 124 1.1 christos /* B16 - B31 */ 125 1.1 christos 5, 4, 7, 6, 9, 8, 11, 10, 126 1.1 christos 13, 12, 15, 14, 17, 16, 19, 18, 127 1.1 christos -1, -1, -1 128 1.1 christos }; 129 1.1 christos 130 1.1 christos static int tic6x_regmap_c62x[] = { 131 1.1 christos /* A0 - A15 */ 132 1.1 christos 19, 18, 21, 20, 23, 22, 25, 24, 133 1.1 christos 27, 26, 29, 28, 31, 30, 33, 32, 134 1.1 christos /* B0 - B15 */ 135 1.1 christos 5, 4, 7, 6, 9, 8, 11, 10, 136 1.1 christos 13, 12, 15, 14, 17, 16, 35, 34, 137 1.1 christos /* CSR, PC */ 138 1.1 christos 3, 2, 139 1.1 christos -1, -1, -1, -1, -1, -1, -1, -1, 140 1.1 christos -1, -1, -1, -1, -1, -1, -1, -1, 141 1.1 christos -1, -1, -1, -1, -1, -1, -1, -1, 142 1.1 christos -1, -1, -1, -1, -1, -1, -1, -1, 143 1.1 christos -1, -1, -1 144 1.1 christos }; 145 1.1 christos 146 1.1 christos #else 147 1.1 christos static int tic6x_regmap_c64xp[] = { 148 1.1 christos /* A0 - A15 */ 149 1.1 christos 52, 53, 54, 55, 56, 57, 58, 59, 150 1.1 christos 60, 61, 62, 63, 64, 65, 66, 67, 151 1.1 christos /* B0 - B15 */ 152 1.1 christos 22, 23, 24, 25, 26, 27, 28, 29, 153 1.1 christos 30, 31, 32, 33, 34, 35, 68, 69, 154 1.1 christos /* CSR PC */ 155 1.1 christos 4, 5, 156 1.1 christos /* A16 - A31 */ 157 1.1 christos 36, 37, 38, 39, 40, 41, 42, 43, 158 1.1 christos 44, 45, 46, 47, 48, 49, 50, 51, 159 1.1 christos /* B16 -B31 */ 160 1.1 christos 6, 7, 8, 9, 10, 11, 12, 13, 161 1.1 christos 14, 15, 16, 17, 18, 19, 20, 31, 162 1.1 christos /* TSR, ILC, RILC */ 163 1.1 christos 0, 3, 2 164 1.1 christos }; 165 1.1 christos 166 1.1 christos static int tic6x_regmap_c64x[] = { 167 1.1 christos /* A0 - A15 */ 168 1.1 christos 50, 51, 52, 53, 54, 55, 56, 57, 169 1.1 christos 58, 59, 60, 61, 62, 63, 64, 65, 170 1.1 christos /* B0 - B15 */ 171 1.1 christos 20, 21, 22, 23, 24, 25, 26, 27, 172 1.1 christos 28, 29, 30, 31, 32, 33, 66, 67, 173 1.1 christos /* CSR PC */ 174 1.1 christos 2, 3, 175 1.1 christos /* A16 - A31 */ 176 1.1 christos 34, 35, 36, 37, 38, 39, 40, 41, 177 1.1 christos 42, 43, 44, 45, 46, 47, 48, 49, 178 1.1 christos /* B16 - B31 */ 179 1.1 christos 4, 5, 6, 7, 8, 9, 10, 11, 180 1.1 christos 12, 13, 14, 15, 16, 17, 18, 19, 181 1.1 christos -1, -1, -1 182 1.1 christos }; 183 1.1 christos 184 1.1 christos static int tic6x_regmap_c62x[] = { 185 1.1 christos /* A0 - A15 */ 186 1.1 christos 18, 19, 20, 21, 22, 23, 24, 25, 187 1.1 christos 26, 27, 28, 29, 30, 31, 32, 33, 188 1.1 christos /* B0 - B15 */ 189 1.1 christos 4, 5, 6, 7, 8, 9, 10, 11, 190 1.1 christos 12, 13, 14, 15, 16, 17, 34, 35, 191 1.1 christos /* CSR PC */ 192 1.1 christos 2, 3, 193 1.1 christos -1, -1, -1, -1, -1, -1, -1, -1, 194 1.1 christos -1, -1, -1, -1, -1, -1, -1, -1, 195 1.1 christos -1, -1, -1, -1, -1, -1, -1, -1, 196 1.1 christos -1, -1, -1, -1, -1, -1, -1, -1, 197 1.1 christos -1, -1, -1 198 1.1 christos }; 199 1.1 christos 200 1.1 christos #endif 201 1.1 christos 202 1.1 christos static int *tic6x_regmap; 203 1.1 christos static unsigned int tic6x_breakpoint; 204 1.1 christos #define tic6x_breakpoint_len 4 205 1.1 christos 206 1.1 christos /* Implementation of target ops method "sw_breakpoint_from_kind". */ 207 1.1 christos 208 1.1 christos const gdb_byte * 209 1.1 christos tic6x_target::sw_breakpoint_from_kind (int kind, int *size) 210 1.1 christos { 211 1.1 christos *size = tic6x_breakpoint_len; 212 1.1 christos return (const gdb_byte *) &tic6x_breakpoint; 213 1.1 christos } 214 1.1 christos 215 1.1 christos static struct usrregs_info tic6x_usrregs_info = 216 1.1 christos { 217 1.1 christos TIC6X_NUM_REGS, 218 1.1 christos NULL, /* Set in tic6x_read_description. */ 219 1.1 christos }; 220 1.1 christos 221 1.1 christos static const struct target_desc * 222 1.1 christos tic6x_read_description (enum c6x_feature feature) 223 1.1 christos { 224 1.1 christos static target_desc *tdescs[C6X_LAST] = { }; 225 1.1 christos struct target_desc **tdesc = &tdescs[feature]; 226 1.1 christos 227 1.1 christos if (*tdesc == NULL) 228 1.1 christos { 229 1.1 christos *tdesc = tic6x_create_target_description (feature); 230 1.1 christos static const char *expedite_regs[] = { "A15", "PC", NULL }; 231 1.1 christos init_target_desc (*tdesc, expedite_regs); 232 1.1 christos } 233 1.1 christos 234 1.1 christos return *tdesc; 235 1.1 christos } 236 1.1 christos 237 1.1 christos bool 238 1.1 christos tic6x_target::low_cannot_fetch_register (int regno) 239 1.1 christos { 240 1.1 christos return (tic6x_regmap[regno] == -1); 241 1.1 christos } 242 1.1 christos 243 1.1 christos bool 244 1.1 christos tic6x_target::low_cannot_store_register (int regno) 245 1.1 christos { 246 1.1 christos return (tic6x_regmap[regno] == -1); 247 1.1 christos } 248 1.1 christos 249 1.1 christos bool 250 1.1 christos tic6x_target::low_supports_breakpoints () 251 1.1 christos { 252 1.1 christos return true; 253 1.1 christos } 254 1.1 christos 255 1.1 christos CORE_ADDR 256 1.1 christos tic6x_target::low_get_pc (regcache *regcache) 257 1.1 christos { 258 1.1 christos union tic6x_register pc; 259 1.1 christos 260 1.1 christos collect_register_by_name (regcache, "PC", pc.buf); 261 1.1 christos return pc.reg32; 262 1.1 christos } 263 1.1 christos 264 1.1 christos void 265 1.1 christos tic6x_target::low_set_pc (regcache *regcache, CORE_ADDR pc) 266 1.1 christos { 267 1.1 christos union tic6x_register newpc; 268 1.1 christos 269 1.1 christos newpc.reg32 = pc; 270 1.1 christos supply_register_by_name (regcache, "PC", newpc.buf); 271 1.1 christos } 272 1.1 christos 273 1.1 christos bool 274 1.1 christos tic6x_target::low_breakpoint_at (CORE_ADDR where) 275 1.1 christos { 276 1.1 christos unsigned int insn; 277 1.1 christos 278 1.1 christos read_memory (where, (unsigned char *) &insn, 4); 279 1.1 christos if (insn == tic6x_breakpoint) 280 1.1 christos return true; 281 1.1 christos 282 1.1 christos /* If necessary, recognize more trap instructions here. GDB only uses the 283 1.1 christos one. */ 284 1.1 christos return false; 285 1.1 christos } 286 1.1 christos 287 1.1 christos /* Fetch the thread-local storage pointer for libthread_db. */ 288 1.1 christos 289 1.1 christos ps_err_e 290 1.1 christos ps_get_thread_area (struct ps_prochandle *ph, 291 1.1 christos lwpid_t lwpid, int idx, void **base) 292 1.1 christos { 293 1.1 christos if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) 294 1.1 christos return PS_ERR; 295 1.1 christos 296 1.1 christos /* IDX is the bias from the thread pointer to the beginning of the 297 1.1 christos thread descriptor. It has to be subtracted due to implementation 298 1.1 christos quirks in libthread_db. */ 299 1.1 christos *base = (void *) ((char *) *base - idx); 300 1.1 christos 301 1.1 christos return PS_OK; 302 1.1 christos } 303 1.1 christos 304 1.1 christos static void 305 1.1 christos tic6x_collect_register (struct regcache *regcache, int regno, 306 1.1 christos union tic6x_register *reg) 307 1.1 christos { 308 1.1 christos union tic6x_register tmp_reg; 309 1.1 christos 310 1.1 christos collect_register (regcache, regno, &tmp_reg.reg32); 311 1.1 christos reg->reg32 = tmp_reg.reg32; 312 1.1 christos } 313 1.1 christos 314 1.1 christos static void 315 1.1 christos tic6x_supply_register (struct regcache *regcache, int regno, 316 1.1 christos const union tic6x_register *reg) 317 1.1 christos { 318 1.1 christos int offset = 0; 319 1.1 christos 320 1.1 christos supply_register (regcache, regno, reg->buf + offset); 321 1.1 christos } 322 1.1 christos 323 1.1 christos static void 324 1.1 christos tic6x_fill_gregset (struct regcache *regcache, void *buf) 325 1.1 christos { 326 1.1 christos auto regset = static_cast<union tic6x_register *> (buf); 327 1.1 christos int i; 328 1.1 christos 329 1.1 christos for (i = 0; i < TIC6X_NUM_REGS; i++) 330 1.1 christos if (tic6x_regmap[i] != -1) 331 1.1 christos tic6x_collect_register (regcache, i, regset + tic6x_regmap[i]); 332 1.1 christos } 333 1.1 christos 334 1.1 christos static void 335 1.1 christos tic6x_store_gregset (struct regcache *regcache, const void *buf) 336 1.1 christos { 337 1.1 christos const auto regset = static_cast<const union tic6x_register *> (buf); 338 1.1 christos int i; 339 1.1 christos 340 1.1 christos for (i = 0; i < TIC6X_NUM_REGS; i++) 341 1.1 christos if (tic6x_regmap[i] != -1) 342 1.1 christos tic6x_supply_register (regcache, i, regset + tic6x_regmap[i]); 343 1.1 christos } 344 1.1 christos 345 1.1 christos static struct regset_info tic6x_regsets[] = { 346 1.1 christos { PTRACE_GETREGS, PTRACE_SETREGS, 0, TIC6X_NUM_REGS * 4, GENERAL_REGS, 347 1.1 christos tic6x_fill_gregset, tic6x_store_gregset }, 348 1.1 christos NULL_REGSET 349 1.1 christos }; 350 1.1 christos 351 1.1 christos void 352 1.1 christos tic6x_target::low_arch_setup () 353 1.1 christos { 354 1.1 christos register unsigned int csr asm ("B2"); 355 1.1 christos unsigned int cpuid; 356 1.1 christos enum c6x_feature feature = C6X_CORE; 357 1.1 christos 358 1.1 christos /* Determine the CPU we're running on to find the register order. */ 359 1.1 christos __asm__ ("MVC .S2 CSR,%0" : "=r" (csr) :); 360 1.1 christos cpuid = csr >> 24; 361 1.1 christos switch (cpuid) 362 1.1 christos { 363 1.1 christos case 0x00: /* C62x */ 364 1.1 christos case 0x02: /* C67x */ 365 1.1 christos tic6x_regmap = tic6x_regmap_c62x; 366 1.1 christos tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */ 367 1.1 christos feature = C6X_CORE; 368 1.1 christos break; 369 1.1 christos case 0x03: /* C67x+ */ 370 1.1 christos tic6x_regmap = tic6x_regmap_c64x; 371 1.1 christos tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */ 372 1.1 christos feature = C6X_GP; 373 1.1 christos break; 374 1.1 christos case 0x0c: /* C64x */ 375 1.1 christos tic6x_regmap = tic6x_regmap_c64x; 376 1.1 christos tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */ 377 1.1 christos feature = C6X_GP; 378 1.1 christos break; 379 1.1 christos case 0x10: /* C64x+ */ 380 1.1 christos case 0x14: /* C674x */ 381 1.1 christos case 0x15: /* C66x */ 382 1.1 christos tic6x_regmap = tic6x_regmap_c64xp; 383 1.1 christos tic6x_breakpoint = 0x56454314; /* illegal opcode */ 384 1.1 christos feature = C6X_C6XP; 385 1.1 christos break; 386 1.1 christos default: 387 1.1 christos error ("Unknown CPU ID 0x%02x", cpuid); 388 1.1 christos } 389 1.1 christos tic6x_usrregs_info.regmap = tic6x_regmap; 390 1.1 christos 391 1.1 christos current_process ()->tdesc = tic6x_read_description (feature); 392 1.1 christos } 393 1.1 christos 394 1.1 christos static struct regsets_info tic6x_regsets_info = 395 1.1 christos { 396 1.1 christos tic6x_regsets, /* regsets */ 397 1.1 christos 0, /* num_regsets */ 398 1.1 christos NULL, /* disabled_regsets */ 399 1.1 christos }; 400 1.1 christos 401 1.1 christos static struct regs_info myregs_info = 402 1.1 christos { 403 1.1 christos NULL, /* regset_bitmap */ 404 1.1 christos &tic6x_usrregs_info, 405 1.1 christos &tic6x_regsets_info 406 1.1 christos }; 407 1.1 christos 408 1.1 christos const regs_info * 409 1.1 christos tic6x_target::get_regs_info () 410 1.1 christos { 411 1.1 christos return &myregs_info; 412 1.1 christos } 413 1.1 christos 414 1.1 christos #if GDB_SELF_TEST 415 1.1 christos #include "gdbsupport/selftest.h" 416 1.1 christos 417 1.1 christos namespace selftests { 418 1.1 christos namespace tdesc { 419 1.1 christos static void 420 1.1 christos tic6x_tdesc_test () 421 1.1 christos { 422 1.1 christos SELF_CHECK (*tdesc_tic6x_c62x_linux == *tic6x_read_description (C6X_CORE)); 423 1.1 christos SELF_CHECK (*tdesc_tic6x_c64x_linux == *tic6x_read_description (C6X_GP)); 424 1.1 christos SELF_CHECK (*tdesc_tic6x_c64xp_linux == *tic6x_read_description (C6X_C6XP)); 425 1.1 christos } 426 1.1 christos } 427 1.1 christos } 428 1.1 christos #endif 429 1.1 christos 430 1.1 christos /* The linux target ops object. */ 431 1.1 christos 432 1.1 christos linux_process_target *the_linux_target = &the_tic6x_target; 433 1.1 christos 434 1.1 christos void 435 1.1 christos initialize_low_arch (void) 436 1.1 christos { 437 1.1 christos #if GDB_SELF_TEST 438 1.1 christos /* Initialize the Linux target descriptions. */ 439 1.1 christos init_registers_tic6x_c64xp_linux (); 440 1.1 christos init_registers_tic6x_c64x_linux (); 441 1.1 christos init_registers_tic6x_c62x_linux (); 442 1.1 christos 443 1.1 christos selftests::register_test ("tic6x-tdesc", selftests::tdesc::tic6x_tdesc_test); 444 1.1 christos #endif 445 1.1 christos 446 1.1 christos initialize_regsets_info (&tic6x_regsets_info); 447 1.1 christos } 448