gdbserver/linux-low: turn 'arch_setup' into a method
[deliverable/binutils-gdb.git] / gdbserver / linux-xtensa-low.cc
CommitLineData
1525d545 1/* GNU/Linux/Xtensa specific low level interface, for the remote server for GDB.
b811d2c2 2 Copyright (C) 2007-2020 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
20#include "server.h"
21#include "linux-low.h"
22
ef0478f6
TBA
23/* Linux target op definitions for the Xtensa architecture. */
24
25class xtensa_target : public linux_process_target
26{
27public:
28
797bcff5
TBA
29protected:
30
31 void low_arch_setup () override;
ef0478f6
TBA
32};
33
34/* The singleton target ops object. */
35
36static xtensa_target the_xtensa_target;
37
d05b4ac3
UW
38/* Defined in auto-generated file reg-xtensa.c. */
39void init_registers_xtensa (void);
3aee8918 40extern const struct target_desc *tdesc_xtensa;
d05b4ac3 41
e671835b 42#include <asm/ptrace.h>
1525d545 43#include <xtensa-config.h>
40045d91
MF
44#include "arch/xtensa.h"
45#include "gdb_proc_service.h"
1525d545
MG
46
47#include "xtensa-xtregs.c"
48
49enum regnum {
50 R_PC=0, R_PS,
51 R_LBEG, R_LEND, R_LCOUNT,
52 R_SAR,
53 R_WS, R_WB,
a12e714b 54 R_THREADPTR,
1b3f6016 55 R_A0 = 64
1525d545
MG
56};
57
58static void
442ea881 59xtensa_fill_gregset (struct regcache *regcache, void *buf)
1525d545
MG
60{
61 elf_greg_t* rset = (elf_greg_t*)buf;
3aee8918 62 const struct target_desc *tdesc = regcache->tdesc;
1525d545
MG
63 int ar0_regnum;
64 char *ptr;
65 int i;
66
67 /* Take care of AR registers. */
68
3aee8918 69 ar0_regnum = find_regno (tdesc, "ar0");
1525d545
MG
70 ptr = (char*)&rset[R_A0];
71
72 for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++)
73 {
442ea881 74 collect_register (regcache, i, ptr);
3aee8918 75 ptr += register_size (tdesc, i);
1525d545
MG
76 }
77
1a09b50a
MF
78 if (XSHAL_ABI == XTHAL_ABI_CALL0)
79 {
80 int a0_regnum = find_regno (tdesc, "a0");
81 ptr = (char *) &rset[R_A0 + 4 * rset[R_WB]];
82
83 for (i = a0_regnum; i < a0_regnum + C0_NREGS; i++)
84 {
85 if ((4 * rset[R_WB] + i - a0_regnum) == XCHAL_NUM_AREGS)
86 ptr = (char *) &rset[R_A0];
87 collect_register (regcache, i, ptr);
88 ptr += register_size (tdesc, i);
89 }
90 }
91
1525d545
MG
92 /* Loop registers, if hardware has it. */
93
a2d5a9d7 94#if XCHAL_HAVE_LOOPS
442ea881
PA
95 collect_register_by_name (regcache, "lbeg", (char*)&rset[R_LBEG]);
96 collect_register_by_name (regcache, "lend", (char*)&rset[R_LEND]);
97 collect_register_by_name (regcache, "lcount", (char*)&rset[R_LCOUNT]);
1525d545
MG
98#endif
99
442ea881
PA
100 collect_register_by_name (regcache, "sar", (char*)&rset[R_SAR]);
101 collect_register_by_name (regcache, "pc", (char*)&rset[R_PC]);
102 collect_register_by_name (regcache, "ps", (char*)&rset[R_PS]);
103 collect_register_by_name (regcache, "windowbase", (char*)&rset[R_WB]);
104 collect_register_by_name (regcache, "windowstart", (char*)&rset[R_WS]);
a12e714b
MF
105
106#if XCHAL_HAVE_THREADPTR
107 collect_register_by_name (regcache, "threadptr",
108 (char *) &rset[R_THREADPTR]);
109#endif
1525d545
MG
110}
111
112static void
442ea881 113xtensa_store_gregset (struct regcache *regcache, const void *buf)
1525d545
MG
114{
115 const elf_greg_t* rset = (const elf_greg_t*)buf;
3aee8918 116 const struct target_desc *tdesc = regcache->tdesc;
1525d545
MG
117 int ar0_regnum;
118 char *ptr;
119 int i;
120
121 /* Take care of AR registers. */
122
3aee8918 123 ar0_regnum = find_regno (tdesc, "ar0");
1525d545
MG
124 ptr = (char *)&rset[R_A0];
125
126 for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++)
127 {
442ea881 128 supply_register (regcache, i, ptr);
3aee8918 129 ptr += register_size (tdesc, i);
1525d545
MG
130 }
131
1a09b50a
MF
132 if (XSHAL_ABI == XTHAL_ABI_CALL0)
133 {
134 int a0_regnum = find_regno (tdesc, "a0");
135 ptr = (char *) &rset[R_A0 + (4 * rset[R_WB]) % XCHAL_NUM_AREGS];
136
137 for (i = a0_regnum; i < a0_regnum + C0_NREGS; i++)
138 {
139 if ((4 * rset[R_WB] + i - a0_regnum) == XCHAL_NUM_AREGS)
140 ptr = (char *) &rset[R_A0];
141 supply_register (regcache, i, ptr);
142 ptr += register_size (tdesc, i);
143 }
144 }
145
1525d545
MG
146 /* Loop registers, if hardware has it. */
147
a2d5a9d7 148#if XCHAL_HAVE_LOOPS
442ea881
PA
149 supply_register_by_name (regcache, "lbeg", (char*)&rset[R_LBEG]);
150 supply_register_by_name (regcache, "lend", (char*)&rset[R_LEND]);
151 supply_register_by_name (regcache, "lcount", (char*)&rset[R_LCOUNT]);
1525d545
MG
152#endif
153
442ea881
PA
154 supply_register_by_name (regcache, "sar", (char*)&rset[R_SAR]);
155 supply_register_by_name (regcache, "pc", (char*)&rset[R_PC]);
156 supply_register_by_name (regcache, "ps", (char*)&rset[R_PS]);
157 supply_register_by_name (regcache, "windowbase", (char*)&rset[R_WB]);
158 supply_register_by_name (regcache, "windowstart", (char*)&rset[R_WS]);
a12e714b
MF
159
160#if XCHAL_HAVE_THREADPTR
161 supply_register_by_name (regcache, "threadptr",
162 (char *) &rset[R_THREADPTR]);
163#endif
1525d545
MG
164}
165
166/* Xtensa GNU/Linux PTRACE interface includes extended register set. */
167
168static void
442ea881 169xtensa_fill_xtregset (struct regcache *regcache, void *buf)
1525d545
MG
170{
171 const xtensa_regtable_t *ptr;
172
173 for (ptr = xtensa_regmap_table; ptr->name; ptr++)
174 {
442ea881 175 collect_register_by_name (regcache, ptr->name,
1525d545
MG
176 (char*)buf + ptr->ptrace_offset);
177 }
178}
179
180static void
442ea881 181xtensa_store_xtregset (struct regcache *regcache, const void *buf)
1525d545
MG
182{
183 const xtensa_regtable_t *ptr;
184
185 for (ptr = xtensa_regmap_table; ptr->name; ptr++)
186 {
442ea881 187 supply_register_by_name (regcache, ptr->name,
1525d545
MG
188 (char*)buf + ptr->ptrace_offset);
189 }
190}
191
3aee8918 192static struct regset_info xtensa_regsets[] = {
1570b33e 193 { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t),
1525d545
MG
194 GENERAL_REGS,
195 xtensa_fill_gregset, xtensa_store_gregset },
1570b33e 196 { PTRACE_GETXTREGS, PTRACE_SETXTREGS, 0, XTENSA_ELF_XTREG_SIZE,
1525d545
MG
197 EXTENDED_REGS,
198 xtensa_fill_xtregset, xtensa_store_xtregset },
50bc912a 199 NULL_REGSET
1525d545
MG
200};
201
202#if XCHAL_HAVE_BE
203#define XTENSA_BREAKPOINT {0xd2,0x0f}
204#else
205#define XTENSA_BREAKPOINT {0x2d,0xf0}
206#endif
207
dd373349 208static const gdb_byte xtensa_breakpoint[] = XTENSA_BREAKPOINT;
1525d545
MG
209#define xtensa_breakpoint_len 2
210
dd373349
AT
211/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */
212
213static const gdb_byte *
214xtensa_sw_breakpoint_from_kind (int kind, int *size)
215{
216 *size = xtensa_breakpoint_len;
217 return xtensa_breakpoint;
218}
219
1525d545
MG
220static int
221xtensa_breakpoint_at (CORE_ADDR where)
222{
223 unsigned long insn;
224
52405d85
TBA
225 the_target->read_memory (where, (unsigned char *) &insn,
226 xtensa_breakpoint_len);
493e2a69
MS
227 return memcmp((char *) &insn,
228 xtensa_breakpoint, xtensa_breakpoint_len) == 0;
1525d545
MG
229}
230
40045d91
MF
231/* Called by libthread_db. */
232
233ps_err_e
754653a7 234ps_get_thread_area (struct ps_prochandle *ph,
40045d91
MF
235 lwpid_t lwpid, int idx, void **base)
236{
237 xtensa_elf_gregset_t regs;
238
239 if (ptrace (PTRACE_GETREGS, lwpid, NULL, &regs) != 0)
240 return PS_ERR;
241
242 /* IDX is the bias from the thread pointer to the beginning of the
243 thread descriptor. It has to be subtracted due to implementation
244 quirks in libthread_db. */
245 *base = (void *) ((char *) regs.threadptr - idx);
246
247 return PS_OK;
248}
249
3aee8918
PA
250static struct regsets_info xtensa_regsets_info =
251 {
252 xtensa_regsets, /* regsets */
253 0, /* num_regsets */
254 NULL, /* disabled_regsets */
255 };
256
3aee8918
PA
257static struct regs_info regs_info =
258 {
259 NULL, /* regset_bitmap */
deb44829 260 NULL, /* usrregs */
3aee8918
PA
261 &xtensa_regsets_info
262 };
263
797bcff5
TBA
264void
265xtensa_target::low_arch_setup ()
3aee8918
PA
266{
267 current_process ()->tdesc = tdesc_xtensa;
268}
269
7d00775e
AT
270/* Support for hardware single step. */
271
272static int
273xtensa_supports_hardware_single_step (void)
274{
275 return 1;
276}
277
3aee8918
PA
278static const struct regs_info *
279xtensa_regs_info (void)
280{
281 return &regs_info;
282}
283
1525d545 284struct linux_target_ops the_low_target = {
3aee8918 285 xtensa_regs_info,
1525d545
MG
286 0,
287 0,
c14dfd32 288 NULL, /* fetch_register */
276d4552
YQ
289 linux_get_pc_32bit,
290 linux_set_pc_32bit,
dd373349
AT
291 NULL, /* breakpoint_kind_from_pc */
292 xtensa_sw_breakpoint_from_kind,
1525d545
MG
293 NULL,
294 0,
295 xtensa_breakpoint_at,
7d00775e
AT
296 NULL, /* supports_z_point_type */
297 NULL, /* insert_point */
298 NULL, /* remove_point */
299 NULL, /* stopped_by_watchpoint */
300 NULL, /* stopped_data_address */
301 NULL, /* collect_ptrace_register */
302 NULL, /* supply_ptrace_register */
303 NULL, /* siginfo_fixup */
304 NULL, /* new_process */
04ec7890 305 NULL, /* delete_process */
7d00775e 306 NULL, /* new_thread */
466eecee 307 NULL, /* delete_thread */
7d00775e
AT
308 NULL, /* new_fork */
309 NULL, /* prepare_to_resume */
310 NULL, /* process_qsupported */
311 NULL, /* supports_tracepoints */
312 NULL, /* get_thread_area */
313 NULL, /* install_fast_tracepoint_jump_pad */
314 NULL, /* emit_ops */
315 NULL, /* get_min_fast_tracepoint_insn_len */
316 NULL, /* supports_range_stepping */
317 NULL, /* breakpoint_kind_from_current_state */
318 xtensa_supports_hardware_single_step,
1525d545 319};
3aee8918 320
ef0478f6
TBA
321/* The linux target ops object. */
322
323linux_process_target *the_linux_target = &the_xtensa_target;
3aee8918
PA
324
325void
326initialize_low_arch (void)
327{
328 /* Initialize the Linux target descriptions. */
329 init_registers_xtensa ();
330
331 initialize_regsets_info (&xtensa_regsets_info);
332}
This page took 0.997102 seconds and 4 git commands to generate.