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 void low_arch_setup () override
;
52 /* The singleton target ops object. */
54 static tic6x_target the_tic6x_target
;
56 /* Defined in auto-generated file tic6x-c64xp-linux.c. */
57 void init_registers_tic6x_c64xp_linux (void);
58 extern const struct target_desc
*tdesc_tic6x_c64xp_linux
;
60 /* Defined in auto-generated file tic6x-c64x-linux.c. */
61 void init_registers_tic6x_c64x_linux (void);
62 extern const struct target_desc
*tdesc_tic6x_c64x_linux
;
64 /* Defined in auto-generated file tic62x-c6xp-linux.c. */
65 void init_registers_tic6x_c62x_linux (void);
66 extern const struct target_desc
*tdesc_tic6x_c62x_linux
;
75 /* Return the ptrace ``address'' of register REGNO. */
77 #if __BYTE_ORDER == __BIG_ENDIAN
78 static int tic6x_regmap_c64xp
[] = {
80 53, 52, 55, 54, 57, 56, 59, 58,
81 61, 60, 63, 62, 65, 64, 67, 66,
83 23, 22, 25, 24, 27, 26, 29, 28,
84 31, 30, 33, 32, 35, 34, 69, 68,
88 37, 36, 39, 38, 41, 40, 43, 42,
89 45, 44, 47, 46, 49, 48, 51, 50,
91 7, 6, 9, 8, 11, 10, 13, 12,
92 15, 14, 17, 16, 19, 18, 21, 20,
97 static int tic6x_regmap_c64x
[] = {
99 51, 50, 53, 52, 55, 54, 57, 56,
100 59, 58, 61, 60, 63, 62, 65, 64,
102 21, 20, 23, 22, 25, 24, 27, 26,
103 29, 28, 31, 30, 33, 32, 67, 66,
107 35, 34, 37, 36, 39, 38, 41, 40,
108 43, 42, 45, 44, 47, 46, 49, 48,
110 5, 4, 7, 6, 9, 8, 11, 10,
111 13, 12, 15, 14, 17, 16, 19, 18,
115 static int tic6x_regmap_c62x
[] = {
117 19, 18, 21, 20, 23, 22, 25, 24,
118 27, 26, 29, 28, 31, 30, 33, 32,
120 5, 4, 7, 6, 9, 8, 11, 10,
121 13, 12, 15, 14, 17, 16, 35, 34,
124 -1, -1, -1, -1, -1, -1, -1, -1,
125 -1, -1, -1, -1, -1, -1, -1, -1,
126 -1, -1, -1, -1, -1, -1, -1, -1,
127 -1, -1, -1, -1, -1, -1, -1, -1,
132 static int tic6x_regmap_c64xp
[] = {
134 52, 53, 54, 55, 56, 57, 58, 59,
135 60, 61, 62, 63, 64, 65, 66, 67,
137 22, 23, 24, 25, 26, 27, 28, 29,
138 30, 31, 32, 33, 34, 35, 68, 69,
142 36, 37, 38, 39, 40, 41, 42, 43,
143 44, 45, 46, 47, 48, 49, 50, 51,
145 6, 7, 8, 9, 10, 11, 12, 13,
146 14, 15, 16, 17, 18, 19, 20, 31,
151 static int tic6x_regmap_c64x
[] = {
153 50, 51, 52, 53, 54, 55, 56, 57,
154 58, 59, 60, 61, 62, 63, 64, 65,
156 20, 21, 22, 23, 24, 25, 26, 27,
157 28, 29, 30, 31, 32, 33, 66, 67,
161 34, 35, 36, 37, 38, 39, 40, 41,
162 42, 43, 44, 45, 46, 47, 48, 49,
164 4, 5, 6, 7, 8, 9, 10, 11,
165 12, 13, 14, 15, 16, 17, 18, 19,
169 static int tic6x_regmap_c62x
[] = {
171 18, 19, 20, 21, 22, 23, 24, 25,
172 26, 27, 28, 29, 30, 31, 32, 33,
174 4, 5, 6, 7, 8, 9, 10, 11,
175 12, 13, 14, 15, 16, 17, 34, 35,
178 -1, -1, -1, -1, -1, -1, -1, -1,
179 -1, -1, -1, -1, -1, -1, -1, -1,
180 -1, -1, -1, -1, -1, -1, -1, -1,
181 -1, -1, -1, -1, -1, -1, -1, -1,
187 extern struct linux_target_ops the_low_target
;
189 static int *tic6x_regmap
;
190 static unsigned int tic6x_breakpoint
;
191 #define tic6x_breakpoint_len 4
193 /* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */
195 static const gdb_byte
*
196 tic6x_sw_breakpoint_from_kind (int kind
, int *size
)
198 *size
= tic6x_breakpoint_len
;
199 return (const gdb_byte
*) &tic6x_breakpoint
;
202 static struct usrregs_info tic6x_usrregs_info
=
205 NULL
, /* Set in tic6x_read_description. */
208 static const struct target_desc
*
209 tic6x_read_description (enum c6x_feature feature
)
211 static target_desc
*tdescs
[C6X_LAST
] = { };
212 struct target_desc
**tdesc
= &tdescs
[feature
];
216 *tdesc
= tic6x_create_target_description (feature
);
217 static const char *expedite_regs
[] = { "A15", "PC", NULL
};
218 init_target_desc (*tdesc
, expedite_regs
);
225 tic6x_cannot_fetch_register (int regno
)
227 return (tic6x_regmap
[regno
] == -1);
231 tic6x_cannot_store_register (int regno
)
233 return (tic6x_regmap
[regno
] == -1);
237 tic6x_get_pc (struct regcache
*regcache
)
239 union tic6x_register pc
;
241 collect_register_by_name (regcache
, "PC", pc
.buf
);
246 tic6x_set_pc (struct regcache
*regcache
, CORE_ADDR pc
)
248 union tic6x_register newpc
;
251 supply_register_by_name (regcache
, "PC", newpc
.buf
);
255 tic6x_breakpoint_at (CORE_ADDR where
)
259 the_target
->read_memory (where
, (unsigned char *) &insn
, 4);
260 if (insn
== tic6x_breakpoint
)
263 /* If necessary, recognize more trap instructions here. GDB only uses the
268 /* Fetch the thread-local storage pointer for libthread_db. */
271 ps_get_thread_area (struct ps_prochandle
*ph
,
272 lwpid_t lwpid
, int idx
, void **base
)
274 if (ptrace (PTRACE_GET_THREAD_AREA
, lwpid
, NULL
, base
) != 0)
277 /* IDX is the bias from the thread pointer to the beginning of the
278 thread descriptor. It has to be subtracted due to implementation
279 quirks in libthread_db. */
280 *base
= (void *) ((char *) *base
- idx
);
286 tic6x_collect_register (struct regcache
*regcache
, int regno
,
287 union tic6x_register
*reg
)
289 union tic6x_register tmp_reg
;
291 collect_register (regcache
, regno
, &tmp_reg
.reg32
);
292 reg
->reg32
= tmp_reg
.reg32
;
296 tic6x_supply_register (struct regcache
*regcache
, int regno
,
297 const union tic6x_register
*reg
)
301 supply_register (regcache
, regno
, reg
->buf
+ offset
);
305 tic6x_fill_gregset (struct regcache
*regcache
, void *buf
)
307 auto regset
= static_cast<union tic6x_register
*> (buf
);
310 for (i
= 0; i
< TIC6X_NUM_REGS
; i
++)
311 if (tic6x_regmap
[i
] != -1)
312 tic6x_collect_register (regcache
, i
, regset
+ tic6x_regmap
[i
]);
316 tic6x_store_gregset (struct regcache
*regcache
, const void *buf
)
318 const auto regset
= static_cast<const union tic6x_register
*> (buf
);
321 for (i
= 0; i
< TIC6X_NUM_REGS
; i
++)
322 if (tic6x_regmap
[i
] != -1)
323 tic6x_supply_register (regcache
, i
, regset
+ tic6x_regmap
[i
]);
326 static struct regset_info tic6x_regsets
[] = {
327 { PTRACE_GETREGS
, PTRACE_SETREGS
, 0, TIC6X_NUM_REGS
* 4, GENERAL_REGS
,
328 tic6x_fill_gregset
, tic6x_store_gregset
},
333 tic6x_target::low_arch_setup ()
335 register unsigned int csr
asm ("B2");
337 enum c6x_feature feature
= C6X_CORE
;
339 /* Determine the CPU we're running on to find the register order. */
340 __asm__ ("MVC .S2 CSR,%0" : "=r" (csr
) :);
344 case 0x00: /* C62x */
345 case 0x02: /* C67x */
346 tic6x_regmap
= tic6x_regmap_c62x
;
347 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
350 case 0x03: /* C67x+ */
351 tic6x_regmap
= tic6x_regmap_c64x
;
352 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
355 case 0x0c: /* C64x */
356 tic6x_regmap
= tic6x_regmap_c64x
;
357 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
360 case 0x10: /* C64x+ */
361 case 0x14: /* C674x */
362 case 0x15: /* C66x */
363 tic6x_regmap
= tic6x_regmap_c64xp
;
364 tic6x_breakpoint
= 0x56454314; /* illegal opcode */
368 error ("Unknown CPU ID 0x%02x", cpuid
);
370 tic6x_usrregs_info
.regmap
= tic6x_regmap
;
372 current_process ()->tdesc
= tic6x_read_description (feature
);
375 /* Support for hardware single step. */
378 tic6x_supports_hardware_single_step (void)
383 static struct regsets_info tic6x_regsets_info
=
385 tic6x_regsets
, /* regsets */
387 NULL
, /* disabled_regsets */
390 static struct regs_info regs_info
=
392 NULL
, /* regset_bitmap */
397 static const struct regs_info
*
398 tic6x_regs_info (void)
403 struct linux_target_ops the_low_target
= {
405 tic6x_cannot_fetch_register
,
406 tic6x_cannot_store_register
,
407 NULL
, /* fetch_register */
410 NULL
, /* breakpoint_kind_from_pc */
411 tic6x_sw_breakpoint_from_kind
,
415 NULL
, /* supports_z_point_type */
416 NULL
, /* insert_point */
417 NULL
, /* remove_point */
418 NULL
, /* stopped_by_watchpoint */
419 NULL
, /* stopped_data_address */
420 NULL
, /* collect_ptrace_register */
421 NULL
, /* supply_ptrace_register */
422 NULL
, /* siginfo_fixup */
423 NULL
, /* new_process */
424 NULL
, /* delete_process */
425 NULL
, /* new_thread */
426 NULL
, /* delete_thread */
428 NULL
, /* prepare_to_resume */
429 NULL
, /* process_qsupported */
430 NULL
, /* supports_tracepoints */
431 NULL
, /* get_thread_area */
432 NULL
, /* install_fast_tracepoint_jump_pad */
434 NULL
, /* get_min_fast_tracepoint_insn_len */
435 NULL
, /* supports_range_stepping */
436 NULL
, /* breakpoint_kind_from_current_state */
437 tic6x_supports_hardware_single_step
,
441 #include "gdbsupport/selftest.h"
443 namespace selftests
{
448 SELF_CHECK (*tdesc_tic6x_c62x_linux
== *tic6x_read_description (C6X_CORE
));
449 SELF_CHECK (*tdesc_tic6x_c64x_linux
== *tic6x_read_description (C6X_GP
));
450 SELF_CHECK (*tdesc_tic6x_c64xp_linux
== *tic6x_read_description (C6X_C6XP
));
456 /* The linux target ops object. */
458 linux_process_target
*the_linux_target
= &the_tic6x_target
;
461 initialize_low_arch (void)
464 /* Initialize the Linux target descriptions. */
465 init_registers_tic6x_c64xp_linux ();
466 init_registers_tic6x_c64x_linux ();
467 init_registers_tic6x_c62x_linux ();
469 selftests::register_test ("tic6x-tdesc", selftests::tdesc::tic6x_tdesc_test
);
472 initialize_regsets_info (&tic6x_regsets_info
);