linux-tic6x-low.cc revision 1.1.1.2 1 1.1 christos /* Target dependent code for GDB on TI C6x systems.
2 1.1 christos
3 1.1.1.2 christos Copyright (C) 2010-2023 Free Software Foundation, Inc.
4 1.1 christos Contributed by Andrew Jenner <andrew (at) codesourcery.com>
5 1.1 christos Contributed by Yao Qi <yao (at) codesourcery.com>
6 1.1 christos
7 1.1 christos This file is part of GDB.
8 1.1 christos
9 1.1 christos This program is free software; you can redistribute it and/or modify
10 1.1 christos it under the terms of the GNU General Public License as published by
11 1.1 christos the Free Software Foundation; either version 3 of the License, or
12 1.1 christos (at your option) any later version.
13 1.1 christos
14 1.1 christos This program is distributed in the hope that it will be useful,
15 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
16 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 1.1 christos GNU General Public License for more details.
18 1.1 christos
19 1.1 christos You should have received a copy of the GNU General Public License
20 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 1.1 christos
22 1.1 christos #include "server.h"
23 1.1 christos #include "linux-low.h"
24 1.1 christos #include "arch/tic6x.h"
25 1.1 christos #include "tdesc.h"
26 1.1 christos
27 1.1 christos #include "nat/gdb_ptrace.h"
28 1.1 christos #include <endian.h>
29 1.1 christos
30 1.1 christos #include "gdb_proc_service.h"
31 1.1 christos
32 1.1 christos #ifndef PTRACE_GET_THREAD_AREA
33 1.1 christos #define PTRACE_GET_THREAD_AREA 25
34 1.1 christos #endif
35 1.1 christos
36 1.1 christos /* There are at most 69 registers accessible in ptrace. */
37 1.1 christos #define TIC6X_NUM_REGS 69
38 1.1 christos
39 1.1 christos #include <asm/ptrace.h>
40 1.1 christos
41 1.1 christos /* Linux target op definitions for the TI C6x architecture. */
42 1.1 christos
43 1.1 christos class tic6x_target : public linux_process_target
44 1.1 christos {
45 1.1 christos public:
46 1.1 christos
47 1.1 christos const regs_info *get_regs_info () override;
48 1.1 christos
49 1.1 christos const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override;
50 1.1 christos
51 1.1 christos protected:
52 1.1 christos
53 1.1 christos void low_arch_setup () override;
54 1.1 christos
55 1.1 christos bool low_cannot_fetch_register (int regno) override;
56 1.1 christos
57 1.1 christos bool low_cannot_store_register (int regno) override;
58 1.1 christos
59 1.1 christos bool low_supports_breakpoints () override;
60 1.1 christos
61 1.1 christos CORE_ADDR low_get_pc (regcache *regcache) override;
62 1.1 christos
63 1.1 christos void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
64 1.1 christos
65 1.1 christos bool low_breakpoint_at (CORE_ADDR pc) override;
66 1.1 christos };
67 1.1 christos
68 1.1 christos /* The singleton target ops object. */
69 1.1 christos
70 1.1 christos static tic6x_target the_tic6x_target;
71 1.1 christos
72 1.1 christos /* Defined in auto-generated file tic6x-c64xp-linux.c. */
73 1.1 christos void init_registers_tic6x_c64xp_linux (void);
74 1.1 christos extern const struct target_desc *tdesc_tic6x_c64xp_linux;
75 1.1 christos
76 1.1 christos /* Defined in auto-generated file tic6x-c64x-linux.c. */
77 1.1 christos void init_registers_tic6x_c64x_linux (void);
78 1.1 christos extern const struct target_desc *tdesc_tic6x_c64x_linux;
79 1.1 christos
80 1.1 christos /* Defined in auto-generated file tic62x-c6xp-linux.c. */
81 1.1 christos void init_registers_tic6x_c62x_linux (void);
82 1.1 christos extern const struct target_desc *tdesc_tic6x_c62x_linux;
83 1.1 christos
84 1.1 christos union tic6x_register
85 1.1 christos {
86 1.1 christos unsigned char buf[4];
87 1.1 christos
88 1.1 christos int reg32;
89 1.1 christos };
90 1.1 christos
91 1.1 christos /* Return the ptrace ``address'' of register REGNO. */
92 1.1 christos
93 1.1 christos #if __BYTE_ORDER == __BIG_ENDIAN
94 1.1 christos static int tic6x_regmap_c64xp[] = {
95 1.1 christos /* A0 - A15 */
96 1.1 christos 53, 52, 55, 54, 57, 56, 59, 58,
97 1.1 christos 61, 60, 63, 62, 65, 64, 67, 66,
98 1.1 christos /* B0 - B15 */
99 1.1 christos 23, 22, 25, 24, 27, 26, 29, 28,
100 1.1 christos 31, 30, 33, 32, 35, 34, 69, 68,
101 1.1 christos /* CSR PC */
102 1.1 christos 5, 4,
103 1.1 christos /* A16 - A31 */
104 1.1 christos 37, 36, 39, 38, 41, 40, 43, 42,
105 1.1 christos 45, 44, 47, 46, 49, 48, 51, 50,
106 1.1 christos /* B16 - B31 */
107 1.1 christos 7, 6, 9, 8, 11, 10, 13, 12,
108 1.1 christos 15, 14, 17, 16, 19, 18, 21, 20,
109 1.1 christos /* TSR, ILC, RILC */
110 1.1 christos 1, 2, 3
111 1.1 christos };
112 1.1 christos
113 1.1 christos static int tic6x_regmap_c64x[] = {
114 1.1 christos /* A0 - A15 */
115 1.1 christos 51, 50, 53, 52, 55, 54, 57, 56,
116 1.1 christos 59, 58, 61, 60, 63, 62, 65, 64,
117 1.1 christos /* B0 - B15 */
118 1.1 christos 21, 20, 23, 22, 25, 24, 27, 26,
119 1.1 christos 29, 28, 31, 30, 33, 32, 67, 66,
120 1.1 christos /* CSR PC */
121 1.1 christos 3, 2,
122 1.1 christos /* A16 - A31 */
123 1.1 christos 35, 34, 37, 36, 39, 38, 41, 40,
124 1.1 christos 43, 42, 45, 44, 47, 46, 49, 48,
125 1.1 christos /* B16 - B31 */
126 1.1 christos 5, 4, 7, 6, 9, 8, 11, 10,
127 1.1 christos 13, 12, 15, 14, 17, 16, 19, 18,
128 1.1 christos -1, -1, -1
129 1.1 christos };
130 1.1 christos
131 1.1 christos static int tic6x_regmap_c62x[] = {
132 1.1 christos /* A0 - A15 */
133 1.1 christos 19, 18, 21, 20, 23, 22, 25, 24,
134 1.1 christos 27, 26, 29, 28, 31, 30, 33, 32,
135 1.1 christos /* B0 - B15 */
136 1.1 christos 5, 4, 7, 6, 9, 8, 11, 10,
137 1.1 christos 13, 12, 15, 14, 17, 16, 35, 34,
138 1.1 christos /* CSR, PC */
139 1.1 christos 3, 2,
140 1.1 christos -1, -1, -1, -1, -1, -1, -1, -1,
141 1.1 christos -1, -1, -1, -1, -1, -1, -1, -1,
142 1.1 christos -1, -1, -1, -1, -1, -1, -1, -1,
143 1.1 christos -1, -1, -1, -1, -1, -1, -1, -1,
144 1.1 christos -1, -1, -1
145 1.1 christos };
146 1.1 christos
147 1.1 christos #else
148 1.1 christos static int tic6x_regmap_c64xp[] = {
149 1.1 christos /* A0 - A15 */
150 1.1 christos 52, 53, 54, 55, 56, 57, 58, 59,
151 1.1 christos 60, 61, 62, 63, 64, 65, 66, 67,
152 1.1 christos /* B0 - B15 */
153 1.1 christos 22, 23, 24, 25, 26, 27, 28, 29,
154 1.1 christos 30, 31, 32, 33, 34, 35, 68, 69,
155 1.1 christos /* CSR PC */
156 1.1 christos 4, 5,
157 1.1 christos /* A16 - A31 */
158 1.1 christos 36, 37, 38, 39, 40, 41, 42, 43,
159 1.1 christos 44, 45, 46, 47, 48, 49, 50, 51,
160 1.1 christos /* B16 -B31 */
161 1.1 christos 6, 7, 8, 9, 10, 11, 12, 13,
162 1.1 christos 14, 15, 16, 17, 18, 19, 20, 31,
163 1.1 christos /* TSR, ILC, RILC */
164 1.1 christos 0, 3, 2
165 1.1 christos };
166 1.1 christos
167 1.1 christos static int tic6x_regmap_c64x[] = {
168 1.1 christos /* A0 - A15 */
169 1.1 christos 50, 51, 52, 53, 54, 55, 56, 57,
170 1.1 christos 58, 59, 60, 61, 62, 63, 64, 65,
171 1.1 christos /* B0 - B15 */
172 1.1 christos 20, 21, 22, 23, 24, 25, 26, 27,
173 1.1 christos 28, 29, 30, 31, 32, 33, 66, 67,
174 1.1 christos /* CSR PC */
175 1.1 christos 2, 3,
176 1.1 christos /* A16 - A31 */
177 1.1 christos 34, 35, 36, 37, 38, 39, 40, 41,
178 1.1 christos 42, 43, 44, 45, 46, 47, 48, 49,
179 1.1 christos /* B16 - B31 */
180 1.1 christos 4, 5, 6, 7, 8, 9, 10, 11,
181 1.1 christos 12, 13, 14, 15, 16, 17, 18, 19,
182 1.1 christos -1, -1, -1
183 1.1 christos };
184 1.1 christos
185 1.1 christos static int tic6x_regmap_c62x[] = {
186 1.1 christos /* A0 - A15 */
187 1.1 christos 18, 19, 20, 21, 22, 23, 24, 25,
188 1.1 christos 26, 27, 28, 29, 30, 31, 32, 33,
189 1.1 christos /* B0 - B15 */
190 1.1 christos 4, 5, 6, 7, 8, 9, 10, 11,
191 1.1 christos 12, 13, 14, 15, 16, 17, 34, 35,
192 1.1 christos /* CSR PC */
193 1.1 christos 2, 3,
194 1.1 christos -1, -1, -1, -1, -1, -1, -1, -1,
195 1.1 christos -1, -1, -1, -1, -1, -1, -1, -1,
196 1.1 christos -1, -1, -1, -1, -1, -1, -1, -1,
197 1.1 christos -1, -1, -1, -1, -1, -1, -1, -1,
198 1.1 christos -1, -1, -1
199 1.1 christos };
200 1.1 christos
201 1.1 christos #endif
202 1.1 christos
203 1.1 christos static int *tic6x_regmap;
204 1.1 christos static unsigned int tic6x_breakpoint;
205 1.1 christos #define tic6x_breakpoint_len 4
206 1.1 christos
207 1.1 christos /* Implementation of target ops method "sw_breakpoint_from_kind". */
208 1.1 christos
209 1.1 christos const gdb_byte *
210 1.1 christos tic6x_target::sw_breakpoint_from_kind (int kind, int *size)
211 1.1 christos {
212 1.1 christos *size = tic6x_breakpoint_len;
213 1.1 christos return (const gdb_byte *) &tic6x_breakpoint;
214 1.1 christos }
215 1.1 christos
216 1.1 christos static struct usrregs_info tic6x_usrregs_info =
217 1.1 christos {
218 1.1 christos TIC6X_NUM_REGS,
219 1.1 christos NULL, /* Set in tic6x_read_description. */
220 1.1 christos };
221 1.1 christos
222 1.1 christos static const struct target_desc *
223 1.1 christos tic6x_read_description (enum c6x_feature feature)
224 1.1 christos {
225 1.1 christos static target_desc *tdescs[C6X_LAST] = { };
226 1.1 christos struct target_desc **tdesc = &tdescs[feature];
227 1.1 christos
228 1.1 christos if (*tdesc == NULL)
229 1.1 christos {
230 1.1 christos *tdesc = tic6x_create_target_description (feature);
231 1.1 christos static const char *expedite_regs[] = { "A15", "PC", NULL };
232 1.1 christos init_target_desc (*tdesc, expedite_regs);
233 1.1 christos }
234 1.1 christos
235 1.1 christos return *tdesc;
236 1.1 christos }
237 1.1 christos
238 1.1 christos bool
239 1.1 christos tic6x_target::low_cannot_fetch_register (int regno)
240 1.1 christos {
241 1.1 christos return (tic6x_regmap[regno] == -1);
242 1.1 christos }
243 1.1 christos
244 1.1 christos bool
245 1.1 christos tic6x_target::low_cannot_store_register (int regno)
246 1.1 christos {
247 1.1 christos return (tic6x_regmap[regno] == -1);
248 1.1 christos }
249 1.1 christos
250 1.1 christos bool
251 1.1 christos tic6x_target::low_supports_breakpoints ()
252 1.1 christos {
253 1.1 christos return true;
254 1.1 christos }
255 1.1 christos
256 1.1 christos CORE_ADDR
257 1.1 christos tic6x_target::low_get_pc (regcache *regcache)
258 1.1 christos {
259 1.1 christos union tic6x_register pc;
260 1.1 christos
261 1.1 christos collect_register_by_name (regcache, "PC", pc.buf);
262 1.1 christos return pc.reg32;
263 1.1 christos }
264 1.1 christos
265 1.1 christos void
266 1.1 christos tic6x_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
267 1.1 christos {
268 1.1 christos union tic6x_register newpc;
269 1.1 christos
270 1.1 christos newpc.reg32 = pc;
271 1.1 christos supply_register_by_name (regcache, "PC", newpc.buf);
272 1.1 christos }
273 1.1 christos
274 1.1 christos bool
275 1.1 christos tic6x_target::low_breakpoint_at (CORE_ADDR where)
276 1.1 christos {
277 1.1 christos unsigned int insn;
278 1.1 christos
279 1.1 christos read_memory (where, (unsigned char *) &insn, 4);
280 1.1 christos if (insn == tic6x_breakpoint)
281 1.1 christos return true;
282 1.1 christos
283 1.1 christos /* If necessary, recognize more trap instructions here. GDB only uses the
284 1.1 christos one. */
285 1.1 christos return false;
286 1.1 christos }
287 1.1 christos
288 1.1 christos /* Fetch the thread-local storage pointer for libthread_db. */
289 1.1 christos
290 1.1 christos ps_err_e
291 1.1 christos ps_get_thread_area (struct ps_prochandle *ph,
292 1.1 christos lwpid_t lwpid, int idx, void **base)
293 1.1 christos {
294 1.1 christos if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
295 1.1 christos return PS_ERR;
296 1.1 christos
297 1.1 christos /* IDX is the bias from the thread pointer to the beginning of the
298 1.1 christos thread descriptor. It has to be subtracted due to implementation
299 1.1 christos quirks in libthread_db. */
300 1.1 christos *base = (void *) ((char *) *base - idx);
301 1.1 christos
302 1.1 christos return PS_OK;
303 1.1 christos }
304 1.1 christos
305 1.1 christos static void
306 1.1 christos tic6x_collect_register (struct regcache *regcache, int regno,
307 1.1 christos union tic6x_register *reg)
308 1.1 christos {
309 1.1 christos union tic6x_register tmp_reg;
310 1.1 christos
311 1.1 christos collect_register (regcache, regno, &tmp_reg.reg32);
312 1.1 christos reg->reg32 = tmp_reg.reg32;
313 1.1 christos }
314 1.1 christos
315 1.1 christos static void
316 1.1 christos tic6x_supply_register (struct regcache *regcache, int regno,
317 1.1 christos const union tic6x_register *reg)
318 1.1 christos {
319 1.1 christos int offset = 0;
320 1.1 christos
321 1.1 christos supply_register (regcache, regno, reg->buf + offset);
322 1.1 christos }
323 1.1 christos
324 1.1 christos static void
325 1.1 christos tic6x_fill_gregset (struct regcache *regcache, void *buf)
326 1.1 christos {
327 1.1 christos auto regset = static_cast<union tic6x_register *> (buf);
328 1.1 christos int i;
329 1.1 christos
330 1.1 christos for (i = 0; i < TIC6X_NUM_REGS; i++)
331 1.1 christos if (tic6x_regmap[i] != -1)
332 1.1 christos tic6x_collect_register (regcache, i, regset + tic6x_regmap[i]);
333 1.1 christos }
334 1.1 christos
335 1.1 christos static void
336 1.1 christos tic6x_store_gregset (struct regcache *regcache, const void *buf)
337 1.1 christos {
338 1.1 christos const auto regset = static_cast<const union tic6x_register *> (buf);
339 1.1 christos int i;
340 1.1 christos
341 1.1 christos for (i = 0; i < TIC6X_NUM_REGS; i++)
342 1.1 christos if (tic6x_regmap[i] != -1)
343 1.1 christos tic6x_supply_register (regcache, i, regset + tic6x_regmap[i]);
344 1.1 christos }
345 1.1 christos
346 1.1 christos static struct regset_info tic6x_regsets[] = {
347 1.1 christos { PTRACE_GETREGS, PTRACE_SETREGS, 0, TIC6X_NUM_REGS * 4, GENERAL_REGS,
348 1.1 christos tic6x_fill_gregset, tic6x_store_gregset },
349 1.1 christos NULL_REGSET
350 1.1 christos };
351 1.1 christos
352 1.1 christos void
353 1.1 christos tic6x_target::low_arch_setup ()
354 1.1 christos {
355 1.1 christos register unsigned int csr asm ("B2");
356 1.1 christos unsigned int cpuid;
357 1.1 christos enum c6x_feature feature = C6X_CORE;
358 1.1 christos
359 1.1 christos /* Determine the CPU we're running on to find the register order. */
360 1.1 christos __asm__ ("MVC .S2 CSR,%0" : "=r" (csr) :);
361 1.1 christos cpuid = csr >> 24;
362 1.1 christos switch (cpuid)
363 1.1 christos {
364 1.1 christos case 0x00: /* C62x */
365 1.1 christos case 0x02: /* C67x */
366 1.1 christos tic6x_regmap = tic6x_regmap_c62x;
367 1.1 christos tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */
368 1.1 christos feature = C6X_CORE;
369 1.1 christos break;
370 1.1 christos case 0x03: /* C67x+ */
371 1.1 christos tic6x_regmap = tic6x_regmap_c64x;
372 1.1 christos tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */
373 1.1 christos feature = C6X_GP;
374 1.1 christos break;
375 1.1 christos case 0x0c: /* C64x */
376 1.1 christos tic6x_regmap = tic6x_regmap_c64x;
377 1.1 christos tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */
378 1.1 christos feature = C6X_GP;
379 1.1 christos break;
380 1.1 christos case 0x10: /* C64x+ */
381 1.1 christos case 0x14: /* C674x */
382 1.1 christos case 0x15: /* C66x */
383 1.1 christos tic6x_regmap = tic6x_regmap_c64xp;
384 1.1 christos tic6x_breakpoint = 0x56454314; /* illegal opcode */
385 1.1 christos feature = C6X_C6XP;
386 1.1 christos break;
387 1.1 christos default:
388 1.1 christos error ("Unknown CPU ID 0x%02x", cpuid);
389 1.1 christos }
390 1.1 christos tic6x_usrregs_info.regmap = tic6x_regmap;
391 1.1 christos
392 1.1 christos current_process ()->tdesc = tic6x_read_description (feature);
393 1.1 christos }
394 1.1 christos
395 1.1 christos static struct regsets_info tic6x_regsets_info =
396 1.1 christos {
397 1.1 christos tic6x_regsets, /* regsets */
398 1.1 christos 0, /* num_regsets */
399 1.1 christos NULL, /* disabled_regsets */
400 1.1 christos };
401 1.1 christos
402 1.1 christos static struct regs_info myregs_info =
403 1.1 christos {
404 1.1 christos NULL, /* regset_bitmap */
405 1.1 christos &tic6x_usrregs_info,
406 1.1 christos &tic6x_regsets_info
407 1.1 christos };
408 1.1 christos
409 1.1 christos const regs_info *
410 1.1 christos tic6x_target::get_regs_info ()
411 1.1 christos {
412 1.1 christos return &myregs_info;
413 1.1 christos }
414 1.1 christos
415 1.1 christos #if GDB_SELF_TEST
416 1.1 christos #include "gdbsupport/selftest.h"
417 1.1 christos
418 1.1 christos namespace selftests {
419 1.1 christos namespace tdesc {
420 1.1 christos static void
421 1.1 christos tic6x_tdesc_test ()
422 1.1 christos {
423 1.1 christos SELF_CHECK (*tdesc_tic6x_c62x_linux == *tic6x_read_description (C6X_CORE));
424 1.1 christos SELF_CHECK (*tdesc_tic6x_c64x_linux == *tic6x_read_description (C6X_GP));
425 1.1 christos SELF_CHECK (*tdesc_tic6x_c64xp_linux == *tic6x_read_description (C6X_C6XP));
426 1.1 christos }
427 1.1 christos }
428 1.1 christos }
429 1.1 christos #endif
430 1.1 christos
431 1.1 christos /* The linux target ops object. */
432 1.1 christos
433 1.1 christos linux_process_target *the_linux_target = &the_tic6x_target;
434 1.1 christos
435 1.1 christos void
436 1.1 christos initialize_low_arch (void)
437 1.1 christos {
438 1.1 christos #if GDB_SELF_TEST
439 1.1 christos /* Initialize the Linux target descriptions. */
440 1.1 christos init_registers_tic6x_c64xp_linux ();
441 1.1 christos init_registers_tic6x_c64x_linux ();
442 1.1 christos init_registers_tic6x_c62x_linux ();
443 1.1 christos
444 1.1 christos selftests::register_test ("tic6x-tdesc", selftests::tdesc::tic6x_tdesc_test);
445 1.1 christos #endif
446 1.1 christos
447 1.1 christos initialize_regsets_info (&tic6x_regsets_info);
448 1.1 christos }
449