Home | History | Annotate | Line # | Download | only in gdbserver
      1 /* GNU/Linux/m68k specific low level interface, for the remote server for GDB.
      2    Copyright (C) 1995-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 #include "linux-low.h"
     20 
     21 /* Linux target op definitions for the m68k architecture.  */
     22 
     23 class m68k_target : public linux_process_target
     24 {
     25 public:
     26 
     27   const regs_info *get_regs_info () override;
     28 
     29   const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override;
     30 
     31 protected:
     32 
     33   void low_arch_setup () override;
     34 
     35   bool low_cannot_fetch_register (int regno) override;
     36 
     37   bool low_cannot_store_register (int regno) override;
     38 
     39   bool low_supports_breakpoints () override;
     40 
     41   CORE_ADDR low_get_pc (regcache *regcache) override;
     42 
     43   void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
     44 
     45   int low_decr_pc_after_break () override;
     46 
     47   bool low_breakpoint_at (CORE_ADDR pc) override;
     48 };
     49 
     50 /* The singleton target ops object.  */
     51 
     52 static m68k_target the_m68k_target;
     53 
     54 bool
     55 m68k_target::low_supports_breakpoints ()
     56 {
     57   return true;
     58 }
     59 
     60 CORE_ADDR
     61 m68k_target::low_get_pc (regcache *regcache)
     62 {
     63   return linux_get_pc_32bit (regcache);
     64 }
     65 
     66 void
     67 m68k_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
     68 {
     69   linux_set_pc_32bit (regcache, pc);
     70 }
     71 
     72 int
     73 m68k_target::low_decr_pc_after_break ()
     74 {
     75   return 2;
     76 }
     77 
     78 /* Defined in auto-generated file reg-m68k.c.  */
     79 void init_registers_m68k (void);
     80 extern const struct target_desc *tdesc_m68k;
     81 
     82 #ifdef HAVE_SYS_REG_H
     83 #include <sys/reg.h>
     84 #endif
     85 
     86 #define m68k_num_regs 29
     87 #define m68k_num_gregs 18
     88 
     89 /* This table must line up with REGISTER_NAMES in tm-m68k.h */
     90 static int m68k_regmap[] =
     91 {
     92 #ifdef PT_D0
     93   PT_D0 * 4, PT_D1 * 4, PT_D2 * 4, PT_D3 * 4,
     94   PT_D4 * 4, PT_D5 * 4, PT_D6 * 4, PT_D7 * 4,
     95   PT_A0 * 4, PT_A1 * 4, PT_A2 * 4, PT_A3 * 4,
     96   PT_A4 * 4, PT_A5 * 4, PT_A6 * 4, PT_USP * 4,
     97   PT_SR * 4, PT_PC * 4,
     98 #else
     99   14 * 4, 0 * 4, 1 * 4, 2 * 4, 3 * 4, 4 * 4, 5 * 4, 6 * 4,
    100   7 * 4, 8 * 4, 9 * 4, 10 * 4, 11 * 4, 12 * 4, 13 * 4, 15 * 4,
    101   17 * 4, 18 * 4,
    102 #endif
    103 #ifdef PT_FP0
    104   PT_FP0 * 4, PT_FP1 * 4, PT_FP2 * 4, PT_FP3 * 4,
    105   PT_FP4 * 4, PT_FP5 * 4, PT_FP6 * 4, PT_FP7 * 4,
    106   PT_FPCR * 4, PT_FPSR * 4, PT_FPIAR * 4
    107 #else
    108   21 * 4, 24 * 4, 27 * 4, 30 * 4, 33 * 4, 36 * 4,
    109   39 * 4, 42 * 4, 45 * 4, 46 * 4, 47 * 4
    110 #endif
    111 };
    112 
    113 bool
    114 m68k_target::low_cannot_store_register (int regno)
    115 {
    116   return (regno >= m68k_num_regs);
    117 }
    118 
    119 bool
    120 m68k_target::low_cannot_fetch_register (int regno)
    121 {
    122   return (regno >= m68k_num_regs);
    123 }
    124 
    125 #ifdef HAVE_PTRACE_GETREGS
    126 #include <sys/procfs.h>
    127 #include "nat/gdb_ptrace.h"
    128 
    129 static void
    130 m68k_fill_gregset (struct regcache *regcache, void *buf)
    131 {
    132   int i;
    133 
    134   for (i = 0; i < m68k_num_gregs; i++)
    135     collect_register (regcache, i, (char *) buf + m68k_regmap[i]);
    136 }
    137 
    138 static void
    139 m68k_store_gregset (struct regcache *regcache, const void *buf)
    140 {
    141   int i;
    142 
    143   for (i = 0; i < m68k_num_gregs; i++)
    144     supply_register (regcache, i, (const char *) buf + m68k_regmap[i]);
    145 }
    146 
    147 static void
    148 m68k_fill_fpregset (struct regcache *regcache, void *buf)
    149 {
    150   int i;
    151 
    152   for (i = m68k_num_gregs; i < m68k_num_regs; i++)
    153     collect_register (regcache, i, ((char *) buf
    154 			 + (m68k_regmap[i] - m68k_regmap[m68k_num_gregs])));
    155 }
    156 
    157 static void
    158 m68k_store_fpregset (struct regcache *regcache, const void *buf)
    159 {
    160   int i;
    161 
    162   for (i = m68k_num_gregs; i < m68k_num_regs; i++)
    163     supply_register (regcache, i, ((const char *) buf
    164 			 + (m68k_regmap[i] - m68k_regmap[m68k_num_gregs])));
    165 }
    166 
    167 #endif /* HAVE_PTRACE_GETREGS */
    168 
    169 static struct regset_info m68k_regsets[] = {
    170 #ifdef HAVE_PTRACE_GETREGS
    171   { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t),
    172     GENERAL_REGS,
    173     m68k_fill_gregset, m68k_store_gregset },
    174   { PTRACE_GETFPREGS, PTRACE_SETFPREGS, 0, sizeof (elf_fpregset_t),
    175     FP_REGS,
    176     m68k_fill_fpregset, m68k_store_fpregset },
    177 #endif /* HAVE_PTRACE_GETREGS */
    178   NULL_REGSET
    179 };
    180 
    181 static const gdb_byte m68k_breakpoint[] = { 0x4E, 0x4F };
    182 #define m68k_breakpoint_len 2
    183 
    184 /* Implementation of target ops method "sw_breakpoint_from_kind".  */
    185 
    186 const gdb_byte *
    187 m68k_target::sw_breakpoint_from_kind (int kind, int *size)
    188 {
    189   *size = m68k_breakpoint_len;
    190   return m68k_breakpoint;
    191 }
    192 
    193 bool
    194 m68k_target::low_breakpoint_at (CORE_ADDR pc)
    195 {
    196   unsigned char c[2];
    197 
    198   read_inferior_memory (pc, c, 2);
    199   if (c[0] == 0x4E && c[1] == 0x4F)
    200     return true;
    201 
    202   return false;
    203 }
    204 
    205 #include <asm/ptrace.h>
    206 
    207 #ifdef PTRACE_GET_THREAD_AREA
    208 /* Fetch the thread-local storage pointer for libthread_db.  */
    209 
    210 ps_err_e
    211 ps_get_thread_area (struct ps_prochandle *ph,
    212 		    lwpid_t lwpid, int idx, void **base)
    213 {
    214   if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
    215     return PS_ERR;
    216 
    217   /* IDX is the bias from the thread pointer to the beginning of the
    218      thread descriptor.  It has to be subtracted due to implementation
    219      quirks in libthread_db.  */
    220   *base = (void *) ((char *)*base - idx);
    221 
    222   return PS_OK;
    223 }
    224 #endif /* PTRACE_GET_THREAD_AREA */
    225 
    226 static struct regsets_info m68k_regsets_info =
    227   {
    228     m68k_regsets, /* regsets */
    229     0, /* num_regsets */
    230     NULL, /* disabled_regsets */
    231   };
    232 
    233 static struct usrregs_info m68k_usrregs_info =
    234   {
    235     m68k_num_regs,
    236     m68k_regmap,
    237   };
    238 
    239 static struct regs_info myregs_info =
    240   {
    241     NULL, /* regset_bitmap */
    242     &m68k_usrregs_info,
    243     &m68k_regsets_info
    244   };
    245 
    246 const regs_info *
    247 m68k_target::get_regs_info ()
    248 {
    249   return &myregs_info;
    250 }
    251 
    252 void
    253 m68k_target::low_arch_setup ()
    254 {
    255   current_process ()->tdesc = tdesc_m68k;
    256 }
    257 
    258 /* The linux target ops object.  */
    259 
    260 linux_process_target *the_linux_target = &the_m68k_target;
    261 
    262 void
    263 initialize_low_arch (void)
    264 {
    265   /* Initialize the Linux target descriptions.  */
    266   init_registers_m68k ();
    267 
    268   initialize_regsets_info (&m68k_regsets_info);
    269 }
    270