1/* Target-dependent code for GNU/Linux on CSKY. 2 3 Copyright (C) 2012-2023 Free Software Foundation, Inc. 4 5 Contributed by C-SKY Microsystems and Mentor Graphics. 6 7 This file is part of GDB. 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 21 22#include "defs.h" 23#include "osabi.h" 24#include "glibc-tdep.h" 25#include "linux-tdep.h" 26#include "gdbarch.h" 27#include "solib-svr4.h" 28#include "regset.h" 29#include "trad-frame.h" 30#include "tramp-frame.h" 31#include "csky-tdep.h" 32 33/* Functions, definitions, and data structures for C-Sky core file debug. */ 34 35/* General regset pc, r1, r0, psr, r2-r31 for CK810. */ 36#define SIZEOF_CSKY_GREGSET 34*4 37/* Float regset fesr fsr fr0-fr31 for CK810. */ 38#define SIZEOF_CSKY_FREGSET 34*4 39/* Float regset vr0~vr15 fr15~fr31, reserved for CK810 when kernel 4.x. */ 40#define SIZEOF_CSKY_FREGSET_K4X 400 41 42/* Offset mapping table from core_section to regcache of general 43 registers for ck810. */ 44static const int csky_gregset_offset[] = 45{ 46 72, 1, 0, 89, 2, /* pc, r1, r0, psr, r2. */ 47 3, 4, 5, 6, 7, /* r3 ~ r32. */ 48 8, 9, 10, 11, 12, 49 13, 14, 15, 16, 17, 50 18, 19, 20, 21, 22, 51 23, 24, 25, 26, 27, 52 28, 29, 30, 31 53}; 54 55/* Offset mapping table from core_section to regcache of float 56 registers for ck810. */ 57 58static const int csky_fregset_offset[] = 59{ 60 122, 123, 40, 41, 42, /* fcr, fesr, fr0 ~ fr2. */ 61 43, 44, 45, 46, 47, /* fr3 ~ fr15. */ 62 48, 49, 50, 51, 52, 63 53, 54, 55 64}; 65 66/* Implement the supply_regset hook for GP registers in core files. */ 67 68static void 69csky_supply_gregset (const struct regset *regset, 70 struct regcache *regcache, int regnum, 71 const void *regs, size_t len) 72{ 73 int i, gregset_num; 74 const gdb_byte *gregs = (const gdb_byte *) regs ; 75 76 gdb_assert (len >= SIZEOF_CSKY_GREGSET); 77 gregset_num = ARRAY_SIZE (csky_gregset_offset); 78 79 for (i = 0; i < gregset_num; i++) 80 { 81 if ((regnum == csky_gregset_offset[i] || regnum == -1) 82 && csky_gregset_offset[i] != -1) 83 regcache->raw_supply (csky_gregset_offset[i], gregs + 4 * i); 84 } 85} 86 87/* Implement the collect_regset hook for GP registers in core files. */ 88 89static void 90csky_collect_gregset (const struct regset *regset, 91 const struct regcache *regcache, 92 int regnum, void *gregs_buf, size_t len) 93{ 94 int regno, gregset_num; 95 gdb_byte *gregs = (gdb_byte *) gregs_buf ; 96 97 gdb_assert (len >= SIZEOF_CSKY_GREGSET); 98 gregset_num = ARRAY_SIZE (csky_gregset_offset); 99 100 for (regno = 0; regno < gregset_num; regno++) 101 { 102 if ((regnum == csky_gregset_offset[regno] || regnum == -1) 103 && csky_gregset_offset[regno] != -1) 104 regcache->raw_collect (regno, 105 gregs + 4 + csky_gregset_offset[regno]); 106 } 107} 108 109/* Implement the supply_regset hook for FP registers in core files. */ 110 111static void 112csky_supply_fregset (const struct regset *regset, 113 struct regcache *regcache, int regnum, 114 const void *regs, size_t len) 115{ 116 int i; 117 int offset = 0; 118 struct gdbarch *gdbarch = regcache->arch (); 119 const gdb_byte *fregs = (const gdb_byte *) regs; 120 int fregset_num = ARRAY_SIZE (csky_fregset_offset); 121 122 gdb_assert (len >= SIZEOF_CSKY_FREGSET); 123 if (len == SIZEOF_CSKY_FREGSET) 124 { 125 for (i = 0; i < fregset_num; i++) 126 { 127 if ((regnum == csky_fregset_offset[i] || regnum == -1) 128 && csky_fregset_offset[i] != -1) 129 { 130 int num = csky_fregset_offset[i]; 131 offset += register_size (gdbarch, num); 132 regcache->raw_supply (csky_fregset_offset[i], fregs + offset); 133 } 134 } 135 } 136 else if (len == SIZEOF_CSKY_FREGSET_K4X) 137 { 138 /* When kernel version >= 4.x, .reg2 size will be 400. 139 Contents is { 140 unsigned long vr[96]; 141 unsigned long fcr; 142 unsigned long fesr; 143 unsigned long fid; 144 unsigned long reserved; 145 } 146 VR[96] means: (vr0~vr15) + (fr16~fr31), each Vector register is 147 128-bits, each Float register is 64 bits, the total size is 148 (4*96). 149 150 In addition, for fr0~fr15, each FRx is the lower 64 bits of the 151 corresponding VRx. So fr0~fr15 and vr0~vr15 regisetrs use the same 152 offset. */ 153 int fcr_regno[] = {122, 123, 121}; /* fcr, fesr, fid. */ 154 155 /* Supply vr0~vr15. */ 156 for (i = 0; i < 16; i ++) 157 { 158 if (*gdbarch_register_name (gdbarch, (CSKY_VR0_REGNUM + i)) != '\0') 159 { 160 offset = 16 * i; 161 regcache->raw_supply (CSKY_VR0_REGNUM + i, fregs + offset); 162 } 163 } 164 /* Supply fr0~fr15. */ 165 for (i = 0; i < 16; i ++) 166 { 167 if (*gdbarch_register_name (gdbarch, (CSKY_FR0_REGNUM + i)) != '\0') 168 { 169 offset = 16 * i; 170 regcache->raw_supply (CSKY_FR0_REGNUM + i, fregs + offset); 171 } 172 } 173 /* Supply fr16~fr31. */ 174 for (i = 0; i < 16; i ++) 175 { 176 if (*gdbarch_register_name (gdbarch, (CSKY_FR16_REGNUM + i)) != '\0') 177 { 178 offset = (16 * 16) + (8 * i); 179 regcache->raw_supply (CSKY_FR16_REGNUM + i, fregs + offset); 180 } 181 } 182 /* Supply fcr, fesr, fid. */ 183 for (i = 0; i < 3; i ++) 184 { 185 if (*gdbarch_register_name (gdbarch, fcr_regno[i]) != '\0') 186 { 187 offset = (16 * 16) + (16 * 8) + (4 * i); 188 regcache->raw_supply (fcr_regno[i], fregs + offset); 189 } 190 } 191 } 192 else 193 { 194 warning (_("Unknow size %s of section .reg2, can not get value" 195 " of float registers."), pulongest (len)); 196 } 197} 198 199/* Implement the collect_regset hook for FP registers in core files. */ 200 201static void 202csky_collect_fregset (const struct regset *regset, 203 const struct regcache *regcache, 204 int regnum, void *fregs_buf, size_t len) 205{ 206 int regno; 207 struct gdbarch *gdbarch = regcache->arch (); 208 gdb_byte *fregs = (gdb_byte *) fregs_buf ; 209 int fregset_num = ARRAY_SIZE (csky_fregset_offset); 210 int offset = 0; 211 212 gdb_assert (len >= SIZEOF_CSKY_FREGSET); 213 if (len == SIZEOF_CSKY_FREGSET) 214 { 215 for (regno = 0; regno < fregset_num; regno++) 216 { 217 if ((regnum == csky_fregset_offset[regno] || regnum == -1) 218 && csky_fregset_offset[regno] != -1) 219 { 220 offset += register_size (gdbarch, csky_fregset_offset[regno]); 221 regcache->raw_collect (regno, fregs + offset); 222 } 223 } 224 } 225 else if (len == SIZEOF_CSKY_FREGSET_K4X) 226 { 227 /* When kernel version >= 4.x, .reg2 size will be 400. 228 Contents is { 229 unsigned long vr[96]; 230 unsigned long fcr; 231 unsigned long fesr; 232 unsigned long fid; 233 unsigned long reserved; 234 } 235 VR[96] means: (vr0~vr15) + (fr16~fr31), each Vector register is$ 236 128-bits, each Float register is 64 bits, the total size is$ 237 (4*96).$ 238 239 In addition, for fr0~fr15, each FRx is the lower 64 bits of the$ 240 corresponding VRx. So fr0~fr15 and vr0~vr15 regisetrs use the same$ 241 offset. */ 242 int i = 0; 243 int fcr_regno[] = {122, 123, 121}; /* fcr, fesr, fid. */ 244 245 /* Supply vr0~vr15. */ 246 for (i = 0; i < 16; i ++) 247 { 248 if (*gdbarch_register_name (gdbarch, (CSKY_VR0_REGNUM + i)) != '\0') 249 { 250 offset = 16 * i; 251 regcache ->raw_collect (CSKY_VR0_REGNUM + i, fregs + offset); 252 } 253 } 254 /* Supply fr16~fr31. */ 255 for (i = 0; i < 16; i ++) 256 { 257 if (*gdbarch_register_name (gdbarch, (CSKY_FR16_REGNUM + i)) != '\0') 258 { 259 offset = (16 * 16) + (8 * i); 260 regcache ->raw_collect (CSKY_FR16_REGNUM + i, fregs + offset); 261 } 262 } 263 /* Supply fcr, fesr, fid. */ 264 for (i = 0; i < 3; i ++) 265 { 266 if (*gdbarch_register_name (gdbarch, fcr_regno[i]) != '\0') 267 { 268 offset = (16 * 16) + (16 * 8) + (4 * i); 269 regcache ->raw_collect (fcr_regno[i], fregs + offset); 270 } 271 } 272 } 273 else 274 { 275 warning (_("Unknow size %s of section .reg2, will not set value" 276 " of float registers."), pulongest (len)); 277 } 278} 279 280static const struct regset csky_regset_general = 281{ 282 NULL, 283 csky_supply_gregset, 284 csky_collect_gregset 285}; 286 287static const struct regset csky_regset_float = 288{ 289 NULL, 290 csky_supply_fregset, 291 csky_collect_fregset, 292 /* Allow .reg2 to have a different size, and the size of .reg2 should 293 always be bigger than SIZEOF_CSKY_FREGSET. */ 294 1 295}; 296 297/* Iterate over core file register note sections. */ 298 299static void 300csky_linux_iterate_over_regset_sections (struct gdbarch *gdbarch, 301 iterate_over_regset_sections_cb *cb, 302 void *cb_data, 303 const struct regcache *regcache) 304{ 305 cb (".reg", sizeof (csky_gregset_offset), sizeof (csky_gregset_offset), 306 &csky_regset_general, NULL, cb_data); 307 cb (".reg2", sizeof (csky_fregset_offset), sizeof (csky_fregset_offset), 308 &csky_regset_float, NULL, cb_data); 309} 310 311static void 312csky_linux_rt_sigreturn_init (const struct tramp_frame *self, 313 frame_info_ptr this_frame, 314 struct trad_frame_cache *this_cache, 315 CORE_ADDR func) 316{ 317 int i; 318 CORE_ADDR sp = get_frame_register_unsigned (this_frame, 14); 319 320 CORE_ADDR base = sp + CSKY_SIGINFO_OFFSET + CSKY_SIGINFO_SIZE 321 + CSKY_UCONTEXT_SIGCONTEXT 322 + CSKY_SIGCONTEXT_SC_USP 323 + CSKY_SIGCONTEXT_SC_A0; 324 325 /* Set addrs of R0 ~ R13. */ 326 for (i = 0; i < 14; i++) 327 trad_frame_set_reg_addr (this_cache, i, base + i * 4); 328 329 /* Set addrs of SP(R14) and R15. */ 330 trad_frame_set_reg_addr (this_cache, 14, base - 4); 331 trad_frame_set_reg_addr (this_cache, 15, base + 4 * 14); 332 333 /* Set addrs of R16 ~ R31. */ 334 for (i = 15; i < 31; i++) 335 trad_frame_set_reg_addr (this_cache, i, base + i * 4); 336 337 /* Set addrs of PSR and PC. */ 338 trad_frame_set_reg_addr (this_cache, 89, base + 4 * 33); 339 trad_frame_set_reg_addr (this_cache, 72, base + 4 * 34); 340 341 trad_frame_set_id (this_cache, frame_id_build (sp, func)); 342} 343 344static struct tramp_frame 345csky_linux_rt_sigreturn_tramp_frame = { 346 SIGTRAMP_FRAME, 347 4, 348 { 349 { CSKY_MOVI_R7_173, ULONGEST_MAX }, 350 { CSKY_TRAP_0, ULONGEST_MAX }, 351 { TRAMP_SENTINEL_INSN } 352 }, 353 csky_linux_rt_sigreturn_init 354}; 355 356static void 357csky_linux_rt_sigreturn_init_pt_regs (const struct tramp_frame *self, 358 frame_info_ptr this_frame, 359 struct trad_frame_cache *this_cache, 360 CORE_ADDR func) 361{ 362 int i; 363 CORE_ADDR sp = get_frame_register_unsigned (this_frame, CSKY_SP_REGNUM); 364 365 CORE_ADDR base = sp + CSKY_SIGINFO_OFFSET + CSKY_SIGINFO_SIZE 366 + CSKY_UCONTEXT_SIGCONTEXT 367 + CSKY_SIGCONTEXT_PT_REGS_TLS; 368 369 /* LR */ 370 trad_frame_set_reg_addr (this_cache, CSKY_R15_REGNUM, base); 371 372 /* PC */ 373 trad_frame_set_reg_addr (this_cache, CSKY_PC_REGNUM, base + 4); 374 375 /* PSR */ 376 trad_frame_set_reg_addr (this_cache, CSKY_CR0_REGNUM, base + 8); 377 378 /* SP */ 379 trad_frame_set_reg_addr (this_cache, CSKY_SP_REGNUM, base + 12); 380 381 /* Set addrs of R0 ~ R13. */ 382 for (i = 0; i < 14; i++) 383 trad_frame_set_reg_addr (this_cache, i, base + i * 4 + 20); 384 385 trad_frame_set_id (this_cache, frame_id_build (sp, func)); 386} 387 388 389static struct tramp_frame 390csky_linux_rt_sigreturn_tramp_frame_kernel_4x = { 391 SIGTRAMP_FRAME, 392 4, 393 { 394 { CSKY_MOVI_R7_139, ULONGEST_MAX }, 395 { CSKY_TRAP_0, ULONGEST_MAX }, 396 { TRAMP_SENTINEL_INSN } 397 }, 398 csky_linux_rt_sigreturn_init_pt_regs 399}; 400 401/* Hook function for gdbarch_register_osabi. */ 402 403static void 404csky_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 405{ 406 linux_init_abi (info, gdbarch, 0); 407 408 /* Shared library handling. */ 409 set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); 410 set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver); 411 set_solib_svr4_fetch_link_map_offsets (gdbarch, 412 linux_ilp32_fetch_link_map_offsets); 413 414 /* Enable TLS support. */ 415 set_gdbarch_fetch_tls_load_module_address (gdbarch, 416 svr4_fetch_objfile_link_map); 417 418 /* Core file support. */ 419 set_gdbarch_iterate_over_regset_sections ( 420 gdbarch, csky_linux_iterate_over_regset_sections); 421 422 /* Append tramp frame unwinder for SIGNAL. */ 423 424 tramp_frame_prepend_unwinder (gdbarch, 425 &csky_linux_rt_sigreturn_tramp_frame); 426 tramp_frame_prepend_unwinder (gdbarch, 427 &csky_linux_rt_sigreturn_tramp_frame_kernel_4x); 428} 429 430void _initialize_csky_linux_tdep (); 431void 432_initialize_csky_linux_tdep () 433{ 434 gdbarch_register_osabi (bfd_arch_csky, 0, GDB_OSABI_LINUX, 435 csky_linux_init_abi); 436} 437