Home | History | Annotate | Line # | Download | only in gdb
tic6x-linux-tdep.c revision 1.11
      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