
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.
179 lines
5.4 KiB
C
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);
|
|
}
|