blob: 92b389d25f85f514fa90077559ae1c5f1184c846 [file] [log] [blame]
bellardb9adb4a2003-04-29 20:41:16 +00001/* General "disassemble this chunk" code. Used for debugging. */
Peter Maydelld38ea872016-01-29 17:50:05 +00002#include "qemu/osdep.h"
Peter Crosthwaite37b9de42015-06-23 20:57:33 -07003#include "qemu-common.h"
Paolo Bonzini76cad712012-10-24 11:12:21 +02004#include "disas/bfd.h"
bellardb9adb4a2003-04-29 20:41:16 +00005#include "elf.h"
6
bellardc6105c02003-10-27 21:13:58 +00007#include "cpu.h"
Paolo Bonzini76cad712012-10-24 11:12:21 +02008#include "disas/disas.h"
Richard Henderson8ca80762017-09-14 09:41:12 -07009#include "disas/capstone.h"
bellardc6105c02003-10-27 21:13:58 +000010
Blue Swirlf4359b92012-09-08 12:40:00 +000011typedef struct CPUDebug {
12 struct disassemble_info info;
Peter Crosthwaited49190c2015-05-24 14:20:41 -070013 CPUState *cpu;
Blue Swirlf4359b92012-09-08 12:40:00 +000014} CPUDebug;
15
bellardb9adb4a2003-04-29 20:41:16 +000016/* Filled in by elfload.c. Simplistic, but will do for now. */
bellarde80cfcf2004-12-19 23:18:01 +000017struct syminfo *syminfos = NULL;
bellardb9adb4a2003-04-29 20:41:16 +000018
bellardaa0aa4f2003-06-09 15:23:31 +000019/* Get LENGTH bytes from info's buffer, at target address memaddr.
20 Transfer them to myaddr. */
21int
pbrook3a742b72008-10-22 15:55:18 +000022buffer_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
23 struct disassemble_info *info)
bellardaa0aa4f2003-06-09 15:23:31 +000024{
bellardc6105c02003-10-27 21:13:58 +000025 if (memaddr < info->buffer_vma
26 || memaddr + length > info->buffer_vma + info->buffer_length)
27 /* Out of bounds. Use EIO because GDB uses it. */
28 return EIO;
29 memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
30 return 0;
bellardaa0aa4f2003-06-09 15:23:31 +000031}
32
bellardc6105c02003-10-27 21:13:58 +000033/* Get LENGTH bytes from info's buffer, at target address memaddr.
34 Transfer them to myaddr. */
35static int
bellardc27004e2005-01-03 23:35:10 +000036target_read_memory (bfd_vma memaddr,
37 bfd_byte *myaddr,
38 int length,
39 struct disassemble_info *info)
bellardc6105c02003-10-27 21:13:58 +000040{
Blue Swirlf4359b92012-09-08 12:40:00 +000041 CPUDebug *s = container_of(info, CPUDebug, info);
42
Peter Crosthwaited49190c2015-05-24 14:20:41 -070043 cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0);
bellardc6105c02003-10-27 21:13:58 +000044 return 0;
45}
bellardc6105c02003-10-27 21:13:58 +000046
bellardaa0aa4f2003-06-09 15:23:31 +000047/* Print an error message. We can assume that this is in response to
48 an error return from buffer_read_memory. */
49void
pbrook3a742b72008-10-22 15:55:18 +000050perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info)
bellardaa0aa4f2003-06-09 15:23:31 +000051{
52 if (status != EIO)
53 /* Can't happen. */
54 (*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
55 else
56 /* Actually, address between memaddr and memaddr + len was
57 out of bounds. */
58 (*info->fprintf_func) (info->stream,
bellard26a76462006-06-25 18:15:32 +000059 "Address 0x%" PRIx64 " is out of bounds.\n", memaddr);
bellardaa0aa4f2003-06-09 15:23:31 +000060}
61
Jim Meyeringa31f0532012-05-09 05:12:04 +000062/* This could be in a separate file, to save minuscule amounts of space
bellardaa0aa4f2003-06-09 15:23:31 +000063 in statically linked executables. */
64
65/* Just print the address is hex. This is included for completeness even
66 though both GDB and objdump provide their own (to print symbolic
67 addresses). */
68
69void
pbrook3a742b72008-10-22 15:55:18 +000070generic_print_address (bfd_vma addr, struct disassemble_info *info)
bellardaa0aa4f2003-06-09 15:23:31 +000071{
bellard26a76462006-06-25 18:15:32 +000072 (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr);
bellardaa0aa4f2003-06-09 15:23:31 +000073}
74
Peter Maydell636bd282012-06-25 04:55:55 +000075/* Print address in hex, truncated to the width of a host virtual address. */
76static void
77generic_print_host_address(bfd_vma addr, struct disassemble_info *info)
78{
79 uint64_t mask = ~0ULL >> (64 - (sizeof(void *) * 8));
80 generic_print_address(addr & mask, info);
81}
82
bellardaa0aa4f2003-06-09 15:23:31 +000083/* Just return the given address. */
84
85int
pbrook3a742b72008-10-22 15:55:18 +000086generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info)
bellardaa0aa4f2003-06-09 15:23:31 +000087{
88 return 1;
89}
90
Aurelien Jarno903ec552010-03-29 02:12:51 +020091bfd_vma bfd_getl64 (const bfd_byte *addr)
92{
93 unsigned long long v;
94
95 v = (unsigned long long) addr[0];
96 v |= (unsigned long long) addr[1] << 8;
97 v |= (unsigned long long) addr[2] << 16;
98 v |= (unsigned long long) addr[3] << 24;
99 v |= (unsigned long long) addr[4] << 32;
100 v |= (unsigned long long) addr[5] << 40;
101 v |= (unsigned long long) addr[6] << 48;
102 v |= (unsigned long long) addr[7] << 56;
103 return (bfd_vma) v;
104}
105
bellardaa0aa4f2003-06-09 15:23:31 +0000106bfd_vma bfd_getl32 (const bfd_byte *addr)
107{
108 unsigned long v;
109
110 v = (unsigned long) addr[0];
111 v |= (unsigned long) addr[1] << 8;
112 v |= (unsigned long) addr[2] << 16;
113 v |= (unsigned long) addr[3] << 24;
114 return (bfd_vma) v;
115}
116
117bfd_vma bfd_getb32 (const bfd_byte *addr)
118{
119 unsigned long v;
120
121 v = (unsigned long) addr[0] << 24;
122 v |= (unsigned long) addr[1] << 16;
123 v |= (unsigned long) addr[2] << 8;
124 v |= (unsigned long) addr[3];
125 return (bfd_vma) v;
126}
127
bellard6af0bf92005-07-02 14:58:51 +0000128bfd_vma bfd_getl16 (const bfd_byte *addr)
129{
130 unsigned long v;
131
132 v = (unsigned long) addr[0];
133 v |= (unsigned long) addr[1] << 8;
134 return (bfd_vma) v;
135}
136
137bfd_vma bfd_getb16 (const bfd_byte *addr)
138{
139 unsigned long v;
140
141 v = (unsigned long) addr[0] << 24;
142 v |= (unsigned long) addr[1] << 16;
143 return (bfd_vma) v;
144}
145
Richard Hendersonc46ffd52013-08-16 23:29:45 -0700146static int print_insn_objdump(bfd_vma pc, disassemble_info *info,
147 const char *prefix)
148{
149 int i, n = info->buffer_length;
150 uint8_t *buf = g_malloc(n);
151
152 info->read_memory_func(pc, buf, n, info);
153
154 for (i = 0; i < n; ++i) {
155 if (i % 32 == 0) {
156 info->fprintf_func(info->stream, "\n%s: ", prefix);
157 }
158 info->fprintf_func(info->stream, "%02x", buf[i]);
159 }
160
161 g_free(buf);
162 return n;
163}
164
165static int print_insn_od_host(bfd_vma pc, disassemble_info *info)
166{
167 return print_insn_objdump(pc, info, "OBJD-H");
168}
169
170static int print_insn_od_target(bfd_vma pc, disassemble_info *info)
171{
172 return print_insn_objdump(pc, info, "OBJD-T");
173}
174
Richard Henderson8ca80762017-09-14 09:41:12 -0700175#ifdef CONFIG_CAPSTONE
176/* Temporary storage for the capstone library. This will be alloced via
177 malloc with a size private to the library; thus there's no reason not
178 to share this across calls and across host vs target disassembly. */
179static __thread cs_insn *cap_insn;
180
181/* Initialize the Capstone library. */
182/* ??? It would be nice to cache this. We would need one handle for the
183 host and one for the target. For most targets we can reset specific
184 parameters via cs_option(CS_OPT_MODE, new_mode), but we cannot change
185 CS_ARCH_* in this way. Thus we would need to be able to close and
186 re-open the target handle with a different arch for the target in order
187 to handle AArch64 vs AArch32 mode switching. */
188static cs_err cap_disas_start(disassemble_info *info, csh *handle)
189{
190 cs_mode cap_mode = info->cap_mode;
191 cs_err err;
192
193 cap_mode += (info->endian == BFD_ENDIAN_BIG ? CS_MODE_BIG_ENDIAN
194 : CS_MODE_LITTLE_ENDIAN);
195
196 err = cs_open(info->cap_arch, cap_mode, handle);
197 if (err != CS_ERR_OK) {
198 return err;
199 }
200
201 /* ??? There probably ought to be a better place to put this. */
202 if (info->cap_arch == CS_ARCH_X86) {
203 /* We don't care about errors (if for some reason the library
204 is compiled without AT&T syntax); the user will just have
205 to deal with the Intel syntax. */
206 cs_option(*handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
207 }
208
209 /* "Disassemble" unknown insns as ".byte W,X,Y,Z". */
210 cs_option(*handle, CS_OPT_SKIPDATA, CS_OPT_ON);
211
212 /* Allocate temp space for cs_disasm_iter. */
213 if (cap_insn == NULL) {
214 cap_insn = cs_malloc(*handle);
215 if (cap_insn == NULL) {
216 cs_close(handle);
217 return CS_ERR_MEM;
218 }
219 }
220 return CS_ERR_OK;
221}
222
223/* Disassemble SIZE bytes at PC for the target. */
224static bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size)
225{
226 uint8_t cap_buf[1024];
227 csh handle;
228 cs_insn *insn;
229 size_t csize = 0;
230
231 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
232 return false;
233 }
234 insn = cap_insn;
235
236 while (1) {
237 size_t tsize = MIN(sizeof(cap_buf) - csize, size);
238 const uint8_t *cbuf = cap_buf;
239
240 target_read_memory(pc + csize, cap_buf + csize, tsize, info);
241 csize += tsize;
242 size -= tsize;
243
244 while (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) {
245 (*info->fprintf_func)(info->stream,
246 "0x%08" PRIx64 ": %-12s %s\n",
247 insn->address, insn->mnemonic,
248 insn->op_str);
249 }
250
251 /* If the target memory is not consumed, go back for more... */
252 if (size != 0) {
253 /* ... taking care to move any remaining fractional insn
254 to the beginning of the buffer. */
255 if (csize != 0) {
256 memmove(cap_buf, cbuf, csize);
257 }
258 continue;
259 }
260
261 /* Since the target memory is consumed, we should not have
262 a remaining fractional insn. */
263 if (csize != 0) {
264 (*info->fprintf_func)(info->stream,
265 "Disassembler disagrees with translator "
266 "over instruction decoding\n"
267 "Please report this to qemu-devel@nongnu.org\n");
268 }
269 break;
270 }
271
272 cs_close(&handle);
273 return true;
274}
275
276/* Disassemble SIZE bytes at CODE for the host. */
277static bool cap_disas_host(disassemble_info *info, void *code, size_t size)
278{
279 csh handle;
280 const uint8_t *cbuf;
281 cs_insn *insn;
282 uint64_t pc;
283
284 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
285 return false;
286 }
287 insn = cap_insn;
288
289 cbuf = code;
290 pc = (uintptr_t)code;
291
292 while (cs_disasm_iter(handle, &cbuf, &size, &pc, insn)) {
293 (*info->fprintf_func)(info->stream,
294 "0x%08" PRIx64 ": %-12s %s\n",
295 insn->address, insn->mnemonic,
296 insn->op_str);
297 }
298 if (size != 0) {
299 (*info->fprintf_func)(info->stream,
300 "Disassembler disagrees with TCG over instruction encoding\n"
301 "Please report this to qemu-devel@nongnu.org\n");
302 }
303
304 cs_close(&handle);
305 return true;
306}
307
308#if !defined(CONFIG_USER_ONLY)
309/* Disassemble COUNT insns at PC for the target. */
310static bool cap_disas_monitor(disassemble_info *info, uint64_t pc, int count)
311{
312 uint8_t cap_buf[32];
313 csh handle;
314 cs_insn *insn;
315 size_t csize = 0;
316
317 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
318 return false;
319 }
320 insn = cap_insn;
321
322 while (1) {
323 /* We want to read memory for one insn, but generically we do not
324 know how much memory that is. We have a small buffer which is
325 known to be sufficient for all supported targets. Try to not
326 read beyond the page, Just In Case. For even more simplicity,
327 ignore the actual target page size and use a 1k boundary. If
328 that turns out to be insufficient, we'll come back around the
329 loop and read more. */
330 uint64_t epc = QEMU_ALIGN_UP(pc + csize + 1, 1024);
331 size_t tsize = MIN(sizeof(cap_buf) - csize, epc - pc);
332 const uint8_t *cbuf = cap_buf;
333
334 /* Make certain that we can make progress. */
335 assert(tsize != 0);
336 info->read_memory_func(pc, cap_buf + csize, tsize, info);
337 csize += tsize;
338
339 if (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) {
340 (*info->fprintf_func)(info->stream,
341 "0x%08" PRIx64 ": %-12s %s\n",
342 insn->address, insn->mnemonic,
343 insn->op_str);
344 if (--count <= 0) {
345 break;
346 }
347 }
348 memmove(cap_buf, cbuf, csize);
349 }
350
351 cs_close(&handle);
352 return true;
353}
354#endif /* !CONFIG_USER_ONLY */
355#else
356# define cap_disas_target(i, p, s) false
357# define cap_disas_host(i, p, s) false
358# define cap_disas_monitor(i, p, c) false
359#endif /* CONFIG_CAPSTONE */
360
Richard Henderson1d484742017-09-14 08:38:35 -0700361/* Disassemble this for me please... (debugging). */
Peter Crosthwaited49190c2015-05-24 14:20:41 -0700362void target_disas(FILE *out, CPUState *cpu, target_ulong code,
Richard Henderson1d484742017-09-14 08:38:35 -0700363 target_ulong size)
bellardb9adb4a2003-04-29 20:41:16 +0000364{
Peter Crosthwaite37b9de42015-06-23 20:57:33 -0700365 CPUClass *cc = CPU_GET_CLASS(cpu);
bellardc27004e2005-01-03 23:35:10 +0000366 target_ulong pc;
bellardb9adb4a2003-04-29 20:41:16 +0000367 int count;
Blue Swirlf4359b92012-09-08 12:40:00 +0000368 CPUDebug s;
bellardb9adb4a2003-04-29 20:41:16 +0000369
Blue Swirlf4359b92012-09-08 12:40:00 +0000370 INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
bellardb9adb4a2003-04-29 20:41:16 +0000371
Peter Crosthwaited49190c2015-05-24 14:20:41 -0700372 s.cpu = cpu;
Blue Swirlf4359b92012-09-08 12:40:00 +0000373 s.info.read_memory_func = target_read_memory;
374 s.info.buffer_vma = code;
375 s.info.buffer_length = size;
Peter Crosthwaite9504c542015-07-05 13:50:32 -0700376 s.info.print_address_func = generic_print_address;
Richard Henderson8ca80762017-09-14 09:41:12 -0700377 s.info.cap_arch = -1;
378 s.info.cap_mode = 0;
bellardc27004e2005-01-03 23:35:10 +0000379
380#ifdef TARGET_WORDS_BIGENDIAN
Blue Swirlf4359b92012-09-08 12:40:00 +0000381 s.info.endian = BFD_ENDIAN_BIG;
bellardc27004e2005-01-03 23:35:10 +0000382#else
Blue Swirlf4359b92012-09-08 12:40:00 +0000383 s.info.endian = BFD_ENDIAN_LITTLE;
bellardc6105c02003-10-27 21:13:58 +0000384#endif
Peter Crosthwaite37b9de42015-06-23 20:57:33 -0700385
386 if (cc->disas_set_info) {
387 cc->disas_set_info(cpu, &s.info);
388 }
389
Richard Henderson8ca80762017-09-14 09:41:12 -0700390 if (s.info.cap_arch >= 0 && cap_disas_target(&s.info, code, size)) {
391 return;
392 }
393
Peter Crosthwaite2de295c2015-06-23 20:57:32 -0700394 if (s.info.print_insn == NULL) {
395 s.info.print_insn = print_insn_od_target;
Richard Hendersonc46ffd52013-08-16 23:29:45 -0700396 }
bellardc27004e2005-01-03 23:35:10 +0000397
blueswir17e000c22009-02-13 21:44:41 +0000398 for (pc = code; size > 0; pc += count, size -= count) {
bellardfa15e032005-01-31 23:32:31 +0000399 fprintf(out, "0x" TARGET_FMT_lx ": ", pc);
Peter Crosthwaite2de295c2015-06-23 20:57:32 -0700400 count = s.info.print_insn(pc, &s.info);
bellardc27004e2005-01-03 23:35:10 +0000401 fprintf(out, "\n");
402 if (count < 0)
403 break;
malc754d00a2009-04-21 22:26:22 +0000404 if (size < count) {
405 fprintf(out,
406 "Disassembler disagrees with translator over instruction "
407 "decoding\n"
408 "Please report this to qemu-devel@nongnu.org\n");
409 break;
410 }
bellardc27004e2005-01-03 23:35:10 +0000411 }
412}
413
414/* Disassemble this for me please... (debugging). */
415void disas(FILE *out, void *code, unsigned long size)
416{
Stefan Weilb0b0f1c2012-04-12 15:44:35 +0200417 uintptr_t pc;
bellardc27004e2005-01-03 23:35:10 +0000418 int count;
Blue Swirlf4359b92012-09-08 12:40:00 +0000419 CPUDebug s;
Richard Hendersonc46ffd52013-08-16 23:29:45 -0700420 int (*print_insn)(bfd_vma pc, disassemble_info *info) = NULL;
bellardc27004e2005-01-03 23:35:10 +0000421
Blue Swirlf4359b92012-09-08 12:40:00 +0000422 INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
423 s.info.print_address_func = generic_print_host_address;
bellardc6105c02003-10-27 21:13:58 +0000424
Blue Swirlf4359b92012-09-08 12:40:00 +0000425 s.info.buffer = code;
426 s.info.buffer_vma = (uintptr_t)code;
427 s.info.buffer_length = size;
Richard Henderson8ca80762017-09-14 09:41:12 -0700428 s.info.cap_arch = -1;
429 s.info.cap_mode = 0;
bellardb9adb4a2003-04-29 20:41:16 +0000430
Juan Quintelae2542fe2009-07-27 16:13:06 +0200431#ifdef HOST_WORDS_BIGENDIAN
Blue Swirlf4359b92012-09-08 12:40:00 +0000432 s.info.endian = BFD_ENDIAN_BIG;
bellardb9adb4a2003-04-29 20:41:16 +0000433#else
Blue Swirlf4359b92012-09-08 12:40:00 +0000434 s.info.endian = BFD_ENDIAN_LITTLE;
bellardb9adb4a2003-04-29 20:41:16 +0000435#endif
Stefan Weil5826e512011-10-05 20:03:53 +0200436#if defined(CONFIG_TCG_INTERPRETER)
437 print_insn = print_insn_tci;
438#elif defined(__i386__)
Blue Swirlf4359b92012-09-08 12:40:00 +0000439 s.info.mach = bfd_mach_i386_i386;
bellardc27004e2005-01-03 23:35:10 +0000440 print_insn = print_insn_i386;
Richard Hendersonb666d2a2017-09-14 09:50:05 -0700441 s.info.cap_arch = CS_ARCH_X86;
442 s.info.cap_mode = CS_MODE_32;
bellardbc51c5c2004-03-17 23:46:04 +0000443#elif defined(__x86_64__)
Blue Swirlf4359b92012-09-08 12:40:00 +0000444 s.info.mach = bfd_mach_x86_64;
bellardc27004e2005-01-03 23:35:10 +0000445 print_insn = print_insn_i386;
Richard Hendersonb666d2a2017-09-14 09:50:05 -0700446 s.info.cap_arch = CS_ARCH_X86;
447 s.info.cap_mode = CS_MODE_64;
malce58ffeb2009-01-14 18:39:49 +0000448#elif defined(_ARCH_PPC)
Richard Henderson66d4f6a2013-01-31 11:16:21 -0800449 s.info.disassembler_options = (char *)"any";
bellardc27004e2005-01-03 23:35:10 +0000450 print_insn = print_insn_ppc;
Richard Hendersonac226892017-09-14 10:38:40 -0700451 s.info.cap_arch = CS_ARCH_PPC;
452# ifdef _ARCH_PPC64
453 s.info.cap_mode = CS_MODE_64;
454# endif
Claudio Fontana999b53e2014-02-05 17:27:28 +0000455#elif defined(__aarch64__) && defined(CONFIG_ARM_A64_DIS)
456 print_insn = print_insn_arm_a64;
Richard Henderson110f6c72017-09-14 09:51:06 -0700457 s.info.cap_arch = CS_ARCH_ARM64;
bellarda993ba82003-05-11 12:25:45 +0000458#elif defined(__alpha__)
bellardc27004e2005-01-03 23:35:10 +0000459 print_insn = print_insn_alpha;
bellardaa0aa4f2003-06-09 15:23:31 +0000460#elif defined(__sparc__)
bellardc27004e2005-01-03 23:35:10 +0000461 print_insn = print_insn_sparc;
Blue Swirlf4359b92012-09-08 12:40:00 +0000462 s.info.mach = bfd_mach_sparc_v9b;
ths5fafdf22007-09-16 21:08:06 +0000463#elif defined(__arm__)
bellardc27004e2005-01-03 23:35:10 +0000464 print_insn = print_insn_arm;
Richard Henderson110f6c72017-09-14 09:51:06 -0700465 s.info.cap_arch = CS_ARCH_ARM;
466 /* TCG only generates code for arm mode. */
bellard6af0bf92005-07-02 14:58:51 +0000467#elif defined(__MIPSEB__)
468 print_insn = print_insn_big_mips;
469#elif defined(__MIPSEL__)
470 print_insn = print_insn_little_mips;
bellard48024e42005-11-06 16:52:11 +0000471#elif defined(__m68k__)
472 print_insn = print_insn_m68k;
ths8f860bb2007-07-31 23:44:21 +0000473#elif defined(__s390__)
474 print_insn = print_insn_s390;
Richard Henderson429b31a2016-09-29 10:55:53 -0700475#elif defined(__hppa__)
476 print_insn = print_insn_hppa;
bellardb9adb4a2003-04-29 20:41:16 +0000477#endif
Richard Henderson8ca80762017-09-14 09:41:12 -0700478
479 if (s.info.cap_arch >= 0 && cap_disas_host(&s.info, code, size)) {
480 return;
481 }
482
Richard Hendersonc46ffd52013-08-16 23:29:45 -0700483 if (print_insn == NULL) {
484 print_insn = print_insn_od_host;
485 }
Stefan Weilb0b0f1c2012-04-12 15:44:35 +0200486 for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) {
487 fprintf(out, "0x%08" PRIxPTR ": ", pc);
Blue Swirlf4359b92012-09-08 12:40:00 +0000488 count = print_insn(pc, &s.info);
bellardb9adb4a2003-04-29 20:41:16 +0000489 fprintf(out, "\n");
490 if (count < 0)
491 break;
492 }
493}
494
495/* Look up symbol for debugging purpose. Returns "" if unknown. */
bellardc27004e2005-01-03 23:35:10 +0000496const char *lookup_symbol(target_ulong orig_addr)
bellardb9adb4a2003-04-29 20:41:16 +0000497{
pbrook49918a72008-10-22 15:11:31 +0000498 const char *symbol = "";
bellarde80cfcf2004-12-19 23:18:01 +0000499 struct syminfo *s;
ths3b46e622007-09-17 08:09:54 +0000500
bellarde80cfcf2004-12-19 23:18:01 +0000501 for (s = syminfos; s; s = s->next) {
pbrook49918a72008-10-22 15:11:31 +0000502 symbol = s->lookup_symbol(s, orig_addr);
503 if (symbol[0] != '\0') {
504 break;
505 }
bellardb9adb4a2003-04-29 20:41:16 +0000506 }
pbrook49918a72008-10-22 15:11:31 +0000507
508 return symbol;
bellardb9adb4a2003-04-29 20:41:16 +0000509}
bellard9307c4c2004-04-04 12:57:25 +0000510
511#if !defined(CONFIG_USER_ONLY)
512
Paolo Bonzini83c90892012-12-17 18:19:49 +0100513#include "monitor/monitor.h"
bellard3d2cfdf2004-08-01 21:49:07 +0000514
bellard9307c4c2004-04-04 12:57:25 +0000515static int
Richard Hendersonb8d87202017-09-19 09:40:40 -0500516physical_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
blueswir1a5f1b962008-08-17 20:21:51 +0000517 struct disassemble_info *info)
bellard9307c4c2004-04-04 12:57:25 +0000518{
Richard Hendersonb8d87202017-09-19 09:40:40 -0500519 cpu_physical_memory_read(memaddr, myaddr, length);
bellard9307c4c2004-04-04 12:57:25 +0000520 return 0;
521}
522
Richard Henderson1d484742017-09-14 08:38:35 -0700523/* Disassembler for the monitor. */
Peter Crosthwaited49190c2015-05-24 14:20:41 -0700524void monitor_disas(Monitor *mon, CPUState *cpu,
Richard Henderson1d484742017-09-14 08:38:35 -0700525 target_ulong pc, int nb_insn, int is_physical)
bellard9307c4c2004-04-04 12:57:25 +0000526{
Peter Crosthwaite37b9de42015-06-23 20:57:33 -0700527 CPUClass *cc = CPU_GET_CLASS(cpu);
bellard9307c4c2004-04-04 12:57:25 +0000528 int count, i;
Blue Swirlf4359b92012-09-08 12:40:00 +0000529 CPUDebug s;
bellard9307c4c2004-04-04 12:57:25 +0000530
Blue Swirlf4359b92012-09-08 12:40:00 +0000531 INIT_DISASSEMBLE_INFO(s.info, (FILE *)mon, monitor_fprintf);
bellard9307c4c2004-04-04 12:57:25 +0000532
Peter Crosthwaited49190c2015-05-24 14:20:41 -0700533 s.cpu = cpu;
Richard Hendersonb8d87202017-09-19 09:40:40 -0500534 s.info.read_memory_func
535 = (is_physical ? physical_read_memory : target_read_memory);
Peter Crosthwaite9504c542015-07-05 13:50:32 -0700536 s.info.print_address_func = generic_print_address;
Blue Swirlf4359b92012-09-08 12:40:00 +0000537 s.info.buffer_vma = pc;
Richard Henderson8ca80762017-09-14 09:41:12 -0700538 s.info.cap_arch = -1;
539 s.info.cap_mode = 0;
bellard9307c4c2004-04-04 12:57:25 +0000540
541#ifdef TARGET_WORDS_BIGENDIAN
Blue Swirlf4359b92012-09-08 12:40:00 +0000542 s.info.endian = BFD_ENDIAN_BIG;
bellard9307c4c2004-04-04 12:57:25 +0000543#else
Blue Swirlf4359b92012-09-08 12:40:00 +0000544 s.info.endian = BFD_ENDIAN_LITTLE;
bellard9307c4c2004-04-04 12:57:25 +0000545#endif
Peter Crosthwaite37b9de42015-06-23 20:57:33 -0700546
547 if (cc->disas_set_info) {
548 cc->disas_set_info(cpu, &s.info);
549 }
550
Richard Henderson8ca80762017-09-14 09:41:12 -0700551 if (s.info.cap_arch >= 0 && cap_disas_monitor(&s.info, pc, nb_insn)) {
552 return;
553 }
554
Peter Crosthwaite37b9de42015-06-23 20:57:33 -0700555 if (!s.info.print_insn) {
556 monitor_printf(mon, "0x" TARGET_FMT_lx
557 ": Asm output not supported on this arch\n", pc);
558 return;
559 }
bellard9307c4c2004-04-04 12:57:25 +0000560
561 for(i = 0; i < nb_insn; i++) {
aliguori376253e2009-03-05 23:01:23 +0000562 monitor_printf(mon, "0x" TARGET_FMT_lx ": ", pc);
Peter Crosthwaite2de295c2015-06-23 20:57:32 -0700563 count = s.info.print_insn(pc, &s.info);
aliguori376253e2009-03-05 23:01:23 +0000564 monitor_printf(mon, "\n");
bellard9307c4c2004-04-04 12:57:25 +0000565 if (count < 0)
566 break;
567 pc += count;
568 }
569}
570#endif