Home | History | Annotate | Line # | Download | only in gdbserver
      1 /* GNU/Linux/LoongArch specific low level interface, for the remote server
      2    for GDB.
      3    Copyright (C) 2022-2024 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 "linux-low.h"
     21 #include "tdesc.h"
     22 #include "elf/common.h"
     23 #include "arch/loongarch.h"
     24 
     25 /* Linux target ops definitions for the LoongArch architecture.  */
     26 
     27 class loongarch_target : public linux_process_target
     28 {
     29 public:
     30 
     31   const regs_info *get_regs_info () override;
     32 
     33   int breakpoint_kind_from_pc (CORE_ADDR *pcptr) override;
     34 
     35   const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override;
     36 
     37 protected:
     38 
     39   void low_arch_setup () override;
     40 
     41   bool low_cannot_fetch_register (int regno) override;
     42 
     43   bool low_cannot_store_register (int regno) override;
     44 
     45   bool low_fetch_register (regcache *regcache, int regno) override;
     46 
     47   bool low_supports_breakpoints () override;
     48 
     49   CORE_ADDR low_get_pc (regcache *regcache) override;
     50 
     51   void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
     52 
     53   bool low_breakpoint_at (CORE_ADDR pc) override;
     54 };
     55 
     56 /* The singleton target ops object.  */
     57 
     58 static loongarch_target the_loongarch_target;
     59 
     60 bool
     61 loongarch_target::low_cannot_fetch_register (int regno)
     62 {
     63   gdb_assert_not_reached ("linux target op low_cannot_fetch_register "
     64 			  "is not implemented by the target");
     65 }
     66 
     67 bool
     68 loongarch_target::low_cannot_store_register (int regno)
     69 {
     70   gdb_assert_not_reached ("linux target op low_cannot_store_register "
     71 			  "is not implemented by the target");
     72 }
     73 
     74 /* Implementation of linux target ops method "low_arch_setup".  */
     75 
     76 void
     77 loongarch_target::low_arch_setup ()
     78 {
     79   static const char *expedite_regs[] = { "r3", "pc", NULL };
     80   loongarch_gdbarch_features features;
     81   target_desc_up tdesc;
     82 
     83   features.xlen = sizeof (elf_greg_t);
     84   tdesc = loongarch_create_target_description (features);
     85 
     86   if (tdesc->expedite_regs.empty ())
     87     {
     88       init_target_desc (tdesc.get (), expedite_regs);
     89       gdb_assert (!tdesc->expedite_regs.empty ());
     90     }
     91   current_process ()->tdesc = tdesc.release ();
     92 }
     93 
     94 /* Collect GPRs from REGCACHE into BUF.  */
     95 
     96 static void
     97 loongarch_fill_gregset (struct regcache *regcache, void *buf)
     98 {
     99   elf_gregset_t *regset = (elf_gregset_t *) buf;
    100   int i;
    101 
    102   for (i = 1; i < 32; i++)
    103     collect_register (regcache, i, *regset + i);
    104   collect_register (regcache, LOONGARCH_ORIG_A0_REGNUM, *regset + LOONGARCH_ORIG_A0_REGNUM);
    105   collect_register (regcache, LOONGARCH_PC_REGNUM, *regset + LOONGARCH_PC_REGNUM);
    106   collect_register (regcache, LOONGARCH_BADV_REGNUM, *regset + LOONGARCH_BADV_REGNUM);
    107 }
    108 
    109 /* Supply GPRs from BUF into REGCACHE.  */
    110 
    111 static void
    112 loongarch_store_gregset (struct regcache *regcache, const void *buf)
    113 {
    114   const elf_gregset_t *regset = (const elf_gregset_t *) buf;
    115   int i;
    116 
    117   supply_register_zeroed (regcache, 0);
    118   for (i = 1; i < 32; i++)
    119     supply_register (regcache, i, *regset + i);
    120   supply_register (regcache, LOONGARCH_ORIG_A0_REGNUM, *regset + LOONGARCH_ORIG_A0_REGNUM);
    121   supply_register (regcache, LOONGARCH_PC_REGNUM, *regset + LOONGARCH_PC_REGNUM);
    122   supply_register (regcache, LOONGARCH_BADV_REGNUM, *regset + LOONGARCH_BADV_REGNUM);
    123 }
    124 
    125 /* Collect FPRs from REGCACHE into BUF.  */
    126 
    127 static void
    128 loongarch_fill_fpregset (struct regcache *regcache, void *buf)
    129 {
    130   gdb_byte *regbuf = nullptr;
    131   int fprsize = register_size (regcache->tdesc, LOONGARCH_FIRST_FP_REGNUM);
    132   int fccsize = register_size (regcache->tdesc, LOONGARCH_FIRST_FCC_REGNUM);
    133 
    134   for (int i = 0; i < LOONGARCH_LINUX_NUM_FPREGSET; i++)
    135     {
    136       regbuf = (gdb_byte *)buf + fprsize * i;
    137       collect_register (regcache, LOONGARCH_FIRST_FP_REGNUM + i, regbuf);
    138     }
    139 
    140   for (int i = 0; i < LOONGARCH_LINUX_NUM_FCC; i++)
    141     {
    142       regbuf = (gdb_byte *)buf + fprsize * LOONGARCH_LINUX_NUM_FPREGSET +
    143 	fccsize * i;
    144       collect_register (regcache, LOONGARCH_FIRST_FCC_REGNUM + i, regbuf);
    145     }
    146 
    147   regbuf = (gdb_byte *)buf + fprsize * LOONGARCH_LINUX_NUM_FPREGSET +
    148     fccsize * LOONGARCH_LINUX_NUM_FCC;
    149   collect_register (regcache, LOONGARCH_FCSR_REGNUM, regbuf);
    150 }
    151 
    152 /* Supply FPRs from BUF into REGCACHE.  */
    153 
    154 static void
    155 loongarch_store_fpregset (struct regcache *regcache, const void *buf)
    156 {
    157   const gdb_byte *regbuf = nullptr;
    158   int fprsize = register_size (regcache->tdesc, LOONGARCH_FIRST_FP_REGNUM);
    159   int fccsize = register_size (regcache->tdesc, LOONGARCH_FIRST_FCC_REGNUM);
    160 
    161   for (int i = 0; i < LOONGARCH_LINUX_NUM_FPREGSET; i++)
    162     {
    163       regbuf = (const gdb_byte *)buf + fprsize * i;
    164       supply_register (regcache, LOONGARCH_FIRST_FP_REGNUM + i, regbuf);
    165     }
    166 
    167   for (int i = 0; i < LOONGARCH_LINUX_NUM_FCC; i++)
    168     {
    169       regbuf = (const gdb_byte *)buf + fprsize * LOONGARCH_LINUX_NUM_FPREGSET +
    170 	fccsize * i;
    171       supply_register (regcache, LOONGARCH_FIRST_FCC_REGNUM + i, regbuf);
    172     }
    173 
    174   regbuf = (const gdb_byte *)buf + fprsize * LOONGARCH_LINUX_NUM_FPREGSET +
    175     fccsize * LOONGARCH_LINUX_NUM_FCC;
    176   supply_register (regcache, LOONGARCH_FCSR_REGNUM, regbuf);
    177 }
    178 
    179 /* Collect lsx regs from REGCACHE into BUF.  */
    180 
    181 static void
    182 loongarch_fill_lsxregset (struct regcache *regcache, void *buf)
    183 {
    184   elf_lsxregset_t *regset = (elf_lsxregset_t *) buf;
    185   int i;
    186 
    187   for (i = 0; i < LOONGARCH_LINUX_NUM_LSXREGSET; i++)
    188     collect_register (regcache, LOONGARCH_FIRST_LSX_REGNUM + i, *regset + i);
    189 }
    190 
    191 /* Supply lsx regs from BUF into REGCACHE.  */
    192 
    193 static void
    194 loongarch_store_lsxregset (struct regcache *regcache, const void *buf)
    195 {
    196   const elf_lsxregset_t *regset = (const elf_lsxregset_t *) buf;
    197   int i;
    198 
    199   for (i = 0; i < LOONGARCH_LINUX_NUM_LSXREGSET; i++)
    200     supply_register (regcache, LOONGARCH_FIRST_LSX_REGNUM + i, *regset + i);
    201 }
    202 
    203 /* Collect lasx regs from REGCACHE into BUF.  */
    204 
    205 static void
    206 loongarch_fill_lasxregset (struct regcache *regcache, void *buf)
    207 {
    208   elf_lasxregset_t *regset = (elf_lasxregset_t *) buf;
    209   int i;
    210 
    211   for (i = 0; i < LOONGARCH_LINUX_NUM_LASXREGSET; i++)
    212     collect_register (regcache, LOONGARCH_FIRST_LASX_REGNUM + i, *regset + i);
    213 }
    214 
    215 /* Supply lasx regs from BUF into REGCACHE.  */
    216 
    217 static void
    218 loongarch_store_lasxregset (struct regcache *regcache, const void *buf)
    219 {
    220   const elf_lasxregset_t *regset = (const elf_lasxregset_t *) buf;
    221   int i;
    222 
    223   for (i = 0; i < LOONGARCH_LINUX_NUM_LASXREGSET; i++)
    224     supply_register (regcache, LOONGARCH_FIRST_LASX_REGNUM + i, *regset + i);
    225 }
    226 
    227 /* Collect lbt regs from REGCACHE into BUF.  */
    228 
    229 static void
    230 loongarch_fill_lbtregset (struct regcache *regcache, void *buf)
    231 {
    232   gdb_byte *regbuf = (gdb_byte*)buf;
    233   int scrsize = register_size (regcache->tdesc, LOONGARCH_FIRST_SCR_REGNUM);
    234   int eflagssize = register_size (regcache->tdesc, LOONGARCH_EFLAGS_REGNUM);
    235   int i;
    236 
    237   for (i = 0; i < LOONGARCH_LINUX_NUM_SCR; i++)
    238     collect_register (regcache, LOONGARCH_FIRST_SCR_REGNUM + i, regbuf + scrsize * i);
    239 
    240   collect_register (regcache, LOONGARCH_EFLAGS_REGNUM,
    241 		    regbuf + LOONGARCH_LINUX_NUM_SCR * scrsize);
    242   collect_register (regcache, LOONGARCH_FTOP_REGNUM,
    243 		    regbuf + LOONGARCH_LINUX_NUM_SCR * scrsize + eflagssize);
    244 
    245 }
    246 
    247 /* Supply lbt regs from BUF into REGCACHE.  */
    248 
    249 static void
    250 loongarch_store_lbtregset (struct regcache *regcache, const void *buf)
    251 {
    252 
    253   gdb_byte *regbuf = (gdb_byte*)buf;
    254   int scrsize = register_size (regcache->tdesc, LOONGARCH_FIRST_SCR_REGNUM);
    255   int eflagssize = register_size (regcache->tdesc, LOONGARCH_EFLAGS_REGNUM);
    256   int i;
    257 
    258   for (i = 0; i < LOONGARCH_LINUX_NUM_SCR; i++)
    259     supply_register (regcache, LOONGARCH_FIRST_SCR_REGNUM + i, regbuf + scrsize * i);
    260 
    261   supply_register (regcache, LOONGARCH_EFLAGS_REGNUM,
    262 		    regbuf + LOONGARCH_LINUX_NUM_SCR * scrsize);
    263   supply_register (regcache, LOONGARCH_FTOP_REGNUM,
    264 		    regbuf + LOONGARCH_LINUX_NUM_SCR * scrsize + eflagssize);
    265 
    266 }
    267 
    268 /* LoongArch/Linux regsets.  */
    269 static struct regset_info loongarch_regsets[] = {
    270   { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, sizeof (elf_gregset_t),
    271     GENERAL_REGS, loongarch_fill_gregset, loongarch_store_gregset },
    272   { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET, sizeof (elf_fpregset_t),
    273     FP_REGS, loongarch_fill_fpregset, loongarch_store_fpregset },
    274   { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_LARCH_LSX, sizeof (elf_lsxregset_t),
    275     OPTIONAL_REGS, loongarch_fill_lsxregset, loongarch_store_lsxregset },
    276   { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_LARCH_LASX, sizeof (elf_lasxregset_t),
    277     OPTIONAL_REGS, loongarch_fill_lasxregset, loongarch_store_lasxregset },
    278   { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_LARCH_LBT, LOONGARCH_LBT_REGS_SIZE,
    279     OPTIONAL_REGS, loongarch_fill_lbtregset, loongarch_store_lbtregset },
    280   NULL_REGSET
    281 };
    282 
    283 /* LoongArch/Linux regset information.  */
    284 static struct regsets_info loongarch_regsets_info =
    285   {
    286     loongarch_regsets, /* regsets */
    287     0, /* num_regsets */
    288     NULL, /* disabled_regsets */
    289   };
    290 
    291 /* Definition of linux_target_ops data member "regs_info".  */
    292 static struct regs_info loongarch_regs =
    293   {
    294     NULL, /* regset_bitmap */
    295     NULL, /* usrregs */
    296     &loongarch_regsets_info,
    297   };
    298 
    299 /* Implementation of linux target ops method "get_regs_info".  */
    300 
    301 const regs_info *
    302 loongarch_target::get_regs_info ()
    303 {
    304   return &loongarch_regs;
    305 }
    306 
    307 /* Implementation of linux target ops method "low_fetch_register".  */
    308 
    309 bool
    310 loongarch_target::low_fetch_register (regcache *regcache, int regno)
    311 {
    312   if (regno != 0)
    313     return false;
    314   supply_register_zeroed (regcache, 0);
    315   return true;
    316 }
    317 
    318 bool
    319 loongarch_target::low_supports_breakpoints ()
    320 {
    321   return true;
    322 }
    323 
    324 /* Implementation of linux target ops method "low_get_pc".  */
    325 
    326 CORE_ADDR
    327 loongarch_target::low_get_pc (regcache *regcache)
    328 {
    329   if (register_size (regcache->tdesc, 0) == 8)
    330     return linux_get_pc_64bit (regcache);
    331   else
    332     return linux_get_pc_32bit (regcache);
    333 }
    334 
    335 /* Implementation of linux target ops method "low_set_pc".  */
    336 
    337 void
    338 loongarch_target::low_set_pc (regcache *regcache, CORE_ADDR newpc)
    339 {
    340   if (register_size (regcache->tdesc, 0) == 8)
    341     linux_set_pc_64bit (regcache, newpc);
    342   else
    343     linux_set_pc_32bit (regcache, newpc);
    344 }
    345 
    346 #define loongarch_breakpoint_len 4
    347 
    348 /* LoongArch BRK software debug mode instruction.
    349    This instruction needs to match gdb/loongarch-tdep.c
    350    (loongarch_default_breakpoint).  */
    351 static const gdb_byte loongarch_breakpoint[] = {0x05, 0x00, 0x2a, 0x00};
    352 
    353 /* Implementation of target ops method "breakpoint_kind_from_pc".  */
    354 
    355 int
    356 loongarch_target::breakpoint_kind_from_pc (CORE_ADDR *pcptr)
    357 {
    358   return loongarch_breakpoint_len;
    359 }
    360 
    361 /* Implementation of target ops method "sw_breakpoint_from_kind".  */
    362 
    363 const gdb_byte *
    364 loongarch_target::sw_breakpoint_from_kind (int kind, int *size)
    365 {
    366   *size = loongarch_breakpoint_len;
    367   return (const gdb_byte *) &loongarch_breakpoint;
    368 }
    369 
    370 /* Implementation of linux target ops method "low_breakpoint_at".  */
    371 
    372 bool
    373 loongarch_target::low_breakpoint_at (CORE_ADDR pc)
    374 {
    375   gdb_byte insn[loongarch_breakpoint_len];
    376 
    377   read_memory (pc, (unsigned char *) &insn, loongarch_breakpoint_len);
    378   if (memcmp (insn, loongarch_breakpoint, loongarch_breakpoint_len) == 0)
    379     return true;
    380 
    381   return false;
    382 }
    383 
    384 /* The linux target ops object.  */
    385 
    386 linux_process_target *the_linux_target = &the_loongarch_target;
    387 
    388 /* Initialize the LoongArch/Linux target.  */
    389 
    390 void
    391 initialize_low_arch ()
    392 {
    393   initialize_regsets_info (&loongarch_regsets_info);
    394 }
    395