Home | History | Annotate | Line # | Download | only in gdbserver
      1      1.1  christos /* Target dependent code for GDB on TI C6x systems.
      2      1.1  christos 
      3  1.1.1.4  christos    Copyright (C) 2010-2025 Free Software Foundation, Inc.
      4      1.1  christos    Contributed by Andrew Jenner <andrew (at) codesourcery.com>
      5      1.1  christos    Contributed by Yao Qi <yao (at) codesourcery.com>
      6      1.1  christos 
      7      1.1  christos    This file is part of GDB.
      8      1.1  christos 
      9      1.1  christos    This program is free software; you can redistribute it and/or modify
     10      1.1  christos    it under the terms of the GNU General Public License as published by
     11      1.1  christos    the Free Software Foundation; either version 3 of the License, or
     12      1.1  christos    (at your option) any later version.
     13      1.1  christos 
     14      1.1  christos    This program is distributed in the hope that it will be useful,
     15      1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     16      1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17      1.1  christos    GNU General Public License for more details.
     18      1.1  christos 
     19      1.1  christos    You should have received a copy of the GNU General Public License
     20      1.1  christos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     21      1.1  christos 
     22      1.1  christos #include "linux-low.h"
     23      1.1  christos #include "arch/tic6x.h"
     24      1.1  christos #include "tdesc.h"
     25      1.1  christos 
     26      1.1  christos #include "nat/gdb_ptrace.h"
     27      1.1  christos #include <endian.h>
     28      1.1  christos 
     29      1.1  christos #include "gdb_proc_service.h"
     30      1.1  christos 
     31      1.1  christos #ifndef PTRACE_GET_THREAD_AREA
     32      1.1  christos #define PTRACE_GET_THREAD_AREA 25
     33      1.1  christos #endif
     34      1.1  christos 
     35      1.1  christos /* There are at most 69 registers accessible in ptrace.  */
     36      1.1  christos #define TIC6X_NUM_REGS 69
     37      1.1  christos 
     38      1.1  christos #include <asm/ptrace.h>
     39      1.1  christos 
     40      1.1  christos /* Linux target op definitions for the TI C6x architecture.  */
     41      1.1  christos 
     42      1.1  christos class tic6x_target : public linux_process_target
     43      1.1  christos {
     44      1.1  christos public:
     45      1.1  christos 
     46      1.1  christos   const regs_info *get_regs_info () override;
     47      1.1  christos 
     48      1.1  christos   const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override;
     49      1.1  christos 
     50      1.1  christos protected:
     51      1.1  christos 
     52      1.1  christos   void low_arch_setup () override;
     53      1.1  christos 
     54      1.1  christos   bool low_cannot_fetch_register (int regno) override;
     55      1.1  christos 
     56      1.1  christos   bool low_cannot_store_register (int regno) override;
     57      1.1  christos 
     58      1.1  christos   bool low_supports_breakpoints () override;
     59      1.1  christos 
     60      1.1  christos   CORE_ADDR low_get_pc (regcache *regcache) override;
     61      1.1  christos 
     62      1.1  christos   void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
     63      1.1  christos 
     64      1.1  christos   bool low_breakpoint_at (CORE_ADDR pc) override;
     65      1.1  christos };
     66      1.1  christos 
     67      1.1  christos /* The singleton target ops object.  */
     68      1.1  christos 
     69      1.1  christos static tic6x_target the_tic6x_target;
     70      1.1  christos 
     71      1.1  christos /* Defined in auto-generated file tic6x-c64xp-linux.c.  */
     72      1.1  christos void init_registers_tic6x_c64xp_linux (void);
     73      1.1  christos extern const struct target_desc *tdesc_tic6x_c64xp_linux;
     74      1.1  christos 
     75      1.1  christos /* Defined in auto-generated file tic6x-c64x-linux.c.  */
     76      1.1  christos void init_registers_tic6x_c64x_linux (void);
     77      1.1  christos extern const struct target_desc *tdesc_tic6x_c64x_linux;
     78      1.1  christos 
     79      1.1  christos /* Defined in auto-generated file tic62x-c6xp-linux.c.  */
     80      1.1  christos void init_registers_tic6x_c62x_linux (void);
     81      1.1  christos extern const struct target_desc *tdesc_tic6x_c62x_linux;
     82      1.1  christos 
     83      1.1  christos union tic6x_register
     84      1.1  christos {
     85      1.1  christos   unsigned char buf[4];
     86      1.1  christos 
     87      1.1  christos   int reg32;
     88      1.1  christos };
     89      1.1  christos 
     90      1.1  christos /* Return the ptrace ``address'' of register REGNO.  */
     91      1.1  christos 
     92      1.1  christos #if __BYTE_ORDER == __BIG_ENDIAN
     93      1.1  christos static int tic6x_regmap_c64xp[] = {
     94      1.1  christos   /* A0 - A15 */
     95      1.1  christos   53, 52, 55, 54, 57, 56, 59, 58,
     96      1.1  christos   61, 60, 63, 62, 65, 64, 67, 66,
     97      1.1  christos   /* B0 - B15 */
     98      1.1  christos   23, 22, 25, 24, 27, 26, 29, 28,
     99      1.1  christos   31, 30, 33, 32, 35, 34, 69, 68,
    100      1.1  christos   /* CSR PC */
    101      1.1  christos   5, 4,
    102      1.1  christos   /* A16 - A31 */
    103      1.1  christos   37, 36, 39, 38, 41, 40, 43, 42,
    104      1.1  christos   45, 44, 47, 46, 49, 48, 51, 50,
    105      1.1  christos   /* B16 - B31 */
    106      1.1  christos   7,  6,  9,  8,  11, 10, 13, 12,
    107      1.1  christos   15, 14, 17, 16, 19, 18, 21, 20,
    108      1.1  christos   /* TSR, ILC, RILC */
    109      1.1  christos   1,  2, 3
    110      1.1  christos };
    111      1.1  christos 
    112      1.1  christos static int tic6x_regmap_c64x[] = {
    113      1.1  christos   /* A0 - A15 */
    114      1.1  christos   51, 50, 53, 52, 55, 54, 57, 56,
    115      1.1  christos   59, 58, 61, 60, 63, 62, 65, 64,
    116      1.1  christos   /* B0 - B15 */
    117      1.1  christos   21, 20, 23, 22, 25, 24, 27, 26,
    118      1.1  christos   29, 28, 31, 30, 33, 32, 67, 66,
    119      1.1  christos   /* CSR PC */
    120      1.1  christos   3,  2,
    121      1.1  christos   /* A16 - A31 */
    122      1.1  christos   35, 34, 37, 36, 39, 38, 41, 40,
    123      1.1  christos   43, 42, 45, 44, 47, 46, 49, 48,
    124      1.1  christos   /* B16 - B31 */
    125      1.1  christos   5,  4,  7,  6,  9,  8,  11, 10,
    126      1.1  christos   13, 12, 15, 14, 17, 16, 19, 18,
    127      1.1  christos   -1, -1, -1
    128      1.1  christos };
    129      1.1  christos 
    130      1.1  christos static int tic6x_regmap_c62x[] = {
    131      1.1  christos   /* A0 - A15 */
    132      1.1  christos   19, 18, 21, 20, 23, 22, 25, 24,
    133      1.1  christos   27, 26, 29, 28, 31, 30, 33, 32,
    134      1.1  christos   /* B0 - B15 */
    135      1.1  christos    5,  4,  7,  6,  9,  8, 11, 10,
    136      1.1  christos   13, 12, 15, 14, 17, 16, 35, 34,
    137      1.1  christos   /* CSR, PC */
    138      1.1  christos   3, 2,
    139      1.1  christos   -1, -1, -1, -1, -1, -1, -1, -1,
    140      1.1  christos   -1, -1, -1, -1, -1, -1, -1, -1,
    141      1.1  christos   -1, -1, -1, -1, -1, -1, -1, -1,
    142      1.1  christos   -1, -1, -1, -1, -1, -1, -1, -1,
    143      1.1  christos   -1, -1, -1
    144      1.1  christos };
    145      1.1  christos 
    146      1.1  christos #else
    147      1.1  christos static int tic6x_regmap_c64xp[] = {
    148      1.1  christos   /* A0 - A15 */
    149      1.1  christos   52, 53, 54, 55, 56, 57, 58, 59,
    150      1.1  christos   60, 61, 62, 63, 64, 65, 66, 67,
    151      1.1  christos   /* B0 - B15 */
    152      1.1  christos   22, 23, 24, 25, 26, 27, 28, 29,
    153      1.1  christos   30, 31, 32, 33, 34, 35, 68, 69,
    154      1.1  christos   /* CSR PC */
    155      1.1  christos    4,  5,
    156      1.1  christos   /* A16 - A31 */
    157      1.1  christos   36, 37, 38, 39, 40, 41, 42, 43,
    158      1.1  christos   44, 45, 46, 47, 48, 49, 50, 51,
    159      1.1  christos   /* B16 -B31 */
    160      1.1  christos    6,  7,  8,  9, 10, 11, 12, 13,
    161      1.1  christos   14, 15, 16, 17, 18, 19, 20, 31,
    162      1.1  christos   /* TSR, ILC, RILC */
    163      1.1  christos   0,  3, 2
    164      1.1  christos };
    165      1.1  christos 
    166      1.1  christos static int tic6x_regmap_c64x[] = {
    167      1.1  christos   /* A0 - A15 */
    168      1.1  christos   50, 51, 52, 53, 54, 55, 56, 57,
    169      1.1  christos   58, 59, 60, 61, 62, 63, 64, 65,
    170      1.1  christos   /* B0 - B15 */
    171      1.1  christos   20, 21, 22, 23, 24, 25, 26, 27,
    172      1.1  christos   28, 29, 30, 31, 32, 33, 66, 67,
    173      1.1  christos   /* CSR PC */
    174      1.1  christos   2,  3,
    175      1.1  christos   /* A16 - A31 */
    176      1.1  christos   34, 35, 36, 37, 38, 39, 40, 41,
    177      1.1  christos   42, 43, 44, 45, 46, 47, 48, 49,
    178      1.1  christos   /* B16 - B31 */
    179      1.1  christos   4,  5,  6,  7,  8,  9,  10, 11,
    180      1.1  christos   12, 13, 14, 15, 16, 17, 18, 19,
    181      1.1  christos   -1, -1, -1
    182      1.1  christos };
    183      1.1  christos 
    184      1.1  christos static int tic6x_regmap_c62x[] = {
    185      1.1  christos   /* A0 - A15 */
    186      1.1  christos   18, 19, 20, 21, 22, 23, 24, 25,
    187      1.1  christos   26, 27, 28, 29, 30, 31, 32, 33,
    188      1.1  christos   /* B0 - B15 */
    189      1.1  christos   4,  5,  6,  7,  8,  9, 10, 11,
    190      1.1  christos   12, 13, 14, 15, 16, 17, 34, 35,
    191      1.1  christos   /* CSR PC */
    192      1.1  christos   2,  3,
    193      1.1  christos   -1, -1, -1, -1, -1, -1, -1, -1,
    194      1.1  christos   -1, -1, -1, -1, -1, -1, -1, -1,
    195      1.1  christos   -1, -1, -1, -1, -1, -1, -1, -1,
    196      1.1  christos   -1, -1, -1, -1, -1, -1, -1, -1,
    197      1.1  christos   -1, -1, -1
    198      1.1  christos };
    199      1.1  christos 
    200      1.1  christos #endif
    201      1.1  christos 
    202      1.1  christos static int *tic6x_regmap;
    203      1.1  christos static unsigned int tic6x_breakpoint;
    204      1.1  christos #define tic6x_breakpoint_len 4
    205      1.1  christos 
    206      1.1  christos /* Implementation of target ops method "sw_breakpoint_from_kind".  */
    207      1.1  christos 
    208      1.1  christos const gdb_byte *
    209      1.1  christos tic6x_target::sw_breakpoint_from_kind (int kind, int *size)
    210      1.1  christos {
    211      1.1  christos   *size = tic6x_breakpoint_len;
    212      1.1  christos   return (const gdb_byte *) &tic6x_breakpoint;
    213      1.1  christos }
    214      1.1  christos 
    215      1.1  christos static struct usrregs_info tic6x_usrregs_info =
    216      1.1  christos   {
    217      1.1  christos     TIC6X_NUM_REGS,
    218      1.1  christos     NULL, /* Set in tic6x_read_description.  */
    219      1.1  christos   };
    220      1.1  christos 
    221      1.1  christos static const struct target_desc *
    222      1.1  christos tic6x_read_description (enum c6x_feature feature)
    223      1.1  christos {
    224      1.1  christos   static target_desc *tdescs[C6X_LAST] = { };
    225      1.1  christos   struct target_desc **tdesc = &tdescs[feature];
    226      1.1  christos 
    227      1.1  christos   if (*tdesc == NULL)
    228      1.1  christos     {
    229      1.1  christos       *tdesc = tic6x_create_target_description (feature);
    230      1.1  christos       static const char *expedite_regs[] = { "A15", "PC", NULL };
    231      1.1  christos       init_target_desc (*tdesc, expedite_regs);
    232      1.1  christos     }
    233      1.1  christos 
    234      1.1  christos   return *tdesc;
    235      1.1  christos }
    236      1.1  christos 
    237      1.1  christos bool
    238      1.1  christos tic6x_target::low_cannot_fetch_register (int regno)
    239      1.1  christos {
    240      1.1  christos   return (tic6x_regmap[regno] == -1);
    241      1.1  christos }
    242      1.1  christos 
    243      1.1  christos bool
    244      1.1  christos tic6x_target::low_cannot_store_register (int regno)
    245      1.1  christos {
    246      1.1  christos   return (tic6x_regmap[regno] == -1);
    247      1.1  christos }
    248      1.1  christos 
    249      1.1  christos bool
    250      1.1  christos tic6x_target::low_supports_breakpoints ()
    251      1.1  christos {
    252      1.1  christos   return true;
    253      1.1  christos }
    254      1.1  christos 
    255      1.1  christos CORE_ADDR
    256      1.1  christos tic6x_target::low_get_pc (regcache *regcache)
    257      1.1  christos {
    258      1.1  christos   union tic6x_register pc;
    259      1.1  christos 
    260      1.1  christos   collect_register_by_name (regcache, "PC", pc.buf);
    261      1.1  christos   return pc.reg32;
    262      1.1  christos }
    263      1.1  christos 
    264      1.1  christos void
    265      1.1  christos tic6x_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
    266      1.1  christos {
    267      1.1  christos   union tic6x_register newpc;
    268      1.1  christos 
    269      1.1  christos   newpc.reg32 = pc;
    270      1.1  christos   supply_register_by_name (regcache, "PC", newpc.buf);
    271      1.1  christos }
    272      1.1  christos 
    273      1.1  christos bool
    274      1.1  christos tic6x_target::low_breakpoint_at (CORE_ADDR where)
    275      1.1  christos {
    276      1.1  christos   unsigned int insn;
    277      1.1  christos 
    278      1.1  christos   read_memory (where, (unsigned char *) &insn, 4);
    279      1.1  christos   if (insn == tic6x_breakpoint)
    280      1.1  christos     return true;
    281      1.1  christos 
    282      1.1  christos   /* If necessary, recognize more trap instructions here.  GDB only uses the
    283      1.1  christos      one.  */
    284      1.1  christos   return false;
    285      1.1  christos }
    286      1.1  christos 
    287      1.1  christos /* Fetch the thread-local storage pointer for libthread_db.  */
    288      1.1  christos 
    289      1.1  christos ps_err_e
    290      1.1  christos ps_get_thread_area (struct ps_prochandle *ph,
    291      1.1  christos 		    lwpid_t lwpid, int idx, void **base)
    292      1.1  christos {
    293      1.1  christos   if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
    294      1.1  christos     return PS_ERR;
    295      1.1  christos 
    296      1.1  christos   /* IDX is the bias from the thread pointer to the beginning of the
    297      1.1  christos      thread descriptor.  It has to be subtracted due to implementation
    298      1.1  christos      quirks in libthread_db.  */
    299      1.1  christos   *base = (void *) ((char *) *base - idx);
    300      1.1  christos 
    301      1.1  christos   return PS_OK;
    302      1.1  christos }
    303      1.1  christos 
    304      1.1  christos static void
    305      1.1  christos tic6x_collect_register (struct regcache *regcache, int regno,
    306      1.1  christos 			union tic6x_register *reg)
    307      1.1  christos {
    308      1.1  christos   union tic6x_register tmp_reg;
    309      1.1  christos 
    310      1.1  christos   collect_register (regcache, regno, &tmp_reg.reg32);
    311      1.1  christos   reg->reg32 = tmp_reg.reg32;
    312      1.1  christos }
    313      1.1  christos 
    314      1.1  christos static void
    315      1.1  christos tic6x_supply_register (struct regcache *regcache, int regno,
    316      1.1  christos 		       const union tic6x_register *reg)
    317      1.1  christos {
    318      1.1  christos   int offset = 0;
    319      1.1  christos 
    320      1.1  christos   supply_register (regcache, regno, reg->buf + offset);
    321      1.1  christos }
    322      1.1  christos 
    323      1.1  christos static void
    324      1.1  christos tic6x_fill_gregset (struct regcache *regcache, void *buf)
    325      1.1  christos {
    326      1.1  christos   auto regset = static_cast<union tic6x_register *> (buf);
    327      1.1  christos   int i;
    328      1.1  christos 
    329      1.1  christos   for (i = 0; i < TIC6X_NUM_REGS; i++)
    330      1.1  christos     if (tic6x_regmap[i] != -1)
    331      1.1  christos       tic6x_collect_register (regcache, i, regset + tic6x_regmap[i]);
    332      1.1  christos }
    333      1.1  christos 
    334      1.1  christos static void
    335      1.1  christos tic6x_store_gregset (struct regcache *regcache, const void *buf)
    336      1.1  christos {
    337      1.1  christos   const auto regset = static_cast<const union tic6x_register *> (buf);
    338      1.1  christos   int i;
    339      1.1  christos 
    340      1.1  christos   for (i = 0; i < TIC6X_NUM_REGS; i++)
    341      1.1  christos     if (tic6x_regmap[i] != -1)
    342      1.1  christos       tic6x_supply_register (regcache, i, regset + tic6x_regmap[i]);
    343      1.1  christos }
    344      1.1  christos 
    345      1.1  christos static struct regset_info tic6x_regsets[] = {
    346      1.1  christos   { PTRACE_GETREGS, PTRACE_SETREGS, 0, TIC6X_NUM_REGS * 4, GENERAL_REGS,
    347      1.1  christos     tic6x_fill_gregset, tic6x_store_gregset },
    348      1.1  christos   NULL_REGSET
    349      1.1  christos };
    350      1.1  christos 
    351      1.1  christos void
    352      1.1  christos tic6x_target::low_arch_setup ()
    353      1.1  christos {
    354      1.1  christos   register unsigned int csr asm ("B2");
    355      1.1  christos   unsigned int cpuid;
    356      1.1  christos   enum c6x_feature feature = C6X_CORE;
    357      1.1  christos 
    358      1.1  christos   /* Determine the CPU we're running on to find the register order.  */
    359      1.1  christos   __asm__ ("MVC .S2 CSR,%0" : "=r" (csr) :);
    360      1.1  christos   cpuid = csr >> 24;
    361      1.1  christos   switch (cpuid)
    362      1.1  christos     {
    363      1.1  christos     case 0x00: /* C62x */
    364      1.1  christos     case 0x02: /* C67x */
    365      1.1  christos       tic6x_regmap = tic6x_regmap_c62x;
    366      1.1  christos       tic6x_breakpoint = 0x0000a122;  /* BNOP .S2 0,5 */
    367      1.1  christos       feature = C6X_CORE;
    368      1.1  christos       break;
    369      1.1  christos     case 0x03: /* C67x+ */
    370      1.1  christos       tic6x_regmap = tic6x_regmap_c64x;
    371      1.1  christos       tic6x_breakpoint = 0x0000a122;  /* BNOP .S2 0,5 */
    372      1.1  christos       feature = C6X_GP;
    373      1.1  christos       break;
    374      1.1  christos     case 0x0c: /* C64x */
    375      1.1  christos       tic6x_regmap = tic6x_regmap_c64x;
    376      1.1  christos       tic6x_breakpoint = 0x0000a122;  /* BNOP .S2 0,5 */
    377      1.1  christos       feature = C6X_GP;
    378      1.1  christos       break;
    379      1.1  christos     case 0x10: /* C64x+ */
    380      1.1  christos     case 0x14: /* C674x */
    381      1.1  christos     case 0x15: /* C66x */
    382      1.1  christos       tic6x_regmap = tic6x_regmap_c64xp;
    383      1.1  christos       tic6x_breakpoint = 0x56454314;  /* illegal opcode */
    384      1.1  christos       feature = C6X_C6XP;
    385      1.1  christos       break;
    386      1.1  christos     default:
    387      1.1  christos       error ("Unknown CPU ID 0x%02x", cpuid);
    388      1.1  christos     }
    389      1.1  christos   tic6x_usrregs_info.regmap = tic6x_regmap;
    390      1.1  christos 
    391      1.1  christos   current_process ()->tdesc = tic6x_read_description (feature);
    392      1.1  christos }
    393      1.1  christos 
    394      1.1  christos static struct regsets_info tic6x_regsets_info =
    395      1.1  christos   {
    396      1.1  christos     tic6x_regsets, /* regsets */
    397      1.1  christos     0, /* num_regsets */
    398      1.1  christos     NULL, /* disabled_regsets */
    399      1.1  christos   };
    400      1.1  christos 
    401      1.1  christos static struct regs_info myregs_info =
    402      1.1  christos   {
    403      1.1  christos     NULL, /* regset_bitmap */
    404      1.1  christos     &tic6x_usrregs_info,
    405      1.1  christos     &tic6x_regsets_info
    406      1.1  christos   };
    407      1.1  christos 
    408      1.1  christos const regs_info *
    409      1.1  christos tic6x_target::get_regs_info ()
    410      1.1  christos {
    411      1.1  christos   return &myregs_info;
    412      1.1  christos }
    413      1.1  christos 
    414      1.1  christos #if GDB_SELF_TEST
    415      1.1  christos #include "gdbsupport/selftest.h"
    416      1.1  christos 
    417      1.1  christos namespace selftests {
    418      1.1  christos namespace tdesc {
    419      1.1  christos static void
    420      1.1  christos tic6x_tdesc_test ()
    421      1.1  christos {
    422      1.1  christos   SELF_CHECK (*tdesc_tic6x_c62x_linux == *tic6x_read_description (C6X_CORE));
    423      1.1  christos   SELF_CHECK (*tdesc_tic6x_c64x_linux == *tic6x_read_description (C6X_GP));
    424      1.1  christos   SELF_CHECK (*tdesc_tic6x_c64xp_linux == *tic6x_read_description (C6X_C6XP));
    425      1.1  christos }
    426      1.1  christos }
    427      1.1  christos }
    428      1.1  christos #endif
    429      1.1  christos 
    430      1.1  christos /* The linux target ops object.  */
    431      1.1  christos 
    432      1.1  christos linux_process_target *the_linux_target = &the_tic6x_target;
    433      1.1  christos 
    434      1.1  christos void
    435      1.1  christos initialize_low_arch (void)
    436      1.1  christos {
    437      1.1  christos #if GDB_SELF_TEST
    438      1.1  christos   /* Initialize the Linux target descriptions.  */
    439      1.1  christos   init_registers_tic6x_c64xp_linux ();
    440      1.1  christos   init_registers_tic6x_c64x_linux ();
    441      1.1  christos   init_registers_tic6x_c62x_linux ();
    442      1.1  christos 
    443      1.1  christos   selftests::register_test ("tic6x-tdesc", selftests::tdesc::tic6x_tdesc_test);
    444      1.1  christos #endif
    445      1.1  christos 
    446      1.1  christos   initialize_regsets_info (&tic6x_regsets_info);
    447      1.1  christos }
    448