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