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