1 /* Target dependent code for GDB on TI C6x systems.
3 Copyright (C) 2010-2024 Free Software Foundation, Inc.
4 Contributed by Andrew Jenner <andrew@codesourcery.com>
5 Contributed by Yao Qi <yao@codesourcery.com>
7 This file is part of GDB.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
23 #include "linux-low.h"
24 #include "arch/tic6x.h"
27 #include "nat/gdb_ptrace.h"
30 #include "gdb_proc_service.h"
32 #ifndef PTRACE_GET_THREAD_AREA
33 #define PTRACE_GET_THREAD_AREA 25
36 /* There are at most 69 registers accessible in ptrace. */
37 #define TIC6X_NUM_REGS 69
39 #include <asm/ptrace.h>
41 /* Linux target op definitions for the TI C6x architecture. */
43 class tic6x_target
: public linux_process_target
47 const regs_info
*get_regs_info () override
;
49 const gdb_byte
*sw_breakpoint_from_kind (int kind
, int *size
) override
;
53 void low_arch_setup () override
;
55 bool low_cannot_fetch_register (int regno
) override
;
57 bool low_cannot_store_register (int regno
) override
;
59 bool low_supports_breakpoints () override
;
61 CORE_ADDR
low_get_pc (regcache
*regcache
) override
;
63 void low_set_pc (regcache
*regcache
, CORE_ADDR newpc
) override
;
65 bool low_breakpoint_at (CORE_ADDR pc
) override
;
68 /* The singleton target ops object. */
70 static tic6x_target the_tic6x_target
;
72 /* Defined in auto-generated file tic6x-c64xp-linux.c. */
73 void init_registers_tic6x_c64xp_linux (void);
74 extern const struct target_desc
*tdesc_tic6x_c64xp_linux
;
76 /* Defined in auto-generated file tic6x-c64x-linux.c. */
77 void init_registers_tic6x_c64x_linux (void);
78 extern const struct target_desc
*tdesc_tic6x_c64x_linux
;
80 /* Defined in auto-generated file tic62x-c6xp-linux.c. */
81 void init_registers_tic6x_c62x_linux (void);
82 extern const struct target_desc
*tdesc_tic6x_c62x_linux
;
91 /* Return the ptrace ``address'' of register REGNO. */
93 #if __BYTE_ORDER == __BIG_ENDIAN
94 static int tic6x_regmap_c64xp
[] = {
96 53, 52, 55, 54, 57, 56, 59, 58,
97 61, 60, 63, 62, 65, 64, 67, 66,
99 23, 22, 25, 24, 27, 26, 29, 28,
100 31, 30, 33, 32, 35, 34, 69, 68,
104 37, 36, 39, 38, 41, 40, 43, 42,
105 45, 44, 47, 46, 49, 48, 51, 50,
107 7, 6, 9, 8, 11, 10, 13, 12,
108 15, 14, 17, 16, 19, 18, 21, 20,
113 static int tic6x_regmap_c64x
[] = {
115 51, 50, 53, 52, 55, 54, 57, 56,
116 59, 58, 61, 60, 63, 62, 65, 64,
118 21, 20, 23, 22, 25, 24, 27, 26,
119 29, 28, 31, 30, 33, 32, 67, 66,
123 35, 34, 37, 36, 39, 38, 41, 40,
124 43, 42, 45, 44, 47, 46, 49, 48,
126 5, 4, 7, 6, 9, 8, 11, 10,
127 13, 12, 15, 14, 17, 16, 19, 18,
131 static int tic6x_regmap_c62x
[] = {
133 19, 18, 21, 20, 23, 22, 25, 24,
134 27, 26, 29, 28, 31, 30, 33, 32,
136 5, 4, 7, 6, 9, 8, 11, 10,
137 13, 12, 15, 14, 17, 16, 35, 34,
140 -1, -1, -1, -1, -1, -1, -1, -1,
141 -1, -1, -1, -1, -1, -1, -1, -1,
142 -1, -1, -1, -1, -1, -1, -1, -1,
143 -1, -1, -1, -1, -1, -1, -1, -1,
148 static int tic6x_regmap_c64xp
[] = {
150 52, 53, 54, 55, 56, 57, 58, 59,
151 60, 61, 62, 63, 64, 65, 66, 67,
153 22, 23, 24, 25, 26, 27, 28, 29,
154 30, 31, 32, 33, 34, 35, 68, 69,
158 36, 37, 38, 39, 40, 41, 42, 43,
159 44, 45, 46, 47, 48, 49, 50, 51,
161 6, 7, 8, 9, 10, 11, 12, 13,
162 14, 15, 16, 17, 18, 19, 20, 31,
167 static int tic6x_regmap_c64x
[] = {
169 50, 51, 52, 53, 54, 55, 56, 57,
170 58, 59, 60, 61, 62, 63, 64, 65,
172 20, 21, 22, 23, 24, 25, 26, 27,
173 28, 29, 30, 31, 32, 33, 66, 67,
177 34, 35, 36, 37, 38, 39, 40, 41,
178 42, 43, 44, 45, 46, 47, 48, 49,
180 4, 5, 6, 7, 8, 9, 10, 11,
181 12, 13, 14, 15, 16, 17, 18, 19,
185 static int tic6x_regmap_c62x
[] = {
187 18, 19, 20, 21, 22, 23, 24, 25,
188 26, 27, 28, 29, 30, 31, 32, 33,
190 4, 5, 6, 7, 8, 9, 10, 11,
191 12, 13, 14, 15, 16, 17, 34, 35,
194 -1, -1, -1, -1, -1, -1, -1, -1,
195 -1, -1, -1, -1, -1, -1, -1, -1,
196 -1, -1, -1, -1, -1, -1, -1, -1,
197 -1, -1, -1, -1, -1, -1, -1, -1,
203 static int *tic6x_regmap
;
204 static unsigned int tic6x_breakpoint
;
205 #define tic6x_breakpoint_len 4
207 /* Implementation of target ops method "sw_breakpoint_from_kind". */
210 tic6x_target::sw_breakpoint_from_kind (int kind
, int *size
)
212 *size
= tic6x_breakpoint_len
;
213 return (const gdb_byte
*) &tic6x_breakpoint
;
216 static struct usrregs_info tic6x_usrregs_info
=
219 NULL
, /* Set in tic6x_read_description. */
222 static const struct target_desc
*
223 tic6x_read_description (enum c6x_feature feature
)
225 static target_desc
*tdescs
[C6X_LAST
] = { };
226 struct target_desc
**tdesc
= &tdescs
[feature
];
230 *tdesc
= tic6x_create_target_description (feature
);
231 static const char *expedite_regs
[] = { "A15", "PC", NULL
};
232 init_target_desc (*tdesc
, expedite_regs
);
239 tic6x_target::low_cannot_fetch_register (int regno
)
241 return (tic6x_regmap
[regno
] == -1);
245 tic6x_target::low_cannot_store_register (int regno
)
247 return (tic6x_regmap
[regno
] == -1);
251 tic6x_target::low_supports_breakpoints ()
257 tic6x_target::low_get_pc (regcache
*regcache
)
259 union tic6x_register pc
;
261 collect_register_by_name (regcache
, "PC", pc
.buf
);
266 tic6x_target::low_set_pc (regcache
*regcache
, CORE_ADDR pc
)
268 union tic6x_register newpc
;
271 supply_register_by_name (regcache
, "PC", newpc
.buf
);
275 tic6x_target::low_breakpoint_at (CORE_ADDR where
)
279 read_memory (where
, (unsigned char *) &insn
, 4);
280 if (insn
== tic6x_breakpoint
)
283 /* If necessary, recognize more trap instructions here. GDB only uses the
288 /* Fetch the thread-local storage pointer for libthread_db. */
291 ps_get_thread_area (struct ps_prochandle
*ph
,
292 lwpid_t lwpid
, int idx
, void **base
)
294 if (ptrace (PTRACE_GET_THREAD_AREA
, lwpid
, NULL
, base
) != 0)
297 /* IDX is the bias from the thread pointer to the beginning of the
298 thread descriptor. It has to be subtracted due to implementation
299 quirks in libthread_db. */
300 *base
= (void *) ((char *) *base
- idx
);
306 tic6x_collect_register (struct regcache
*regcache
, int regno
,
307 union tic6x_register
*reg
)
309 union tic6x_register tmp_reg
;
311 collect_register (regcache
, regno
, &tmp_reg
.reg32
);
312 reg
->reg32
= tmp_reg
.reg32
;
316 tic6x_supply_register (struct regcache
*regcache
, int regno
,
317 const union tic6x_register
*reg
)
321 supply_register (regcache
, regno
, reg
->buf
+ offset
);
325 tic6x_fill_gregset (struct regcache
*regcache
, void *buf
)
327 auto regset
= static_cast<union tic6x_register
*> (buf
);
330 for (i
= 0; i
< TIC6X_NUM_REGS
; i
++)
331 if (tic6x_regmap
[i
] != -1)
332 tic6x_collect_register (regcache
, i
, regset
+ tic6x_regmap
[i
]);
336 tic6x_store_gregset (struct regcache
*regcache
, const void *buf
)
338 const auto regset
= static_cast<const union tic6x_register
*> (buf
);
341 for (i
= 0; i
< TIC6X_NUM_REGS
; i
++)
342 if (tic6x_regmap
[i
] != -1)
343 tic6x_supply_register (regcache
, i
, regset
+ tic6x_regmap
[i
]);
346 static struct regset_info tic6x_regsets
[] = {
347 { PTRACE_GETREGS
, PTRACE_SETREGS
, 0, TIC6X_NUM_REGS
* 4, GENERAL_REGS
,
348 tic6x_fill_gregset
, tic6x_store_gregset
},
353 tic6x_target::low_arch_setup ()
355 register unsigned int csr
asm ("B2");
357 enum c6x_feature feature
= C6X_CORE
;
359 /* Determine the CPU we're running on to find the register order. */
360 __asm__ ("MVC .S2 CSR,%0" : "=r" (csr
) :);
364 case 0x00: /* C62x */
365 case 0x02: /* C67x */
366 tic6x_regmap
= tic6x_regmap_c62x
;
367 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
370 case 0x03: /* C67x+ */
371 tic6x_regmap
= tic6x_regmap_c64x
;
372 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
375 case 0x0c: /* C64x */
376 tic6x_regmap
= tic6x_regmap_c64x
;
377 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
380 case 0x10: /* C64x+ */
381 case 0x14: /* C674x */
382 case 0x15: /* C66x */
383 tic6x_regmap
= tic6x_regmap_c64xp
;
384 tic6x_breakpoint
= 0x56454314; /* illegal opcode */
388 error ("Unknown CPU ID 0x%02x", cpuid
);
390 tic6x_usrregs_info
.regmap
= tic6x_regmap
;
392 current_process ()->tdesc
= tic6x_read_description (feature
);
395 static struct regsets_info tic6x_regsets_info
=
397 tic6x_regsets
, /* regsets */
399 NULL
, /* disabled_regsets */
402 static struct regs_info myregs_info
=
404 NULL
, /* regset_bitmap */
410 tic6x_target::get_regs_info ()
416 #include "gdbsupport/selftest.h"
418 namespace selftests
{
423 SELF_CHECK (*tdesc_tic6x_c62x_linux
== *tic6x_read_description (C6X_CORE
));
424 SELF_CHECK (*tdesc_tic6x_c64x_linux
== *tic6x_read_description (C6X_GP
));
425 SELF_CHECK (*tdesc_tic6x_c64xp_linux
== *tic6x_read_description (C6X_C6XP
));
431 /* The linux target ops object. */
433 linux_process_target
*the_linux_target
= &the_tic6x_target
;
436 initialize_low_arch (void)
439 /* Initialize the Linux target descriptions. */
440 init_registers_tic6x_c64xp_linux ();
441 init_registers_tic6x_c64x_linux ();
442 init_registers_tic6x_c62x_linux ();
444 selftests::register_test ("tic6x-tdesc", selftests::tdesc::tic6x_tdesc_test
);
447 initialize_regsets_info (&tic6x_regsets_info
);