1 /* Target dependent code for GDB on TI C6x systems.
3 Copyright (C) 2010-2020 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
49 /* The singleton target ops object. */
51 static tic6x_target the_tic6x_target
;
53 /* Defined in auto-generated file tic6x-c64xp-linux.c. */
54 void init_registers_tic6x_c64xp_linux (void);
55 extern const struct target_desc
*tdesc_tic6x_c64xp_linux
;
57 /* Defined in auto-generated file tic6x-c64x-linux.c. */
58 void init_registers_tic6x_c64x_linux (void);
59 extern const struct target_desc
*tdesc_tic6x_c64x_linux
;
61 /* Defined in auto-generated file tic62x-c6xp-linux.c. */
62 void init_registers_tic6x_c62x_linux (void);
63 extern const struct target_desc
*tdesc_tic6x_c62x_linux
;
72 /* Return the ptrace ``address'' of register REGNO. */
74 #if __BYTE_ORDER == __BIG_ENDIAN
75 static int tic6x_regmap_c64xp
[] = {
77 53, 52, 55, 54, 57, 56, 59, 58,
78 61, 60, 63, 62, 65, 64, 67, 66,
80 23, 22, 25, 24, 27, 26, 29, 28,
81 31, 30, 33, 32, 35, 34, 69, 68,
85 37, 36, 39, 38, 41, 40, 43, 42,
86 45, 44, 47, 46, 49, 48, 51, 50,
88 7, 6, 9, 8, 11, 10, 13, 12,
89 15, 14, 17, 16, 19, 18, 21, 20,
94 static int tic6x_regmap_c64x
[] = {
96 51, 50, 53, 52, 55, 54, 57, 56,
97 59, 58, 61, 60, 63, 62, 65, 64,
99 21, 20, 23, 22, 25, 24, 27, 26,
100 29, 28, 31, 30, 33, 32, 67, 66,
104 35, 34, 37, 36, 39, 38, 41, 40,
105 43, 42, 45, 44, 47, 46, 49, 48,
107 5, 4, 7, 6, 9, 8, 11, 10,
108 13, 12, 15, 14, 17, 16, 19, 18,
112 static int tic6x_regmap_c62x
[] = {
114 19, 18, 21, 20, 23, 22, 25, 24,
115 27, 26, 29, 28, 31, 30, 33, 32,
117 5, 4, 7, 6, 9, 8, 11, 10,
118 13, 12, 15, 14, 17, 16, 35, 34,
121 -1, -1, -1, -1, -1, -1, -1, -1,
122 -1, -1, -1, -1, -1, -1, -1, -1,
123 -1, -1, -1, -1, -1, -1, -1, -1,
124 -1, -1, -1, -1, -1, -1, -1, -1,
129 static int tic6x_regmap_c64xp
[] = {
131 52, 53, 54, 55, 56, 57, 58, 59,
132 60, 61, 62, 63, 64, 65, 66, 67,
134 22, 23, 24, 25, 26, 27, 28, 29,
135 30, 31, 32, 33, 34, 35, 68, 69,
139 36, 37, 38, 39, 40, 41, 42, 43,
140 44, 45, 46, 47, 48, 49, 50, 51,
142 6, 7, 8, 9, 10, 11, 12, 13,
143 14, 15, 16, 17, 18, 19, 20, 31,
148 static int tic6x_regmap_c64x
[] = {
150 50, 51, 52, 53, 54, 55, 56, 57,
151 58, 59, 60, 61, 62, 63, 64, 65,
153 20, 21, 22, 23, 24, 25, 26, 27,
154 28, 29, 30, 31, 32, 33, 66, 67,
158 34, 35, 36, 37, 38, 39, 40, 41,
159 42, 43, 44, 45, 46, 47, 48, 49,
161 4, 5, 6, 7, 8, 9, 10, 11,
162 12, 13, 14, 15, 16, 17, 18, 19,
166 static int tic6x_regmap_c62x
[] = {
168 18, 19, 20, 21, 22, 23, 24, 25,
169 26, 27, 28, 29, 30, 31, 32, 33,
171 4, 5, 6, 7, 8, 9, 10, 11,
172 12, 13, 14, 15, 16, 17, 34, 35,
175 -1, -1, -1, -1, -1, -1, -1, -1,
176 -1, -1, -1, -1, -1, -1, -1, -1,
177 -1, -1, -1, -1, -1, -1, -1, -1,
178 -1, -1, -1, -1, -1, -1, -1, -1,
184 extern struct linux_target_ops the_low_target
;
186 static int *tic6x_regmap
;
187 static unsigned int tic6x_breakpoint
;
188 #define tic6x_breakpoint_len 4
190 /* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */
192 static const gdb_byte
*
193 tic6x_sw_breakpoint_from_kind (int kind
, int *size
)
195 *size
= tic6x_breakpoint_len
;
196 return (const gdb_byte
*) &tic6x_breakpoint
;
199 static struct usrregs_info tic6x_usrregs_info
=
202 NULL
, /* Set in tic6x_read_description. */
205 static const struct target_desc
*
206 tic6x_read_description (enum c6x_feature feature
)
208 static target_desc
*tdescs
[C6X_LAST
] = { };
209 struct target_desc
**tdesc
= &tdescs
[feature
];
213 *tdesc
= tic6x_create_target_description (feature
);
214 static const char *expedite_regs
[] = { "A15", "PC", NULL
};
215 init_target_desc (*tdesc
, expedite_regs
);
222 tic6x_cannot_fetch_register (int regno
)
224 return (tic6x_regmap
[regno
] == -1);
228 tic6x_cannot_store_register (int regno
)
230 return (tic6x_regmap
[regno
] == -1);
234 tic6x_get_pc (struct regcache
*regcache
)
236 union tic6x_register pc
;
238 collect_register_by_name (regcache
, "PC", pc
.buf
);
243 tic6x_set_pc (struct regcache
*regcache
, CORE_ADDR pc
)
245 union tic6x_register newpc
;
248 supply_register_by_name (regcache
, "PC", newpc
.buf
);
252 tic6x_breakpoint_at (CORE_ADDR where
)
256 the_target
->read_memory (where
, (unsigned char *) &insn
, 4);
257 if (insn
== tic6x_breakpoint
)
260 /* If necessary, recognize more trap instructions here. GDB only uses the
265 /* Fetch the thread-local storage pointer for libthread_db. */
268 ps_get_thread_area (struct ps_prochandle
*ph
,
269 lwpid_t lwpid
, int idx
, void **base
)
271 if (ptrace (PTRACE_GET_THREAD_AREA
, lwpid
, NULL
, base
) != 0)
274 /* IDX is the bias from the thread pointer to the beginning of the
275 thread descriptor. It has to be subtracted due to implementation
276 quirks in libthread_db. */
277 *base
= (void *) ((char *) *base
- idx
);
283 tic6x_collect_register (struct regcache
*regcache
, int regno
,
284 union tic6x_register
*reg
)
286 union tic6x_register tmp_reg
;
288 collect_register (regcache
, regno
, &tmp_reg
.reg32
);
289 reg
->reg32
= tmp_reg
.reg32
;
293 tic6x_supply_register (struct regcache
*regcache
, int regno
,
294 const union tic6x_register
*reg
)
298 supply_register (regcache
, regno
, reg
->buf
+ offset
);
302 tic6x_fill_gregset (struct regcache
*regcache
, void *buf
)
304 auto regset
= static_cast<union tic6x_register
*> (buf
);
307 for (i
= 0; i
< TIC6X_NUM_REGS
; i
++)
308 if (tic6x_regmap
[i
] != -1)
309 tic6x_collect_register (regcache
, i
, regset
+ tic6x_regmap
[i
]);
313 tic6x_store_gregset (struct regcache
*regcache
, const void *buf
)
315 const auto regset
= static_cast<const union tic6x_register
*> (buf
);
318 for (i
= 0; i
< TIC6X_NUM_REGS
; i
++)
319 if (tic6x_regmap
[i
] != -1)
320 tic6x_supply_register (regcache
, i
, regset
+ tic6x_regmap
[i
]);
323 static struct regset_info tic6x_regsets
[] = {
324 { PTRACE_GETREGS
, PTRACE_SETREGS
, 0, TIC6X_NUM_REGS
* 4, GENERAL_REGS
,
325 tic6x_fill_gregset
, tic6x_store_gregset
},
330 tic6x_arch_setup (void)
332 register unsigned int csr
asm ("B2");
334 enum c6x_feature feature
= C6X_CORE
;
336 /* Determine the CPU we're running on to find the register order. */
337 __asm__ ("MVC .S2 CSR,%0" : "=r" (csr
) :);
341 case 0x00: /* C62x */
342 case 0x02: /* C67x */
343 tic6x_regmap
= tic6x_regmap_c62x
;
344 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
347 case 0x03: /* C67x+ */
348 tic6x_regmap
= tic6x_regmap_c64x
;
349 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
352 case 0x0c: /* C64x */
353 tic6x_regmap
= tic6x_regmap_c64x
;
354 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
357 case 0x10: /* C64x+ */
358 case 0x14: /* C674x */
359 case 0x15: /* C66x */
360 tic6x_regmap
= tic6x_regmap_c64xp
;
361 tic6x_breakpoint
= 0x56454314; /* illegal opcode */
365 error ("Unknown CPU ID 0x%02x", cpuid
);
367 tic6x_usrregs_info
.regmap
= tic6x_regmap
;
369 current_process ()->tdesc
= tic6x_read_description (feature
);
372 /* Support for hardware single step. */
375 tic6x_supports_hardware_single_step (void)
380 static struct regsets_info tic6x_regsets_info
=
382 tic6x_regsets
, /* regsets */
384 NULL
, /* disabled_regsets */
387 static struct regs_info regs_info
=
389 NULL
, /* regset_bitmap */
394 static const struct regs_info
*
395 tic6x_regs_info (void)
400 struct linux_target_ops the_low_target
= {
403 tic6x_cannot_fetch_register
,
404 tic6x_cannot_store_register
,
405 NULL
, /* fetch_register */
408 NULL
, /* breakpoint_kind_from_pc */
409 tic6x_sw_breakpoint_from_kind
,
413 NULL
, /* supports_z_point_type */
414 NULL
, /* insert_point */
415 NULL
, /* remove_point */
416 NULL
, /* stopped_by_watchpoint */
417 NULL
, /* stopped_data_address */
418 NULL
, /* collect_ptrace_register */
419 NULL
, /* supply_ptrace_register */
420 NULL
, /* siginfo_fixup */
421 NULL
, /* new_process */
422 NULL
, /* delete_process */
423 NULL
, /* new_thread */
424 NULL
, /* delete_thread */
426 NULL
, /* prepare_to_resume */
427 NULL
, /* process_qsupported */
428 NULL
, /* supports_tracepoints */
429 NULL
, /* get_thread_area */
430 NULL
, /* install_fast_tracepoint_jump_pad */
432 NULL
, /* get_min_fast_tracepoint_insn_len */
433 NULL
, /* supports_range_stepping */
434 NULL
, /* breakpoint_kind_from_current_state */
435 tic6x_supports_hardware_single_step
,
439 #include "gdbsupport/selftest.h"
441 namespace selftests
{
446 SELF_CHECK (*tdesc_tic6x_c62x_linux
== *tic6x_read_description (C6X_CORE
));
447 SELF_CHECK (*tdesc_tic6x_c64x_linux
== *tic6x_read_description (C6X_GP
));
448 SELF_CHECK (*tdesc_tic6x_c64xp_linux
== *tic6x_read_description (C6X_C6XP
));
454 /* The linux target ops object. */
456 linux_process_target
*the_linux_target
= &the_tic6x_target
;
459 initialize_low_arch (void)
462 /* Initialize the Linux target descriptions. */
463 init_registers_tic6x_c64xp_linux ();
464 init_registers_tic6x_c64x_linux ();
465 init_registers_tic6x_c62x_linux ();
467 selftests::register_test ("tic6x-tdesc", selftests::tdesc::tic6x_tdesc_test
);
470 initialize_regsets_info (&tic6x_regsets_info
);