Home | History | Annotate | Line # | Download | only in gdbserver
      1 /* GNU/Linux/Microblaze specific low level interface, for the remote server for
      2    GDB.
      3    Copyright (C) 1995-2025 Free Software Foundation, Inc.
      4 
      5    This file is part of GDB.
      6 
      7    This program is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3 of the License, or
     10    (at your option) any later version.
     11 
     12    This program is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19 
     20 #include "server.h"
     21 #include "linux-low.h"
     22 
     23 #include "elf/common.h"
     24 #include "nat/gdb_ptrace.h"
     25 #include <endian.h>
     26 
     27 #include <asm/ptrace.h>
     28 #include <sys/procfs.h>
     29 #include <sys/ptrace.h>
     30 
     31 #include "gdb_proc_service.h"
     32 
     33 
     34 static int microblaze_regmap[] =
     35  {PT_GPR(0),     PT_GPR(1),     PT_GPR(2),     PT_GPR(3),
     36   PT_GPR(4),     PT_GPR(5),     PT_GPR(6),     PT_GPR(7),
     37   PT_GPR(8),     PT_GPR(9),     PT_GPR(10),    PT_GPR(11),
     38   PT_GPR(12),    PT_GPR(13),    PT_GPR(14),    PT_GPR(15),
     39   PT_GPR(16),    PT_GPR(17),    PT_GPR(18),    PT_GPR(19),
     40   PT_GPR(20),    PT_GPR(21),    PT_GPR(22),    PT_GPR(23),
     41   PT_GPR(24),    PT_GPR(25),    PT_GPR(26),    PT_GPR(27),
     42   PT_GPR(28),    PT_GPR(29),    PT_GPR(30),    PT_GPR(31),
     43   PT_PC,         PT_MSR,        PT_EAR,        PT_ESR,
     44   PT_FSR
     45   };
     46 
     47 
     48 
     49 class microblaze_target : public linux_process_target
     50 {
     51 public:
     52 
     53   const regs_info *get_regs_info () override;
     54 
     55   const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override;
     56 
     57 protected:
     58 
     59   void low_arch_setup () override;
     60 
     61   bool low_cannot_fetch_register (int regno) override;
     62 
     63   bool low_cannot_store_register (int regno) override;
     64 
     65   bool low_supports_breakpoints () override;
     66 
     67   CORE_ADDR low_get_pc (regcache *regcache) override;
     68 
     69   void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
     70 
     71   bool low_breakpoint_at (CORE_ADDR pc) override;
     72 };
     73 
     74 /* The singleton target ops object.  */
     75 
     76 static microblaze_target the_microblaze_target;
     77 
     78 constexpr auto microblaze_num_regs
     79   = sizeof (microblaze_regmap) / sizeof (microblaze_regmap[0]);
     80 
     81 /* Defined in auto-generated file microblaze-linux-generated.c.  */
     82 void init_registers_microblaze_linux ();
     83 extern const target_desc *tdesc_microblaze_linux;
     84 
     85 bool
     86 microblaze_target::low_supports_breakpoints ()
     87 {
     88   return true;
     89 }
     90 
     91 bool
     92 microblaze_target::low_cannot_store_register (int regno)
     93 {
     94   if (microblaze_regmap[regno] == -1 || regno == 0)
     95     return 1;
     96 
     97   return 0;
     98 }
     99 
    100 bool
    101 microblaze_target::low_cannot_fetch_register (int regno)
    102 {
    103   return 0;
    104 }
    105 
    106 CORE_ADDR
    107 microblaze_target::low_get_pc (regcache *regcache)
    108 {
    109   unsigned long pc;
    110 
    111   collect_register_by_name (regcache, "rpc", &pc);
    112   return pc;
    113 }
    114 
    115 void
    116 microblaze_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
    117 {
    118   unsigned long newpc = pc;
    119 
    120   supply_register_by_name (regcache, "rpc", &newpc);
    121 }
    122 
    123 /* dbtrap insn */
    124 /* brki r16, 0x18; */
    125 static const uint32_t microblaze_breakpoint = 0xba0c0018;
    126 #define microblaze_breakpoint_len 4
    127 
    128 const gdb_byte *
    129 microblaze_target::sw_breakpoint_from_kind (int kind, int *size)
    130 {
    131   *size = microblaze_breakpoint_len;
    132   return reinterpret_cast<const gdb_byte *> (&microblaze_breakpoint);
    133 }
    134 
    135 bool
    136 microblaze_target::low_breakpoint_at (CORE_ADDR where)
    137 {
    138   uint32_t insn;
    139 
    140   read_memory (where, (unsigned char *) &insn, 4);
    141   /* If necessary, recognize more trap instructions here.  GDB only uses the
    142      one.  */
    143   return insn == microblaze_breakpoint;
    144 }
    145 
    146 #ifdef HAVE_PTRACE_GETREGS
    147 
    148 static void
    149 microblaze_collect_ptrace_register (struct regcache *regcache, int regno,
    150 				    char *buf)
    151 {
    152   memset (buf, 0, sizeof (long));
    153 
    154   if (__BYTE_ORDER == __LITTLE_ENDIAN)
    155     {
    156       collect_register (regcache, regno, buf);
    157     }
    158   else if (__BYTE_ORDER == __BIG_ENDIAN)
    159     {
    160 	int size = register_size (regcache->tdesc, regno);
    161 
    162 	if (size < sizeof (long))
    163 		collect_register (regcache, regno, buf + sizeof (long) - size);
    164 	else
    165 		collect_register (regcache, regno, buf);
    166     }
    167 }
    168 
    169 /* Collect GPRs from REGCACHE into BUF.  */
    170 
    171 static void microblaze_fill_gregset (struct regcache *regcache, void *buf)
    172 {
    173   int i;
    174 
    175   for (i = 0; i < microblaze_num_regs; i++)
    176     microblaze_collect_ptrace_register (regcache, i,
    177 					(char *) buf + microblaze_regmap[i]);
    178 }
    179 
    180 /* Supply GPRs from BUF into REGCACHE.  */
    181 
    182 static void
    183 microblaze_store_gregset (struct regcache *regcache, const void *buf)
    184 {
    185   int i;
    186 
    187   for (i = 0; i < microblaze_num_regs; i++)
    188     supply_register (regcache, i, (char *) buf + microblaze_regmap[i]);
    189 }
    190 
    191 static struct regset_info microblaze_regsets[] = {
    192   { PTRACE_GETREGS, PTRACE_SETREGS, NT_PRSTATUS,
    193     sizeof (elf_gregset_t), GENERAL_REGS,
    194     microblaze_fill_gregset, microblaze_store_gregset
    195   },
    196   NULL_REGSET
    197 };
    198 #endif /* HAVE_PTRACE_GETREGS */
    199 
    200 static struct usrregs_info microblaze_usrregs_info =
    201   {
    202     microblaze_num_regs,
    203     microblaze_regmap,
    204   };
    205 
    206 #ifdef HAVE_PTRACE_GETREGS
    207 static struct regsets_info microblaze_regsets_info =
    208   {
    209     microblaze_regsets, /* regsets */
    210     0, /* num_regsets */
    211     nullptr /* disabled_regsets */
    212   };
    213 #endif /* HAVE_PTRACE_GETREGS */
    214 
    215 static struct regs_info microblaze_regs_info =
    216   {
    217     nullptr, /* regset_bitmap */
    218     &microblaze_usrregs_info,
    219 #ifdef HAVE_PTRACE_GETREGS
    220     &microblaze_regsets_info
    221 #endif /* HAVE_PTRACE_GETREGS */
    222   };
    223 
    224 const regs_info *
    225 microblaze_target::get_regs_info ()
    226 {
    227   return &microblaze_regs_info;
    228 }
    229 
    230 void
    231 microblaze_target::low_arch_setup ()
    232 {
    233   current_process ()->tdesc = tdesc_microblaze_linux;
    234 }
    235 
    236 linux_process_target *the_linux_target = &the_microblaze_target;
    237 
    238 void
    239 initialize_low_arch ()
    240 {
    241   init_registers_microblaze_linux ();
    242 #ifdef HAVE_PTRACE_GETREGS
    243   initialize_regsets_info (&microblaze_regsets_info);
    244 #endif /* HAVE_PTRACE_GETREGS */
    245 }
    246