/* Target dependent code for GDB on TI C6x systems.
- Copyright (C) 2010-2013 Free Software Foundation, Inc.
+ Copyright (C) 2010-2018 Free Software Foundation, Inc.
Contributed by Andrew Jenner <andrew@codesourcery.com>
Contributed by Yao Qi <yao@codesourcery.com>
#include "server.h"
#include "linux-low.h"
+#include "arch/tic6x.h"
+#include "tdesc.h"
-#include <sys/ptrace.h>
+#include "nat/gdb_ptrace.h"
#include <endian.h>
#include "gdb_proc_service.h"
/* Defined in auto-generated file tic6x-c64xp-linux.c. */
void init_registers_tic6x_c64xp_linux (void);
+extern const struct target_desc *tdesc_tic6x_c64xp_linux;
+
/* Defined in auto-generated file tic6x-c64x-linux.c. */
void init_registers_tic6x_c64x_linux (void);
+extern const struct target_desc *tdesc_tic6x_c64x_linux;
+
/* Defined in auto-generated file tic62x-c6xp-linux.c. */
void init_registers_tic6x_c62x_linux (void);
+extern const struct target_desc *tdesc_tic6x_c62x_linux;
union tic6x_register
{
static int *tic6x_regmap;
static unsigned int tic6x_breakpoint;
+#define tic6x_breakpoint_len 4
-static void
-tic6x_arch_setup (void)
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */
+
+static const gdb_byte *
+tic6x_sw_breakpoint_from_kind (int kind, int *size)
{
- register unsigned int csr asm ("B2");
- unsigned int cpuid;
+ *size = tic6x_breakpoint_len;
+ return (const gdb_byte *) &tic6x_breakpoint;
+}
- /* Determine the CPU we're running on to find the register order. */
- __asm__ ("MVC .S2 CSR,%0" : "=r" (csr) :);
- cpuid = csr >> 24;
- switch (cpuid)
+static struct usrregs_info tic6x_usrregs_info =
+ {
+ TIC6X_NUM_REGS,
+ NULL, /* Set in tic6x_read_description. */
+ };
+
+static const struct target_desc *
+tic6x_read_description (enum c6x_feature feature)
+{
+ static target_desc *tdescs[C6X_LAST] = { };
+ struct target_desc **tdesc = &tdescs[feature];
+
+ if (*tdesc == NULL)
{
- case 0x00: /* C62x */
- case 0x02: /* C67x */
- tic6x_regmap = tic6x_regmap_c62x;
- tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */
- init_registers_tic6x_c62x_linux ();
- break;
- case 0x03: /* C67x+ */
- tic6x_regmap = tic6x_regmap_c64x;
- tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */
- init_registers_tic6x_c64x_linux ();
- break;
- case 0x0c: /* C64x */
- tic6x_regmap = tic6x_regmap_c64x;
- tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */
- init_registers_tic6x_c64x_linux ();
- break;
- case 0x10: /* C64x+ */
- case 0x14: /* C674x */
- case 0x15: /* C66x */
- tic6x_regmap = tic6x_regmap_c64xp;
- tic6x_breakpoint = 0x56454314; /* illegal opcode */
- init_registers_tic6x_c64xp_linux ();
- break;
- default:
- error ("Unknown CPU ID 0x%02x", cpuid);
+ *tdesc = tic6x_create_target_description (feature);
+ static const char *expedite_regs[] = { "A15", "PC", NULL };
+ init_target_desc (*tdesc, expedite_regs);
}
- the_low_target.regmap = tic6x_regmap;
+
+ return *tdesc;
}
static int
supply_register_by_name (regcache, "PC", newpc.buf);
}
-#define tic6x_breakpoint_len 4
-
static int
tic6x_breakpoint_at (CORE_ADDR where)
{
/* Fetch the thread-local storage pointer for libthread_db. */
ps_err_e
-ps_get_thread_area (const struct ps_prochandle *ph,
+ps_get_thread_area (struct ps_prochandle *ph,
lwpid_t lwpid, int idx, void **base)
{
if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
static void
tic6x_fill_gregset (struct regcache *regcache, void *buf)
{
- union tic6x_register *regset = buf;
+ auto regset = static_cast<union tic6x_register *> (buf);
int i;
for (i = 0; i < TIC6X_NUM_REGS; i++)
static void
tic6x_store_gregset (struct regcache *regcache, const void *buf)
{
- const union tic6x_register *regset = buf;
+ const auto regset = static_cast<const union tic6x_register *> (buf);
int i;
for (i = 0; i < TIC6X_NUM_REGS; i++)
tic6x_supply_register (regcache, i, regset + tic6x_regmap[i]);
}
-struct regset_info target_regsets[] = {
+static struct regset_info tic6x_regsets[] = {
{ PTRACE_GETREGS, PTRACE_SETREGS, 0, TIC6X_NUM_REGS * 4, GENERAL_REGS,
tic6x_fill_gregset, tic6x_store_gregset },
- { 0, 0, 0, -1, -1, NULL, NULL }
+ NULL_REGSET
};
+static void
+tic6x_arch_setup (void)
+{
+ register unsigned int csr asm ("B2");
+ unsigned int cpuid;
+ enum c6x_feature feature = C6X_CORE;
+
+ /* Determine the CPU we're running on to find the register order. */
+ __asm__ ("MVC .S2 CSR,%0" : "=r" (csr) :);
+ cpuid = csr >> 24;
+ switch (cpuid)
+ {
+ case 0x00: /* C62x */
+ case 0x02: /* C67x */
+ tic6x_regmap = tic6x_regmap_c62x;
+ tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */
+ feature = C6X_CORE;
+ break;
+ case 0x03: /* C67x+ */
+ tic6x_regmap = tic6x_regmap_c64x;
+ tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */
+ feature = C6X_GP;
+ break;
+ case 0x0c: /* C64x */
+ tic6x_regmap = tic6x_regmap_c64x;
+ tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */
+ feature = C6X_GP;
+ break;
+ case 0x10: /* C64x+ */
+ case 0x14: /* C674x */
+ case 0x15: /* C66x */
+ tic6x_regmap = tic6x_regmap_c64xp;
+ tic6x_breakpoint = 0x56454314; /* illegal opcode */
+ feature = C6X_C6XP;
+ break;
+ default:
+ error ("Unknown CPU ID 0x%02x", cpuid);
+ }
+ tic6x_usrregs_info.regmap = tic6x_regmap;
+
+ current_process ()->tdesc = tic6x_read_description (feature);
+}
+
+/* Support for hardware single step. */
+
+static int
+tic6x_supports_hardware_single_step (void)
+{
+ return 1;
+}
+
+static struct regsets_info tic6x_regsets_info =
+ {
+ tic6x_regsets, /* regsets */
+ 0, /* num_regsets */
+ NULL, /* disabled_regsets */
+ };
+
+static struct regs_info regs_info =
+ {
+ NULL, /* regset_bitmap */
+ &tic6x_usrregs_info,
+ &tic6x_regsets_info
+ };
+
+static const struct regs_info *
+tic6x_regs_info (void)
+{
+ return ®s_info;
+}
+
struct linux_target_ops the_low_target = {
tic6x_arch_setup,
- TIC6X_NUM_REGS,
- 0,
- NULL,
+ tic6x_regs_info,
tic6x_cannot_fetch_register,
tic6x_cannot_store_register,
NULL, /* fetch_register */
tic6x_get_pc,
tic6x_set_pc,
- (const unsigned char *) &tic6x_breakpoint,
- tic6x_breakpoint_len,
+ NULL, /* breakpoint_kind_from_pc */
+ tic6x_sw_breakpoint_from_kind,
NULL,
0,
tic6x_breakpoint_at,
+ NULL, /* supports_z_point_type */
+ NULL, /* insert_point */
+ NULL, /* remove_point */
+ NULL, /* stopped_by_watchpoint */
+ NULL, /* stopped_data_address */
+ NULL, /* collect_ptrace_register */
+ NULL, /* supply_ptrace_register */
+ NULL, /* siginfo_fixup */
+ NULL, /* new_process */
+ NULL, /* delete_process */
+ NULL, /* new_thread */
+ NULL, /* delete_thread */
+ NULL, /* new_fork */
+ NULL, /* prepare_to_resume */
+ NULL, /* process_qsupported */
+ NULL, /* supports_tracepoints */
+ NULL, /* get_thread_area */
+ NULL, /* install_fast_tracepoint_jump_pad */
+ NULL, /* emit_ops */
+ NULL, /* get_min_fast_tracepoint_insn_len */
+ NULL, /* supports_range_stepping */
+ NULL, /* breakpoint_kind_from_current_state */
+ tic6x_supports_hardware_single_step,
};
+
+#if GDB_SELF_TEST
+#include "common/selftest.h"
+
+namespace selftests {
+namespace tdesc {
+static void
+tic6x_tdesc_test ()
+{
+ SELF_CHECK (*tdesc_tic6x_c62x_linux == *tic6x_read_description (C6X_CORE));
+ SELF_CHECK (*tdesc_tic6x_c64x_linux == *tic6x_read_description (C6X_GP));
+ SELF_CHECK (*tdesc_tic6x_c64xp_linux == *tic6x_read_description (C6X_C6XP));
+}
+}
+}
+#endif
+
+void
+initialize_low_arch (void)
+{
+#if GDB_SELF_TEST
+ /* Initialize the Linux target descriptions. */
+ init_registers_tic6x_c64xp_linux ();
+ init_registers_tic6x_c64x_linux ();
+ init_registers_tic6x_c62x_linux ();
+
+ selftests::register_test ("tic6x-tdesc", selftests::tdesc::tic6x_tdesc_test);
+#endif
+
+ initialize_regsets_info (&tic6x_regsets_info);
+}