]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdbserver/linux-xtensa-low.cc
gdbsupport: constify some return values in print-utils.{h,cc}
[thirdparty/binutils-gdb.git] / gdbserver / linux-xtensa-low.cc
CommitLineData
1525d545 1/* GNU/Linux/Xtensa specific low level interface, for the remote server for GDB.
1d506c26 2 Copyright (C) 2007-2024 Free Software Foundation, Inc.
1525d545
MG
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
1525d545
MG
20#include "linux-low.h"
21
ef0478f6
TBA
22/* Linux target op definitions for the Xtensa architecture. */
23
24class xtensa_target : public linux_process_target
25{
26public:
27
aa8d21c9
TBA
28 const regs_info *get_regs_info () override;
29
3ca4edb6
TBA
30 const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override;
31
797bcff5
TBA
32protected:
33
34 void low_arch_setup () override;
daca57a7
TBA
35
36 bool low_cannot_fetch_register (int regno) override;
37
38 bool low_cannot_store_register (int regno) override;
bf9ae9d8
TBA
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;
d7146cda
TBA
45
46 bool low_breakpoint_at (CORE_ADDR pc) override;
ef0478f6
TBA
47};
48
49/* The singleton target ops object. */
50
51static xtensa_target the_xtensa_target;
52
daca57a7
TBA
53bool
54xtensa_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
60bool
61xtensa_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
bf9ae9d8
TBA
67bool
68xtensa_target::low_supports_breakpoints ()
69{
70 return true;
71}
72
73CORE_ADDR
74xtensa_target::low_get_pc (regcache *regcache)
75{
76 return linux_get_pc_32bit (regcache);
77}
78
79void
80xtensa_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
81{
82 linux_set_pc_32bit (regcache, pc);
83}
84
d05b4ac3
UW
85/* Defined in auto-generated file reg-xtensa.c. */
86void init_registers_xtensa (void);
3aee8918 87extern const struct target_desc *tdesc_xtensa;
d05b4ac3 88
e671835b 89#include <asm/ptrace.h>
1525d545 90#include <xtensa-config.h>
40045d91
MF
91#include "arch/xtensa.h"
92#include "gdb_proc_service.h"
1525d545
MG
93
94#include "xtensa-xtregs.c"
95
96enum regnum {
97 R_PC=0, R_PS,
98 R_LBEG, R_LEND, R_LCOUNT,
99 R_SAR,
100 R_WS, R_WB,
a12e714b 101 R_THREADPTR,
1b3f6016 102 R_A0 = 64
1525d545
MG
103};
104
105static void
442ea881 106xtensa_fill_gregset (struct regcache *regcache, void *buf)
1525d545
MG
107{
108 elf_greg_t* rset = (elf_greg_t*)buf;
3aee8918 109 const struct target_desc *tdesc = regcache->tdesc;
1525d545
MG
110 int ar0_regnum;
111 char *ptr;
112 int i;
113
114 /* Take care of AR registers. */
115
3aee8918 116 ar0_regnum = find_regno (tdesc, "ar0");
1525d545
MG
117 ptr = (char*)&rset[R_A0];
118
119 for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++)
120 {
442ea881 121 collect_register (regcache, i, ptr);
3aee8918 122 ptr += register_size (tdesc, i);
1525d545
MG
123 }
124
1a09b50a
MF
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
1525d545
MG
139 /* Loop registers, if hardware has it. */
140
a2d5a9d7 141#if XCHAL_HAVE_LOOPS
442ea881
PA
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]);
1525d545
MG
145#endif
146
442ea881
PA
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]);
a12e714b
MF
152
153#if XCHAL_HAVE_THREADPTR
154 collect_register_by_name (regcache, "threadptr",
155 (char *) &rset[R_THREADPTR]);
156#endif
1525d545
MG
157}
158
159static void
442ea881 160xtensa_store_gregset (struct regcache *regcache, const void *buf)
1525d545
MG
161{
162 const elf_greg_t* rset = (const elf_greg_t*)buf;
3aee8918 163 const struct target_desc *tdesc = regcache->tdesc;
1525d545
MG
164 int ar0_regnum;
165 char *ptr;
166 int i;
167
168 /* Take care of AR registers. */
169
3aee8918 170 ar0_regnum = find_regno (tdesc, "ar0");
1525d545
MG
171 ptr = (char *)&rset[R_A0];
172
173 for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++)
174 {
442ea881 175 supply_register (regcache, i, ptr);
3aee8918 176 ptr += register_size (tdesc, i);
1525d545
MG
177 }
178
1a09b50a
MF
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
1525d545
MG
193 /* Loop registers, if hardware has it. */
194
a2d5a9d7 195#if XCHAL_HAVE_LOOPS
442ea881
PA
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]);
1525d545
MG
199#endif
200
442ea881
PA
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]);
a12e714b
MF
206
207#if XCHAL_HAVE_THREADPTR
208 supply_register_by_name (regcache, "threadptr",
209 (char *) &rset[R_THREADPTR]);
210#endif
1525d545
MG
211}
212
213/* Xtensa GNU/Linux PTRACE interface includes extended register set. */
214
215static void
442ea881 216xtensa_fill_xtregset (struct regcache *regcache, void *buf)
1525d545
MG
217{
218 const xtensa_regtable_t *ptr;
219
220 for (ptr = xtensa_regmap_table; ptr->name; ptr++)
221 {
442ea881 222 collect_register_by_name (regcache, ptr->name,
1525d545
MG
223 (char*)buf + ptr->ptrace_offset);
224 }
225}
226
227static void
442ea881 228xtensa_store_xtregset (struct regcache *regcache, const void *buf)
1525d545
MG
229{
230 const xtensa_regtable_t *ptr;
231
232 for (ptr = xtensa_regmap_table; ptr->name; ptr++)
233 {
442ea881 234 supply_register_by_name (regcache, ptr->name,
1525d545
MG
235 (char*)buf + ptr->ptrace_offset);
236 }
237}
238
3aee8918 239static struct regset_info xtensa_regsets[] = {
1570b33e 240 { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t),
1525d545
MG
241 GENERAL_REGS,
242 xtensa_fill_gregset, xtensa_store_gregset },
1570b33e 243 { PTRACE_GETXTREGS, PTRACE_SETXTREGS, 0, XTENSA_ELF_XTREG_SIZE,
1525d545
MG
244 EXTENDED_REGS,
245 xtensa_fill_xtregset, xtensa_store_xtregset },
50bc912a 246 NULL_REGSET
1525d545
MG
247};
248
249#if XCHAL_HAVE_BE
250#define XTENSA_BREAKPOINT {0xd2,0x0f}
251#else
252#define XTENSA_BREAKPOINT {0x2d,0xf0}
253#endif
254
dd373349 255static const gdb_byte xtensa_breakpoint[] = XTENSA_BREAKPOINT;
1525d545
MG
256#define xtensa_breakpoint_len 2
257
3ca4edb6 258/* Implementation of target ops method "sw_breakpoint_from_kind". */
dd373349 259
3ca4edb6
TBA
260const gdb_byte *
261xtensa_target::sw_breakpoint_from_kind (int kind, int *size)
dd373349
AT
262{
263 *size = xtensa_breakpoint_len;
264 return xtensa_breakpoint;
265}
266
d7146cda
TBA
267bool
268xtensa_target::low_breakpoint_at (CORE_ADDR where)
1525d545
MG
269{
270 unsigned long insn;
271
d7146cda 272 read_memory (where, (unsigned char *) &insn, xtensa_breakpoint_len);
493e2a69
MS
273 return memcmp((char *) &insn,
274 xtensa_breakpoint, xtensa_breakpoint_len) == 0;
1525d545
MG
275}
276
40045d91
MF
277/* Called by libthread_db. */
278
279ps_err_e
754653a7 280ps_get_thread_area (struct ps_prochandle *ph,
dda83cd7 281 lwpid_t lwpid, int idx, void **base)
40045d91
MF
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
3aee8918
PA
296static struct regsets_info xtensa_regsets_info =
297 {
298 xtensa_regsets, /* regsets */
299 0, /* num_regsets */
300 NULL, /* disabled_regsets */
301 };
302
aa8d21c9 303static struct regs_info myregs_info =
3aee8918
PA
304 {
305 NULL, /* regset_bitmap */
deb44829 306 NULL, /* usrregs */
3aee8918
PA
307 &xtensa_regsets_info
308 };
309
797bcff5
TBA
310void
311xtensa_target::low_arch_setup ()
3aee8918
PA
312{
313 current_process ()->tdesc = tdesc_xtensa;
314}
315
aa8d21c9
TBA
316const regs_info *
317xtensa_target::get_regs_info ()
3aee8918 318{
aa8d21c9 319 return &myregs_info;
3aee8918
PA
320}
321
ef0478f6
TBA
322/* The linux target ops object. */
323
324linux_process_target *the_linux_target = &the_xtensa_target;
3aee8918
PA
325
326void
327initialize_low_arch (void)
328{
329 /* Initialize the Linux target descriptions. */
330 init_registers_xtensa ();
331
332 initialize_regsets_info (&xtensa_regsets_info);
333}