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
;
54 /* The singleton target ops object. */
56 static tic6x_target the_tic6x_target
;
58 /* Defined in auto-generated file tic6x-c64xp-linux.c. */
59 void init_registers_tic6x_c64xp_linux (void);
60 extern const struct target_desc
*tdesc_tic6x_c64xp_linux
;
62 /* Defined in auto-generated file tic6x-c64x-linux.c. */
63 void init_registers_tic6x_c64x_linux (void);
64 extern const struct target_desc
*tdesc_tic6x_c64x_linux
;
66 /* Defined in auto-generated file tic62x-c6xp-linux.c. */
67 void init_registers_tic6x_c62x_linux (void);
68 extern const struct target_desc
*tdesc_tic6x_c62x_linux
;
77 /* Return the ptrace ``address'' of register REGNO. */
79 #if __BYTE_ORDER == __BIG_ENDIAN
80 static int tic6x_regmap_c64xp
[] = {
82 53, 52, 55, 54, 57, 56, 59, 58,
83 61, 60, 63, 62, 65, 64, 67, 66,
85 23, 22, 25, 24, 27, 26, 29, 28,
86 31, 30, 33, 32, 35, 34, 69, 68,
90 37, 36, 39, 38, 41, 40, 43, 42,
91 45, 44, 47, 46, 49, 48, 51, 50,
93 7, 6, 9, 8, 11, 10, 13, 12,
94 15, 14, 17, 16, 19, 18, 21, 20,
99 static int tic6x_regmap_c64x
[] = {
101 51, 50, 53, 52, 55, 54, 57, 56,
102 59, 58, 61, 60, 63, 62, 65, 64,
104 21, 20, 23, 22, 25, 24, 27, 26,
105 29, 28, 31, 30, 33, 32, 67, 66,
109 35, 34, 37, 36, 39, 38, 41, 40,
110 43, 42, 45, 44, 47, 46, 49, 48,
112 5, 4, 7, 6, 9, 8, 11, 10,
113 13, 12, 15, 14, 17, 16, 19, 18,
117 static int tic6x_regmap_c62x
[] = {
119 19, 18, 21, 20, 23, 22, 25, 24,
120 27, 26, 29, 28, 31, 30, 33, 32,
122 5, 4, 7, 6, 9, 8, 11, 10,
123 13, 12, 15, 14, 17, 16, 35, 34,
126 -1, -1, -1, -1, -1, -1, -1, -1,
127 -1, -1, -1, -1, -1, -1, -1, -1,
128 -1, -1, -1, -1, -1, -1, -1, -1,
129 -1, -1, -1, -1, -1, -1, -1, -1,
134 static int tic6x_regmap_c64xp
[] = {
136 52, 53, 54, 55, 56, 57, 58, 59,
137 60, 61, 62, 63, 64, 65, 66, 67,
139 22, 23, 24, 25, 26, 27, 28, 29,
140 30, 31, 32, 33, 34, 35, 68, 69,
144 36, 37, 38, 39, 40, 41, 42, 43,
145 44, 45, 46, 47, 48, 49, 50, 51,
147 6, 7, 8, 9, 10, 11, 12, 13,
148 14, 15, 16, 17, 18, 19, 20, 31,
153 static int tic6x_regmap_c64x
[] = {
155 50, 51, 52, 53, 54, 55, 56, 57,
156 58, 59, 60, 61, 62, 63, 64, 65,
158 20, 21, 22, 23, 24, 25, 26, 27,
159 28, 29, 30, 31, 32, 33, 66, 67,
163 34, 35, 36, 37, 38, 39, 40, 41,
164 42, 43, 44, 45, 46, 47, 48, 49,
166 4, 5, 6, 7, 8, 9, 10, 11,
167 12, 13, 14, 15, 16, 17, 18, 19,
171 static int tic6x_regmap_c62x
[] = {
173 18, 19, 20, 21, 22, 23, 24, 25,
174 26, 27, 28, 29, 30, 31, 32, 33,
176 4, 5, 6, 7, 8, 9, 10, 11,
177 12, 13, 14, 15, 16, 17, 34, 35,
180 -1, -1, -1, -1, -1, -1, -1, -1,
181 -1, -1, -1, -1, -1, -1, -1, -1,
182 -1, -1, -1, -1, -1, -1, -1, -1,
183 -1, -1, -1, -1, -1, -1, -1, -1,
189 extern struct linux_target_ops the_low_target
;
191 static int *tic6x_regmap
;
192 static unsigned int tic6x_breakpoint
;
193 #define tic6x_breakpoint_len 4
195 /* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */
197 static const gdb_byte
*
198 tic6x_sw_breakpoint_from_kind (int kind
, int *size
)
200 *size
= tic6x_breakpoint_len
;
201 return (const gdb_byte
*) &tic6x_breakpoint
;
204 static struct usrregs_info tic6x_usrregs_info
=
207 NULL
, /* Set in tic6x_read_description. */
210 static const struct target_desc
*
211 tic6x_read_description (enum c6x_feature feature
)
213 static target_desc
*tdescs
[C6X_LAST
] = { };
214 struct target_desc
**tdesc
= &tdescs
[feature
];
218 *tdesc
= tic6x_create_target_description (feature
);
219 static const char *expedite_regs
[] = { "A15", "PC", NULL
};
220 init_target_desc (*tdesc
, expedite_regs
);
227 tic6x_cannot_fetch_register (int regno
)
229 return (tic6x_regmap
[regno
] == -1);
233 tic6x_cannot_store_register (int regno
)
235 return (tic6x_regmap
[regno
] == -1);
239 tic6x_get_pc (struct regcache
*regcache
)
241 union tic6x_register pc
;
243 collect_register_by_name (regcache
, "PC", pc
.buf
);
248 tic6x_set_pc (struct regcache
*regcache
, CORE_ADDR pc
)
250 union tic6x_register newpc
;
253 supply_register_by_name (regcache
, "PC", newpc
.buf
);
257 tic6x_breakpoint_at (CORE_ADDR where
)
261 the_target
->read_memory (where
, (unsigned char *) &insn
, 4);
262 if (insn
== tic6x_breakpoint
)
265 /* If necessary, recognize more trap instructions here. GDB only uses the
270 /* Fetch the thread-local storage pointer for libthread_db. */
273 ps_get_thread_area (struct ps_prochandle
*ph
,
274 lwpid_t lwpid
, int idx
, void **base
)
276 if (ptrace (PTRACE_GET_THREAD_AREA
, lwpid
, NULL
, base
) != 0)
279 /* IDX is the bias from the thread pointer to the beginning of the
280 thread descriptor. It has to be subtracted due to implementation
281 quirks in libthread_db. */
282 *base
= (void *) ((char *) *base
- idx
);
288 tic6x_collect_register (struct regcache
*regcache
, int regno
,
289 union tic6x_register
*reg
)
291 union tic6x_register tmp_reg
;
293 collect_register (regcache
, regno
, &tmp_reg
.reg32
);
294 reg
->reg32
= tmp_reg
.reg32
;
298 tic6x_supply_register (struct regcache
*regcache
, int regno
,
299 const union tic6x_register
*reg
)
303 supply_register (regcache
, regno
, reg
->buf
+ offset
);
307 tic6x_fill_gregset (struct regcache
*regcache
, void *buf
)
309 auto regset
= static_cast<union tic6x_register
*> (buf
);
312 for (i
= 0; i
< TIC6X_NUM_REGS
; i
++)
313 if (tic6x_regmap
[i
] != -1)
314 tic6x_collect_register (regcache
, i
, regset
+ tic6x_regmap
[i
]);
318 tic6x_store_gregset (struct regcache
*regcache
, const void *buf
)
320 const auto regset
= static_cast<const union tic6x_register
*> (buf
);
323 for (i
= 0; i
< TIC6X_NUM_REGS
; i
++)
324 if (tic6x_regmap
[i
] != -1)
325 tic6x_supply_register (regcache
, i
, regset
+ tic6x_regmap
[i
]);
328 static struct regset_info tic6x_regsets
[] = {
329 { PTRACE_GETREGS
, PTRACE_SETREGS
, 0, TIC6X_NUM_REGS
* 4, GENERAL_REGS
,
330 tic6x_fill_gregset
, tic6x_store_gregset
},
335 tic6x_target::low_arch_setup ()
337 register unsigned int csr
asm ("B2");
339 enum c6x_feature feature
= C6X_CORE
;
341 /* Determine the CPU we're running on to find the register order. */
342 __asm__ ("MVC .S2 CSR,%0" : "=r" (csr
) :);
346 case 0x00: /* C62x */
347 case 0x02: /* C67x */
348 tic6x_regmap
= tic6x_regmap_c62x
;
349 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
352 case 0x03: /* C67x+ */
353 tic6x_regmap
= tic6x_regmap_c64x
;
354 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
357 case 0x0c: /* C64x */
358 tic6x_regmap
= tic6x_regmap_c64x
;
359 tic6x_breakpoint
= 0x0000a122; /* BNOP .S2 0,5 */
362 case 0x10: /* C64x+ */
363 case 0x14: /* C674x */
364 case 0x15: /* C66x */
365 tic6x_regmap
= tic6x_regmap_c64xp
;
366 tic6x_breakpoint
= 0x56454314; /* illegal opcode */
370 error ("Unknown CPU ID 0x%02x", cpuid
);
372 tic6x_usrregs_info
.regmap
= tic6x_regmap
;
374 current_process ()->tdesc
= tic6x_read_description (feature
);
377 /* Support for hardware single step. */
380 tic6x_supports_hardware_single_step (void)
385 static struct regsets_info tic6x_regsets_info
=
387 tic6x_regsets
, /* regsets */
389 NULL
, /* disabled_regsets */
392 static struct regs_info myregs_info
=
394 NULL
, /* regset_bitmap */
400 tic6x_target::get_regs_info ()
405 struct linux_target_ops the_low_target
= {
406 tic6x_cannot_fetch_register
,
407 tic6x_cannot_store_register
,
408 NULL
, /* fetch_register */
411 NULL
, /* breakpoint_kind_from_pc */
412 tic6x_sw_breakpoint_from_kind
,
416 NULL
, /* supports_z_point_type */
417 NULL
, /* insert_point */
418 NULL
, /* remove_point */
419 NULL
, /* stopped_by_watchpoint */
420 NULL
, /* stopped_data_address */
421 NULL
, /* collect_ptrace_register */
422 NULL
, /* supply_ptrace_register */
423 NULL
, /* siginfo_fixup */
424 NULL
, /* new_process */
425 NULL
, /* delete_process */
426 NULL
, /* new_thread */
427 NULL
, /* delete_thread */
429 NULL
, /* prepare_to_resume */
430 NULL
, /* process_qsupported */
431 NULL
, /* supports_tracepoints */
432 NULL
, /* get_thread_area */
433 NULL
, /* install_fast_tracepoint_jump_pad */
435 NULL
, /* get_min_fast_tracepoint_insn_len */
436 NULL
, /* supports_range_stepping */
437 NULL
, /* breakpoint_kind_from_current_state */
438 tic6x_supports_hardware_single_step
,
442 #include "gdbsupport/selftest.h"
444 namespace selftests
{
449 SELF_CHECK (*tdesc_tic6x_c62x_linux
== *tic6x_read_description (C6X_CORE
));
450 SELF_CHECK (*tdesc_tic6x_c64x_linux
== *tic6x_read_description (C6X_GP
));
451 SELF_CHECK (*tdesc_tic6x_c64xp_linux
== *tic6x_read_description (C6X_C6XP
));
457 /* The linux target ops object. */
459 linux_process_target
*the_linux_target
= &the_tic6x_target
;
462 initialize_low_arch (void)
465 /* Initialize the Linux target descriptions. */
466 init_registers_tic6x_c64xp_linux ();
467 init_registers_tic6x_c64x_linux ();
468 init_registers_tic6x_c62x_linux ();
470 selftests::register_test ("tic6x-tdesc", selftests::tdesc::tic6x_tdesc_test
);
473 initialize_regsets_info (&tic6x_regsets_info
);