a7ed08541f5f45948f0293a1faecc0f8ac7044fe
[deliverable/binutils-gdb.git] / gdbserver / linux-xtensa-low.cc
1 /* GNU/Linux/Xtensa specific low level interface, for the remote server for GDB.
2 Copyright (C) 2007-2020 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
20 #include "server.h"
21 #include "linux-low.h"
22
23 /* Linux target op definitions for the Xtensa architecture. */
24
25 class xtensa_target : public linux_process_target
26 {
27 public:
28
29 protected:
30
31 void low_arch_setup () override;
32 };
33
34 /* The singleton target ops object. */
35
36 static xtensa_target the_xtensa_target;
37
38 /* Defined in auto-generated file reg-xtensa.c. */
39 void init_registers_xtensa (void);
40 extern const struct target_desc *tdesc_xtensa;
41
42 #include <asm/ptrace.h>
43 #include <xtensa-config.h>
44 #include "arch/xtensa.h"
45 #include "gdb_proc_service.h"
46
47 #include "xtensa-xtregs.c"
48
49 enum regnum {
50 R_PC=0, R_PS,
51 R_LBEG, R_LEND, R_LCOUNT,
52 R_SAR,
53 R_WS, R_WB,
54 R_THREADPTR,
55 R_A0 = 64
56 };
57
58 static void
59 xtensa_fill_gregset (struct regcache *regcache, void *buf)
60 {
61 elf_greg_t* rset = (elf_greg_t*)buf;
62 const struct target_desc *tdesc = regcache->tdesc;
63 int ar0_regnum;
64 char *ptr;
65 int i;
66
67 /* Take care of AR registers. */
68
69 ar0_regnum = find_regno (tdesc, "ar0");
70 ptr = (char*)&rset[R_A0];
71
72 for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++)
73 {
74 collect_register (regcache, i, ptr);
75 ptr += register_size (tdesc, i);
76 }
77
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
92 /* Loop registers, if hardware has it. */
93
94 #if XCHAL_HAVE_LOOPS
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]);
98 #endif
99
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]);
105
106 #if XCHAL_HAVE_THREADPTR
107 collect_register_by_name (regcache, "threadptr",
108 (char *) &rset[R_THREADPTR]);
109 #endif
110 }
111
112 static void
113 xtensa_store_gregset (struct regcache *regcache, const void *buf)
114 {
115 const elf_greg_t* rset = (const elf_greg_t*)buf;
116 const struct target_desc *tdesc = regcache->tdesc;
117 int ar0_regnum;
118 char *ptr;
119 int i;
120
121 /* Take care of AR registers. */
122
123 ar0_regnum = find_regno (tdesc, "ar0");
124 ptr = (char *)&rset[R_A0];
125
126 for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++)
127 {
128 supply_register (regcache, i, ptr);
129 ptr += register_size (tdesc, i);
130 }
131
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
146 /* Loop registers, if hardware has it. */
147
148 #if XCHAL_HAVE_LOOPS
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]);
152 #endif
153
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]);
159
160 #if XCHAL_HAVE_THREADPTR
161 supply_register_by_name (regcache, "threadptr",
162 (char *) &rset[R_THREADPTR]);
163 #endif
164 }
165
166 /* Xtensa GNU/Linux PTRACE interface includes extended register set. */
167
168 static void
169 xtensa_fill_xtregset (struct regcache *regcache, void *buf)
170 {
171 const xtensa_regtable_t *ptr;
172
173 for (ptr = xtensa_regmap_table; ptr->name; ptr++)
174 {
175 collect_register_by_name (regcache, ptr->name,
176 (char*)buf + ptr->ptrace_offset);
177 }
178 }
179
180 static void
181 xtensa_store_xtregset (struct regcache *regcache, const void *buf)
182 {
183 const xtensa_regtable_t *ptr;
184
185 for (ptr = xtensa_regmap_table; ptr->name; ptr++)
186 {
187 supply_register_by_name (regcache, ptr->name,
188 (char*)buf + ptr->ptrace_offset);
189 }
190 }
191
192 static struct regset_info xtensa_regsets[] = {
193 { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t),
194 GENERAL_REGS,
195 xtensa_fill_gregset, xtensa_store_gregset },
196 { PTRACE_GETXTREGS, PTRACE_SETXTREGS, 0, XTENSA_ELF_XTREG_SIZE,
197 EXTENDED_REGS,
198 xtensa_fill_xtregset, xtensa_store_xtregset },
199 NULL_REGSET
200 };
201
202 #if XCHAL_HAVE_BE
203 #define XTENSA_BREAKPOINT {0xd2,0x0f}
204 #else
205 #define XTENSA_BREAKPOINT {0x2d,0xf0}
206 #endif
207
208 static const gdb_byte xtensa_breakpoint[] = XTENSA_BREAKPOINT;
209 #define xtensa_breakpoint_len 2
210
211 /* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */
212
213 static const gdb_byte *
214 xtensa_sw_breakpoint_from_kind (int kind, int *size)
215 {
216 *size = xtensa_breakpoint_len;
217 return xtensa_breakpoint;
218 }
219
220 static int
221 xtensa_breakpoint_at (CORE_ADDR where)
222 {
223 unsigned long insn;
224
225 the_target->read_memory (where, (unsigned char *) &insn,
226 xtensa_breakpoint_len);
227 return memcmp((char *) &insn,
228 xtensa_breakpoint, xtensa_breakpoint_len) == 0;
229 }
230
231 /* Called by libthread_db. */
232
233 ps_err_e
234 ps_get_thread_area (struct ps_prochandle *ph,
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
250 static struct regsets_info xtensa_regsets_info =
251 {
252 xtensa_regsets, /* regsets */
253 0, /* num_regsets */
254 NULL, /* disabled_regsets */
255 };
256
257 static struct regs_info regs_info =
258 {
259 NULL, /* regset_bitmap */
260 NULL, /* usrregs */
261 &xtensa_regsets_info
262 };
263
264 void
265 xtensa_target::low_arch_setup ()
266 {
267 current_process ()->tdesc = tdesc_xtensa;
268 }
269
270 /* Support for hardware single step. */
271
272 static int
273 xtensa_supports_hardware_single_step (void)
274 {
275 return 1;
276 }
277
278 static const struct regs_info *
279 xtensa_regs_info (void)
280 {
281 return &regs_info;
282 }
283
284 struct linux_target_ops the_low_target = {
285 xtensa_regs_info,
286 0,
287 0,
288 NULL, /* fetch_register */
289 linux_get_pc_32bit,
290 linux_set_pc_32bit,
291 NULL, /* breakpoint_kind_from_pc */
292 xtensa_sw_breakpoint_from_kind,
293 NULL,
294 0,
295 xtensa_breakpoint_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 */
305 NULL, /* delete_process */
306 NULL, /* new_thread */
307 NULL, /* delete_thread */
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,
319 };
320
321 /* The linux target ops object. */
322
323 linux_process_target *the_linux_target = &the_xtensa_target;
324
325 void
326 initialize_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.035432 seconds and 3 git commands to generate.