xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/disasm-selftests.c (revision 70f7362772ba52b749c976fb5e86e39a8b2c9afc)
1 /* Self tests for disassembler for GDB, the GNU debugger.
2 
3    Copyright (C) 2017-2020 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 /* Test disassembly of one instruction.  */
29 
30 static void
31 print_one_insn_test (struct gdbarch *gdbarch)
32 {
33   size_t len = 0;
34   const gdb_byte *insn = NULL;
35 
36   switch (gdbarch_bfd_arch_info (gdbarch)->arch)
37     {
38     case bfd_arch_bfin:
39       /* M3.L = 0xe117 */
40       static const gdb_byte bfin_insn[] = {0x17, 0xe1, 0xff, 0xff};
41 
42       insn = bfin_insn;
43       len = sizeof (bfin_insn);
44       break;
45     case bfd_arch_arm:
46       /* mov     r0, #0 */
47       static const gdb_byte arm_insn[] = {0x0, 0x0, 0xa0, 0xe3};
48 
49       insn = arm_insn;
50       len = sizeof (arm_insn);
51       break;
52     case bfd_arch_ia64:
53     case bfd_arch_mep:
54     case bfd_arch_mips:
55     case bfd_arch_tic6x:
56     case bfd_arch_xtensa:
57       return;
58     case bfd_arch_s390:
59       /* nopr %r7 */
60       static const gdb_byte s390_insn[] = {0x07, 0x07};
61 
62       insn = s390_insn;
63       len = sizeof (s390_insn);
64       break;
65     case bfd_arch_xstormy16:
66       /* nop */
67       static const gdb_byte xstormy16_insn[] = {0x0, 0x0};
68 
69       insn = xstormy16_insn;
70       len = sizeof (xstormy16_insn);
71       break;
72     case bfd_arch_arc:
73       /* PR 21003 */
74       if (gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_arc_arc601)
75 	return;
76       /* fall through */
77     case bfd_arch_nios2:
78     case bfd_arch_score:
79     case bfd_arch_riscv:
80       /* nios2, riscv, and score need to know the current instruction
81 	 to select breakpoint instruction.  Give the breakpoint
82 	 instruction kind explicitly.  */
83       {
84 	int bplen;
85 	insn = gdbarch_sw_breakpoint_from_kind (gdbarch, 4, &bplen);
86 	len = bplen;
87       }
88       break;
89     default:
90       {
91 	/* Test disassemble breakpoint instruction.  */
92 	CORE_ADDR pc = 0;
93 	int kind = gdbarch_breakpoint_kind_from_pc (gdbarch, &pc);
94 	int bplen;
95 
96 	insn = gdbarch_sw_breakpoint_from_kind (gdbarch, kind, &bplen);
97 	len = bplen;
98 
99 	break;
100       }
101     }
102   SELF_CHECK (len > 0);
103 
104   /* Test gdb_disassembler for a given gdbarch by reading data from a
105      pre-allocated buffer.  If you want to see the disassembled
106      instruction printed to gdb_stdout, set verbose to true.  */
107   static const bool verbose = false;
108 
109   class gdb_disassembler_test : public gdb_disassembler
110   {
111   public:
112 
113     explicit gdb_disassembler_test (struct gdbarch *gdbarch,
114 				    const gdb_byte *insn,
115 				    size_t len)
116       : gdb_disassembler (gdbarch,
117 			  (verbose ? gdb_stdout : &null_stream),
118 			  gdb_disassembler_test::read_memory),
119 	m_insn (insn), m_len (len)
120     {
121     }
122 
123     int
124     print_insn (CORE_ADDR memaddr)
125     {
126       if (verbose)
127 	{
128 	  fprintf_unfiltered (stream (), "%s ",
129 			      gdbarch_bfd_arch_info (arch ())->arch_name);
130 	}
131 
132       int len = gdb_disassembler::print_insn (memaddr);
133 
134       if (verbose)
135 	fprintf_unfiltered (stream (), "\n");
136 
137       return len;
138     }
139 
140   private:
141     /* A buffer contain one instruction.  */
142     const gdb_byte *m_insn;
143 
144     /* Length of the buffer.  */
145     size_t m_len;
146 
147     static int read_memory (bfd_vma memaddr, gdb_byte *myaddr,
148 			    unsigned int len, struct disassemble_info *info)
149     {
150       gdb_disassembler_test *self
151 	= static_cast<gdb_disassembler_test *>(info->application_data);
152 
153       /* The disassembler in opcodes may read more data than one
154 	 instruction.  Supply infinite consecutive copies
155 	 of the same instruction.  */
156       for (size_t i = 0; i < len; i++)
157 	myaddr[i] = self->m_insn[(memaddr + i) % self->m_len];
158 
159       return 0;
160     }
161   };
162 
163   gdb_disassembler_test di (gdbarch, insn, len);
164 
165   SELF_CHECK (di.print_insn (0) == len);
166 }
167 
168 /* Test disassembly on memory error.  */
169 
170 static void
171 memory_error_test (struct gdbarch *gdbarch)
172 {
173   class gdb_disassembler_test : public gdb_disassembler
174   {
175   public:
176     gdb_disassembler_test (struct gdbarch *gdbarch)
177       : gdb_disassembler (gdbarch, &null_stream,
178 			  gdb_disassembler_test::read_memory)
179     {
180     }
181 
182     static int read_memory (bfd_vma memaddr, gdb_byte *myaddr,
183 			    unsigned int len,
184 			    struct disassemble_info *info)
185     {
186       /* Always return an error.  */
187       return -1;
188     }
189   };
190 
191   gdb_disassembler_test di (gdbarch);
192   bool saw_memory_error = false;
193 
194   try
195     {
196       di.print_insn (0);
197     }
198   catch (const gdb_exception_error &ex)
199     {
200       if (ex.error == MEMORY_ERROR)
201 	saw_memory_error = true;
202     }
203 
204   /* Expect MEMORY_ERROR.  */
205   SELF_CHECK (saw_memory_error);
206 }
207 
208 } // namespace selftests
209 
210 void _initialize_disasm_selftests ();
211 void
212 _initialize_disasm_selftests ()
213 {
214   selftests::register_test_foreach_arch ("print_one_insn",
215 					 selftests::print_one_insn_test);
216   selftests::register_test_foreach_arch ("memory_error",
217 					 selftests::memory_error_test);
218 }
219