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/>. */
22 #include "linux-low.h"
23 #include "arch/tic6x.h"
26 #include "nat/gdb_ptrace.h"
29 #include "gdb_proc_service.h"
31 #ifndef PTRACE_GET_THREAD_AREA
32 #define PTRACE_GET_THREAD_AREA 25
35 /* There are at most 69 registers accessible in ptrace. */
36 #define TIC6X_NUM_REGS 69
38 #include <asm/ptrace.h>
40 /* Linux target op definitions for the TI C6x architecture. */
42 class tic6x_target
: public linux_process_target
46 const regs_info
*get_regs_info () override
;
48 const gdb_byte
*sw_breakpoint_from_kind (int kind
, int *size
) override
;
52 void low_arch_setup () override
;
54 bool low_cannot_fetch_register (int regno
) override
;
56 bool low_cannot_store_register (int regno
) override
;
58 bool low_supports_breakpoints () override
;
60 CORE_ADDR
low_get_pc (regcache
*regcache
) override
;
62 void low_set_pc (regcache
*regcache
, CORE_ADDR newpc
) override
;
64 bool low_breakpoint_at (CORE_ADDR pc
) override
;
67 /* The singleton target ops object. */
69 static tic6x_target the_tic6x_target
;
71 /* Defined in auto-generated file tic6x-c64xp-linux.c. */
72 void init_registers_tic6x_c64xp_linux (void);
73 extern const struct target_desc
*tdesc_tic6x_c64xp_linux
;
75 /* Defined in auto-generated file tic6x-c64x-linux.c. */
76 void init_registers_tic6x_c64x_linux (void);
77 extern const struct target_desc
*tdesc_tic6x_c64x_linux
;
79 /* Defined in auto-generated file tic62x-c6xp-linux.c. */
80 void init_registers_tic6x_c62x_linux (void);
81 extern const struct target_desc
*tdesc_tic6x_c62x_linux
;
90 /* Return the ptrace ``address'' of register REGNO. */
92 #if __BYTE_ORDER == __BIG_ENDIAN
93 static int tic6x_regmap_c64xp
[] = {
95 53, 52, 55, 54, 57, 56, 59, 58,
96 61, 60, 63, 62, 65, 64, 67, 66,
98 23, 22, 25, 24, 27, 26, 29, 28,
99 31, 30, 33, 32, 35, 34, 69, 68,
103 37, 36, 39, 38, 41, 40, 43, 42,
104 45, 44, 47, 46, 49, 48, 51, 50,
106 7, 6, 9, 8, 11, 10, 13, 12,
107 15, 14, 17, 16, 19, 18, 21, 20,
112 static int tic6x_regmap_c64x
[] = {
114 51, 50, 53, 52, 55, 54, 57, 56,
115 59, 58, 61, 60, 63, 62, 65, 64,
117 21, 20, 23, 22, 25, 24, 27, 26,
118 29, 28, 31, 30, 33, 32, 67, 66,
122 35, 34, 37, 36, 39, 38, 41, 40,
123 43, 42, 45, 44, 47, 46, 49, 48,
125 5, 4, 7, 6, 9, 8, 11, 10,
126 13, 12, 15, 14, 17, 16, 19, 18,
130 static int tic6x_regmap_c62x
[] = {
132 19, 18, 21, 20, 23, 22, 25, 24,
133 27, 26, 29, 28, 31, 30, 33, 32,
135 5, 4, 7, 6, 9, 8, 11, 10,
136 13, 12, 15, 14, 17, 16, 35, 34,
139 -1, -1, -1, -1, -1, -1, -1, -1,
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,
147 static int tic6x_regmap_c64xp
[] = {
149 52, 53, 54, 55, 56, 57, 58, 59,
150 60, 61, 62, 63, 64, 65, 66, 67,
152 22, 23, 24, 25, 26, 27, 28, 29,
153 30, 31, 32, 33, 34, 35, 68, 69,
157 36, 37, 38, 39, 40, 41, 42, 43,
158 44, 45, 46, 47, 48, 49, 50, 51,
160 6, 7, 8, 9, 10, 11, 12, 13,
161 14, 15, 16, 17, 18, 19, 20, 31,
166 static int tic6x_regmap_c64x
[] = {
168 50, 51, 52, 53, 54, 55, 56, 57,
169 58, 59, 60, 61, 62, 63, 64, 65,
171 20, 21, 22, 23, 24, 25, 26, 27,
172 28, 29, 30, 31, 32, 33, 66, 67,
176 34, 35, 36, 37, 38, 39, 40, 41,
177 42, 43, 44, 45, 46, 47, 48, 49,
179 4, 5, 6, 7, 8, 9, 10, 11,
180 12, 13, 14, 15, 16, 17, 18, 19,
184 static int tic6x_regmap_c62x
[] = {
186 18, 19, 20, 21, 22, 23, 24, 25,
187 26, 27, 28, 29, 30, 31, 32, 33,
189 4, 5, 6, 7, 8, 9, 10, 11,
190 12, 13, 14, 15, 16, 17, 34, 35,
193 -1, -1, -1, -1, -1, -1, -1, -1,
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,
202 static int *tic6x_regmap
;
203 static unsigned int tic6x_breakpoint
;
204 #define tic6x_breakpoint_len 4
206 /* Implementation of target ops method "sw_breakpoint_from_kind". */
209 tic6x_target::sw_breakpoint_from_kind (int kind
, int *size
)
211 *size
= tic6x_breakpoint_len
;
212 return (const gdb_byte
*) &tic6x_breakpoint
;
215 static struct usrregs_info tic6x_usrregs_info
=
218 NULL
, /* Set in tic6x_read_description. */
221 static const struct target_desc
*
222 tic6x_read_description (enum c6x_feature feature
)
224 static target_desc
*tdescs
[C6X_LAST
] = { };
225 struct target_desc
**tdesc
= &tdescs
[feature
];
229 *tdesc
= tic6x_create_target_description (feature
);
230 static const char *expedite_regs
[] = { "A15", "PC", NULL
};
231 init_target_desc (*tdesc
, expedite_regs
);
238 tic6x_target::low_cannot_fetch_register (int regno
)
240 return (tic6x_regmap
[regno
] == -1);
244 tic6x_target::low_cannot_store_register (int regno
)
246 return (tic6x_regmap
[regno
] == -1);
250 tic6x_target::low_supports_breakpoints ()
256 tic6x_target::low_get_pc (regcache
*regcache
)
258 union tic6x_register pc
;
260 collect_register_by_name (regcache
, "PC", pc
.buf
);
265 tic6x_target::low_set_pc (regcache
*regcache
, CORE_ADDR pc
)
267 union tic6x_register newpc
;
270 supply_register_by_name (regcache
, "PC", newpc
.buf
);
274 tic6x_target::low_breakpoint_at (CORE_ADDR where
)
278 read_memory (where
, (unsigned char *) &insn
, 4);
279 if (insn
== tic6x_breakpoint
)
282 /* If necessary, recognize more trap instructions here. GDB only uses the
287 /* Fetch the thread-local storage pointer for libthread_db. */
290 ps_get_thread_area (struct ps_prochandle
*ph
,
291 lwpid_t lwpid
, int idx
, void **base
)
293 if (ptrace (PTRACE_GET_THREAD_AREA
, lwpid
, NULL
, base
) != 0)
296 /* IDX is the bias from the thread pointer to the beginning of the
297 thread descriptor. It has to be subtracted due to implementation
298 quirks in libthread_db. */
299 *base
= (void *) ((char *) *base
- idx
);
305 tic6x_collect_register (struct regcache
*regcache
, int regno
,
306 union tic6x_register
*reg
)
308 union tic6x_register tmp_reg
;
310 collect_register (regcache
, regno
, &tmp_reg
.reg32
);
311 reg
->reg32
= tmp_reg
.reg32
;
315 tic6x_supply_register (struct regcache
*regcache
, int regno
,
316 const union tic6x_register
*reg
)
320 supply_register (regcache
, regno
, reg
->buf
+ offset
);
324 tic6x_fill_gregset (struct regcache
*regcache
, void *buf
)
326 auto regset
= static_cast<union tic6x_register
*> (buf
);
329 for (i
= 0; i
< TIC6X_NUM_REGS
; i
++)
330 if (tic6x_regmap
[i
] != -1)
331 tic6x_collect_register (regcache
, i
, regset
+ tic6x_regmap
[i
]);
335 tic6x_store_gregset (struct regcache
*regcache
, const void *buf
)
337 const auto regset
= static_cast<const union tic6x_register
*> (buf
);
340 for (i
= 0; i
< TIC6X_NUM_REGS
; i
++)
341 if (tic6x_regmap
[i
] != -1)
342 tic6x_supply_register (regcache
, i
, regset
+ tic6x_regmap
[i
]);
345 static struct regset_info tic6x_regsets
[] = {
346 { PTRACE_GETREGS
, PTRACE_SETREGS
, 0, TIC6X_NUM_REGS
* 4, GENERAL_REGS
,
347 tic6x_fill_gregset
, tic6x_store_gregset
},
352 tic6x_target::low_arch_setup ()
354 register unsigned int csr
asm ("B2");
356 enum c6x_feature feature
= C6X_CORE
;
358 /* Determine the CPU we're running on to find the register order. */
359 __asm__ ("MVC .S2 CSR,%0" : "=r" (csr
) :);
363 case 0x00: /* C62x */
364 case 0x02: /* C67x */
365 tic6x_regmap
= tic6x_regmap_c62x
;
366 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
369 case 0x03: /* C67x+ */
370 tic6x_regmap
= tic6x_regmap_c64x
;
371 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
374 case 0x0c: /* C64x */
375 tic6x_regmap
= tic6x_regmap_c64x
;
376 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
379 case 0x10: /* C64x+ */
380 case 0x14: /* C674x */
381 case 0x15: /* C66x */
382 tic6x_regmap
= tic6x_regmap_c64xp
;
383 tic6x_breakpoint
= 0x56454314; /* illegal opcode */
387 error ("Unknown CPU ID 0x%02x", cpuid
);
389 tic6x_usrregs_info
.regmap
= tic6x_regmap
;
391 current_process ()->tdesc
= tic6x_read_description (feature
);
394 static struct regsets_info tic6x_regsets_info
=
396 tic6x_regsets
, /* regsets */
398 NULL
, /* disabled_regsets */
401 static struct regs_info myregs_info
=
403 NULL
, /* regset_bitmap */
409 tic6x_target::get_regs_info ()
415 #include "gdbsupport/selftest.h"
417 namespace selftests
{
422 SELF_CHECK (*tdesc_tic6x_c62x_linux
== *tic6x_read_description (C6X_CORE
));
423 SELF_CHECK (*tdesc_tic6x_c64x_linux
== *tic6x_read_description (C6X_GP
));
424 SELF_CHECK (*tdesc_tic6x_c64xp_linux
== *tic6x_read_description (C6X_C6XP
));
430 /* The linux target ops object. */
432 linux_process_target
*the_linux_target
= &the_tic6x_target
;
435 initialize_low_arch (void)
438 /* Initialize the Linux target descriptions. */
439 init_registers_tic6x_c64xp_linux ();
440 init_registers_tic6x_c64x_linux ();
441 init_registers_tic6x_c62x_linux ();
443 selftests::register_test ("tic6x-tdesc", selftests::tdesc::tic6x_tdesc_test
);
446 initialize_regsets_info (&tic6x_regsets_info
);