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