Home | History | Annotate | Line # | Download | only in gdb
disasm-selftests.c revision 1.1.1.5
      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_nios2:
     96     case bfd_arch_score:
     97     case bfd_arch_riscv:
     98       /* nios2, riscv, and score need to know the current instruction
     99 	 to select breakpoint instruction.  Give the breakpoint
    100 	 instruction kind explicitly.  */
    101       {
    102 	int bplen;
    103 	insn = gdbarch_sw_breakpoint_from_kind (gdbarch, 4, &bplen);
    104 	*len = bplen;
    105       }
    106       break;
    107     case bfd_arch_arc:
    108       /* PR 21003 */
    109       if (gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_arc_arc601)
    110 	return insn;
    111       goto generic_case;
    112     case bfd_arch_z80:
    113       {
    114 	int bplen;
    115 	insn = gdbarch_sw_breakpoint_from_kind (gdbarch, 0x0008, &bplen);
    116 	*len = bplen;
    117       }
    118       break;
    119     case bfd_arch_i386:
    120       {
    121 	const struct bfd_arch_info *info = gdbarch_bfd_arch_info (gdbarch);
    122 	/* The disassembly tests will fail on x86-linux because
    123 	   opcodes rejects an attempt to disassemble for an arch with
    124 	   a 64-bit address size when bfd_vma is 32-bit.  */
    125 	if (info->bits_per_address > sizeof (bfd_vma) * CHAR_BIT)
    126 	  return insn;
    127       }
    128       [[fallthrough]];
    129     default:
    130     generic_case:
    131       {
    132 	/* Test disassemble breakpoint instruction.  */
    133 	CORE_ADDR pc = 0;
    134 	int kind;
    135 	int bplen;
    136 
    137 	struct gdbarch_info info;
    138 	info.bfd_arch_info = gdbarch_bfd_arch_info (gdbarch);
    139 
    140 	enum gdb_osabi it;
    141 	bool found = false;
    142 	for (it = GDB_OSABI_UNKNOWN; it != GDB_OSABI_INVALID;
    143 	     it = static_cast<enum gdb_osabi>(static_cast<int>(it) + 1))
    144 	  {
    145 	    if (it == GDB_OSABI_UNKNOWN)
    146 	      continue;
    147 
    148 	    info.osabi = it;
    149 
    150 	    if (it != GDB_OSABI_NONE)
    151 	      {
    152 		if (!has_gdb_osabi_handler (info))
    153 		  /* Unsupported.  Skip to prevent warnings like:
    154 		     A handler for the OS ABI <x> is not built into this
    155 		     configuration of GDB.  Attempting to continue with the
    156 		     default <y> settings.  */
    157 		  continue;
    158 	      }
    159 
    160 	    gdbarch = gdbarch_find_by_info (info);
    161 	    SELF_CHECK (gdbarch != NULL);
    162 
    163 	    try
    164 	      {
    165 		kind = gdbarch_breakpoint_kind_from_pc (gdbarch, &pc);
    166 		insn = gdbarch_sw_breakpoint_from_kind (gdbarch, kind, &bplen);
    167 	      }
    168 	    catch (...)
    169 	      {
    170 		continue;
    171 	      }
    172 	    found = true;
    173 	    break;
    174 	  }
    175 
    176 	/* Assert that we have found an instruction to disassemble.  */
    177 	SELF_CHECK (found);
    178 
    179 	*len = bplen;
    180 	break;
    181       }
    182     }
    183   SELF_CHECK (*len > 0);
    184 
    185   return insn;
    186 }
    187 
    188 /* Test disassembly of one instruction.  */
    189 
    190 static void
    191 print_one_insn_test (struct gdbarch *gdbarch)
    192 {
    193   size_t len;
    194   const gdb_byte *insn = get_test_insn (gdbarch, &len);
    195 
    196   if (insn == nullptr)
    197     return;
    198 
    199   /* Test gdb_disassembler for a given gdbarch by reading data from a
    200      pre-allocated buffer.  If you want to see the disassembled
    201      instruction printed to gdb_stdout, use maint selftest -verbose.  */
    202 
    203   class gdb_disassembler_test : public gdb_disassembler
    204   {
    205   public:
    206 
    207     explicit gdb_disassembler_test (struct gdbarch *gdbarch,
    208 				    const gdb_byte *insn,
    209 				    size_t len)
    210       : gdb_disassembler (gdbarch,
    211 			  (run_verbose () ? gdb_stdlog : &null_stream),
    212 			  gdb_disassembler_test::read_memory),
    213 	m_insn (insn), m_len (len)
    214     {
    215     }
    216 
    217     int
    218     print_insn (CORE_ADDR memaddr)
    219     {
    220       int len = gdb_disassembler::print_insn (memaddr);
    221 
    222       if (run_verbose ())
    223 	debug_printf ("\n");
    224 
    225       return len;
    226     }
    227 
    228   private:
    229     /* A buffer contain one instruction.  */
    230     const gdb_byte *m_insn;
    231 
    232     /* Length of the buffer.  */
    233     size_t m_len;
    234 
    235     static int read_memory (bfd_vma memaddr, gdb_byte *myaddr,
    236 			    unsigned int len,
    237 			    struct disassemble_info *info) noexcept
    238     {
    239       gdb_disassembler_test *self
    240 	= static_cast<gdb_disassembler_test *>(info->application_data);
    241 
    242       /* The disassembler in opcodes may read more data than one
    243 	 instruction.  Supply infinite consecutive copies
    244 	 of the same instruction.  */
    245       for (size_t i = 0; i < len; i++)
    246 	myaddr[i] = self->m_insn[(memaddr + i) % self->m_len];
    247 
    248       return 0;
    249     }
    250   };
    251 
    252   gdb_disassembler_test di (gdbarch, insn, len);
    253 
    254   SELF_CHECK (di.print_insn (0) == len);
    255 }
    256 
    257 /* Test the gdb_buffered_insn_length function.  */
    258 
    259 static void
    260 buffered_insn_length_test (struct gdbarch *gdbarch)
    261 {
    262   size_t buf_len;
    263   const gdb_byte *insn = get_test_insn (gdbarch, &buf_len);
    264 
    265   if (insn == nullptr)
    266     return;
    267 
    268   /* The tic6x architecture is VLIW.  Disassembling requires that the
    269      entire instruction bundle be available.  However, the buffer we got
    270      back from get_test_insn only contains a single instruction, which is
    271      just part of an instruction bundle.  As a result, the disassemble will
    272      fail.  To avoid this, skip tic6x tests now.  */
    273   if (gdbarch_bfd_arch_info (gdbarch)->arch == bfd_arch_tic6x)
    274     return;
    275 
    276   CORE_ADDR insn_address = 0;
    277   int calculated_len = gdb_buffered_insn_length (gdbarch, insn, buf_len,
    278 						 insn_address);
    279 
    280   SELF_CHECK (calculated_len == buf_len);
    281 }
    282 
    283 /* Test disassembly on memory error.  */
    284 
    285 static void
    286 memory_error_test (struct gdbarch *gdbarch)
    287 {
    288   class gdb_disassembler_test : public gdb_disassembler
    289   {
    290   public:
    291     gdb_disassembler_test (struct gdbarch *gdbarch)
    292       : gdb_disassembler (gdbarch, &null_stream,
    293 			  gdb_disassembler_test::read_memory)
    294     {
    295     }
    296 
    297     static int read_memory (bfd_vma memaddr, gdb_byte *myaddr,
    298 			    unsigned int len,
    299 			    struct disassemble_info *info) noexcept
    300     {
    301       /* Always return an error.  */
    302       return -1;
    303     }
    304   };
    305 
    306   if (gdbarch_bfd_arch_info (gdbarch)->arch == bfd_arch_i386)
    307     {
    308       const struct bfd_arch_info *info = gdbarch_bfd_arch_info (gdbarch);
    309       /* This test will fail on x86-linux because opcodes rejects an
    310 	 attempt to disassemble for an arch with a 64-bit address size
    311 	 when bfd_vma is 32-bit.  */
    312       if (info->bits_per_address > sizeof (bfd_vma) * CHAR_BIT)
    313 	return;
    314     }
    315 
    316   gdb_disassembler_test di (gdbarch);
    317   bool saw_memory_error = false;
    318 
    319   try
    320     {
    321       di.print_insn (0);
    322     }
    323   catch (const gdb_exception_error &ex)
    324     {
    325       if (ex.error == MEMORY_ERROR)
    326 	saw_memory_error = true;
    327     }
    328 
    329   /* Expect MEMORY_ERROR.  */
    330   SELF_CHECK (saw_memory_error);
    331 }
    332 
    333 } // namespace selftests
    334 
    335 void _initialize_disasm_selftests ();
    336 void
    337 _initialize_disasm_selftests ()
    338 {
    339   selftests::register_test_foreach_arch ("print_one_insn",
    340 					 selftests::print_one_insn_test);
    341   selftests::register_test_foreach_arch ("memory_error",
    342 					 selftests::memory_error_test);
    343   selftests::register_test_foreach_arch ("buffered_insn_length",
    344 					 selftests::buffered_insn_length_test);
    345 }
    346