gdb/riscv: Add command to switch between numeric & abi register names

In RISC-V, the general registers can be shown in their abi
form (e.g. sp, a0) or their numeric form (e.g. x2, x10).
Depending on context/preference, someone may prefer to
see one form over the other. The disassembler already
supports this configuration, which can be changed using
the 'set disassembler-options numeric' command.

This commit adds a new set/show command to change gdb's
preference: 'set riscv numeric-registers-names on/off'.

If on, 'info registers' and other situations will print
the numeric register names, rather than the abi versions.
The alias generation has been modified so that the abi
versions are still available for access if specifically
requested such as 'print $ra'. This was done by changing
the behaviour of the code which adds the aliases: all
register names will be added as aliases, even if the name
is the primary one.

There is also no functional downside to adding aliases
which are surplus-to-requirement, since they will be
ignored if there is a 'true' register with the same
name.

Approved-By: Andrew Burgess <aburgess@redhat.com>
This commit is contained in:
Ciaran Woodward
2023-09-13 12:32:55 +01:00
parent fb570a6fe3
commit 2047479c10
3 changed files with 86 additions and 27 deletions

View File

@@ -32,6 +32,12 @@ maintenance check psymtabs
maintenance check symtabs
Renamed from maintenance check-symtabs
set riscv numeric-register-names on|off
show riscv numeric-register-names
Controls whether GDB refers to risc-v registers by their numeric names
(e.g 'x1') or their abi names (e.g. 'ra').
Defaults to 'off', matching the old behaviour (abi names).
* Python API
** New class gdb.Color for dealing with colors.

View File

@@ -26465,6 +26465,7 @@ all uses of @value{GDBN} with the architecture, both native and cross.
* Sparc64::
* S12Z::
* AMD GPU:: @acronym{AMD GPU} architectures
* RISC-V::
@end menu
@node AArch64
@@ -27428,6 +27429,29 @@ was not attached.
@end enumerate
@node RISC-V
@subsection RISC-V
@cindex RISC-V support
When @value{GDBN} is debugging a RISC-V architecture, it provides the
following special commands:
@table @code
@item set riscv numeric-register-names @r{[}on@r{|}off@r{]}
@kindex set riscv numeric-register-names
This command controls whether @value{GDBN} displays RISC-V register names using
their numeric or abi names. When @samp{on}, @value{GDBN} displays registers
by their numeric names (e.g. @samp{x1}). When @samp{off}, @value{GDBN}
displays registers by their abi names (e.g. @samp{ra}). The default is
@samp{off}.
@item show riscv numeric-register-names
Show whether @value{GDBN} will refer to registers by their numeric names.
@end table
@node Controlling GDB
@chapter Controlling @value{GDBN}

View File

@@ -134,6 +134,11 @@ static const char *riscv_feature_name_vector = "org.gnu.gdb.riscv.vector";
/* The current set of options to be passed to the disassembler. */
static std::string riscv_disassembler_options;
/* When true, prefer to show register names in their numeric form (eg. x28).
When false, show them in their abi form (eg. t3). */
static bool numeric_register_names = false;
/* Cached information about a frame. */
struct riscv_unwind_cache
@@ -226,11 +231,9 @@ struct riscv_register_feature
/* Look in FEATURE for a register with a name from this classes names
list. If the register is found then register its number with
TDESC_DATA and add all its aliases to the ALIASES list.
PREFER_FIRST_NAME_P is used when deciding which aliases to create. */
TDESC_DATA and add all its aliases to the ALIASES list. */
bool check (struct tdesc_arch_data *tdesc_data,
const struct tdesc_feature *feature,
bool prefer_first_name_p,
std::vector<riscv_pending_register_alias> *aliases) const;
};
@@ -265,7 +268,6 @@ bool
riscv_register_feature::register_info::check
(struct tdesc_arch_data *tdesc_data,
const struct tdesc_feature *feature,
bool prefer_first_name_p,
std::vector<riscv_pending_register_alias> *aliases) const
{
for (const char *name : this->names)
@@ -276,16 +278,11 @@ riscv_register_feature::register_info::check
{
/* We know that the target description mentions this
register. In RISCV_REGISTER_NAME we ensure that GDB
always uses the first name for each register, so here we
add aliases for all of the remaining names. */
int start_index = prefer_first_name_p ? 1 : 0;
for (int i = start_index; i < this->names.size (); ++i)
{
const char *alias = this->names[i];
if (alias == name && !prefer_first_name_p)
continue;
aliases->emplace_back (alias, (void *) &this->regnum);
}
always refers to the register by its user-configured name.
Here, we add aliases for all possible names, so that
the user can refer to the register by any of them. */
for (const char *alias : this->names)
aliases->emplace_back (alias, (void *) &this->regnum);
return true;
}
}
@@ -342,6 +339,8 @@ struct riscv_xreg_feature : public riscv_register_feature
const char *register_name (int regnum) const
{
gdb_assert (regnum >= RISCV_ZERO_REGNUM && regnum <= m_registers.size ());
if (numeric_register_names && (regnum <= RISCV_ZERO_REGNUM + 31))
return m_registers[regnum].names[1];
return m_registers[regnum].names[0];
}
@@ -360,7 +359,7 @@ struct riscv_xreg_feature : public riscv_register_feature
bool seen_an_optional_reg_p = false;
for (const auto &reg : m_registers)
{
bool found = reg.check (tdesc_data, feature_cpu, true, aliases);
bool found = reg.check (tdesc_data, feature_cpu, aliases);
bool is_optional_reg_p = (reg.regnum >= RISCV_ZERO_REGNUM + 16
&& reg.regnum < RISCV_ZERO_REGNUM + 32);
@@ -444,6 +443,8 @@ struct riscv_freg_feature : public riscv_register_feature
gdb_assert (regnum >= RISCV_FIRST_FP_REGNUM
&& regnum <= RISCV_LAST_FP_REGNUM);
regnum -= RISCV_FIRST_FP_REGNUM;
if (numeric_register_names && (regnum <= 31))
return m_registers[regnum].names[1];
return m_registers[regnum].names[0];
}
@@ -469,7 +470,7 @@ struct riscv_freg_feature : public riscv_register_feature
are missing this is not fatal. */
for (const auto &reg : m_registers)
{
bool found = reg.check (tdesc_data, feature_fpu, true, aliases);
bool found = reg.check (tdesc_data, feature_fpu, aliases);
bool is_ctrl_reg_p = reg.regnum > RISCV_LAST_FP_REGNUM;
@@ -543,7 +544,7 @@ struct riscv_virtual_feature : public riscv_register_feature
/* We don't check the return value from the call to check here, all the
registers in this feature are optional. */
for (const auto &reg : m_registers)
reg.check (tdesc_data, feature_virtual, true, aliases);
reg.check (tdesc_data, feature_virtual, aliases);
return true;
}
@@ -583,7 +584,7 @@ struct riscv_csr_feature : public riscv_register_feature
/* We don't check the return value from the call to check here, all the
registers in this feature are optional. */
for (const auto &reg : m_registers)
reg.check (tdesc_data, feature_csr, true, aliases);
reg.check (tdesc_data, feature_csr, aliases);
return true;
}
@@ -683,7 +684,7 @@ struct riscv_vector_feature : public riscv_register_feature
/* Check all of the vector registers are present. */
for (const auto &reg : m_registers)
{
if (!reg.check (tdesc_data, feature_vector, true, aliases))
if (!reg.check (tdesc_data, feature_vector, aliases))
return false;
}
@@ -736,6 +737,18 @@ show_use_compressed_breakpoints (struct ui_file *file, int from_tty,
"to %s.\n"), value);
}
/* The show callback for 'show riscv numeric-register-names'. */
static void
show_numeric_register_names (struct ui_file *file, int from_tty,
struct cmd_list_element *c,
const char *value)
{
gdb_printf (file,
_("Displaying registers with their numeric names is %s.\n"),
value);
}
/* The set and show lists for 'set riscv' and 'show riscv' prefixes. */
static struct cmd_list_element *setriscvcmdlist = NULL;
@@ -918,17 +931,18 @@ riscv_register_name (struct gdbarch *gdbarch, int regnum)
if (name[0] == '\0')
return name;
/* We want GDB to use the ABI names for registers even if the target
gives us a target description with the architectural name. For
example we want to see 'ra' instead of 'x1' whatever the target
description called it. */
/* We want GDB to use the user-configured names for registers even
if the target gives us a target description with something different.
For example, we want to see 'ra' if numeric_register_names is false,
or 'x1' if numeric_register_names is true - regardless of what the
target description called it. */
if (regnum >= RISCV_ZERO_REGNUM && regnum < RISCV_FIRST_FP_REGNUM)
return riscv_xreg_feature.register_name (regnum);
/* Like with the x-regs we prefer the abi names for the floating point
registers. If the target doesn't have floating point registers then
the tdesc_register_name call above should have returned an empty
string. */
/* Like with the x-regs we refer to the user configuration for the
floating point register names. If the target doesn't have floating
point registers then the tdesc_register_name call above should have
returned an empty string. */
if (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
{
gdb_assert (riscv_has_fp_regs (gdbarch));
@@ -4836,4 +4850,19 @@ this option can be used."),
show_use_compressed_breakpoints,
&setriscvcmdlist,
&showriscvcmdlist);
add_setshow_boolean_cmd ("numeric-register-names", no_class,
&numeric_register_names,
_("\
Set displaying registers with numeric names instead of abi names."), _("\
Show whether registers are displayed with numeric names instead of abi names."),
_("\
When enabled, registers will be shown with their numeric names (such as x28)\n\
instead of their abi names (such as t0).\n\
Also consider using the 'set disassembler-options numeric' command for the\n\
equivalent change in the disassembler output."),
NULL,
show_numeric_register_names,
&setriscvcmdlist,
&showriscvcmdlist);
}