[PATCH 4/6] Disassembly unit test: disassemble one instruction
Luis Machado
lgustavo@codesourcery.com
Tue Jan 17 14:33:00 GMT 2017
On 01/16/2017 04:02 AM, Yao Qi wrote:
> This patch adds one unit test, which disassemble one instruction for
> every gdbarch if available. The test needs one valid instruction of
> each gdbarch, and most of them are got from breakpoint instruction.
> For the rest gdbarch whose breakpoint instruction isn't a valid
> instruction, I copy one instruction from the gas/testsuite/gas/
> directory.
>
> I get the valid instruction of most gdbarch except ia64, mep, mips,
> tic6x, and xtensa. People familiar with these arch should be easy
> to extend the test.
>
> In order to achieve "do the unit test for every gdbarch", I add
> selftest-arch.[c,h], so that we can register a function pointer,
> which has one argument gdbarch. selftest.c will iterate over all
> gdbarches to call the registered function pointer.
>
> v2:
> - Add comments for getting breakpoint instructions for score and
> nios2,
> - Provide more contents in gdb_disassembler_test::read_memory if
> caller requests more than one instruction,
> - Stop using compound literal,
> - Use null_stream,
> - Split "selftest for each gdbarch" out of selftest.{c,h},
>
> gdb:
>
> 2017-01-13 Yao Qi <yao.qi@linaro.org>
>
> * Makefile.in (SFILES): Add disasm-selftests.c and
> selftest-arch.c.
> (COMMON_OBS): Add disasm-selftests.o and selftest-arch.o.
> * disasm-selftests.c: New file.
> * selftest-arch.c: New file.
> * selftest-arch.h: New file.
> ---
> gdb/Makefile.in | 5 ++
> gdb/disasm-selftests.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++
> gdb/selftest-arch.c | 103 ++++++++++++++++++++++++++++
> gdb/selftest-arch.h | 26 ++++++++
> 4 files changed, 312 insertions(+)
> create mode 100644 gdb/disasm-selftests.c
> create mode 100644 gdb/selftest-arch.c
> create mode 100644 gdb/selftest-arch.h
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 3ce7d69..e0fe442 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -1039,6 +1039,7 @@ SFILES = \
> dfp.c \
> dictionary.c \
> disasm.c \
> + disasm-selftests.c \
> doublest.c \
> dtrace-probe.c \
> dummy-frame.c \
> @@ -1140,6 +1141,7 @@ SFILES = \
> rust-exp.y \
> rust-lang.c \
> selftest.c \
> + selftest-arch.c \
> sentinel-frame.c \
> ser-base.c \
> ser-event.c \
> @@ -1396,6 +1398,7 @@ HFILES_NO_SRCDIR = \
> rs6000-tdep.h \
> s390-linux-tdep.h \
> score-tdep.h \
> + selftest-arch.h \
> sentinel-frame.h \
> ser-base.h \
> ser-event.h \
> @@ -1643,6 +1646,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
> dfp.o \
> dictionary.o \
> disasm.o \
> + disasm-selftests.o \
> doublest.o \
> dummy-frame.o \
> dwarf2-frame.o \
> @@ -1744,6 +1748,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
> run-time-clock.o \
> rust-lang.o \
> selftest.o \
> + selftest-arch.o \
> sentinel-frame.o \
> ser-event.o \
> serial.o \
> diff --git a/gdb/disasm-selftests.c b/gdb/disasm-selftests.c
> new file mode 100644
> index 0000000..46a0a21
> --- /dev/null
> +++ b/gdb/disasm-selftests.c
> @@ -0,0 +1,178 @@
> +/* Self tests for disassembler for GDB, the GNU debugger.
> +
> + Copyright (C) 2017 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 "disasm.h"
> +
> +#if GDB_SELF_TEST
> +#include "selftest.h"
> +#include "selftest-arch.h"
> +
> +namespace selftests {
> +
> +/* Test disassembly of one instruction. */
> +
> +static void
> +gdb_disassembler_print_one_insn_test (struct gdbarch *gdbarch)
One suggestion. Do you think it is worth repeating the context of the
test in the function names? We already know this is a gdb disassembler
selftest from the name of the source file.
If we don't think it is worth it, we could significantly reduce the
length of the name of these functions.
> +{
> + size_t len = 0;
> + const gdb_byte *insn = NULL;
> +
> + switch (gdbarch_bfd_arch_info (gdbarch)->arch)
> + {
> + case bfd_arch_bfin:
> + /* M3.L = 0xe117 */
> + static const gdb_byte bfin_insn[] = {0x17, 0xe1, 0xff, 0xff};
> +
> + insn = bfin_insn;
> + len = sizeof (bfin_insn);
> + break;
> + case bfd_arch_arm:
> + /* mov r0, #0 */
> + static const gdb_byte arm_insn[] = {0x0, 0x0, 0xa0, 0xe3};
> +
> + insn = arm_insn;
> + len = sizeof (arm_insn);
> + break;
> + case bfd_arch_ia64:
> + case bfd_arch_mep:
> + case bfd_arch_mips:
> + case bfd_arch_tic6x:
> + case bfd_arch_xtensa:
> + return;
> + case bfd_arch_s390:
> + /* nopr %r7 */
> + static const gdb_byte s390_insn[] = {0x07, 0x07};
> +
> + insn = s390_insn;
> + len = sizeof (s390_insn);
> + break;
> + case bfd_arch_xstormy16:
> + /* nop */
> + static const gdb_byte xstormy16_insn[] = {0x0, 0x0};
> +
> + insn = xstormy16_insn;
> + len = sizeof (xstormy16_insn);
> + break;
> + case bfd_arch_arc:
> + {
> + /* PR 21003 */
> + if (gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_arc_arc601)
> + return;
> + }
> + case bfd_arch_nios2:
> + case bfd_arch_score:
> + /* nios2 and score need to know the current instruction to select
> + breakpoint instruction. Give the breakpoint instruction kind
> + explicitly. */
> + insn = gdbarch_sw_breakpoint_from_kind (gdbarch, 4, (int *) &len);
> + break;
> + default:
> + {
> + /* Test disassemble breakpoint instruction. */
> + CORE_ADDR pc = 0;
> + int kind = gdbarch_breakpoint_kind_from_pc (gdbarch, &pc);
> +
> + insn = gdbarch_sw_breakpoint_from_kind (gdbarch, kind,
> + (int *) &len);
> +
> + break;
> + }
> + }
> + SELF_CHECK (len > 0);
> +
> + /* Test gdb_disassembler for a given gdbarch by reading data from a
> + pre-allocated buffer. If you want to see the disassembled
> + instruction printed to gdb_stdout, set DISASSEMBLER_TEST_VERBOSE
> + to true. */
> +
> + class gdb_disassembler_test : public gdb_disassembler
> + {
> + public:
> +
> + const bool DISASSEMBLER_TEST_VERBOSE = false;
> +
> + explicit gdb_disassembler_test (struct gdbarch *gdbarch,
> + const gdb_byte *insn,
> + size_t len)
> + : gdb_disassembler (gdbarch,
> + (DISASSEMBLER_TEST_VERBOSE
> + ? gdb_stdout : null_stream ()),
> + gdb_disassembler_test::read_memory),
> + m_insn (insn), m_len (len)
> + {
> + }
> +
> + int
Can this ever return negative? If not, then unsigned? This ties down
with the comment on the other patch.
> + print_insn (CORE_ADDR memaddr)
> + {
> + if (DISASSEMBLER_TEST_VERBOSE)
> + {
> + fprintf_unfiltered (stream (), "%s ",
> + gdbarch_bfd_arch_info (arch ())->arch_name);
> + }
> +
> + int len = gdb_disassembler::print_insn (memaddr);
> +
> + if (DISASSEMBLER_TEST_VERBOSE)
> + fprintf_unfiltered (stream (), "\n");
> +
> + return len;
> + }
> +
> + private:
> + /* A buffer contain one instruction. */
"A buffer containing..." or "A buffer contains ..."
> + const gdb_byte *m_insn;
> +
> + /* Length of the buffer. */
> + size_t m_len;
> +
> + static int read_memory (bfd_vma memaddr, gdb_byte *myaddr,
> + unsigned int len, struct disassemble_info *info)
> + {
> + gdb_disassembler_test *self
> + = static_cast<gdb_disassembler_test *>(info->application_data);
> +
> + /* The disassembler in opcodes may read more data than one
> + instruction. */
> + for (unsigned int i = 0; i < len; i++)
> + myaddr[i] = self->m_insn[(memaddr + i) % self->m_len];
> +
> + return 0;
> + }
> + };
> +
> + gdb_disassembler_test di (gdbarch, insn, len);
> +
> + SELF_CHECK (di.print_insn (0) == len);
> +}
> +
> +} // namespace selftests
> +#endif /* GDB_SELF_TEST */
> +
> +/* Suppress warning from -Wmissing-prototypes. */
> +extern initialize_file_ftype _initialize_disasm_test;
> +
> +void
> +_initialize_disasm_test (void)
> +{
> +#if GDB_SELF_TEST
> + register_self_test (selftests::gdb_disassembler_print_one_insn_test);
> +#endif
> +}
> diff --git a/gdb/selftest-arch.c b/gdb/selftest-arch.c
> new file mode 100644
> index 0000000..aa716be
> --- /dev/null
> +++ b/gdb/selftest-arch.c
> @@ -0,0 +1,103 @@
> +/* GDB self-test for each gdbarch.
> + Copyright (C) 2017 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"
> +
> +#if GDB_SELF_TEST
> +#include "selftest.h"
> +#include "selftest-arch.h"
> +#include "arch-utils.h"
> +
> +static std::vector<self_test_function_with_gdbarch *> gdbarch_tests;
> +
> +void
> +register_self_test (self_test_function_with_gdbarch *function)
> +{
> + gdbarch_tests.push_back (function);
> +}
> +
> +namespace selftests {
> +
> +static void
> +tests_with_arch (void)
> +{
> + int failed = 0;
> +
> + for (const auto &f : gdbarch_tests)
> + {
> + const char **arches = gdbarch_printable_names ();
> + int i;
> +
> + for (i = 0; arches[i] != NULL; i++)
> + {
> + if (strcmp ("fr300", arches[i]) == 0)
> + {
> + /* PR 20946 */
> + continue;
> + }
> + else if (strcmp ("powerpc:EC603e", arches[i]) == 0
> + || strcmp ("powerpc:e500mc", arches[i]) == 0
> + || strcmp ("powerpc:e500mc64", arches[i]) == 0
> + || strcmp ("powerpc:titan", arches[i]) == 0
> + || strcmp ("powerpc:vle", arches[i]) == 0
> + || strcmp ("powerpc:e5500", arches[i]) == 0
> + || strcmp ("powerpc:e6500", arches[i]) == 0)
> + {
> + /* PR 19797 */
> + continue;
> + }
> +
> + QUIT;
> +
> + TRY
> + {
> + struct gdbarch_info info;
> +
> + gdbarch_info_init (&info);
> + info.bfd_arch_info = bfd_scan_arch (arches[i]);
> +
> + struct gdbarch *gdbarch = gdbarch_find_by_info (info);
> + SELF_CHECK (gdbarch != NULL);
> + f (gdbarch);
> + }
> + CATCH (ex, RETURN_MASK_ERROR)
> + {
> + ++failed;
> + exception_fprintf (gdb_stderr, ex,
> + _("Self test failed: arch %s: "), arches[i]);
> + }
> + END_CATCH
> + }
> + }
> +
> + SELF_CHECK (failed == 0);
> +}
> +
> +} // namespace selftests
> +#endif /* GDB_SELF_TEST */
> +
> +/* Suppress warning from -Wmissing-prototypes. */
> +extern initialize_file_ftype _initialize_selftests_with_arch;
> +
> +void
> +_initialize_selftests_with_arch (void)
> +{
> +#if GDB_SELF_TEST
> + register_self_test (selftests::tests_with_arch);
> +#endif
> +}
> diff --git a/gdb/selftest-arch.h b/gdb/selftest-arch.h
> new file mode 100644
> index 0000000..d63c2d2
> --- /dev/null
> +++ b/gdb/selftest-arch.h
> @@ -0,0 +1,26 @@
> +/* GDB self-test for each gdbarch.
> + Copyright (C) 2017 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/>. */
> +
> +#ifndef SELFTEST_ARCH_H
> +#define SELFTEST_ARCH_H
> +
> +typedef void self_test_function_with_gdbarch (struct gdbarch *);
> +
> +extern void register_self_test (self_test_function_with_gdbarch *function);
> +
> +#endif /* SELFTEST_ARCH_H */
>
Otherwise looks OK
More information about the Gdb-patches
mailing list