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