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
47 const regs_info
*get_regs_info () override
;
51 void low_arch_setup () override
;
53 bool low_cannot_fetch_register (int regno
) override
;
55 bool low_cannot_store_register (int regno
) override
;
58 /* The singleton target ops object. */
60 static tic6x_target the_tic6x_target
;
62 /* Defined in auto-generated file tic6x-c64xp-linux.c. */
63 void init_registers_tic6x_c64xp_linux (void);
64 extern const struct target_desc
*tdesc_tic6x_c64xp_linux
;
66 /* Defined in auto-generated file tic6x-c64x-linux.c. */
67 void init_registers_tic6x_c64x_linux (void);
68 extern const struct target_desc
*tdesc_tic6x_c64x_linux
;
70 /* Defined in auto-generated file tic62x-c6xp-linux.c. */
71 void init_registers_tic6x_c62x_linux (void);
72 extern const struct target_desc
*tdesc_tic6x_c62x_linux
;
81 /* Return the ptrace ``address'' of register REGNO. */
83 #if __BYTE_ORDER == __BIG_ENDIAN
84 static int tic6x_regmap_c64xp
[] = {
86 53, 52, 55, 54, 57, 56, 59, 58,
87 61, 60, 63, 62, 65, 64, 67, 66,
89 23, 22, 25, 24, 27, 26, 29, 28,
90 31, 30, 33, 32, 35, 34, 69, 68,
94 37, 36, 39, 38, 41, 40, 43, 42,
95 45, 44, 47, 46, 49, 48, 51, 50,
97 7, 6, 9, 8, 11, 10, 13, 12,
98 15, 14, 17, 16, 19, 18, 21, 20,
103 static int tic6x_regmap_c64x
[] = {
105 51, 50, 53, 52, 55, 54, 57, 56,
106 59, 58, 61, 60, 63, 62, 65, 64,
108 21, 20, 23, 22, 25, 24, 27, 26,
109 29, 28, 31, 30, 33, 32, 67, 66,
113 35, 34, 37, 36, 39, 38, 41, 40,
114 43, 42, 45, 44, 47, 46, 49, 48,
116 5, 4, 7, 6, 9, 8, 11, 10,
117 13, 12, 15, 14, 17, 16, 19, 18,
121 static int tic6x_regmap_c62x
[] = {
123 19, 18, 21, 20, 23, 22, 25, 24,
124 27, 26, 29, 28, 31, 30, 33, 32,
126 5, 4, 7, 6, 9, 8, 11, 10,
127 13, 12, 15, 14, 17, 16, 35, 34,
130 -1, -1, -1, -1, -1, -1, -1, -1,
131 -1, -1, -1, -1, -1, -1, -1, -1,
132 -1, -1, -1, -1, -1, -1, -1, -1,
133 -1, -1, -1, -1, -1, -1, -1, -1,
138 static int tic6x_regmap_c64xp
[] = {
140 52, 53, 54, 55, 56, 57, 58, 59,
141 60, 61, 62, 63, 64, 65, 66, 67,
143 22, 23, 24, 25, 26, 27, 28, 29,
144 30, 31, 32, 33, 34, 35, 68, 69,
148 36, 37, 38, 39, 40, 41, 42, 43,
149 44, 45, 46, 47, 48, 49, 50, 51,
151 6, 7, 8, 9, 10, 11, 12, 13,
152 14, 15, 16, 17, 18, 19, 20, 31,
157 static int tic6x_regmap_c64x
[] = {
159 50, 51, 52, 53, 54, 55, 56, 57,
160 58, 59, 60, 61, 62, 63, 64, 65,
162 20, 21, 22, 23, 24, 25, 26, 27,
163 28, 29, 30, 31, 32, 33, 66, 67,
167 34, 35, 36, 37, 38, 39, 40, 41,
168 42, 43, 44, 45, 46, 47, 48, 49,
170 4, 5, 6, 7, 8, 9, 10, 11,
171 12, 13, 14, 15, 16, 17, 18, 19,
175 static int tic6x_regmap_c62x
[] = {
177 18, 19, 20, 21, 22, 23, 24, 25,
178 26, 27, 28, 29, 30, 31, 32, 33,
180 4, 5, 6, 7, 8, 9, 10, 11,
181 12, 13, 14, 15, 16, 17, 34, 35,
184 -1, -1, -1, -1, -1, -1, -1, -1,
185 -1, -1, -1, -1, -1, -1, -1, -1,
186 -1, -1, -1, -1, -1, -1, -1, -1,
187 -1, -1, -1, -1, -1, -1, -1, -1,
193 extern struct linux_target_ops the_low_target
;
195 static int *tic6x_regmap
;
196 static unsigned int tic6x_breakpoint
;
197 #define tic6x_breakpoint_len 4
199 /* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */
201 static const gdb_byte
*
202 tic6x_sw_breakpoint_from_kind (int kind
, int *size
)
204 *size
= tic6x_breakpoint_len
;
205 return (const gdb_byte
*) &tic6x_breakpoint
;
208 static struct usrregs_info tic6x_usrregs_info
=
211 NULL
, /* Set in tic6x_read_description. */
214 static const struct target_desc
*
215 tic6x_read_description (enum c6x_feature feature
)
217 static target_desc
*tdescs
[C6X_LAST
] = { };
218 struct target_desc
**tdesc
= &tdescs
[feature
];
222 *tdesc
= tic6x_create_target_description (feature
);
223 static const char *expedite_regs
[] = { "A15", "PC", NULL
};
224 init_target_desc (*tdesc
, expedite_regs
);
231 tic6x_target::low_cannot_fetch_register (int regno
)
233 return (tic6x_regmap
[regno
] == -1);
237 tic6x_target::low_cannot_store_register (int regno
)
239 return (tic6x_regmap
[regno
] == -1);
243 tic6x_get_pc (struct regcache
*regcache
)
245 union tic6x_register pc
;
247 collect_register_by_name (regcache
, "PC", pc
.buf
);
252 tic6x_set_pc (struct regcache
*regcache
, CORE_ADDR pc
)
254 union tic6x_register newpc
;
257 supply_register_by_name (regcache
, "PC", newpc
.buf
);
261 tic6x_breakpoint_at (CORE_ADDR where
)
265 the_target
->read_memory (where
, (unsigned char *) &insn
, 4);
266 if (insn
== tic6x_breakpoint
)
269 /* If necessary, recognize more trap instructions here. GDB only uses the
274 /* Fetch the thread-local storage pointer for libthread_db. */
277 ps_get_thread_area (struct ps_prochandle
*ph
,
278 lwpid_t lwpid
, int idx
, void **base
)
280 if (ptrace (PTRACE_GET_THREAD_AREA
, lwpid
, NULL
, base
) != 0)
283 /* IDX is the bias from the thread pointer to the beginning of the
284 thread descriptor. It has to be subtracted due to implementation
285 quirks in libthread_db. */
286 *base
= (void *) ((char *) *base
- idx
);
292 tic6x_collect_register (struct regcache
*regcache
, int regno
,
293 union tic6x_register
*reg
)
295 union tic6x_register tmp_reg
;
297 collect_register (regcache
, regno
, &tmp_reg
.reg32
);
298 reg
->reg32
= tmp_reg
.reg32
;
302 tic6x_supply_register (struct regcache
*regcache
, int regno
,
303 const union tic6x_register
*reg
)
307 supply_register (regcache
, regno
, reg
->buf
+ offset
);
311 tic6x_fill_gregset (struct regcache
*regcache
, void *buf
)
313 auto regset
= static_cast<union tic6x_register
*> (buf
);
316 for (i
= 0; i
< TIC6X_NUM_REGS
; i
++)
317 if (tic6x_regmap
[i
] != -1)
318 tic6x_collect_register (regcache
, i
, regset
+ tic6x_regmap
[i
]);
322 tic6x_store_gregset (struct regcache
*regcache
, const void *buf
)
324 const auto regset
= static_cast<const union tic6x_register
*> (buf
);
327 for (i
= 0; i
< TIC6X_NUM_REGS
; i
++)
328 if (tic6x_regmap
[i
] != -1)
329 tic6x_supply_register (regcache
, i
, regset
+ tic6x_regmap
[i
]);
332 static struct regset_info tic6x_regsets
[] = {
333 { PTRACE_GETREGS
, PTRACE_SETREGS
, 0, TIC6X_NUM_REGS
* 4, GENERAL_REGS
,
334 tic6x_fill_gregset
, tic6x_store_gregset
},
339 tic6x_target::low_arch_setup ()
341 register unsigned int csr
asm ("B2");
343 enum c6x_feature feature
= C6X_CORE
;
345 /* Determine the CPU we're running on to find the register order. */
346 __asm__ ("MVC .S2 CSR,%0" : "=r" (csr
) :);
350 case 0x00: /* C62x */
351 case 0x02: /* C67x */
352 tic6x_regmap
= tic6x_regmap_c62x
;
353 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
356 case 0x03: /* C67x+ */
357 tic6x_regmap
= tic6x_regmap_c64x
;
358 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
361 case 0x0c: /* C64x */
362 tic6x_regmap
= tic6x_regmap_c64x
;
363 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
366 case 0x10: /* C64x+ */
367 case 0x14: /* C674x */
368 case 0x15: /* C66x */
369 tic6x_regmap
= tic6x_regmap_c64xp
;
370 tic6x_breakpoint
= 0x56454314; /* illegal opcode */
374 error ("Unknown CPU ID 0x%02x", cpuid
);
376 tic6x_usrregs_info
.regmap
= tic6x_regmap
;
378 current_process ()->tdesc
= tic6x_read_description (feature
);
381 /* Support for hardware single step. */
384 tic6x_supports_hardware_single_step (void)
389 static struct regsets_info tic6x_regsets_info
=
391 tic6x_regsets
, /* regsets */
393 NULL
, /* disabled_regsets */
396 static struct regs_info myregs_info
=
398 NULL
, /* regset_bitmap */
404 tic6x_target::get_regs_info ()
409 struct linux_target_ops the_low_target
= {
410 NULL
, /* fetch_register */
413 NULL
, /* breakpoint_kind_from_pc */
414 tic6x_sw_breakpoint_from_kind
,
418 NULL
, /* supports_z_point_type */
419 NULL
, /* insert_point */
420 NULL
, /* remove_point */
421 NULL
, /* stopped_by_watchpoint */
422 NULL
, /* stopped_data_address */
423 NULL
, /* collect_ptrace_register */
424 NULL
, /* supply_ptrace_register */
425 NULL
, /* siginfo_fixup */
426 NULL
, /* new_process */
427 NULL
, /* delete_process */
428 NULL
, /* new_thread */
429 NULL
, /* delete_thread */
431 NULL
, /* prepare_to_resume */
432 NULL
, /* process_qsupported */
433 NULL
, /* supports_tracepoints */
434 NULL
, /* get_thread_area */
435 NULL
, /* install_fast_tracepoint_jump_pad */
437 NULL
, /* get_min_fast_tracepoint_insn_len */
438 NULL
, /* supports_range_stepping */
439 NULL
, /* breakpoint_kind_from_current_state */
440 tic6x_supports_hardware_single_step
,
444 #include "gdbsupport/selftest.h"
446 namespace selftests
{
451 SELF_CHECK (*tdesc_tic6x_c62x_linux
== *tic6x_read_description (C6X_CORE
));
452 SELF_CHECK (*tdesc_tic6x_c64x_linux
== *tic6x_read_description (C6X_GP
));
453 SELF_CHECK (*tdesc_tic6x_c64xp_linux
== *tic6x_read_description (C6X_C6XP
));
459 /* The linux target ops object. */
461 linux_process_target
*the_linux_target
= &the_tic6x_target
;
464 initialize_low_arch (void)
467 /* Initialize the Linux target descriptions. */
468 init_registers_tic6x_c64xp_linux ();
469 init_registers_tic6x_c64x_linux ();
470 init_registers_tic6x_c62x_linux ();
472 selftests::register_test ("tic6x-tdesc", selftests::tdesc::tic6x_tdesc_test
);
475 initialize_regsets_info (&tic6x_regsets_info
);