Home | History | Annotate | Line # | Download | only in gdbserver
      1 /* GNU/Linux/Xtensa specific low level interface, for the remote server for GDB.
      2    Copyright (C) 2007-2024 Free Software Foundation, Inc.
      3 
      4    This file is part of GDB.
      5 
      6    This program is free software; you can redistribute it and/or modify
      7    it under the terms of the GNU General Public License as published by
      8    the Free Software Foundation; either version 3 of the License, or
      9    (at your option) any later version.
     10 
     11    This program is distributed in the hope that it will be useful,
     12    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14    GNU General Public License for more details.
     15 
     16    You should have received a copy of the GNU General Public License
     17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     18 
     19 
     20 #include "linux-low.h"
     21 
     22 /* Linux target op definitions for the Xtensa architecture.  */
     23 
     24 class xtensa_target : public linux_process_target
     25 {
     26 public:
     27 
     28   const regs_info *get_regs_info () override;
     29 
     30   const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override;
     31 
     32 protected:
     33 
     34   void low_arch_setup () override;
     35 
     36   bool low_cannot_fetch_register (int regno) override;
     37 
     38   bool low_cannot_store_register (int regno) override;
     39 
     40   bool low_supports_breakpoints () override;
     41 
     42   CORE_ADDR low_get_pc (regcache *regcache) override;
     43 
     44   void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
     45 
     46   bool low_breakpoint_at (CORE_ADDR pc) override;
     47 };
     48 
     49 /* The singleton target ops object.  */
     50 
     51 static xtensa_target the_xtensa_target;
     52 
     53 bool
     54 xtensa_target::low_cannot_fetch_register (int regno)
     55 {
     56   gdb_assert_not_reached ("linux target op low_cannot_fetch_register "
     57 			  "is not implemented by the target");
     58 }
     59 
     60 bool
     61 xtensa_target::low_cannot_store_register (int regno)
     62 {
     63   gdb_assert_not_reached ("linux target op low_cannot_store_register "
     64 			  "is not implemented by the target");
     65 }
     66 
     67 bool
     68 xtensa_target::low_supports_breakpoints ()
     69 {
     70   return true;
     71 }
     72 
     73 CORE_ADDR
     74 xtensa_target::low_get_pc (regcache *regcache)
     75 {
     76   return linux_get_pc_32bit (regcache);
     77 }
     78 
     79 void
     80 xtensa_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
     81 {
     82   linux_set_pc_32bit (regcache, pc);
     83 }
     84 
     85 /* Defined in auto-generated file reg-xtensa.c.  */
     86 void init_registers_xtensa (void);
     87 extern const struct target_desc *tdesc_xtensa;
     88 
     89 #include <asm/ptrace.h>
     90 #include <xtensa-config.h>
     91 #include "arch/xtensa.h"
     92 #include "gdb_proc_service.h"
     93 
     94 #include "xtensa-xtregs.c"
     95 
     96 enum regnum {
     97 	R_PC=0,	R_PS,
     98 	R_LBEG,	R_LEND,	R_LCOUNT,
     99 	R_SAR,
    100 	R_WS, R_WB,
    101 	R_THREADPTR,
    102 	R_A0 = 64
    103 };
    104 
    105 static void
    106 xtensa_fill_gregset (struct regcache *regcache, void *buf)
    107 {
    108   elf_greg_t* rset = (elf_greg_t*)buf;
    109   const struct target_desc *tdesc = regcache->tdesc;
    110   int ar0_regnum;
    111   char *ptr;
    112   int i;
    113 
    114   /* Take care of AR registers.  */
    115 
    116   ar0_regnum = find_regno (tdesc, "ar0");
    117   ptr = (char*)&rset[R_A0];
    118 
    119   for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++)
    120     {
    121       collect_register (regcache, i, ptr);
    122       ptr += register_size (tdesc, i);
    123     }
    124 
    125   if (XSHAL_ABI == XTHAL_ABI_CALL0)
    126     {
    127       int a0_regnum = find_regno (tdesc, "a0");
    128       ptr = (char *) &rset[R_A0 + 4 * rset[R_WB]];
    129 
    130       for (i = a0_regnum; i < a0_regnum + C0_NREGS; i++)
    131 	{
    132 	  if ((4 * rset[R_WB] + i - a0_regnum) == XCHAL_NUM_AREGS)
    133 	    ptr = (char *) &rset[R_A0];
    134 	  collect_register (regcache, i, ptr);
    135 	  ptr += register_size (tdesc, i);
    136 	}
    137     }
    138 
    139   /* Loop registers, if hardware has it.  */
    140 
    141 #if XCHAL_HAVE_LOOPS
    142   collect_register_by_name (regcache, "lbeg", (char*)&rset[R_LBEG]);
    143   collect_register_by_name (regcache, "lend", (char*)&rset[R_LEND]);
    144   collect_register_by_name (regcache, "lcount", (char*)&rset[R_LCOUNT]);
    145 #endif
    146 
    147   collect_register_by_name (regcache, "sar", (char*)&rset[R_SAR]);
    148   collect_register_by_name (regcache, "pc", (char*)&rset[R_PC]);
    149   collect_register_by_name (regcache, "ps", (char*)&rset[R_PS]);
    150   collect_register_by_name (regcache, "windowbase", (char*)&rset[R_WB]);
    151   collect_register_by_name (regcache, "windowstart", (char*)&rset[R_WS]);
    152 
    153 #if XCHAL_HAVE_THREADPTR
    154   collect_register_by_name (regcache, "threadptr",
    155 			    (char *) &rset[R_THREADPTR]);
    156 #endif
    157 }
    158 
    159 static void
    160 xtensa_store_gregset (struct regcache *regcache, const void *buf)
    161 {
    162   const elf_greg_t* rset = (const elf_greg_t*)buf;
    163   const struct target_desc *tdesc = regcache->tdesc;
    164   int ar0_regnum;
    165   char *ptr;
    166   int i;
    167 
    168   /* Take care of AR registers.  */
    169 
    170   ar0_regnum = find_regno (tdesc, "ar0");
    171   ptr = (char *)&rset[R_A0];
    172 
    173   for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++)
    174     {
    175       supply_register (regcache, i, ptr);
    176       ptr += register_size (tdesc, i);
    177     }
    178 
    179   if (XSHAL_ABI == XTHAL_ABI_CALL0)
    180     {
    181       int a0_regnum = find_regno (tdesc, "a0");
    182       ptr = (char *) &rset[R_A0 + (4 * rset[R_WB]) % XCHAL_NUM_AREGS];
    183 
    184       for (i = a0_regnum; i < a0_regnum + C0_NREGS; i++)
    185 	{
    186 	  if ((4 * rset[R_WB] + i - a0_regnum) == XCHAL_NUM_AREGS)
    187 	    ptr = (char *) &rset[R_A0];
    188 	  supply_register (regcache, i, ptr);
    189 	  ptr += register_size (tdesc, i);
    190 	}
    191     }
    192 
    193   /* Loop registers, if hardware has it.  */
    194 
    195 #if XCHAL_HAVE_LOOPS
    196   supply_register_by_name (regcache, "lbeg", (char*)&rset[R_LBEG]);
    197   supply_register_by_name (regcache, "lend", (char*)&rset[R_LEND]);
    198   supply_register_by_name (regcache, "lcount", (char*)&rset[R_LCOUNT]);
    199 #endif
    200 
    201   supply_register_by_name (regcache, "sar", (char*)&rset[R_SAR]);
    202   supply_register_by_name (regcache, "pc", (char*)&rset[R_PC]);
    203   supply_register_by_name (regcache, "ps", (char*)&rset[R_PS]);
    204   supply_register_by_name (regcache, "windowbase", (char*)&rset[R_WB]);
    205   supply_register_by_name (regcache, "windowstart", (char*)&rset[R_WS]);
    206 
    207 #if XCHAL_HAVE_THREADPTR
    208   supply_register_by_name (regcache, "threadptr",
    209 			   (char *) &rset[R_THREADPTR]);
    210 #endif
    211 }
    212 
    213 /* Xtensa GNU/Linux PTRACE interface includes extended register set.  */
    214 
    215 static void
    216 xtensa_fill_xtregset (struct regcache *regcache, void *buf)
    217 {
    218   const xtensa_regtable_t *ptr;
    219 
    220   for (ptr = xtensa_regmap_table; ptr->name; ptr++)
    221     {
    222       collect_register_by_name (regcache, ptr->name,
    223 				(char*)buf + ptr->ptrace_offset);
    224     }
    225 }
    226 
    227 static void
    228 xtensa_store_xtregset (struct regcache *regcache, const void *buf)
    229 {
    230   const xtensa_regtable_t *ptr;
    231 
    232   for (ptr = xtensa_regmap_table; ptr->name; ptr++)
    233     {
    234       supply_register_by_name (regcache, ptr->name,
    235 				(char*)buf + ptr->ptrace_offset);
    236     }
    237 }
    238 
    239 static struct regset_info xtensa_regsets[] = {
    240   { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t),
    241     GENERAL_REGS,
    242     xtensa_fill_gregset, xtensa_store_gregset },
    243   { PTRACE_GETXTREGS, PTRACE_SETXTREGS, 0, XTENSA_ELF_XTREG_SIZE,
    244     EXTENDED_REGS,
    245     xtensa_fill_xtregset, xtensa_store_xtregset },
    246   NULL_REGSET
    247 };
    248 
    249 #if XCHAL_HAVE_BE
    250 #define XTENSA_BREAKPOINT {0xd2,0x0f}
    251 #else
    252 #define XTENSA_BREAKPOINT {0x2d,0xf0}
    253 #endif
    254 
    255 static const gdb_byte xtensa_breakpoint[] = XTENSA_BREAKPOINT;
    256 #define xtensa_breakpoint_len 2
    257 
    258 /* Implementation of target ops method "sw_breakpoint_from_kind".  */
    259 
    260 const gdb_byte *
    261 xtensa_target::sw_breakpoint_from_kind (int kind, int *size)
    262 {
    263   *size = xtensa_breakpoint_len;
    264   return xtensa_breakpoint;
    265 }
    266 
    267 bool
    268 xtensa_target::low_breakpoint_at (CORE_ADDR where)
    269 {
    270     unsigned long insn;
    271 
    272     read_memory (where, (unsigned char *) &insn, xtensa_breakpoint_len);
    273     return memcmp((char *) &insn,
    274 		  xtensa_breakpoint, xtensa_breakpoint_len) == 0;
    275 }
    276 
    277 /* Called by libthread_db.  */
    278 
    279 ps_err_e
    280 ps_get_thread_area (struct ps_prochandle *ph,
    281 		    lwpid_t lwpid, int idx, void **base)
    282 {
    283   xtensa_elf_gregset_t regs;
    284 
    285   if (ptrace (PTRACE_GETREGS, lwpid, NULL, &regs) != 0)
    286     return PS_ERR;
    287 
    288   /* IDX is the bias from the thread pointer to the beginning of the
    289      thread descriptor.  It has to be subtracted due to implementation
    290      quirks in libthread_db.  */
    291   *base = (void *) ((char *) regs.threadptr - idx);
    292 
    293   return PS_OK;
    294 }
    295 
    296 static struct regsets_info xtensa_regsets_info =
    297   {
    298     xtensa_regsets, /* regsets */
    299     0, /* num_regsets */
    300     NULL, /* disabled_regsets */
    301   };
    302 
    303 static struct regs_info myregs_info =
    304   {
    305     NULL, /* regset_bitmap */
    306     NULL, /* usrregs */
    307     &xtensa_regsets_info
    308   };
    309 
    310 void
    311 xtensa_target::low_arch_setup ()
    312 {
    313   current_process ()->tdesc = tdesc_xtensa;
    314 }
    315 
    316 const regs_info *
    317 xtensa_target::get_regs_info ()
    318 {
    319   return &myregs_info;
    320 }
    321 
    322 /* The linux target ops object.  */
    323 
    324 linux_process_target *the_linux_target = &the_xtensa_target;
    325 
    326 void
    327 initialize_low_arch (void)
    328 {
    329   /* Initialize the Linux target descriptions.  */
    330   init_registers_xtensa ();
    331 
    332   initialize_regsets_info (&xtensa_regsets_info);
    333 }
    334