+2020-06-25 Andrew Burgess <andrew.burgess@embecosm.com>
+
+ * target-descriptions.c (tdesc_use_registers): Add new parameter a
+ callback, use the callback (when not null) to help number unknown
+ registers.
+ * target-descriptions.h (tdesc_unknown_register_ftype): New typedef.
+ (tdesc_use_registers): Add extra parameter to declaration.
+
2020-06-25 Andrew Burgess <andrew.burgess@embecosm.com>
* riscv-tdep.c (value_of_riscv_user_reg): Moved to here from later
void
tdesc_use_registers (struct gdbarch *gdbarch,
const struct target_desc *target_desc,
- struct tdesc_arch_data *early_data)
+ struct tdesc_arch_data *early_data,
+ tdesc_unknown_register_ftype unk_reg_cb)
{
int num_regs = gdbarch_num_regs (gdbarch);
struct tdesc_arch_data *data;
while (data->arch_regs.size () < num_regs)
data->arch_regs.emplace_back (nullptr, nullptr);
+ /* First we give the target a chance to number previously unknown
+ registers. This allows targets to record the numbers assigned based
+ on which feature the register was from. */
+ if (unk_reg_cb != NULL)
+ {
+ for (const tdesc_feature_up &feature : target_desc->features)
+ for (const tdesc_reg_up ® : feature->registers)
+ if (htab_find (reg_hash, reg.get ()) != NULL)
+ {
+ int regno = unk_reg_cb (gdbarch, feature.get (),
+ reg->name.c_str (), num_regs);
+ gdb_assert (regno == -1 || regno >= num_regs);
+ if (regno != -1)
+ {
+ while (regno >= data->arch_regs.size ())
+ data->arch_regs.emplace_back (nullptr, nullptr);
+ data->arch_regs[regno] = tdesc_arch_reg (reg.get (), NULL);
+ num_regs = regno + 1;
+ htab_remove_elt (reg_hash, reg.get ());
+ }
+ }
+ }
+
+ /* Ensure the array was sized correctly above. */
+ gdb_assert (data->arch_regs.size () == num_regs);
+
+ /* Now in a final pass we assign register numbers to any remaining
+ unnumbered registers. */
for (const tdesc_feature_up &feature : target_desc->features)
for (const tdesc_reg_up ® : feature->registers)
if (htab_find (reg_hash, reg.get ()) != NULL)
(struct gdbarch *gdbarch,
gdbarch_register_reggroup_p_ftype *pseudo_reggroup_p);
+/* Pointer to a function that should be called for each unknown register in
+ a target description, used by TDESC_USE_REGISTERS.
+
+ GDBARCH is the architecture the target description is for, FEATURE is
+ the feature the unknown register is in, and REG_NAME is the name of the
+ register from the target description. The POSSIBLE_REGNUM is a proposed
+ (GDB internal) number for this register.
+
+ The callback function can return, (-1) to indicate that the register
+ should not be assigned POSSIBLE_REGNUM now (though it might be later),
+ GDB will number the register automatically later on. Return
+ POSSIBLE_REGNUM (or greater) to have this register assigned that number.
+ Returning a value less that POSSIBLE_REGNUM is also acceptable, but take
+ care not to clash with a register number that has already been
+ assigned.
+
+ The callback will always be called on the registers in the order they
+ appear in the target description. This means all unknown registers
+ within a single feature will be called one after another. */
+
+typedef int (*tdesc_unknown_register_ftype)
+ (struct gdbarch *gdbarch, tdesc_feature *feature,
+ const char *reg_name, int possible_regnum);
+
/* Update GDBARCH to use the TARGET_DESC for registers. TARGET_DESC
may be GDBARCH's target description or (if GDBARCH does not have
one which describes registers) another target description
void tdesc_use_registers (struct gdbarch *gdbarch,
const struct target_desc *target_desc,
- struct tdesc_arch_data *early_data);
+ struct tdesc_arch_data *early_data,
+ tdesc_unknown_register_ftype unk_reg_cb = NULL);
/* Allocate initial data for validation of a target description during
gdbarch initialization. */