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
;
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 extern struct linux_target_ops the_low_target
;
205 static int *tic6x_regmap
;
206 static unsigned int tic6x_breakpoint
;
207 #define tic6x_breakpoint_len 4
209 /* Implementation of target ops method "sw_breakpoint_from_kind". */
212 tic6x_target::sw_breakpoint_from_kind (int kind
, int *size
)
214 *size
= tic6x_breakpoint_len
;
215 return (const gdb_byte
*) &tic6x_breakpoint
;
218 static struct usrregs_info tic6x_usrregs_info
=
221 NULL
, /* Set in tic6x_read_description. */
224 static const struct target_desc
*
225 tic6x_read_description (enum c6x_feature feature
)
227 static target_desc
*tdescs
[C6X_LAST
] = { };
228 struct target_desc
**tdesc
= &tdescs
[feature
];
232 *tdesc
= tic6x_create_target_description (feature
);
233 static const char *expedite_regs
[] = { "A15", "PC", NULL
};
234 init_target_desc (*tdesc
, expedite_regs
);
241 tic6x_target::low_cannot_fetch_register (int regno
)
243 return (tic6x_regmap
[regno
] == -1);
247 tic6x_target::low_cannot_store_register (int regno
)
249 return (tic6x_regmap
[regno
] == -1);
253 tic6x_target::low_supports_breakpoints ()
259 tic6x_target::low_get_pc (regcache
*regcache
)
261 union tic6x_register pc
;
263 collect_register_by_name (regcache
, "PC", pc
.buf
);
268 tic6x_target::low_set_pc (regcache
*regcache
, CORE_ADDR pc
)
270 union tic6x_register newpc
;
273 supply_register_by_name (regcache
, "PC", newpc
.buf
);
277 tic6x_target::low_breakpoint_at (CORE_ADDR where
)
281 read_memory (where
, (unsigned char *) &insn
, 4);
282 if (insn
== tic6x_breakpoint
)
285 /* If necessary, recognize more trap instructions here. GDB only uses the
290 /* Fetch the thread-local storage pointer for libthread_db. */
293 ps_get_thread_area (struct ps_prochandle
*ph
,
294 lwpid_t lwpid
, int idx
, void **base
)
296 if (ptrace (PTRACE_GET_THREAD_AREA
, lwpid
, NULL
, base
) != 0)
299 /* IDX is the bias from the thread pointer to the beginning of the
300 thread descriptor. It has to be subtracted due to implementation
301 quirks in libthread_db. */
302 *base
= (void *) ((char *) *base
- idx
);
308 tic6x_collect_register (struct regcache
*regcache
, int regno
,
309 union tic6x_register
*reg
)
311 union tic6x_register tmp_reg
;
313 collect_register (regcache
, regno
, &tmp_reg
.reg32
);
314 reg
->reg32
= tmp_reg
.reg32
;
318 tic6x_supply_register (struct regcache
*regcache
, int regno
,
319 const union tic6x_register
*reg
)
323 supply_register (regcache
, regno
, reg
->buf
+ offset
);
327 tic6x_fill_gregset (struct regcache
*regcache
, void *buf
)
329 auto regset
= static_cast<union tic6x_register
*> (buf
);
332 for (i
= 0; i
< TIC6X_NUM_REGS
; i
++)
333 if (tic6x_regmap
[i
] != -1)
334 tic6x_collect_register (regcache
, i
, regset
+ tic6x_regmap
[i
]);
338 tic6x_store_gregset (struct regcache
*regcache
, const void *buf
)
340 const auto regset
= static_cast<const union tic6x_register
*> (buf
);
343 for (i
= 0; i
< TIC6X_NUM_REGS
; i
++)
344 if (tic6x_regmap
[i
] != -1)
345 tic6x_supply_register (regcache
, i
, regset
+ tic6x_regmap
[i
]);
348 static struct regset_info tic6x_regsets
[] = {
349 { PTRACE_GETREGS
, PTRACE_SETREGS
, 0, TIC6X_NUM_REGS
* 4, GENERAL_REGS
,
350 tic6x_fill_gregset
, tic6x_store_gregset
},
355 tic6x_target::low_arch_setup ()
357 register unsigned int csr
asm ("B2");
359 enum c6x_feature feature
= C6X_CORE
;
361 /* Determine the CPU we're running on to find the register order. */
362 __asm__ ("MVC .S2 CSR,%0" : "=r" (csr
) :);
366 case 0x00: /* C62x */
367 case 0x02: /* C67x */
368 tic6x_regmap
= tic6x_regmap_c62x
;
369 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
372 case 0x03: /* C67x+ */
373 tic6x_regmap
= tic6x_regmap_c64x
;
374 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
377 case 0x0c: /* C64x */
378 tic6x_regmap
= tic6x_regmap_c64x
;
379 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
382 case 0x10: /* C64x+ */
383 case 0x14: /* C674x */
384 case 0x15: /* C66x */
385 tic6x_regmap
= tic6x_regmap_c64xp
;
386 tic6x_breakpoint
= 0x56454314; /* illegal opcode */
390 error ("Unknown CPU ID 0x%02x", cpuid
);
392 tic6x_usrregs_info
.regmap
= tic6x_regmap
;
394 current_process ()->tdesc
= tic6x_read_description (feature
);
397 /* Support for hardware single step. */
400 tic6x_supports_hardware_single_step (void)
405 static struct regsets_info tic6x_regsets_info
=
407 tic6x_regsets
, /* regsets */
409 NULL
, /* disabled_regsets */
412 static struct regs_info myregs_info
=
414 NULL
, /* regset_bitmap */
420 tic6x_target::get_regs_info ()
425 struct linux_target_ops the_low_target
= {
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 tic6x_supports_hardware_single_step
,
443 #include "gdbsupport/selftest.h"
445 namespace selftests
{
450 SELF_CHECK (*tdesc_tic6x_c62x_linux
== *tic6x_read_description (C6X_CORE
));
451 SELF_CHECK (*tdesc_tic6x_c64x_linux
== *tic6x_read_description (C6X_GP
));
452 SELF_CHECK (*tdesc_tic6x_c64xp_linux
== *tic6x_read_description (C6X_C6XP
));
458 /* The linux target ops object. */
460 linux_process_target
*the_linux_target
= &the_tic6x_target
;
463 initialize_low_arch (void)
466 /* Initialize the Linux target descriptions. */
467 init_registers_tic6x_c64xp_linux ();
468 init_registers_tic6x_c64x_linux ();
469 init_registers_tic6x_c62x_linux ();
471 selftests::register_test ("tic6x-tdesc", selftests::tdesc::tic6x_tdesc_test
);
474 initialize_regsets_info (&tic6x_regsets_info
);