xref: /netbsd-src/external/gpl3/gdb/dist/gdbserver/linux-sh-low.cc (revision 13ed34fa5696ce1ff8e9519eeb5619eee4331db8)
1 /* GNU/Linux/SH 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 SH architecture.  */
22 
23 class sh_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   bool low_breakpoint_at (CORE_ADDR pc) override;
46 };
47 
48 /* The singleton target ops object.  */
49 
50 static sh_target the_sh_target;
51 
52 bool
53 sh_target::low_supports_breakpoints ()
54 {
55   return true;
56 }
57 
58 CORE_ADDR
59 sh_target::low_get_pc (regcache *regcache)
60 {
61   return linux_get_pc_32bit (regcache);
62 }
63 
64 void
65 sh_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
66 {
67   linux_set_pc_32bit (regcache, pc);
68 }
69 
70 /* Defined in auto-generated file reg-sh.c.  */
71 void init_registers_sh (void);
72 extern const struct target_desc *tdesc_sh;
73 
74 #ifdef HAVE_SYS_REG_H
75 #include <sys/reg.h>
76 #endif
77 
78 #include <asm/ptrace.h>
79 
80 #define sh_num_regs 41
81 
82 /* Currently, don't check/send MQ.  */
83 static int sh_regmap[] = {
84  0,	4,	8,	12,	16,	20,	24,	28,
85  32,	36,	40,	44,	48,	52,	56,	60,
86 
87  REG_PC*4,   REG_PR*4,   REG_GBR*4,  -1,
88  REG_MACH*4, REG_MACL*4, REG_SR*4,
89  REG_FPUL*4, REG_FPSCR*4,
90 
91  REG_FPREG0*4+0,   REG_FPREG0*4+4,   REG_FPREG0*4+8,   REG_FPREG0*4+12,
92  REG_FPREG0*4+16,  REG_FPREG0*4+20,  REG_FPREG0*4+24,  REG_FPREG0*4+28,
93  REG_FPREG0*4+32,  REG_FPREG0*4+36,  REG_FPREG0*4+40,  REG_FPREG0*4+44,
94  REG_FPREG0*4+48,  REG_FPREG0*4+52,  REG_FPREG0*4+56,  REG_FPREG0*4+60,
95 };
96 
97 bool
98 sh_target::low_cannot_store_register (int regno)
99 {
100   return false;
101 }
102 
103 bool
104 sh_target::low_cannot_fetch_register (int regno)
105 {
106   return false;
107 }
108 
109 /* Correct in either endianness, obviously.  */
110 static const unsigned short sh_breakpoint = 0xc3c3;
111 #define sh_breakpoint_len 2
112 
113 /* Implementation of target ops method "sw_breakpoint_from_kind".  */
114 
115 const gdb_byte *
116 sh_target::sw_breakpoint_from_kind (int kind, int *size)
117 {
118   *size = sh_breakpoint_len;
119   return (const gdb_byte *) &sh_breakpoint;
120 }
121 
122 bool
123 sh_target::low_breakpoint_at (CORE_ADDR where)
124 {
125   unsigned short insn;
126 
127   read_memory (where, (unsigned char *) &insn, 2);
128   if (insn == sh_breakpoint)
129     return true;
130 
131   /* If necessary, recognize more trap instructions here.  GDB only uses the
132      one.  */
133   return false;
134 }
135 
136 /* Provide only a fill function for the general register set.  ps_lgetregs
137    will use this for NPTL support.  */
138 
139 static void sh_fill_gregset (struct regcache *regcache, void *buf)
140 {
141   int i;
142 
143   for (i = 0; i < 23; i++)
144     if (sh_regmap[i] != -1)
145       collect_register (regcache, i, (char *) buf + sh_regmap[i]);
146 }
147 
148 static struct regset_info sh_regsets[] = {
149   { 0, 0, 0, 0, GENERAL_REGS, sh_fill_gregset, NULL },
150   NULL_REGSET
151 };
152 
153 static struct regsets_info sh_regsets_info =
154   {
155     sh_regsets, /* regsets */
156     0, /* num_regsets */
157     NULL, /* disabled_regsets */
158   };
159 
160 static struct usrregs_info sh_usrregs_info =
161   {
162     sh_num_regs,
163     sh_regmap,
164   };
165 
166 static struct regs_info myregs_info =
167   {
168     NULL, /* regset_bitmap */
169     &sh_usrregs_info,
170     &sh_regsets_info
171   };
172 
173 const regs_info *
174 sh_target::get_regs_info ()
175 {
176   return &myregs_info;
177 }
178 
179 void
180 sh_target::low_arch_setup ()
181 {
182   current_process ()->tdesc = tdesc_sh;
183 }
184 
185 /* The linux target ops object.  */
186 
187 linux_process_target *the_linux_target = &the_sh_target;
188 
189 void
190 initialize_low_arch (void)
191 {
192   init_registers_sh ();
193 
194   initialize_regsets_info (&sh_regsets_info);
195 }
196