GDB (API)
|
00001 /* GNU/Linux on TI C6x target support. 00002 Copyright (C) 2011-2013 Free Software Foundation, Inc. 00003 Contributed by Yao Qi <yao@codesourcery.com> 00004 00005 This file is part of GDB. 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 00019 00020 #include "defs.h" 00021 #include "solib.h" 00022 #include "osabi.h" 00023 #include "linux-tdep.h" 00024 #include "tic6x-tdep.h" 00025 #include "trad-frame.h" 00026 #include "tramp-frame.h" 00027 #include "gdb_assert.h" 00028 #include "elf-bfd.h" 00029 #include "elf/tic6x.h" 00030 00031 #include "features/tic6x-c64xp-linux.c" 00032 #include "features/tic6x-c64x-linux.c" 00033 #include "features/tic6x-c62x-linux.c" 00034 00035 /* The offset from rt_sigframe pointer to SP register. */ 00036 #define TIC6X_SP_RT_SIGFRAME 8 00037 /* Size of struct siginfo info. */ 00038 #define TIC6X_SIGINFO_SIZE 128 00039 /* Size of type stack_t, which contains three fields of type void*, int, and 00040 size_t respectively. */ 00041 #define TIC6X_STACK_T_SIZE (3 * 4) 00042 00043 static const gdb_byte tic6x_bkpt_bnop_be[] = { 0x00, 0x00, 0xa1, 0x22 }; 00044 static const gdb_byte tic6x_bkpt_bnop_le[] = { 0x22, 0xa1, 0x00, 0x00 }; 00045 00046 /* Return the offset of register REGNUM in struct sigcontext. Return 0 if no 00047 such register in sigcontext. */ 00048 00049 static unsigned int 00050 tic6x_register_sigcontext_offset (unsigned int regnum, struct gdbarch *gdbarch) 00051 { 00052 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 00053 00054 if (regnum == TIC6X_A4_REGNUM || regnum == TIC6X_A4_REGNUM + 2 00055 || regnum == TIC6X_A4_REGNUM + 4) 00056 return 4 * (regnum - TIC6X_A4_REGNUM + 2); /* A4, A6, A8 */ 00057 else if (regnum == TIC6X_A5_REGNUM || regnum == TIC6X_A5_REGNUM + 2 00058 || regnum == TIC6X_A5_REGNUM + 4) 00059 return 4 * (regnum - TIC6X_A5_REGNUM + 12); /* A5, A7, A9 */ 00060 else if (regnum == TIC6X_B4_REGNUM || regnum == TIC6X_B4_REGNUM + 2 00061 || regnum == TIC6X_B4_REGNUM + 4) 00062 return 4 * (regnum - TIC6X_B4_REGNUM + 3); /* B4, B6, B8 */ 00063 else if (regnum == TIC6X_B5_REGNUM || regnum == TIC6X_B5_REGNUM + 2 00064 || regnum == TIC6X_B5_REGNUM + 4) 00065 return 4 * (regnum - TIC6X_B5_REGNUM + 19); /* B5, B7, B9 */ 00066 else if (regnum < TIC6X_A4_REGNUM) 00067 return 4 * (regnum - 0 + 8); /* A0 - A3 */ 00068 else if (regnum >= TIC6X_B0_REGNUM && regnum < TIC6X_B4_REGNUM) 00069 return 4 * (regnum - TIC6X_B0_REGNUM + 15); /* B0 - B3 */ 00070 else if (regnum >= 34 && regnum < 34 + 32) 00071 return 4 * (regnum - 34 + 23); /* A16 - A31, B16 - B31 */ 00072 else if (regnum == TIC6X_PC_REGNUM) 00073 return 4 * (tdep->has_gp ? 55 : 23); 00074 else if (regnum == TIC6X_SP_REGNUM) 00075 return 4; 00076 00077 return 0; 00078 } 00079 00080 /* Support unwinding frame in signal trampoline. We don't check sigreturn, 00081 since it is not used in kernel. */ 00082 00083 static void 00084 tic6x_linux_rt_sigreturn_init (const struct tramp_frame *self, 00085 struct frame_info *this_frame, 00086 struct trad_frame_cache *this_cache, 00087 CORE_ADDR func) 00088 { 00089 struct gdbarch *gdbarch = get_frame_arch (this_frame); 00090 CORE_ADDR sp = get_frame_register_unsigned (this_frame, TIC6X_SP_REGNUM); 00091 /* The base of struct sigcontext is computed by examining the definition of 00092 struct rt_sigframe in linux kernel source arch/c6x/kernel/signal.c. */ 00093 CORE_ADDR base = (sp + TIC6X_SP_RT_SIGFRAME 00094 /* Pointer type *pinfo and *puc in struct rt_sigframe. */ 00095 + 4 + 4 00096 + TIC6X_SIGINFO_SIZE 00097 + 4 + 4 /* uc_flags and *uc_link in struct ucontext. */ 00098 + TIC6X_STACK_T_SIZE); 00099 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 00100 unsigned int reg_offset; 00101 unsigned int i; 00102 00103 for (i = 0; i < 10; i++) /* A0 - A9 */ 00104 { 00105 reg_offset = tic6x_register_sigcontext_offset (i, gdbarch); 00106 gdb_assert (reg_offset != 0); 00107 00108 trad_frame_set_reg_addr (this_cache, i, base + reg_offset); 00109 } 00110 00111 for (i = TIC6X_B0_REGNUM; i < TIC6X_B0_REGNUM + 10; i++) /* B0 - B9 */ 00112 { 00113 reg_offset = tic6x_register_sigcontext_offset (i, gdbarch); 00114 gdb_assert (reg_offset != 0); 00115 00116 trad_frame_set_reg_addr (this_cache, i, base + reg_offset); 00117 } 00118 00119 if (tdep->has_gp) 00120 for (i = 34; i < 34 + 32; i++) /* A16 - A31, B16 - B31 */ 00121 { 00122 reg_offset = tic6x_register_sigcontext_offset (i, gdbarch); 00123 gdb_assert (reg_offset != 0); 00124 00125 trad_frame_set_reg_addr (this_cache, i, base + reg_offset); 00126 } 00127 00128 trad_frame_set_reg_addr (this_cache, TIC6X_PC_REGNUM, 00129 base + tic6x_register_sigcontext_offset (TIC6X_PC_REGNUM, 00130 gdbarch)); 00131 trad_frame_set_reg_addr (this_cache, TIC6X_SP_REGNUM, 00132 base + tic6x_register_sigcontext_offset (TIC6X_SP_REGNUM, 00133 gdbarch)); 00134 00135 /* Save a frame ID. */ 00136 trad_frame_set_id (this_cache, frame_id_build (sp, func)); 00137 } 00138 00139 static struct tramp_frame tic6x_linux_rt_sigreturn_tramp_frame = 00140 { 00141 SIGTRAMP_FRAME, 00142 4, 00143 { 00144 {0x000045aa, 0x0fffffff}, /* mvk .S2 139,b0 */ 00145 {0x10000000, -1}, /* swe */ 00146 {TRAMP_SENTINEL_INSN} 00147 }, 00148 tic6x_linux_rt_sigreturn_init 00149 }; 00150 00151 /* When FRAME is at a syscall instruction, return the PC of the next 00152 instruction to be executed. */ 00153 00154 static CORE_ADDR 00155 tic6x_linux_syscall_next_pc (struct frame_info *frame) 00156 { 00157 ULONGEST syscall_number = get_frame_register_unsigned (frame, 00158 TIC6X_B0_REGNUM); 00159 CORE_ADDR pc = get_frame_pc (frame); 00160 00161 if (syscall_number == 139 /* rt_sigreturn */) 00162 return frame_unwind_caller_pc (frame); 00163 00164 return pc + 4; 00165 } 00166 00167 00168 extern struct target_so_ops dsbt_so_ops; 00169 static void 00170 tic6x_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 00171 { 00172 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 00173 00174 linux_init_abi (info, gdbarch); 00175 00176 /* Shared library handling. */ 00177 set_solib_ops (gdbarch, &dsbt_so_ops); 00178 00179 tdep->syscall_next_pc = tic6x_linux_syscall_next_pc; 00180 00181 #ifdef HAVE_ELF 00182 /* In tic6x Linux kernel, breakpoint instructions varies on different archs. 00183 On C64x+ and C67x+, breakpoint instruction is 0x56454314, which is an 00184 illegal opcode. On other arch, breakpoint instruction is 0x0000a122 00185 (BNOP .S2 0,5). */ 00186 if (info.abfd) 00187 switch (bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_PROC, Tag_ISA)) 00188 { 00189 case C6XABI_Tag_ISA_C64XP: 00190 case C6XABI_Tag_ISA_C67XP: 00191 if (info.byte_order == BFD_ENDIAN_BIG) 00192 tdep->breakpoint = tic6x_bkpt_illegal_opcode_be; 00193 else 00194 tdep->breakpoint = tic6x_bkpt_illegal_opcode_le; 00195 break; 00196 default: 00197 { 00198 if (info.byte_order == BFD_ENDIAN_BIG) 00199 tdep->breakpoint = tic6x_bkpt_bnop_be; 00200 else 00201 tdep->breakpoint = tic6x_bkpt_bnop_le; 00202 } 00203 } 00204 #endif 00205 00206 /* Signal trampoline support. */ 00207 tramp_frame_prepend_unwinder (gdbarch, 00208 &tic6x_linux_rt_sigreturn_tramp_frame); 00209 } 00210 00211 /* Provide a prototype to silence -Wmissing-prototypes. */ 00212 extern initialize_file_ftype _initialize_tic6x_linux_tdep; 00213 00214 void 00215 _initialize_tic6x_linux_tdep (void) 00216 { 00217 gdbarch_register_osabi (bfd_arch_tic6x, 0, GDB_OSABI_LINUX, 00218 tic6x_uclinux_init_abi); 00219 00220 initialize_tdesc_tic6x_c64xp_linux (); 00221 initialize_tdesc_tic6x_c64x_linux (); 00222 initialize_tdesc_tic6x_c62x_linux (); 00223 }