Support for target descriptions layered on top of sparc32/sparc64
which describe more registers than native ones.
Pseudo registers always come after the real registers.
One more step forward to modernize sparc tdep's.
Submitted to upstream as:
https://sourceware.org/bugzilla/show_bug.cgi?id=20936
--- gdb-7.11/gdb/sparc-tdep.c.orig 2016-11-18 06:00:18.299687730 -0800
+++ gdb-7.11/gdb/sparc-tdep.c 2016-11-18 06:01:36.293409472 -0800
@@ -33,6 +33,7 @@
#include "osabi.h"
#include "regcache.h"
#include "target.h"
+#include "target-descriptions.h"
#include "value.h"
#include "sparc-tdep.h"
@@ -295,20 +296,23 @@
}
/* Register information. */
+#define SPARC32_FPU_REGISTERS \
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", \
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"
+#define SPARC32_CP0_REGISTERS \
+ "y", "psr", "wim", "tbr", "pc", "npc", "fsr", "csr"
+static const char *sparc_core_register_names[] = { SPARC_CORE_REGISTERS };
+static const char *sparc32_fpu_register_names[] = { SPARC32_FPU_REGISTERS };
+static const char *sparc32_cp0_register_names[] = { SPARC32_CP0_REGISTERS };
+
static const char *sparc32_register_names[] =
{
- "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
- "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
- "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
- "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7",
-
- "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
- "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
- "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
- "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
-
- "y", "psr", "wim", "tbr", "pc", "npc", "fsr", "csr"
+ SPARC_CORE_REGISTERS,
+ SPARC32_FPU_REGISTERS,
+ SPARC32_CP0_REGISTERS
};
/* Total number of registers. */
@@ -327,7 +331,19 @@
#define SPARC32_NUM_PSEUDO_REGS ARRAY_SIZE (sparc32_pseudo_register_names)
/* Return the name of register REGNUM. */
+static const char *
+sparc32_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
+{
+ regnum -= gdbarch_num_regs (gdbarch);
+ if (regnum < SPARC32_NUM_PSEUDO_REGS)
+ return sparc32_pseudo_register_names[regnum];
+
+ internal_error (__FILE__, __LINE__,
+ _("sparc32_pseudo_register_name: bad register number %d"),
+ regnum);
+}
+
static const char *
sparc32_register_name (struct gdbarch *gdbarch, int regnum)
{
@@ -334,10 +350,10 @@
if (regnum >= 0 && regnum < SPARC32_NUM_REGS)
return sparc32_register_names[regnum];
- if (regnum < SPARC32_NUM_REGS + SPARC32_NUM_PSEUDO_REGS)
- return sparc32_pseudo_register_names[regnum - SPARC32_NUM_REGS];
+ if (regnum >= gdbarch_num_regs (gdbarch))
+ return sparc32_pseudo_register_name (gdbarch, regnum);
- return NULL;
+ return tdesc_register_name (gdbarch, regnum);
}
/* Construct types for ISA-specific registers. */
@@ -399,7 +415,19 @@
/* Return the GDB type object for the "standard" data type of data in
register REGNUM. */
+static struct type *
+sparc32_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
+{
+ regnum -= gdbarch_num_regs (gdbarch);
+ if (regnum >= SPARC32_D0_REGNUM && regnum <= SPARC32_D30_REGNUM)
+ return builtin_type (gdbarch)->builtin_double;
+
+ internal_error (__FILE__, __LINE__,
+ _("sparc32_pseudo_register_type: bad register number %d"),
+ regnum);
+}
+
static struct type *
sparc32_register_type (struct gdbarch *gdbarch, int regnum)
{
@@ -406,9 +434,6 @@
if (regnum >= SPARC_F0_REGNUM && regnum <= SPARC_F31_REGNUM)
return builtin_type (gdbarch)->builtin_float;
- if (regnum >= SPARC32_D0_REGNUM && regnum <= SPARC32_D30_REGNUM)
- return builtin_type (gdbarch)->builtin_double;
-
if (regnum == SPARC_SP_REGNUM || regnum == SPARC_FP_REGNUM)
return builtin_type (gdbarch)->builtin_data_ptr;
@@ -421,6 +446,9 @@
if (regnum == SPARC32_FSR_REGNUM)
return sparc_fsr_type (gdbarch);
+ if (regnum >= gdbarch_num_regs (gdbarch))
+ return sparc32_pseudo_register_type (gdbarch, regnum);
+
return builtin_type (gdbarch)->builtin_int32;
}
@@ -431,6 +459,7 @@
{
enum register_status status;
+ regnum -= gdbarch_num_regs (gdbarch);
gdb_assert (regnum >= SPARC32_D0_REGNUM && regnum <= SPARC32_D30_REGNUM);
regnum = SPARC_F0_REGNUM + 2 * (regnum - SPARC32_D0_REGNUM);
@@ -445,6 +474,7 @@
struct regcache *regcache,
int regnum, const gdb_byte *buf)
{
+ regnum -= gdbarch_num_regs (gdbarch);
gdb_assert (regnum >= SPARC32_D0_REGNUM && regnum <= SPARC32_D30_REGNUM);
regnum = SPARC_F0_REGNUM + 2 * (regnum - SPARC32_D0_REGNUM);
@@ -1660,11 +1690,36 @@
}
+static int
+validate_tdesc_registers (const struct target_desc *tdesc,
+ struct tdesc_arch_data *tdesc_data,
+ const char *feature_name,
+ const char *register_names[],
+ unsigned int registers_num,
+ unsigned int reg_start)
+{
+ int valid_p = 1;
+ const struct tdesc_feature *feature;
+
+ feature = tdesc_find_feature (tdesc, feature_name);
+ if (feature == NULL)
+ return 0;
+
+ for (unsigned int i = 0; i < registers_num; i++)
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ reg_start + i,
+ register_names[i]);
+
+ return valid_p;
+}
+
static struct gdbarch *
sparc32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
struct gdbarch_tdep *tdep;
+ const struct target_desc *tdesc = info.target_desc;
struct gdbarch *gdbarch;
+ int valid_p = 1;
/* If there is already a candidate, use it. */
arches = gdbarch_list_lookup_by_info (arches, &info);
@@ -1678,6 +1733,10 @@
tdep->pc_regnum = SPARC32_PC_REGNUM;
tdep->npc_regnum = SPARC32_NPC_REGNUM;
tdep->step_trap = sparc_step_trap;
+ tdep->fpu_register_names = sparc32_fpu_register_names;
+ tdep->fpu_registers_num = ARRAY_SIZE (sparc32_fpu_register_names);
+ tdep->cp0_register_names = sparc32_cp0_register_names;
+ tdep->cp0_registers_num = ARRAY_SIZE (sparc32_cp0_register_names);
set_gdbarch_long_double_bit (gdbarch, 128);
set_gdbarch_long_double_format (gdbarch, floatformats_sparc_quad);
@@ -1686,6 +1745,8 @@
set_gdbarch_register_name (gdbarch, sparc32_register_name);
set_gdbarch_register_type (gdbarch, sparc32_register_type);
set_gdbarch_num_pseudo_regs (gdbarch, SPARC32_NUM_PSEUDO_REGS);
+ set_tdesc_pseudo_register_name (gdbarch, sparc32_pseudo_register_name);
+ set_tdesc_pseudo_register_type (gdbarch, sparc32_pseudo_register_type);
set_gdbarch_pseudo_register_read (gdbarch, sparc32_pseudo_register_read);
set_gdbarch_pseudo_register_write (gdbarch, sparc32_pseudo_register_write);
@@ -1734,6 +1795,39 @@
frame_unwind_append_unwinder (gdbarch, &sparc32_frame_unwind);
+ if (tdesc_has_registers (tdesc))
+ {
+ struct tdesc_arch_data *tdesc_data = tdesc_data_alloc ();
+
+ /* Validate that the descriptor provides the mandatory registers
+ and allocate their numbers. */
+ valid_p &= validate_tdesc_registers (tdesc, tdesc_data,
+ "org.gnu.gdb.sparc.cpu",
+ sparc_core_register_names,
+ ARRAY_SIZE (sparc_core_register_names),
+ SPARC_G0_REGNUM);
+ valid_p &= validate_tdesc_registers (tdesc, tdesc_data,
+ "org.gnu.gdb.sparc.fpu",
+ tdep->fpu_register_names,
+ tdep->fpu_registers_num,
+ SPARC_F0_REGNUM);
+ valid_p &= validate_tdesc_registers (tdesc, tdesc_data,
+ "org.gnu.gdb.sparc.cp0",
+ tdep->cp0_register_names,
+ tdep->cp0_registers_num,
+ SPARC_F0_REGNUM +
+ tdep->fpu_registers_num);
+ if (!valid_p)
+ {
+ tdesc_data_cleanup (tdesc_data);
+ return NULL;
+ }
+
+ /* Target description may have changed. */
+ info.tdep_info = tdesc_data;
+ tdesc_use_registers (gdbarch, tdesc, tdesc_data);
+ }
+
/* If we have register sets, enable the generic core file support. */
if (tdep->gregset)
set_gdbarch_iterate_over_regset_sections