123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- /* Self tests for disassembler 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 "disasm.h"
- #include "gdbsupport/selftest.h"
- #include "selftest-arch.h"
- #include "gdbarch.h"
- namespace selftests {
- /* Test disassembly of one instruction. */
- static void
- print_one_insn_test (struct gdbarch *gdbarch)
- {
- 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_nios2:
- case bfd_arch_score:
- case bfd_arch_riscv:
- /* nios2, riscv, and score need to know the current instruction
- to select breakpoint instruction. Give the breakpoint
- instruction kind explicitly. */
- {
- int bplen;
- insn = gdbarch_sw_breakpoint_from_kind (gdbarch, 4, &bplen);
- len = bplen;
- }
- break;
- case bfd_arch_arc:
- /* PR 21003 */
- if (gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_arc_arc601)
- return;
- goto generic_case;
- case bfd_arch_i386:
- {
- const struct bfd_arch_info *info = gdbarch_bfd_arch_info (gdbarch);
- /* The disassembly tests will fail on x86-linux because
- opcodes rejects an attempt to disassemble for an arch with
- a 64-bit address size when bfd_vma is 32-bit. */
- if (info->bits_per_address > sizeof (bfd_vma) * CHAR_BIT)
- return;
- }
- /* fall through */
- default:
- generic_case:
- {
- /* Test disassemble breakpoint instruction. */
- CORE_ADDR pc = 0;
- int kind = gdbarch_breakpoint_kind_from_pc (gdbarch, &pc);
- int bplen;
- insn = gdbarch_sw_breakpoint_from_kind (gdbarch, kind, &bplen);
- len = bplen;
- 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, use maint selftest -verbose. */
- class gdb_disassembler_test : public gdb_disassembler
- {
- public:
- explicit gdb_disassembler_test (struct gdbarch *gdbarch,
- const gdb_byte *insn,
- size_t len)
- : gdb_disassembler (gdbarch,
- (run_verbose () ? gdb_stdout : &null_stream),
- gdb_disassembler_test::read_memory),
- m_insn (insn), m_len (len)
- {
- }
- int
- print_insn (CORE_ADDR memaddr)
- {
- if (run_verbose ())
- {
- gdb_printf (stream (), "%s ",
- gdbarch_bfd_arch_info (arch ())->arch_name);
- }
- int len = gdb_disassembler::print_insn (memaddr);
- if (run_verbose ())
- gdb_printf (stream (), "\n");
- return len;
- }
- private:
- /* A buffer contain one instruction. */
- 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. Supply infinite consecutive copies
- of the same instruction. */
- for (size_t 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);
- }
- /* Test disassembly on memory error. */
- static void
- memory_error_test (struct gdbarch *gdbarch)
- {
- class gdb_disassembler_test : public gdb_disassembler
- {
- public:
- gdb_disassembler_test (struct gdbarch *gdbarch)
- : gdb_disassembler (gdbarch, &null_stream,
- gdb_disassembler_test::read_memory)
- {
- }
- static int read_memory (bfd_vma memaddr, gdb_byte *myaddr,
- unsigned int len,
- struct disassemble_info *info)
- {
- /* Always return an error. */
- return -1;
- }
- };
- if (gdbarch_bfd_arch_info (gdbarch)->arch == bfd_arch_i386)
- {
- const struct bfd_arch_info *info = gdbarch_bfd_arch_info (gdbarch);
- /* This test will fail on x86-linux because opcodes rejects an
- attempt to disassemble for an arch with a 64-bit address size
- when bfd_vma is 32-bit. */
- if (info->bits_per_address > sizeof (bfd_vma) * CHAR_BIT)
- return;
- }
- gdb_disassembler_test di (gdbarch);
- bool saw_memory_error = false;
- try
- {
- di.print_insn (0);
- }
- catch (const gdb_exception_error &ex)
- {
- if (ex.error == MEMORY_ERROR)
- saw_memory_error = true;
- }
- /* Expect MEMORY_ERROR. */
- SELF_CHECK (saw_memory_error);
- }
- } // namespace selftests
- void _initialize_disasm_selftests ();
- void
- _initialize_disasm_selftests ()
- {
- selftests::register_test_foreach_arch ("print_one_insn",
- selftests::print_one_insn_test);
- selftests::register_test_foreach_arch ("memory_error",
- selftests::memory_error_test);
- }
|