| /* Target-dependent code for GNU/Linux on CSKY. |
| |
| Copyright (C) 2012-2021 Free Software Foundation, Inc. |
| |
| Contributed by C-SKY Microsystems and Mentor Graphics. |
| |
| This file is part of GDB. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| |
| #include "defs.h" |
| #include "osabi.h" |
| #include "glibc-tdep.h" |
| #include "linux-tdep.h" |
| #include "gdbarch.h" |
| #include "solib-svr4.h" |
| #include "regset.h" |
| #include "trad-frame.h" |
| #include "tramp-frame.h" |
| #include "csky-tdep.h" |
| |
| /* Functions, definitions, and data structures for C-Sky core file debug. */ |
| |
| /* General regset pc, r1, r0, psr, r2-r31 for CK810. */ |
| #define SIZEOF_CSKY_GREGSET 34*4 |
| /* Float regset fesr fsr fr0-fr31 for CK810. */ |
| #define SIZEOF_CSKY_FREGSET 34*4 |
| |
| /* Offset mapping table from core_section to regcache of general |
| registers for ck810. */ |
| static const int csky_gregset_offset[] = |
| { |
| 72, 1, 0, 89, 2, /* pc, r1, r0, psr, r2. */ |
| 3, 4, 5, 6, 7, /* r3 ~ r32. */ |
| 8, 9, 10, 11, 12, |
| 13, 14, 15, 16, 17, |
| 18, 19, 20, 21, 22, |
| 23, 24, 25, 26, 27, |
| 28, 29, 30, 31 |
| }; |
| |
| /* Offset mapping table from core_section to regcache of float |
| registers for ck810. */ |
| |
| static const int csky_fregset_offset[] = |
| { |
| 122, 123, 40, 41, 42, /* fcr, fesr, fr0 ~ fr2. */ |
| 43, 44, 45, 46, 47, /* fr3 ~ fr15. */ |
| 48, 49, 50, 51, 52, |
| 53, 54, 55 |
| }; |
| |
| /* Implement the supply_regset hook for GP registers in core files. */ |
| |
| static void |
| csky_supply_gregset (const struct regset *regset, |
| struct regcache *regcache, int regnum, |
| const void *regs, size_t len) |
| { |
| int i, gregset_num; |
| const gdb_byte *gregs = (const gdb_byte *) regs ; |
| |
| gdb_assert (len >= SIZEOF_CSKY_GREGSET); |
| gregset_num = ARRAY_SIZE (csky_gregset_offset); |
| |
| for (i = 0; i < gregset_num; i++) |
| { |
| if ((regnum == csky_gregset_offset[i] || regnum == -1) |
| && csky_gregset_offset[i] != -1) |
| regcache->raw_supply (csky_gregset_offset[i], gregs + 4 * i); |
| } |
| } |
| |
| /* Implement the collect_regset hook for GP registers in core files. */ |
| |
| static void |
| csky_collect_gregset (const struct regset *regset, |
| const struct regcache *regcache, |
| int regnum, void *gregs_buf, size_t len) |
| { |
| int regno, gregset_num; |
| gdb_byte *gregs = (gdb_byte *) gregs_buf ; |
| |
| gdb_assert (len >= SIZEOF_CSKY_GREGSET); |
| gregset_num = ARRAY_SIZE (csky_gregset_offset); |
| |
| for (regno = 0; regno < gregset_num; regno++) |
| { |
| if ((regnum == csky_gregset_offset[regno] || regnum == -1) |
| && csky_gregset_offset[regno] != -1) |
| regcache->raw_collect (regno, |
| gregs + 4 + csky_gregset_offset[regno]); |
| } |
| } |
| |
| /* Implement the supply_regset hook for FP registers in core files. */ |
| |
| static void |
| csky_supply_fregset (const struct regset *regset, |
| struct regcache *regcache, int regnum, |
| const void *regs, size_t len) |
| { |
| int i; |
| int offset = 0; |
| struct gdbarch *gdbarch = regcache->arch (); |
| const gdb_byte *fregs = (const gdb_byte *) regs; |
| int fregset_num = ARRAY_SIZE (csky_fregset_offset); |
| |
| gdb_assert (len >= SIZEOF_CSKY_FREGSET); |
| for (i = 0; i < fregset_num; i++) |
| { |
| if ((regnum == csky_fregset_offset[i] || regnum == -1) |
| && csky_fregset_offset[i] != -1) |
| { |
| int num = csky_fregset_offset[i]; |
| offset += register_size (gdbarch, num); |
| regcache->raw_supply (csky_fregset_offset[i], fregs + offset); |
| } |
| } |
| } |
| |
| /* Implement the collect_regset hook for FP registers in core files. */ |
| |
| static void |
| csky_collect_fregset (const struct regset *regset, |
| const struct regcache *regcache, |
| int regnum, void *fregs_buf, size_t len) |
| { |
| int regno; |
| struct gdbarch *gdbarch = regcache->arch (); |
| gdb_byte *fregs = (gdb_byte *) fregs_buf ; |
| int fregset_num = ARRAY_SIZE (csky_fregset_offset); |
| int offset = 0; |
| |
| gdb_assert (len >= SIZEOF_CSKY_FREGSET); |
| for (regno = 0; regno < fregset_num; regno++) |
| { |
| if ((regnum == csky_fregset_offset[regno] || regnum == -1) |
| && csky_fregset_offset[regno] != -1) |
| { |
| offset += register_size (gdbarch, csky_fregset_offset[regno]); |
| regcache->raw_collect (regno, fregs + offset); |
| } |
| } |
| } |
| |
| static const struct regset csky_regset_general = |
| { |
| NULL, |
| csky_supply_gregset, |
| csky_collect_gregset |
| }; |
| |
| static const struct regset csky_regset_float = |
| { |
| NULL, |
| csky_supply_fregset, |
| csky_collect_fregset |
| }; |
| |
| /* Iterate over core file register note sections. */ |
| |
| static void |
| csky_linux_iterate_over_regset_sections (struct gdbarch *gdbarch, |
| iterate_over_regset_sections_cb *cb, |
| void *cb_data, |
| const struct regcache *regcache) |
| { |
| cb (".reg", sizeof (csky_gregset_offset), sizeof (csky_gregset_offset), |
| &csky_regset_general, NULL, cb_data); |
| cb (".reg2", sizeof (csky_fregset_offset), sizeof (csky_fregset_offset), |
| &csky_regset_float, NULL, cb_data); |
| } |
| |
| static void |
| csky_linux_rt_sigreturn_init (const struct tramp_frame *self, |
| struct frame_info *this_frame, |
| struct trad_frame_cache *this_cache, |
| CORE_ADDR func) |
| { |
| int i; |
| CORE_ADDR sp = get_frame_register_unsigned (this_frame, 14); |
| |
| CORE_ADDR base = sp + CSKY_SIGINFO_OFFSET + CSKY_SIGINFO_SIZE |
| + CSKY_UCONTEXT_SIGCONTEXT |
| + CSKY_SIGCONTEXT_SC_USP |
| + CSKY_SIGCONTEXT_SC_A0; |
| |
| /* Set addrs of R0 ~ R13. */ |
| for (i = 0; i < 14; i++) |
| trad_frame_set_reg_addr (this_cache, i, base + i * 4); |
| |
| /* Set addrs of SP(R14) and R15. */ |
| trad_frame_set_reg_addr (this_cache, 14, base - 4); |
| trad_frame_set_reg_addr (this_cache, 15, base + 4 * 14); |
| |
| /* Set addrs of R16 ~ R31. */ |
| for (i = 15; i < 31; i++) |
| trad_frame_set_reg_addr (this_cache, i, base + i * 4); |
| |
| /* Set addrs of PSR and PC. */ |
| trad_frame_set_reg_addr (this_cache, 89, base + 4 * 33); |
| trad_frame_set_reg_addr (this_cache, 72, base + 4 * 34); |
| |
| trad_frame_set_id (this_cache, frame_id_build (sp, func)); |
| } |
| |
| static struct tramp_frame |
| csky_linux_rt_sigreturn_tramp_frame = { |
| SIGTRAMP_FRAME, |
| 4, |
| { |
| { CSKY_MOVI_R7_173, ULONGEST_MAX }, |
| { CSKY_TRAP_0, ULONGEST_MAX }, |
| { TRAMP_SENTINEL_INSN } |
| }, |
| csky_linux_rt_sigreturn_init |
| }; |
| |
| /* Hook function for gdbarch_register_osabi. */ |
| |
| static void |
| csky_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) |
| { |
| linux_init_abi (info, gdbarch, 0); |
| |
| /* Shared library handling. */ |
| set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); |
| set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver); |
| set_solib_svr4_fetch_link_map_offsets (gdbarch, |
| linux_ilp32_fetch_link_map_offsets); |
| |
| /* Enable TLS support. */ |
| set_gdbarch_fetch_tls_load_module_address (gdbarch, |
| svr4_fetch_objfile_link_map); |
| |
| /* Core file support. */ |
| set_gdbarch_iterate_over_regset_sections ( |
| gdbarch, csky_linux_iterate_over_regset_sections); |
| |
| /* Append tramp frame unwinder for SIGNAL. */ |
| |
| tramp_frame_prepend_unwinder (gdbarch, |
| &csky_linux_rt_sigreturn_tramp_frame); |
| } |
| |
| void _initialize_csky_linux_tdep (); |
| void |
| _initialize_csky_linux_tdep () |
| { |
| gdbarch_register_osabi (bfd_arch_csky, 0, GDB_OSABI_LINUX, |
| csky_linux_init_abi); |
| } |