binutils-gdb/gdb/gdbarch-selftests.c
Andrew Burgess 9a103324fe gdb: check for duplicate register names in selftest
Building on the previous commit, this commit extends the register_name
selftest to check for duplicate register names.

If two registers in the cooked register set (real + pseudo registers)
have the same name, then this will show up as duplicate registers in
the 'info all-registers' output, but the user will only be able to
interact with one copy of the register.

In this commit I extend the selftest that I added in the previous
commit to check for duplicate register names, I didn't include this
functionality in the previous commit because one architecture needed
fixing, and I wanted to keep those fixes separate from the fixes in
the previous commit.

The problematic architecture(s) are powerpc:750 and powerpc:604.  In
both of these cases the 'dabr' register appears twice, there's a
definition of dabr in power-oea.xml which is included into both
powerpc-604.xml and powerpc-750.xml.  Both of these later two xml
files also define the dabr register.

I'm hopeful that this change shouldn't break anything, but I don't
have the ability to actually test this change, however:

On the gdbserver side, neither powerpc-604.xml nor powerpc-750.xml are
mentioned in gdbserver/configure.srv, which I think means that
gdbserver will never use these descriptions, and,

Within GDB the problematic descriptions are held in the variables
tdesc_powerpc_604 and tdesc_powerpc_750, which are only mentioned in
the variants array in rs6000-tdep.c, this is used when looking up a
description based on the architecture.

For a native Linux target however, this will not be used as
ppc_linux_nat_target::read_description exists, which calls
ppc_linux_match_description, which I don't believe can return either
of the problematic descriptions.

This leaves the other native targets, FreeBSD, AIX, etc.  These don't
appear to override the ::read_description method, so will potentially
return the problematic descriptions, but, in each case I think the
::fetch_registers and ::store_registers methods will ignore the dabr
register, which will leave the register as <unavailable>.

So, my proposed solution is to just remove the duplicate register from
each of powerpc-604.xml and powerpc-750.xml, then regenerate the
corresponding C++ source file.  With this change made, the selftest
now passes for all architectures.
2022-10-02 14:21:24 +01:00

179 lines
5.4 KiB
C

/* Self tests for gdbarch for GDB, the GNU debugger.
Copyright (C) 2017-2022 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "gdbsupport/selftest.h"
#include "selftest-arch.h"
#include "target.h"
#include "test-target.h"
#include "target-float.h"
#include "gdbsupport/def-vector.h"
#include "gdbarch.h"
#include "scoped-mock-context.h"
#include <map>
namespace selftests {
/* Test gdbarch methods register_to_value and value_to_register. */
static void
register_to_value_test (struct gdbarch *gdbarch)
{
const struct builtin_type *builtin = builtin_type (gdbarch);
struct type *types[] =
{
builtin->builtin_void,
builtin->builtin_char,
builtin->builtin_short,
builtin->builtin_int,
builtin->builtin_long,
builtin->builtin_signed_char,
builtin->builtin_unsigned_short,
builtin->builtin_unsigned_int,
builtin->builtin_unsigned_long,
builtin->builtin_float,
builtin->builtin_double,
builtin->builtin_long_double,
builtin->builtin_complex,
builtin->builtin_double_complex,
builtin->builtin_string,
builtin->builtin_bool,
builtin->builtin_long_long,
builtin->builtin_unsigned_long_long,
builtin->builtin_int8,
builtin->builtin_uint8,
builtin->builtin_int16,
builtin->builtin_uint16,
builtin->builtin_int32,
builtin->builtin_uint32,
builtin->builtin_int64,
builtin->builtin_uint64,
builtin->builtin_int128,
builtin->builtin_uint128,
builtin->builtin_char16,
builtin->builtin_char32,
};
scoped_mock_context<test_target_ops> mockctx (gdbarch);
struct frame_info *frame = get_current_frame ();
const int num_regs = gdbarch_num_cooked_regs (gdbarch);
/* Test gdbarch methods register_to_value and value_to_register with
different combinations of register numbers and types. */
for (const auto &type : types)
{
for (auto regnum = 0; regnum < num_regs; regnum++)
{
if (gdbarch_convert_register_p (gdbarch, regnum, type))
{
std::vector<gdb_byte> expected (type->length (), 0);
if (type->code () == TYPE_CODE_FLT)
{
/* Generate valid float format. */
target_float_from_string (expected.data (), type, "1.25");
}
else
{
for (auto j = 0; j < expected.size (); j++)
expected[j] = (regnum + j) % 16;
}
gdbarch_value_to_register (gdbarch, frame, regnum, type,
expected.data ());
/* Allocate two bytes more for overflow check. */
std::vector<gdb_byte> buf (type->length () + 2, 0);
int optim, unavail, ok;
/* Set the fingerprint in the last two bytes. */
buf [type->length ()]= 'w';
buf [type->length () + 1]= 'l';
ok = gdbarch_register_to_value (gdbarch, frame, regnum, type,
buf.data (), &optim, &unavail);
SELF_CHECK (ok);
SELF_CHECK (!optim);
SELF_CHECK (!unavail);
SELF_CHECK (buf[type->length ()] == 'w');
SELF_CHECK (buf[type->length () + 1] == 'l');
for (auto k = 0; k < type->length (); k++)
SELF_CHECK (buf[k] == expected[k]);
}
}
}
}
/* Test function gdbarch_register_name. */
static void
register_name_test (struct gdbarch *gdbarch)
{
scoped_mock_context<test_target_ops> mockctx (gdbarch);
/* Track the number of times each register name appears. */
std::map<const std::string, int> name_counts;
const int num_regs = gdbarch_num_cooked_regs (gdbarch);
for (auto regnum = 0; regnum < num_regs; regnum++)
{
/* If a register is to be hidden from the user then we should get
back an empty string, not nullptr. Every other register should
return a non-empty string. */
const char *name = gdbarch_register_name (gdbarch, regnum);
if (run_verbose() && name == nullptr)
debug_printf ("arch: %s, register: %d returned nullptr\n",
gdbarch_bfd_arch_info (gdbarch)->printable_name,
regnum);
SELF_CHECK (name != nullptr);
/* Every register name, that is not the empty string, should be
unique. If this is not the case then the user will see duplicate
copies of the register in e.g. 'info registers' output, but will
only be able to interact with one of the copies. */
if (*name != '\0')
{
std::string s (name);
name_counts[s]++;
if (run_verbose() && name_counts[s] > 1)
debug_printf ("arch: %s, register: %d (%s) is a duplicate\n",
gdbarch_bfd_arch_info (gdbarch)->printable_name,
regnum, name);
SELF_CHECK (name_counts[s] == 1);
}
}
}
} // namespace selftests
void _initialize_gdbarch_selftests ();
void
_initialize_gdbarch_selftests ()
{
selftests::register_test_foreach_arch ("register_to_value",
selftests::register_to_value_test);
selftests::register_test_foreach_arch ("register_name",
selftests::register_name_test);
}