Home | History | Annotate | Line # | Download | only in gdb
tic6x-linux-tdep.c revision 1.6
      1  1.1  christos /* GNU/Linux on  TI C6x target support.
      2  1.6  christos    Copyright (C) 2011-2016 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 "defs.h"
     21  1.1  christos #include "solib.h"
     22  1.1  christos #include "osabi.h"
     23  1.1  christos #include "linux-tdep.h"
     24  1.1  christos #include "tic6x-tdep.h"
     25  1.1  christos #include "trad-frame.h"
     26  1.1  christos #include "tramp-frame.h"
     27  1.1  christos #include "elf-bfd.h"
     28  1.1  christos #include "elf/tic6x.h"
     29  1.1  christos 
     30  1.1  christos #include "features/tic6x-c64xp-linux.c"
     31  1.1  christos #include "features/tic6x-c64x-linux.c"
     32  1.1  christos #include "features/tic6x-c62x-linux.c"
     33  1.1  christos 
     34  1.1  christos /* The offset from rt_sigframe pointer to SP register.  */
     35  1.1  christos #define TIC6X_SP_RT_SIGFRAME 8
     36  1.1  christos /* Size of struct siginfo info.  */
     37  1.1  christos #define TIC6X_SIGINFO_SIZE 128
     38  1.1  christos /* Size of type stack_t, which contains three fields of type void*, int, and
     39  1.1  christos    size_t respectively.  */
     40  1.1  christos #define TIC6X_STACK_T_SIZE (3 * 4)
     41  1.1  christos 
     42  1.1  christos static const gdb_byte tic6x_bkpt_bnop_be[] = { 0x00, 0x00, 0xa1, 0x22 };
     43  1.1  christos static const gdb_byte tic6x_bkpt_bnop_le[] = { 0x22, 0xa1, 0x00, 0x00 };
     44  1.1  christos 
     45  1.1  christos /* Return the offset of register REGNUM in struct sigcontext.  Return 0 if no
     46  1.1  christos    such register in sigcontext.  */
     47  1.1  christos 
     48  1.1  christos static unsigned int
     49  1.1  christos tic6x_register_sigcontext_offset (unsigned int regnum, struct gdbarch *gdbarch)
     50  1.1  christos {
     51  1.1  christos   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
     52  1.1  christos 
     53  1.1  christos   if (regnum == TIC6X_A4_REGNUM || regnum == TIC6X_A4_REGNUM + 2
     54  1.1  christos       || regnum == TIC6X_A4_REGNUM + 4)
     55  1.1  christos     return 4 * (regnum - TIC6X_A4_REGNUM + 2);	/* A4, A6, A8 */
     56  1.1  christos   else if (regnum == TIC6X_A5_REGNUM || regnum == TIC6X_A5_REGNUM + 2
     57  1.1  christos 	   || regnum == TIC6X_A5_REGNUM + 4)
     58  1.1  christos     return 4 * (regnum - TIC6X_A5_REGNUM + 12);	/* A5, A7, A9 */
     59  1.1  christos   else if (regnum == TIC6X_B4_REGNUM || regnum == TIC6X_B4_REGNUM + 2
     60  1.1  christos 	   || regnum == TIC6X_B4_REGNUM + 4)
     61  1.1  christos     return 4 * (regnum - TIC6X_B4_REGNUM + 3);	/* B4, B6, B8 */
     62  1.1  christos   else if (regnum == TIC6X_B5_REGNUM || regnum == TIC6X_B5_REGNUM + 2
     63  1.1  christos 	   || regnum == TIC6X_B5_REGNUM + 4)
     64  1.1  christos     return 4 * (regnum - TIC6X_B5_REGNUM + 19);	/* B5, B7, B9 */
     65  1.1  christos   else if (regnum < TIC6X_A4_REGNUM)
     66  1.1  christos     return 4 * (regnum - 0 + 8);	/* A0 - A3 */
     67  1.1  christos   else if (regnum >= TIC6X_B0_REGNUM && regnum < TIC6X_B4_REGNUM)
     68  1.1  christos     return 4 * (regnum - TIC6X_B0_REGNUM + 15);	/* B0 - B3 */
     69  1.1  christos   else if (regnum >= 34 && regnum < 34 + 32)
     70  1.1  christos     return 4 * (regnum - 34 + 23);	/* A16 - A31, B16 - B31 */
     71  1.1  christos   else if (regnum == TIC6X_PC_REGNUM)
     72  1.1  christos     return 4 * (tdep->has_gp ? 55 : 23);
     73  1.1  christos   else if (regnum == TIC6X_SP_REGNUM)
     74  1.1  christos     return 4;
     75  1.1  christos 
     76  1.1  christos   return 0;
     77  1.1  christos }
     78  1.1  christos 
     79  1.1  christos /* Support unwinding frame in signal trampoline.  We don't check sigreturn,
     80  1.1  christos    since it is not used in kernel.  */
     81  1.1  christos 
     82  1.1  christos static void
     83  1.1  christos tic6x_linux_rt_sigreturn_init (const struct tramp_frame *self,
     84  1.1  christos 			       struct frame_info *this_frame,
     85  1.1  christos 			       struct trad_frame_cache *this_cache,
     86  1.1  christos 			       CORE_ADDR func)
     87  1.1  christos {
     88  1.1  christos   struct gdbarch *gdbarch = get_frame_arch (this_frame);
     89  1.1  christos   CORE_ADDR sp = get_frame_register_unsigned (this_frame, TIC6X_SP_REGNUM);
     90  1.1  christos   /* The base of struct sigcontext is computed by examining the definition of
     91  1.1  christos      struct rt_sigframe in linux kernel source arch/c6x/kernel/signal.c.  */
     92  1.1  christos   CORE_ADDR base = (sp + TIC6X_SP_RT_SIGFRAME
     93  1.1  christos 		    /* Pointer type *pinfo and *puc in struct rt_sigframe.  */
     94  1.1  christos 		    + 4 + 4
     95  1.1  christos 		    + TIC6X_SIGINFO_SIZE
     96  1.1  christos 		    + 4 + 4 /* uc_flags and *uc_link in struct ucontext.  */
     97  1.1  christos 		    + TIC6X_STACK_T_SIZE);
     98  1.1  christos   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
     99  1.1  christos   unsigned int reg_offset;
    100  1.1  christos   unsigned int i;
    101  1.1  christos 
    102  1.1  christos   for (i = 0; i < 10; i++)	/* A0 - A9 */
    103  1.1  christos     {
    104  1.1  christos       reg_offset = tic6x_register_sigcontext_offset (i, gdbarch);
    105  1.1  christos       gdb_assert (reg_offset != 0);
    106  1.1  christos 
    107  1.1  christos       trad_frame_set_reg_addr (this_cache, i, base + reg_offset);
    108  1.1  christos     }
    109  1.1  christos 
    110  1.1  christos   for (i = TIC6X_B0_REGNUM; i < TIC6X_B0_REGNUM + 10; i++)	/* B0 - B9 */
    111  1.1  christos     {
    112  1.1  christos       reg_offset = tic6x_register_sigcontext_offset (i, gdbarch);
    113  1.1  christos       gdb_assert (reg_offset != 0);
    114  1.1  christos 
    115  1.1  christos       trad_frame_set_reg_addr (this_cache, i, base + reg_offset);
    116  1.1  christos     }
    117  1.1  christos 
    118  1.1  christos   if (tdep->has_gp)
    119  1.1  christos     for (i = 34; i < 34 + 32; i++)	/* A16 - A31, B16 - B31 */
    120  1.1  christos       {
    121  1.1  christos 	reg_offset = tic6x_register_sigcontext_offset (i, gdbarch);
    122  1.1  christos 	gdb_assert (reg_offset != 0);
    123  1.1  christos 
    124  1.1  christos 	trad_frame_set_reg_addr (this_cache, i, base + reg_offset);
    125  1.1  christos       }
    126  1.1  christos 
    127  1.1  christos   trad_frame_set_reg_addr (this_cache, TIC6X_PC_REGNUM,
    128  1.1  christos 			   base + tic6x_register_sigcontext_offset (TIC6X_PC_REGNUM,
    129  1.1  christos 								    gdbarch));
    130  1.1  christos   trad_frame_set_reg_addr (this_cache, TIC6X_SP_REGNUM,
    131  1.1  christos 			   base + tic6x_register_sigcontext_offset (TIC6X_SP_REGNUM,
    132  1.1  christos 								    gdbarch));
    133  1.1  christos 
    134  1.1  christos   /* Save a frame ID.  */
    135  1.1  christos   trad_frame_set_id (this_cache, frame_id_build (sp, func));
    136  1.1  christos }
    137  1.1  christos 
    138  1.1  christos static struct tramp_frame tic6x_linux_rt_sigreturn_tramp_frame =
    139  1.1  christos {
    140  1.1  christos   SIGTRAMP_FRAME,
    141  1.1  christos   4,
    142  1.1  christos   {
    143  1.1  christos     {0x000045aa, 0x0fffffff},	/* mvk .S2 139,b0 */
    144  1.1  christos     {0x10000000, -1},		/* swe */
    145  1.1  christos     {TRAMP_SENTINEL_INSN}
    146  1.1  christos   },
    147  1.1  christos   tic6x_linux_rt_sigreturn_init
    148  1.1  christos };
    149  1.1  christos 
    150  1.1  christos /* When FRAME is at a syscall instruction, return the PC of the next
    151  1.1  christos    instruction to be executed.  */
    152  1.1  christos 
    153  1.1  christos static CORE_ADDR
    154  1.1  christos tic6x_linux_syscall_next_pc (struct frame_info *frame)
    155  1.1  christos {
    156  1.1  christos   ULONGEST syscall_number = get_frame_register_unsigned (frame,
    157  1.1  christos 							 TIC6X_B0_REGNUM);
    158  1.1  christos   CORE_ADDR pc = get_frame_pc (frame);
    159  1.1  christos 
    160  1.1  christos   if (syscall_number == 139 /* rt_sigreturn */)
    161  1.1  christos     return frame_unwind_caller_pc (frame);
    162  1.1  christos 
    163  1.1  christos   return pc + 4;
    164  1.1  christos }
    165  1.1  christos 
    166  1.1  christos 
    167  1.1  christos extern struct target_so_ops dsbt_so_ops;
    168  1.1  christos static void
    169  1.1  christos tic6x_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
    170  1.1  christos {
    171  1.1  christos   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
    172  1.1  christos 
    173  1.1  christos   linux_init_abi (info, gdbarch);
    174  1.1  christos 
    175  1.1  christos   /* Shared library handling.  */
    176  1.1  christos   set_solib_ops (gdbarch, &dsbt_so_ops);
    177  1.1  christos 
    178  1.1  christos   tdep->syscall_next_pc = tic6x_linux_syscall_next_pc;
    179  1.1  christos 
    180  1.1  christos #ifdef HAVE_ELF
    181  1.1  christos   /* In tic6x Linux kernel, breakpoint instructions varies on different archs.
    182  1.1  christos      On C64x+ and C67x+, breakpoint instruction is 0x56454314, which is an
    183  1.1  christos      illegal opcode.  On other arch, breakpoint instruction is 0x0000a122
    184  1.1  christos      (BNOP .S2 0,5).  */
    185  1.1  christos   if (info.abfd)
    186  1.1  christos     switch (bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_PROC, Tag_ISA))
    187  1.1  christos       {
    188  1.1  christos       case C6XABI_Tag_ISA_C64XP:
    189  1.1  christos       case C6XABI_Tag_ISA_C67XP:
    190  1.1  christos 	if (info.byte_order == BFD_ENDIAN_BIG)
    191  1.1  christos 	  tdep->breakpoint = tic6x_bkpt_illegal_opcode_be;
    192  1.1  christos 	else
    193  1.1  christos 	  tdep->breakpoint = tic6x_bkpt_illegal_opcode_le;
    194  1.1  christos 	break;
    195  1.1  christos       default:
    196  1.1  christos 	{
    197  1.1  christos 	  if (info.byte_order == BFD_ENDIAN_BIG)
    198  1.1  christos 	    tdep->breakpoint = tic6x_bkpt_bnop_be;
    199  1.1  christos 	  else
    200  1.1  christos 	    tdep->breakpoint = tic6x_bkpt_bnop_le;
    201  1.1  christos 	}
    202  1.1  christos       }
    203  1.1  christos #endif
    204  1.1  christos 
    205  1.1  christos   /* Signal trampoline support.  */
    206  1.1  christos   tramp_frame_prepend_unwinder (gdbarch,
    207  1.1  christos 				&tic6x_linux_rt_sigreturn_tramp_frame);
    208  1.1  christos }
    209  1.1  christos 
    210  1.1  christos /* Provide a prototype to silence -Wmissing-prototypes.  */
    211  1.1  christos extern initialize_file_ftype _initialize_tic6x_linux_tdep;
    212  1.1  christos 
    213  1.1  christos void
    214  1.1  christos _initialize_tic6x_linux_tdep (void)
    215  1.1  christos {
    216  1.1  christos   gdbarch_register_osabi (bfd_arch_tic6x, 0, GDB_OSABI_LINUX,
    217  1.1  christos 			  tic6x_uclinux_init_abi);
    218  1.1  christos 
    219  1.1  christos   initialize_tdesc_tic6x_c64xp_linux ();
    220  1.1  christos   initialize_tdesc_tic6x_c64x_linux ();
    221  1.1  christos   initialize_tdesc_tic6x_c62x_linux ();
    222  1.1  christos }
    223