gdb/tic6x-linux-tdep.c - gdb

Global variables defined

Functions defined

Macros defined

Source code

  1. /* GNU/Linux on  TI C6x target support.
  2.    Copyright (C) 2011-2015 Free Software Foundation, Inc.
  3.    Contributed by Yao Qi <yao@codesourcery.com>

  4.    This file is part of GDB.

  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 3 of the License, or
  8.    (at your option) any later version.

  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.

  13.    You should have received a copy of the GNU General Public License
  14.    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

  15. #include "defs.h"
  16. #include "solib.h"
  17. #include "osabi.h"
  18. #include "linux-tdep.h"
  19. #include "tic6x-tdep.h"
  20. #include "trad-frame.h"
  21. #include "tramp-frame.h"
  22. #include "elf-bfd.h"
  23. #include "elf/tic6x.h"

  24. #include "features/tic6x-c64xp-linux.c"
  25. #include "features/tic6x-c64x-linux.c"
  26. #include "features/tic6x-c62x-linux.c"

  27. /* The offset from rt_sigframe pointer to SP register.  */
  28. #define TIC6X_SP_RT_SIGFRAME 8
  29. /* Size of struct siginfo info.  */
  30. #define TIC6X_SIGINFO_SIZE 128
  31. /* Size of type stack_t, which contains three fields of type void*, int, and
  32.    size_t respectively.  */
  33. #define TIC6X_STACK_T_SIZE (3 * 4)

  34. static const gdb_byte tic6x_bkpt_bnop_be[] = { 0x00, 0x00, 0xa1, 0x22 };
  35. static const gdb_byte tic6x_bkpt_bnop_le[] = { 0x22, 0xa1, 0x00, 0x00 };

  36. /* Return the offset of register REGNUM in struct sigcontext.  Return 0 if no
  37.    such register in sigcontext.  */

  38. static unsigned int
  39. tic6x_register_sigcontext_offset (unsigned int regnum, struct gdbarch *gdbarch)
  40. {
  41.   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

  42.   if (regnum == TIC6X_A4_REGNUM || regnum == TIC6X_A4_REGNUM + 2
  43.       || regnum == TIC6X_A4_REGNUM + 4)
  44.     return 4 * (regnum - TIC6X_A4_REGNUM + 2);        /* A4, A6, A8 */
  45.   else if (regnum == TIC6X_A5_REGNUM || regnum == TIC6X_A5_REGNUM + 2
  46.            || regnum == TIC6X_A5_REGNUM + 4)
  47.     return 4 * (regnum - TIC6X_A5_REGNUM + 12);        /* A5, A7, A9 */
  48.   else if (regnum == TIC6X_B4_REGNUM || regnum == TIC6X_B4_REGNUM + 2
  49.            || regnum == TIC6X_B4_REGNUM + 4)
  50.     return 4 * (regnum - TIC6X_B4_REGNUM + 3);        /* B4, B6, B8 */
  51.   else if (regnum == TIC6X_B5_REGNUM || regnum == TIC6X_B5_REGNUM + 2
  52.            || regnum == TIC6X_B5_REGNUM + 4)
  53.     return 4 * (regnum - TIC6X_B5_REGNUM + 19);        /* B5, B7, B9 */
  54.   else if (regnum < TIC6X_A4_REGNUM)
  55.     return 4 * (regnum - 0 + 8);        /* A0 - A3 */
  56.   else if (regnum >= TIC6X_B0_REGNUM && regnum < TIC6X_B4_REGNUM)
  57.     return 4 * (regnum - TIC6X_B0_REGNUM + 15);        /* B0 - B3 */
  58.   else if (regnum >= 34 && regnum < 34 + 32)
  59.     return 4 * (regnum - 34 + 23);        /* A16 - A31, B16 - B31 */
  60.   else if (regnum == TIC6X_PC_REGNUM)
  61.     return 4 * (tdep->has_gp ? 55 : 23);
  62.   else if (regnum == TIC6X_SP_REGNUM)
  63.     return 4;

  64.   return 0;
  65. }

  66. /* Support unwinding frame in signal trampoline.  We don't check sigreturn,
  67.    since it is not used in kernel.  */

  68. static void
  69. tic6x_linux_rt_sigreturn_init (const struct tramp_frame *self,
  70.                                struct frame_info *this_frame,
  71.                                struct trad_frame_cache *this_cache,
  72.                                CORE_ADDR func)
  73. {
  74.   struct gdbarch *gdbarch = get_frame_arch (this_frame);
  75.   CORE_ADDR sp = get_frame_register_unsigned (this_frame, TIC6X_SP_REGNUM);
  76.   /* The base of struct sigcontext is computed by examining the definition of
  77.      struct rt_sigframe in linux kernel source arch/c6x/kernel/signal.c.  */
  78.   CORE_ADDR base = (sp + TIC6X_SP_RT_SIGFRAME
  79.                     /* Pointer type *pinfo and *puc in struct rt_sigframe.  */
  80.                     + 4 + 4
  81.                     + TIC6X_SIGINFO_SIZE
  82.                     + 4 + 4 /* uc_flags and *uc_link in struct ucontext.  */
  83.                     + TIC6X_STACK_T_SIZE);
  84.   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  85.   unsigned int reg_offset;
  86.   unsigned int i;

  87.   for (i = 0; i < 10; i++)        /* A0 - A9 */
  88.     {
  89.       reg_offset = tic6x_register_sigcontext_offset (i, gdbarch);
  90.       gdb_assert (reg_offset != 0);

  91.       trad_frame_set_reg_addr (this_cache, i, base + reg_offset);
  92.     }

  93.   for (i = TIC6X_B0_REGNUM; i < TIC6X_B0_REGNUM + 10; i++)        /* B0 - B9 */
  94.     {
  95.       reg_offset = tic6x_register_sigcontext_offset (i, gdbarch);
  96.       gdb_assert (reg_offset != 0);

  97.       trad_frame_set_reg_addr (this_cache, i, base + reg_offset);
  98.     }

  99.   if (tdep->has_gp)
  100.     for (i = 34; i < 34 + 32; i++)        /* A16 - A31, B16 - B31 */
  101.       {
  102.         reg_offset = tic6x_register_sigcontext_offset (i, gdbarch);
  103.         gdb_assert (reg_offset != 0);

  104.         trad_frame_set_reg_addr (this_cache, i, base + reg_offset);
  105.       }

  106.   trad_frame_set_reg_addr (this_cache, TIC6X_PC_REGNUM,
  107.                            base + tic6x_register_sigcontext_offset (TIC6X_PC_REGNUM,
  108.                                                                     gdbarch));
  109.   trad_frame_set_reg_addr (this_cache, TIC6X_SP_REGNUM,
  110.                            base + tic6x_register_sigcontext_offset (TIC6X_SP_REGNUM,
  111.                                                                     gdbarch));

  112.   /* Save a frame ID.  */
  113.   trad_frame_set_id (this_cache, frame_id_build (sp, func));
  114. }

  115. static struct tramp_frame tic6x_linux_rt_sigreturn_tramp_frame =
  116. {
  117.   SIGTRAMP_FRAME,
  118.   4,
  119.   {
  120.     {0x000045aa, 0x0fffffff},        /* mvk .S2 139,b0 */
  121.     {0x10000000, -1},                /* swe */
  122.     {TRAMP_SENTINEL_INSN}
  123.   },
  124.   tic6x_linux_rt_sigreturn_init
  125. };

  126. /* When FRAME is at a syscall instruction, return the PC of the next
  127.    instruction to be executed.  */

  128. static CORE_ADDR
  129. tic6x_linux_syscall_next_pc (struct frame_info *frame)
  130. {
  131.   ULONGEST syscall_number = get_frame_register_unsigned (frame,
  132.                                                          TIC6X_B0_REGNUM);
  133.   CORE_ADDR pc = get_frame_pc (frame);

  134.   if (syscall_number == 139 /* rt_sigreturn */)
  135.     return frame_unwind_caller_pc (frame);

  136.   return pc + 4;
  137. }


  138. extern struct target_so_ops dsbt_so_ops;
  139. static void
  140. tic6x_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
  141. {
  142.   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

  143.   linux_init_abi (info, gdbarch);

  144.   /* Shared library handling.  */
  145.   set_solib_ops (gdbarch, &dsbt_so_ops);

  146.   tdep->syscall_next_pc = tic6x_linux_syscall_next_pc;

  147. #ifdef HAVE_ELF
  148.   /* In tic6x Linux kernel, breakpoint instructions varies on different archs.
  149.      On C64x+ and C67x+, breakpoint instruction is 0x56454314, which is an
  150.      illegal opcode.  On other arch, breakpoint instruction is 0x0000a122
  151.      (BNOP .S2 0,5).  */
  152.   if (info.abfd)
  153.     switch (bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_PROC, Tag_ISA))
  154.       {
  155.       case C6XABI_Tag_ISA_C64XP:
  156.       case C6XABI_Tag_ISA_C67XP:
  157.         if (info.byte_order == BFD_ENDIAN_BIG)
  158.           tdep->breakpoint = tic6x_bkpt_illegal_opcode_be;
  159.         else
  160.           tdep->breakpoint = tic6x_bkpt_illegal_opcode_le;
  161.         break;
  162.       default:
  163.         {
  164.           if (info.byte_order == BFD_ENDIAN_BIG)
  165.             tdep->breakpoint = tic6x_bkpt_bnop_be;
  166.           else
  167.             tdep->breakpoint = tic6x_bkpt_bnop_le;
  168.         }
  169.       }
  170. #endif

  171.   /* Signal trampoline support.  */
  172.   tramp_frame_prepend_unwinder (gdbarch,
  173.                                 &tic6x_linux_rt_sigreturn_tramp_frame);
  174. }

  175. /* Provide a prototype to silence -Wmissing-prototypes.  */
  176. extern initialize_file_ftype _initialize_tic6x_linux_tdep;

  177. void
  178. _initialize_tic6x_linux_tdep (void)
  179. {
  180.   gdbarch_register_osabi (bfd_arch_tic6x, 0, GDB_OSABI_LINUX,
  181.                           tic6x_uclinux_init_abi);

  182.   initialize_tdesc_tic6x_c64xp_linux ();
  183.   initialize_tdesc_tic6x_c64x_linux ();
  184.   initialize_tdesc_tic6x_c62x_linux ();
  185. }