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
;
57 bool low_supports_breakpoints () override
;
59 CORE_ADDR
low_get_pc (regcache
*regcache
) override
;
61 void low_set_pc (regcache
*regcache
, CORE_ADDR newpc
) override
;
64 /* The singleton target ops object. */
66 static tic6x_target the_tic6x_target
;
68 /* Defined in auto-generated file tic6x-c64xp-linux.c. */
69 void init_registers_tic6x_c64xp_linux (void);
70 extern const struct target_desc
*tdesc_tic6x_c64xp_linux
;
72 /* Defined in auto-generated file tic6x-c64x-linux.c. */
73 void init_registers_tic6x_c64x_linux (void);
74 extern const struct target_desc
*tdesc_tic6x_c64x_linux
;
76 /* Defined in auto-generated file tic62x-c6xp-linux.c. */
77 void init_registers_tic6x_c62x_linux (void);
78 extern const struct target_desc
*tdesc_tic6x_c62x_linux
;
87 /* Return the ptrace ``address'' of register REGNO. */
89 #if __BYTE_ORDER == __BIG_ENDIAN
90 static int tic6x_regmap_c64xp
[] = {
92 53, 52, 55, 54, 57, 56, 59, 58,
93 61, 60, 63, 62, 65, 64, 67, 66,
95 23, 22, 25, 24, 27, 26, 29, 28,
96 31, 30, 33, 32, 35, 34, 69, 68,
100 37, 36, 39, 38, 41, 40, 43, 42,
101 45, 44, 47, 46, 49, 48, 51, 50,
103 7, 6, 9, 8, 11, 10, 13, 12,
104 15, 14, 17, 16, 19, 18, 21, 20,
109 static int tic6x_regmap_c64x
[] = {
111 51, 50, 53, 52, 55, 54, 57, 56,
112 59, 58, 61, 60, 63, 62, 65, 64,
114 21, 20, 23, 22, 25, 24, 27, 26,
115 29, 28, 31, 30, 33, 32, 67, 66,
119 35, 34, 37, 36, 39, 38, 41, 40,
120 43, 42, 45, 44, 47, 46, 49, 48,
122 5, 4, 7, 6, 9, 8, 11, 10,
123 13, 12, 15, 14, 17, 16, 19, 18,
127 static int tic6x_regmap_c62x
[] = {
129 19, 18, 21, 20, 23, 22, 25, 24,
130 27, 26, 29, 28, 31, 30, 33, 32,
132 5, 4, 7, 6, 9, 8, 11, 10,
133 13, 12, 15, 14, 17, 16, 35, 34,
136 -1, -1, -1, -1, -1, -1, -1, -1,
137 -1, -1, -1, -1, -1, -1, -1, -1,
138 -1, -1, -1, -1, -1, -1, -1, -1,
139 -1, -1, -1, -1, -1, -1, -1, -1,
144 static int tic6x_regmap_c64xp
[] = {
146 52, 53, 54, 55, 56, 57, 58, 59,
147 60, 61, 62, 63, 64, 65, 66, 67,
149 22, 23, 24, 25, 26, 27, 28, 29,
150 30, 31, 32, 33, 34, 35, 68, 69,
154 36, 37, 38, 39, 40, 41, 42, 43,
155 44, 45, 46, 47, 48, 49, 50, 51,
157 6, 7, 8, 9, 10, 11, 12, 13,
158 14, 15, 16, 17, 18, 19, 20, 31,
163 static int tic6x_regmap_c64x
[] = {
165 50, 51, 52, 53, 54, 55, 56, 57,
166 58, 59, 60, 61, 62, 63, 64, 65,
168 20, 21, 22, 23, 24, 25, 26, 27,
169 28, 29, 30, 31, 32, 33, 66, 67,
173 34, 35, 36, 37, 38, 39, 40, 41,
174 42, 43, 44, 45, 46, 47, 48, 49,
176 4, 5, 6, 7, 8, 9, 10, 11,
177 12, 13, 14, 15, 16, 17, 18, 19,
181 static int tic6x_regmap_c62x
[] = {
183 18, 19, 20, 21, 22, 23, 24, 25,
184 26, 27, 28, 29, 30, 31, 32, 33,
186 4, 5, 6, 7, 8, 9, 10, 11,
187 12, 13, 14, 15, 16, 17, 34, 35,
190 -1, -1, -1, -1, -1, -1, -1, -1,
191 -1, -1, -1, -1, -1, -1, -1, -1,
192 -1, -1, -1, -1, -1, -1, -1, -1,
193 -1, -1, -1, -1, -1, -1, -1, -1,
199 extern struct linux_target_ops the_low_target
;
201 static int *tic6x_regmap
;
202 static unsigned int tic6x_breakpoint
;
203 #define tic6x_breakpoint_len 4
205 /* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */
207 static const gdb_byte
*
208 tic6x_sw_breakpoint_from_kind (int kind
, int *size
)
210 *size
= tic6x_breakpoint_len
;
211 return (const gdb_byte
*) &tic6x_breakpoint
;
214 static struct usrregs_info tic6x_usrregs_info
=
217 NULL
, /* Set in tic6x_read_description. */
220 static const struct target_desc
*
221 tic6x_read_description (enum c6x_feature feature
)
223 static target_desc
*tdescs
[C6X_LAST
] = { };
224 struct target_desc
**tdesc
= &tdescs
[feature
];
228 *tdesc
= tic6x_create_target_description (feature
);
229 static const char *expedite_regs
[] = { "A15", "PC", NULL
};
230 init_target_desc (*tdesc
, expedite_regs
);
237 tic6x_target::low_cannot_fetch_register (int regno
)
239 return (tic6x_regmap
[regno
] == -1);
243 tic6x_target::low_cannot_store_register (int regno
)
245 return (tic6x_regmap
[regno
] == -1);
249 tic6x_target::low_supports_breakpoints ()
255 tic6x_target::low_get_pc (regcache
*regcache
)
257 union tic6x_register pc
;
259 collect_register_by_name (regcache
, "PC", pc
.buf
);
264 tic6x_target::low_set_pc (regcache
*regcache
, CORE_ADDR pc
)
266 union tic6x_register newpc
;
269 supply_register_by_name (regcache
, "PC", newpc
.buf
);
273 tic6x_breakpoint_at (CORE_ADDR where
)
277 the_target
->read_memory (where
, (unsigned char *) &insn
, 4);
278 if (insn
== tic6x_breakpoint
)
281 /* If necessary, recognize more trap instructions here. GDB only uses the
286 /* Fetch the thread-local storage pointer for libthread_db. */
289 ps_get_thread_area (struct ps_prochandle
*ph
,
290 lwpid_t lwpid
, int idx
, void **base
)
292 if (ptrace (PTRACE_GET_THREAD_AREA
, lwpid
, NULL
, base
) != 0)
295 /* IDX is the bias from the thread pointer to the beginning of the
296 thread descriptor. It has to be subtracted due to implementation
297 quirks in libthread_db. */
298 *base
= (void *) ((char *) *base
- idx
);
304 tic6x_collect_register (struct regcache
*regcache
, int regno
,
305 union tic6x_register
*reg
)
307 union tic6x_register tmp_reg
;
309 collect_register (regcache
, regno
, &tmp_reg
.reg32
);
310 reg
->reg32
= tmp_reg
.reg32
;
314 tic6x_supply_register (struct regcache
*regcache
, int regno
,
315 const union tic6x_register
*reg
)
319 supply_register (regcache
, regno
, reg
->buf
+ offset
);
323 tic6x_fill_gregset (struct regcache
*regcache
, void *buf
)
325 auto regset
= static_cast<union tic6x_register
*> (buf
);
328 for (i
= 0; i
< TIC6X_NUM_REGS
; i
++)
329 if (tic6x_regmap
[i
] != -1)
330 tic6x_collect_register (regcache
, i
, regset
+ tic6x_regmap
[i
]);
334 tic6x_store_gregset (struct regcache
*regcache
, const void *buf
)
336 const auto regset
= static_cast<const union tic6x_register
*> (buf
);
339 for (i
= 0; i
< TIC6X_NUM_REGS
; i
++)
340 if (tic6x_regmap
[i
] != -1)
341 tic6x_supply_register (regcache
, i
, regset
+ tic6x_regmap
[i
]);
344 static struct regset_info tic6x_regsets
[] = {
345 { PTRACE_GETREGS
, PTRACE_SETREGS
, 0, TIC6X_NUM_REGS
* 4, GENERAL_REGS
,
346 tic6x_fill_gregset
, tic6x_store_gregset
},
351 tic6x_target::low_arch_setup ()
353 register unsigned int csr
asm ("B2");
355 enum c6x_feature feature
= C6X_CORE
;
357 /* Determine the CPU we're running on to find the register order. */
358 __asm__ ("MVC .S2 CSR,%0" : "=r" (csr
) :);
362 case 0x00: /* C62x */
363 case 0x02: /* C67x */
364 tic6x_regmap
= tic6x_regmap_c62x
;
365 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
368 case 0x03: /* C67x+ */
369 tic6x_regmap
= tic6x_regmap_c64x
;
370 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
373 case 0x0c: /* C64x */
374 tic6x_regmap
= tic6x_regmap_c64x
;
375 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
378 case 0x10: /* C64x+ */
379 case 0x14: /* C674x */
380 case 0x15: /* C66x */
381 tic6x_regmap
= tic6x_regmap_c64xp
;
382 tic6x_breakpoint
= 0x56454314; /* illegal opcode */
386 error ("Unknown CPU ID 0x%02x", cpuid
);
388 tic6x_usrregs_info
.regmap
= tic6x_regmap
;
390 current_process ()->tdesc
= tic6x_read_description (feature
);
393 /* Support for hardware single step. */
396 tic6x_supports_hardware_single_step (void)
401 static struct regsets_info tic6x_regsets_info
=
403 tic6x_regsets
, /* regsets */
405 NULL
, /* disabled_regsets */
408 static struct regs_info myregs_info
=
410 NULL
, /* regset_bitmap */
416 tic6x_target::get_regs_info ()
421 struct linux_target_ops the_low_target
= {
422 tic6x_sw_breakpoint_from_kind
,
426 NULL
, /* supports_z_point_type */
427 NULL
, /* insert_point */
428 NULL
, /* remove_point */
429 NULL
, /* stopped_by_watchpoint */
430 NULL
, /* stopped_data_address */
431 NULL
, /* collect_ptrace_register */
432 NULL
, /* supply_ptrace_register */
433 NULL
, /* siginfo_fixup */
434 NULL
, /* new_process */
435 NULL
, /* delete_process */
436 NULL
, /* new_thread */
437 NULL
, /* delete_thread */
439 NULL
, /* prepare_to_resume */
440 NULL
, /* process_qsupported */
441 NULL
, /* supports_tracepoints */
442 NULL
, /* get_thread_area */
443 NULL
, /* install_fast_tracepoint_jump_pad */
445 NULL
, /* get_min_fast_tracepoint_insn_len */
446 NULL
, /* supports_range_stepping */
447 tic6x_supports_hardware_single_step
,
451 #include "gdbsupport/selftest.h"
453 namespace selftests
{
458 SELF_CHECK (*tdesc_tic6x_c62x_linux
== *tic6x_read_description (C6X_CORE
));
459 SELF_CHECK (*tdesc_tic6x_c64x_linux
== *tic6x_read_description (C6X_GP
));
460 SELF_CHECK (*tdesc_tic6x_c64xp_linux
== *tic6x_read_description (C6X_C6XP
));
466 /* The linux target ops object. */
468 linux_process_target
*the_linux_target
= &the_tic6x_target
;
471 initialize_low_arch (void)
474 /* Initialize the Linux target descriptions. */
475 init_registers_tic6x_c64xp_linux ();
476 init_registers_tic6x_c64x_linux ();
477 init_registers_tic6x_c62x_linux ();
479 selftests::register_test ("tic6x-tdesc", selftests::tdesc::tic6x_tdesc_test
);
482 initialize_regsets_info (&tic6x_regsets_info
);