1 1.1 christos /* GNU/Linux on TI C6x target support. 2 1.11 christos Copyright (C) 2011-2024 Free Software Foundation, Inc. 3 1.1 christos Contributed by Yao Qi <yao (at) codesourcery.com> 4 1.1 christos 5 1.1 christos This file is part of GDB. 6 1.1 christos 7 1.1 christos This program is free software; you can redistribute it and/or modify 8 1.1 christos it under the terms of the GNU General Public License as published by 9 1.1 christos the Free Software Foundation; either version 3 of the License, or 10 1.1 christos (at your option) any later version. 11 1.1 christos 12 1.1 christos This program is distributed in the hope that it will be useful, 13 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 14 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 1.1 christos GNU General Public License for more details. 16 1.1 christos 17 1.1 christos You should have received a copy of the GNU General Public License 18 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 1.1 christos 20 1.1 christos #include "solib.h" 21 1.1 christos #include "osabi.h" 22 1.1 christos #include "linux-tdep.h" 23 1.1 christos #include "tic6x-tdep.h" 24 1.1 christos #include "trad-frame.h" 25 1.1 christos #include "tramp-frame.h" 26 1.1 christos #include "elf-bfd.h" 27 1.1 christos #include "elf/tic6x.h" 28 1.9 christos #include "gdbarch.h" 29 1.10 christos #include "solib-dsbt.h" 30 1.1 christos 31 1.1 christos /* The offset from rt_sigframe pointer to SP register. */ 32 1.1 christos #define TIC6X_SP_RT_SIGFRAME 8 33 1.1 christos /* Size of struct siginfo info. */ 34 1.1 christos #define TIC6X_SIGINFO_SIZE 128 35 1.1 christos /* Size of type stack_t, which contains three fields of type void*, int, and 36 1.1 christos size_t respectively. */ 37 1.1 christos #define TIC6X_STACK_T_SIZE (3 * 4) 38 1.1 christos 39 1.1 christos static const gdb_byte tic6x_bkpt_bnop_be[] = { 0x00, 0x00, 0xa1, 0x22 }; 40 1.1 christos static const gdb_byte tic6x_bkpt_bnop_le[] = { 0x22, 0xa1, 0x00, 0x00 }; 41 1.1 christos 42 1.1 christos /* Return the offset of register REGNUM in struct sigcontext. Return 0 if no 43 1.1 christos such register in sigcontext. */ 44 1.1 christos 45 1.1 christos static unsigned int 46 1.1 christos tic6x_register_sigcontext_offset (unsigned int regnum, struct gdbarch *gdbarch) 47 1.1 christos { 48 1.10 christos tic6x_gdbarch_tdep *tdep = gdbarch_tdep<tic6x_gdbarch_tdep> (gdbarch); 49 1.1 christos 50 1.1 christos if (regnum == TIC6X_A4_REGNUM || regnum == TIC6X_A4_REGNUM + 2 51 1.1 christos || regnum == TIC6X_A4_REGNUM + 4) 52 1.1 christos return 4 * (regnum - TIC6X_A4_REGNUM + 2); /* A4, A6, A8 */ 53 1.1 christos else if (regnum == TIC6X_A5_REGNUM || regnum == TIC6X_A5_REGNUM + 2 54 1.1 christos || regnum == TIC6X_A5_REGNUM + 4) 55 1.1 christos return 4 * (regnum - TIC6X_A5_REGNUM + 12); /* A5, A7, A9 */ 56 1.1 christos else if (regnum == TIC6X_B4_REGNUM || regnum == TIC6X_B4_REGNUM + 2 57 1.1 christos || regnum == TIC6X_B4_REGNUM + 4) 58 1.1 christos return 4 * (regnum - TIC6X_B4_REGNUM + 3); /* B4, B6, B8 */ 59 1.1 christos else if (regnum == TIC6X_B5_REGNUM || regnum == TIC6X_B5_REGNUM + 2 60 1.1 christos || regnum == TIC6X_B5_REGNUM + 4) 61 1.1 christos return 4 * (regnum - TIC6X_B5_REGNUM + 19); /* B5, B7, B9 */ 62 1.1 christos else if (regnum < TIC6X_A4_REGNUM) 63 1.1 christos return 4 * (regnum - 0 + 8); /* A0 - A3 */ 64 1.1 christos else if (regnum >= TIC6X_B0_REGNUM && regnum < TIC6X_B4_REGNUM) 65 1.1 christos return 4 * (regnum - TIC6X_B0_REGNUM + 15); /* B0 - B3 */ 66 1.1 christos else if (regnum >= 34 && regnum < 34 + 32) 67 1.1 christos return 4 * (regnum - 34 + 23); /* A16 - A31, B16 - B31 */ 68 1.1 christos else if (regnum == TIC6X_PC_REGNUM) 69 1.1 christos return 4 * (tdep->has_gp ? 55 : 23); 70 1.1 christos else if (regnum == TIC6X_SP_REGNUM) 71 1.1 christos return 4; 72 1.1 christos 73 1.1 christos return 0; 74 1.1 christos } 75 1.1 christos 76 1.1 christos /* Support unwinding frame in signal trampoline. We don't check sigreturn, 77 1.1 christos since it is not used in kernel. */ 78 1.1 christos 79 1.1 christos static void 80 1.1 christos tic6x_linux_rt_sigreturn_init (const struct tramp_frame *self, 81 1.11 christos const frame_info_ptr &this_frame, 82 1.1 christos struct trad_frame_cache *this_cache, 83 1.1 christos CORE_ADDR func) 84 1.1 christos { 85 1.1 christos struct gdbarch *gdbarch = get_frame_arch (this_frame); 86 1.1 christos CORE_ADDR sp = get_frame_register_unsigned (this_frame, TIC6X_SP_REGNUM); 87 1.1 christos /* The base of struct sigcontext is computed by examining the definition of 88 1.1 christos struct rt_sigframe in linux kernel source arch/c6x/kernel/signal.c. */ 89 1.1 christos CORE_ADDR base = (sp + TIC6X_SP_RT_SIGFRAME 90 1.1 christos /* Pointer type *pinfo and *puc in struct rt_sigframe. */ 91 1.1 christos + 4 + 4 92 1.1 christos + TIC6X_SIGINFO_SIZE 93 1.1 christos + 4 + 4 /* uc_flags and *uc_link in struct ucontext. */ 94 1.1 christos + TIC6X_STACK_T_SIZE); 95 1.10 christos tic6x_gdbarch_tdep *tdep = gdbarch_tdep<tic6x_gdbarch_tdep> (gdbarch); 96 1.1 christos unsigned int reg_offset; 97 1.1 christos unsigned int i; 98 1.1 christos 99 1.1 christos for (i = 0; i < 10; i++) /* A0 - A9 */ 100 1.1 christos { 101 1.1 christos reg_offset = tic6x_register_sigcontext_offset (i, gdbarch); 102 1.1 christos gdb_assert (reg_offset != 0); 103 1.1 christos 104 1.1 christos trad_frame_set_reg_addr (this_cache, i, base + reg_offset); 105 1.1 christos } 106 1.1 christos 107 1.1 christos for (i = TIC6X_B0_REGNUM; i < TIC6X_B0_REGNUM + 10; i++) /* B0 - B9 */ 108 1.1 christos { 109 1.1 christos reg_offset = tic6x_register_sigcontext_offset (i, gdbarch); 110 1.1 christos gdb_assert (reg_offset != 0); 111 1.1 christos 112 1.1 christos trad_frame_set_reg_addr (this_cache, i, base + reg_offset); 113 1.1 christos } 114 1.1 christos 115 1.1 christos if (tdep->has_gp) 116 1.1 christos for (i = 34; i < 34 + 32; i++) /* A16 - A31, B16 - B31 */ 117 1.1 christos { 118 1.1 christos reg_offset = tic6x_register_sigcontext_offset (i, gdbarch); 119 1.1 christos gdb_assert (reg_offset != 0); 120 1.1 christos 121 1.1 christos trad_frame_set_reg_addr (this_cache, i, base + reg_offset); 122 1.1 christos } 123 1.1 christos 124 1.1 christos trad_frame_set_reg_addr (this_cache, TIC6X_PC_REGNUM, 125 1.1 christos base + tic6x_register_sigcontext_offset (TIC6X_PC_REGNUM, 126 1.1 christos gdbarch)); 127 1.1 christos trad_frame_set_reg_addr (this_cache, TIC6X_SP_REGNUM, 128 1.1 christos base + tic6x_register_sigcontext_offset (TIC6X_SP_REGNUM, 129 1.1 christos gdbarch)); 130 1.1 christos 131 1.1 christos /* Save a frame ID. */ 132 1.1 christos trad_frame_set_id (this_cache, frame_id_build (sp, func)); 133 1.1 christos } 134 1.1 christos 135 1.1 christos static struct tramp_frame tic6x_linux_rt_sigreturn_tramp_frame = 136 1.1 christos { 137 1.1 christos SIGTRAMP_FRAME, 138 1.1 christos 4, 139 1.1 christos { 140 1.1 christos {0x000045aa, 0x0fffffff}, /* mvk .S2 139,b0 */ 141 1.8 christos {0x10000000, ULONGEST_MAX}, /* swe */ 142 1.1 christos {TRAMP_SENTINEL_INSN} 143 1.1 christos }, 144 1.1 christos tic6x_linux_rt_sigreturn_init 145 1.1 christos }; 146 1.1 christos 147 1.1 christos /* When FRAME is at a syscall instruction, return the PC of the next 148 1.1 christos instruction to be executed. */ 149 1.1 christos 150 1.1 christos static CORE_ADDR 151 1.11 christos tic6x_linux_syscall_next_pc (const frame_info_ptr &frame) 152 1.1 christos { 153 1.1 christos ULONGEST syscall_number = get_frame_register_unsigned (frame, 154 1.1 christos TIC6X_B0_REGNUM); 155 1.1 christos CORE_ADDR pc = get_frame_pc (frame); 156 1.1 christos 157 1.1 christos if (syscall_number == 139 /* rt_sigreturn */) 158 1.1 christos return frame_unwind_caller_pc (frame); 159 1.1 christos 160 1.1 christos return pc + 4; 161 1.1 christos } 162 1.1 christos 163 1.1 christos 164 1.1 christos static void 165 1.1 christos tic6x_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 166 1.1 christos { 167 1.10 christos tic6x_gdbarch_tdep *tdep = gdbarch_tdep<tic6x_gdbarch_tdep> (gdbarch); 168 1.1 christos 169 1.10 christos linux_init_abi (info, gdbarch, 0); 170 1.1 christos 171 1.1 christos /* Shared library handling. */ 172 1.10 christos set_gdbarch_so_ops (gdbarch, &dsbt_so_ops); 173 1.1 christos 174 1.1 christos tdep->syscall_next_pc = tic6x_linux_syscall_next_pc; 175 1.1 christos 176 1.1 christos #ifdef HAVE_ELF 177 1.1 christos /* In tic6x Linux kernel, breakpoint instructions varies on different archs. 178 1.1 christos On C64x+ and C67x+, breakpoint instruction is 0x56454314, which is an 179 1.1 christos illegal opcode. On other arch, breakpoint instruction is 0x0000a122 180 1.1 christos (BNOP .S2 0,5). */ 181 1.1 christos if (info.abfd) 182 1.1 christos switch (bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_PROC, Tag_ISA)) 183 1.1 christos { 184 1.1 christos case C6XABI_Tag_ISA_C64XP: 185 1.1 christos case C6XABI_Tag_ISA_C67XP: 186 1.1 christos if (info.byte_order == BFD_ENDIAN_BIG) 187 1.1 christos tdep->breakpoint = tic6x_bkpt_illegal_opcode_be; 188 1.1 christos else 189 1.1 christos tdep->breakpoint = tic6x_bkpt_illegal_opcode_le; 190 1.1 christos break; 191 1.1 christos default: 192 1.1 christos { 193 1.1 christos if (info.byte_order == BFD_ENDIAN_BIG) 194 1.1 christos tdep->breakpoint = tic6x_bkpt_bnop_be; 195 1.1 christos else 196 1.1 christos tdep->breakpoint = tic6x_bkpt_bnop_le; 197 1.1 christos } 198 1.1 christos } 199 1.1 christos #endif 200 1.1 christos 201 1.1 christos /* Signal trampoline support. */ 202 1.1 christos tramp_frame_prepend_unwinder (gdbarch, 203 1.1 christos &tic6x_linux_rt_sigreturn_tramp_frame); 204 1.1 christos } 205 1.1 christos 206 1.9 christos void _initialize_tic6x_linux_tdep (); 207 1.1 christos void 208 1.9 christos _initialize_tic6x_linux_tdep () 209 1.1 christos { 210 1.1 christos gdbarch_register_osabi (bfd_arch_tic6x, 0, GDB_OSABI_LINUX, 211 1.1 christos tic6x_uclinux_init_abi); 212 1.1 christos } 213