Home | History | Annotate | Line # | Download | only in gdb
disasm-selftests.c revision 1.1.1.6
      1 /* Self tests for disassembler for GDB, the GNU debugger.
      2 
      3    Copyright (C) 2017-2024 Free Software Foundation, Inc.
      4 
      5    This file is part of GDB.
      6 
      7    This program is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3 of the License, or
     10    (at your option) any later version.
     11 
     12    This program is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19 
     20 #include "disasm.h"
     21 #include "gdbsupport/selftest.h"
     22 #include "selftest-arch.h"
     23 #include "gdbarch.h"
     24 
     25 namespace selftests {
     26 
     27 /* Return a pointer to a buffer containing an instruction that can be
     28    disassembled for architecture GDBARCH.  *LEN will be set to the length
     29    of the returned buffer.
     30 
     31    If there's no known instruction to disassemble for GDBARCH (because we
     32    haven't figured on out, not because no instructions exist) then nullptr
     33    is returned, and *LEN is set to 0.  */
     34 
     35 static const gdb_byte *
     36 get_test_insn (struct gdbarch *gdbarch, size_t *len)
     37 {
     38   *len = 0;
     39   const gdb_byte *insn = nullptr;
     40 
     41   switch (gdbarch_bfd_arch_info (gdbarch)->arch)
     42     {
     43     case bfd_arch_bfin:
     44       /* M3.L = 0xe117 */
     45       static const gdb_byte bfin_insn[] = {0x17, 0xe1, 0xff, 0xff};
     46 
     47       insn = bfin_insn;
     48       *len = sizeof (bfin_insn);
     49       break;
     50     case bfd_arch_arm:
     51       /* mov     r0, #0 */
     52       static const gdb_byte arm_insn[] = {0x0, 0x0, 0xa0, 0xe3};
     53 
     54       insn = arm_insn;
     55       *len = sizeof (arm_insn);
     56       break;
     57     case bfd_arch_ia64:
     58       /* We get:
     59 	 internal-error: gdbarch_sw_breakpoint_from_kind:
     60 	 Assertion `gdbarch->sw_breakpoint_from_kind != NULL' failed.  */
     61       return insn;
     62     case bfd_arch_mep:
     63       /* Disassembles as '*unknown*' insn, then len self-check fails.  */
     64       return insn;
     65     case bfd_arch_mips:
     66       if (gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_mips16)
     67 	/* Disassembles insn, but len self-check fails.  */
     68 	return insn;
     69       goto generic_case;
     70     case bfd_arch_tic6x:
     71       /* Disassembles as '<undefined instruction 0x56454314>' insn, but len
     72 	 self-check passes, so let's allow it.  */
     73       goto generic_case;
     74     case bfd_arch_xtensa:
     75       /* Disassembles insn, but len self-check fails.  */
     76       return insn;
     77     case bfd_arch_or1k:
     78       /* Disassembles as '*unknown*' insn, but len self-check passes, so let's
     79 	 allow it.  */
     80       goto generic_case;
     81     case bfd_arch_s390:
     82       /* nopr %r7 */
     83       static const gdb_byte s390_insn[] = {0x07, 0x07};
     84 
     85       insn = s390_insn;
     86       *len = sizeof (s390_insn);
     87       break;
     88     case bfd_arch_xstormy16:
     89       /* nop */
     90       static const gdb_byte xstormy16_insn[] = {0x0, 0x0};
     91 
     92       insn = xstormy16_insn;
     93       *len = sizeof (xstormy16_insn);
     94       break;
     95     case bfd_arch_score:
     96     case bfd_arch_riscv:
     97       /* riscv and score need to know the current instruction
     98 	 to select breakpoint instruction.  Give the breakpoint
     99 	 instruction kind explicitly.  */
    100       {
    101 	int bplen;
    102 	insn = gdbarch_sw_breakpoint_from_kind (gdbarch, 4, &bplen);
    103 	*len = bplen;
    104       }
    105       break;
    106     case bfd_arch_arc:
    107       /* PR 21003 */
    108       if (gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_arc_arc601)
    109 	return insn;
    110       goto generic_case;
    111     case bfd_arch_z80:
    112       {
    113 	int bplen;
    114 	insn = gdbarch_sw_breakpoint_from_kind (gdbarch, 0x0008, &bplen);
    115 	*len = bplen;
    116       }
    117       break;
    118     case bfd_arch_i386:
    119       {
    120 	const struct bfd_arch_info *info = gdbarch_bfd_arch_info (gdbarch);
    121 	/* The disassembly tests will fail on x86-linux because
    122 	   opcodes rejects an attempt to disassemble for an arch with
    123 	   a 64-bit address size when bfd_vma is 32-bit.  */
    124 	if (info->bits_per_address > sizeof (bfd_vma) * CHAR_BIT)
    125 	  return insn;
    126       }
    127       [[fallthrough]];
    128     default:
    129     generic_case:
    130       {
    131 	/* Test disassemble breakpoint instruction.  */
    132 	CORE_ADDR pc = 0;
    133 	int kind;
    134 	int bplen;
    135 
    136 	struct gdbarch_info info;
    137 	info.bfd_arch_info = gdbarch_bfd_arch_info (gdbarch);
    138 
    139 	enum gdb_osabi it;
    140 	bool found = false;
    141 	for (it = GDB_OSABI_UNKNOWN; it != GDB_OSABI_INVALID;
    142 	     it = static_cast<enum gdb_osabi>(static_cast<int>(it) + 1))
    143 	  {
    144 	    if (it == GDB_OSABI_UNKNOWN)
    145 	      continue;
    146 
    147 	    info.osabi = it;
    148 
    149 	    if (it != GDB_OSABI_NONE)
    150 	      {
    151 		if (!has_gdb_osabi_handler (info))
    152 		  /* Unsupported.  Skip to prevent warnings like:
    153 		     A handler for the OS ABI <x> is not built into this
    154 		     configuration of GDB.  Attempting to continue with the
    155 		     default <y> settings.  */
    156 		  continue;
    157 	      }
    158 
    159 	    gdbarch = gdbarch_find_by_info (info);
    160 	    SELF_CHECK (gdbarch != NULL);
    161 
    162 	    try
    163 	      {
    164 		kind = gdbarch_breakpoint_kind_from_pc (gdbarch, &pc);
    165 		insn = gdbarch_sw_breakpoint_from_kind (gdbarch, kind, &bplen);
    166 	      }
    167 	    catch (const gdb_exception_error &)
    168 	      {
    169 		continue;
    170 	      }
    171 	    found = true;
    172 	    break;
    173 	  }
    174 
    175 	/* Assert that we have found an instruction to disassemble.  */
    176 	SELF_CHECK (found);
    177 
    178 	*len = bplen;
    179 	break;
    180       }
    181     }
    182   SELF_CHECK (*len > 0);
    183 
    184   return insn;
    185 }
    186 
    187 /* Test disassembly of one instruction.  */
    188 
    189 static void
    190 print_one_insn_test (struct gdbarch *gdbarch)
    191 {
    192   size_t len;
    193   const gdb_byte *insn = get_test_insn (gdbarch, &len);
    194 
    195   if (insn == nullptr)
    196     return;
    197 
    198   /* Test gdb_disassembler for a given gdbarch by reading data from a
    199      pre-allocated buffer.  If you want to see the disassembled
    200      instruction printed to gdb_stdout, use maint selftest -verbose.  */
    201 
    202   class gdb_disassembler_test : public gdb_disassembler
    203   {
    204   public:
    205 
    206     explicit gdb_disassembler_test (struct gdbarch *gdbarch,
    207 				    const gdb_byte *insn,
    208 				    size_t len)
    209       : gdb_disassembler (gdbarch,
    210 			  (run_verbose () ? gdb_stdlog : &null_stream),
    211 			  gdb_disassembler_test::read_memory),
    212 	m_insn (insn), m_len (len)
    213     {
    214     }
    215 
    216     int
    217     print_insn (CORE_ADDR memaddr)
    218     {
    219       int len = gdb_disassembler::print_insn (memaddr);
    220 
    221       if (run_verbose ())
    222 	debug_printf ("\n");
    223 
    224       return len;
    225     }
    226 
    227   private:
    228     /* A buffer contain one instruction.  */
    229     const gdb_byte *m_insn;
    230 
    231     /* Length of the buffer.  */
    232     size_t m_len;
    233 
    234     static int read_memory (bfd_vma memaddr, gdb_byte *myaddr,
    235 			    unsigned int len,
    236 			    struct disassemble_info *info) noexcept
    237     {
    238       gdb_disassembler_test *self
    239 	= static_cast<gdb_disassembler_test *>(info->application_data);
    240 
    241       /* The disassembler in opcodes may read more data than one
    242 	 instruction.  Supply infinite consecutive copies
    243 	 of the same instruction.  */
    244       for (size_t i = 0; i < len; i++)
    245 	myaddr[i] = self->m_insn[(memaddr + i) % self->m_len];
    246 
    247       return 0;
    248     }
    249   };
    250 
    251   gdb_disassembler_test di (gdbarch, insn, len);
    252 
    253   SELF_CHECK (di.print_insn (0) == len);
    254 }
    255 
    256 /* Test the gdb_buffered_insn_length function.  */
    257 
    258 static void
    259 buffered_insn_length_test (struct gdbarch *gdbarch)
    260 {
    261   size_t buf_len;
    262   const gdb_byte *insn = get_test_insn (gdbarch, &buf_len);
    263 
    264   if (insn == nullptr)
    265     return;
    266 
    267   /* The tic6x architecture is VLIW.  Disassembling requires that the
    268      entire instruction bundle be available.  However, the buffer we got
    269      back from get_test_insn only contains a single instruction, which is
    270      just part of an instruction bundle.  As a result, the disassemble will
    271      fail.  To avoid this, skip tic6x tests now.  */
    272   if (gdbarch_bfd_arch_info (gdbarch)->arch == bfd_arch_tic6x)
    273     return;
    274 
    275   CORE_ADDR insn_address = 0;
    276   int calculated_len = gdb_buffered_insn_length (gdbarch, insn, buf_len,
    277 						 insn_address);
    278 
    279   SELF_CHECK (calculated_len == buf_len);
    280 }
    281 
    282 /* Test disassembly on memory error.  */
    283 
    284 static void
    285 memory_error_test (struct gdbarch *gdbarch)
    286 {
    287   class gdb_disassembler_test : public gdb_disassembler
    288   {
    289   public:
    290     gdb_disassembler_test (struct gdbarch *gdbarch)
    291       : gdb_disassembler (gdbarch, &null_stream,
    292 			  gdb_disassembler_test::read_memory)
    293     {
    294     }
    295 
    296     static int read_memory (bfd_vma memaddr, gdb_byte *myaddr,
    297 			    unsigned int len,
    298 			    struct disassemble_info *info) noexcept
    299     {
    300       /* Always return an error.  */
    301       return -1;
    302     }
    303   };
    304 
    305   if (gdbarch_bfd_arch_info (gdbarch)->arch == bfd_arch_i386)
    306     {
    307       const struct bfd_arch_info *info = gdbarch_bfd_arch_info (gdbarch);
    308       /* This test will fail on x86-linux because opcodes rejects an
    309 	 attempt to disassemble for an arch with a 64-bit address size
    310 	 when bfd_vma is 32-bit.  */
    311       if (info->bits_per_address > sizeof (bfd_vma) * CHAR_BIT)
    312 	return;
    313     }
    314 
    315   gdb_disassembler_test di (gdbarch);
    316   bool saw_memory_error = false;
    317 
    318   try
    319     {
    320       di.print_insn (0);
    321     }
    322   catch (const gdb_exception_error &ex)
    323     {
    324       if (ex.error == MEMORY_ERROR)
    325 	saw_memory_error = true;
    326     }
    327 
    328   /* Expect MEMORY_ERROR.  */
    329   SELF_CHECK (saw_memory_error);
    330 }
    331 
    332 } // namespace selftests
    333 
    334 void _initialize_disasm_selftests ();
    335 void
    336 _initialize_disasm_selftests ()
    337 {
    338   selftests::register_test_foreach_arch ("print_one_insn",
    339 					 selftests::print_one_insn_test);
    340   selftests::register_test_foreach_arch ("memory_error",
    341 					 selftests::memory_error_test);
    342   selftests::register_test_foreach_arch ("buffered_insn_length",
    343 					 selftests::buffered_insn_length_test);
    344 }
    345