]> git.proxmox.com Git - mirror_qemu.git/blame - disas.c
disas: Cleanup plugin_disas
[mirror_qemu.git] / disas.c
CommitLineData
b9adb4a6 1/* General "disassemble this chunk" code. Used for debugging. */
d38ea87a 2#include "qemu/osdep.h"
3979fca4 3#include "disas/dis-asm.h"
b9adb4a6 4#include "elf.h"
30cc9831 5#include "qemu/qemu-print.h"
b9adb4a6 6
c6105c0a 7#include "cpu.h"
76cad711 8#include "disas/disas.h"
8ca80760 9#include "disas/capstone.h"
c6105c0a 10
f4359b9f
BS
11typedef struct CPUDebug {
12 struct disassemble_info info;
d49190c4 13 CPUState *cpu;
f4359b9f
BS
14} CPUDebug;
15
b9adb4a6 16/* Filled in by elfload.c. Simplistic, but will do for now. */
e80cfcfc 17struct syminfo *syminfos = NULL;
b9adb4a6 18
12b6e9b2
RH
19/*
20 * Get LENGTH bytes from info's buffer, at host address memaddr.
21 * Transfer them to myaddr.
22 */
23static int host_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
24 struct disassemble_info *info)
aa0aa4fa 25{
c6105c0a 26 if (memaddr < info->buffer_vma
12b6e9b2 27 || memaddr + length > info->buffer_vma + info->buffer_length) {
c6105c0a
FB
28 /* Out of bounds. Use EIO because GDB uses it. */
29 return EIO;
12b6e9b2 30 }
c6105c0a
FB
31 memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
32 return 0;
aa0aa4fa
FB
33}
34
12b6e9b2
RH
35/*
36 * Get LENGTH bytes from info's buffer, at target address memaddr.
37 * Transfer them to myaddr.
38 */
39static int target_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
40 struct disassemble_info *info)
c6105c0a 41{
f4359b9f 42 CPUDebug *s = container_of(info, CPUDebug, info);
12b6e9b2 43 int r = cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0);
6766ba50 44 return r ? EIO : 0;
c6105c0a 45}
c6105c0a 46
12b6e9b2
RH
47/*
48 * Print an error message. We can assume that this is in response to
49 * an error return from {host,target}_read_memory.
50 */
51static void perror_memory(int status, bfd_vma memaddr,
52 struct disassemble_info *info)
aa0aa4fa 53{
12b6e9b2
RH
54 if (status != EIO) {
55 /* Can't happen. */
56 info->fprintf_func(info->stream, "Unknown error %d\n", status);
57 } else {
58 /* Address between memaddr and memaddr + len was out of bounds. */
59 info->fprintf_func(info->stream,
60 "Address 0x%" PRIx64 " is out of bounds.\n",
61 memaddr);
62 }
aa0aa4fa
FB
63}
64
12b6e9b2
RH
65/* Print address in hex. */
66static void print_address(bfd_vma addr, struct disassemble_info *info)
aa0aa4fa 67{
12b6e9b2 68 info->fprintf_func(info->stream, "0x%" PRIx64, addr);
aa0aa4fa
FB
69}
70
636bd289 71/* Print address in hex, truncated to the width of a host virtual address. */
12b6e9b2 72static void host_print_address(bfd_vma addr, struct disassemble_info *info)
636bd289 73{
12b6e9b2 74 print_address((uintptr_t)addr, info);
636bd289
PM
75}
76
12b6e9b2
RH
77/* Stub prevents some fruitless earching in optabs disassemblers. */
78static int symbol_at_address(bfd_vma addr, struct disassemble_info *info)
aa0aa4fa 79{
12b6e9b2 80 return 1;
aa0aa4fa
FB
81}
82
c46ffd57
RH
83static int print_insn_objdump(bfd_vma pc, disassemble_info *info,
84 const char *prefix)
85{
86 int i, n = info->buffer_length;
87 uint8_t *buf = g_malloc(n);
88
89 info->read_memory_func(pc, buf, n, info);
90
91 for (i = 0; i < n; ++i) {
92 if (i % 32 == 0) {
93 info->fprintf_func(info->stream, "\n%s: ", prefix);
94 }
95 info->fprintf_func(info->stream, "%02x", buf[i]);
96 }
97
98 g_free(buf);
99 return n;
100}
101
102static int print_insn_od_host(bfd_vma pc, disassemble_info *info)
103{
104 return print_insn_objdump(pc, info, "OBJD-H");
105}
106
107static int print_insn_od_target(bfd_vma pc, disassemble_info *info)
108{
109 return print_insn_objdump(pc, info, "OBJD-T");
110}
111
8ca80760
RH
112#ifdef CONFIG_CAPSTONE
113/* Temporary storage for the capstone library. This will be alloced via
114 malloc with a size private to the library; thus there's no reason not
115 to share this across calls and across host vs target disassembly. */
116static __thread cs_insn *cap_insn;
117
118/* Initialize the Capstone library. */
119/* ??? It would be nice to cache this. We would need one handle for the
120 host and one for the target. For most targets we can reset specific
121 parameters via cs_option(CS_OPT_MODE, new_mode), but we cannot change
122 CS_ARCH_* in this way. Thus we would need to be able to close and
123 re-open the target handle with a different arch for the target in order
124 to handle AArch64 vs AArch32 mode switching. */
125static cs_err cap_disas_start(disassemble_info *info, csh *handle)
126{
127 cs_mode cap_mode = info->cap_mode;
128 cs_err err;
129
130 cap_mode += (info->endian == BFD_ENDIAN_BIG ? CS_MODE_BIG_ENDIAN
131 : CS_MODE_LITTLE_ENDIAN);
132
133 err = cs_open(info->cap_arch, cap_mode, handle);
134 if (err != CS_ERR_OK) {
135 return err;
136 }
137
138 /* ??? There probably ought to be a better place to put this. */
139 if (info->cap_arch == CS_ARCH_X86) {
140 /* We don't care about errors (if for some reason the library
141 is compiled without AT&T syntax); the user will just have
142 to deal with the Intel syntax. */
143 cs_option(*handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
144 }
145
146 /* "Disassemble" unknown insns as ".byte W,X,Y,Z". */
147 cs_option(*handle, CS_OPT_SKIPDATA, CS_OPT_ON);
148
149 /* Allocate temp space for cs_disasm_iter. */
150 if (cap_insn == NULL) {
151 cap_insn = cs_malloc(*handle);
152 if (cap_insn == NULL) {
153 cs_close(handle);
154 return CS_ERR_MEM;
155 }
156 }
157 return CS_ERR_OK;
158}
159
15fa1a0a
RH
160static void cap_dump_insn_units(disassemble_info *info, cs_insn *insn,
161 int i, int n)
162{
163 fprintf_function print = info->fprintf_func;
164 FILE *stream = info->stream;
165
166 switch (info->cap_insn_unit) {
167 case 4:
168 if (info->endian == BFD_ENDIAN_BIG) {
169 for (; i < n; i += 4) {
170 print(stream, " %08x", ldl_be_p(insn->bytes + i));
171
172 }
173 } else {
174 for (; i < n; i += 4) {
175 print(stream, " %08x", ldl_le_p(insn->bytes + i));
176 }
177 }
178 break;
179
180 case 2:
181 if (info->endian == BFD_ENDIAN_BIG) {
182 for (; i < n; i += 2) {
183 print(stream, " %04x", lduw_be_p(insn->bytes + i));
184 }
185 } else {
186 for (; i < n; i += 2) {
187 print(stream, " %04x", lduw_le_p(insn->bytes + i));
188 }
189 }
190 break;
191
192 default:
193 for (; i < n; i++) {
194 print(stream, " %02x", insn->bytes[i]);
195 }
196 break;
197 }
198}
199
4c389f6e 200static void cap_dump_insn(disassemble_info *info, cs_insn *insn)
15fa1a0a
RH
201{
202 fprintf_function print = info->fprintf_func;
203 int i, n, split;
204
205 print(info->stream, "0x%08" PRIx64 ": ", insn->address);
206
207 n = insn->size;
208 split = info->cap_insn_split;
209
210 /* Dump the first SPLIT bytes of the instruction. */
211 cap_dump_insn_units(info, insn, 0, MIN(n, split));
212
213 /* Add padding up to SPLIT so that mnemonics line up. */
214 if (n < split) {
215 int width = (split - n) / info->cap_insn_unit;
216 width *= (2 * info->cap_insn_unit + 1);
217 print(info->stream, "%*s", width, "");
218 }
219
220 /* Print the actual instruction. */
4c389f6e 221 print(info->stream, " %-8s %s\n", insn->mnemonic, insn->op_str);
15fa1a0a
RH
222
223 /* Dump any remaining part of the insn on subsequent lines. */
224 for (i = split; i < n; i += split) {
225 print(info->stream, "0x%08" PRIx64 ": ", insn->address + i);
226 cap_dump_insn_units(info, insn, i, MIN(n, i + split));
227 print(info->stream, "\n");
228 }
229}
230
8ca80760
RH
231/* Disassemble SIZE bytes at PC for the target. */
232static bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size)
233{
234 uint8_t cap_buf[1024];
235 csh handle;
236 cs_insn *insn;
237 size_t csize = 0;
238
239 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
240 return false;
241 }
242 insn = cap_insn;
243
244 while (1) {
245 size_t tsize = MIN(sizeof(cap_buf) - csize, size);
246 const uint8_t *cbuf = cap_buf;
247
248 target_read_memory(pc + csize, cap_buf + csize, tsize, info);
249 csize += tsize;
250 size -= tsize;
251
252 while (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) {
4c389f6e 253 cap_dump_insn(info, insn);
8ca80760
RH
254 }
255
256 /* If the target memory is not consumed, go back for more... */
257 if (size != 0) {
258 /* ... taking care to move any remaining fractional insn
259 to the beginning of the buffer. */
260 if (csize != 0) {
261 memmove(cap_buf, cbuf, csize);
262 }
263 continue;
264 }
265
266 /* Since the target memory is consumed, we should not have
267 a remaining fractional insn. */
268 if (csize != 0) {
269 (*info->fprintf_func)(info->stream,
270 "Disassembler disagrees with translator "
271 "over instruction decoding\n"
272 "Please report this to qemu-devel@nongnu.org\n");
273 }
274 break;
275 }
276
277 cs_close(&handle);
278 return true;
279}
280
281/* Disassemble SIZE bytes at CODE for the host. */
4c389f6e 282static bool cap_disas_host(disassemble_info *info, void *code, size_t size)
8ca80760
RH
283{
284 csh handle;
285 const uint8_t *cbuf;
286 cs_insn *insn;
287 uint64_t pc;
288
289 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
290 return false;
291 }
292 insn = cap_insn;
293
294 cbuf = code;
295 pc = (uintptr_t)code;
296
297 while (cs_disasm_iter(handle, &cbuf, &size, &pc, insn)) {
4c389f6e 298 cap_dump_insn(info, insn);
8ca80760
RH
299 }
300 if (size != 0) {
301 (*info->fprintf_func)(info->stream,
302 "Disassembler disagrees with TCG over instruction encoding\n"
303 "Please report this to qemu-devel@nongnu.org\n");
304 }
305
306 cs_close(&handle);
307 return true;
308}
309
310#if !defined(CONFIG_USER_ONLY)
311/* Disassemble COUNT insns at PC for the target. */
312static bool cap_disas_monitor(disassemble_info *info, uint64_t pc, int count)
313{
314 uint8_t cap_buf[32];
315 csh handle;
316 cs_insn *insn;
317 size_t csize = 0;
318
319 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
320 return false;
321 }
322 insn = cap_insn;
323
324 while (1) {
325 /* We want to read memory for one insn, but generically we do not
326 know how much memory that is. We have a small buffer which is
327 known to be sufficient for all supported targets. Try to not
328 read beyond the page, Just In Case. For even more simplicity,
329 ignore the actual target page size and use a 1k boundary. If
330 that turns out to be insufficient, we'll come back around the
331 loop and read more. */
332 uint64_t epc = QEMU_ALIGN_UP(pc + csize + 1, 1024);
333 size_t tsize = MIN(sizeof(cap_buf) - csize, epc - pc);
334 const uint8_t *cbuf = cap_buf;
335
336 /* Make certain that we can make progress. */
337 assert(tsize != 0);
338 info->read_memory_func(pc, cap_buf + csize, tsize, info);
339 csize += tsize;
340
341 if (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) {
4c389f6e 342 cap_dump_insn(info, insn);
8ca80760
RH
343 if (--count <= 0) {
344 break;
345 }
346 }
347 memmove(cap_buf, cbuf, csize);
348 }
349
350 cs_close(&handle);
351 return true;
352}
353#endif /* !CONFIG_USER_ONLY */
354#else
355# define cap_disas_target(i, p, s) false
4c389f6e 356# define cap_disas_host(i, p, s) false
8ca80760 357# define cap_disas_monitor(i, p, c) false
cbafa236 358# define cap_disas_plugin(i, p, c) false
8ca80760
RH
359#endif /* CONFIG_CAPSTONE */
360
12b6e9b2
RH
361static void initialize_debug(CPUDebug *s)
362{
363 memset(s, 0, sizeof(*s));
364 s->info.arch = bfd_arch_unknown;
365 s->info.cap_arch = -1;
366 s->info.cap_insn_unit = 4;
367 s->info.cap_insn_split = 4;
368 s->info.memory_error_func = perror_memory;
369 s->info.symbol_at_address_func = symbol_at_address;
370}
371
372static void initialize_debug_target(CPUDebug *s, CPUState *cpu)
373{
374 initialize_debug(s);
375
376 s->cpu = cpu;
377 s->info.read_memory_func = target_read_memory;
378 s->info.print_address_func = print_address;
379#ifdef TARGET_WORDS_BIGENDIAN
380 s->info.endian = BFD_ENDIAN_BIG;
381#else
382 s->info.endian = BFD_ENDIAN_LITTLE;
383#endif
384
385 CPUClass *cc = CPU_GET_CLASS(cpu);
386 if (cc->disas_set_info) {
387 cc->disas_set_info(cpu, &s->info);
388 }
389}
390
391static void initialize_debug_host(CPUDebug *s)
392{
393 initialize_debug(s);
394
395 s->info.read_memory_func = host_read_memory;
396 s->info.print_address_func = host_print_address;
397#ifdef HOST_WORDS_BIGENDIAN
398 s->info.endian = BFD_ENDIAN_BIG;
399#else
400 s->info.endian = BFD_ENDIAN_LITTLE;
401#endif
402#if defined(CONFIG_TCG_INTERPRETER)
403 s->info.print_insn = print_insn_tci;
404#elif defined(__i386__)
405 s->info.mach = bfd_mach_i386_i386;
406 s->info.print_insn = print_insn_i386;
407 s->info.cap_arch = CS_ARCH_X86;
408 s->info.cap_mode = CS_MODE_32;
409 s->info.cap_insn_unit = 1;
410 s->info.cap_insn_split = 8;
411#elif defined(__x86_64__)
412 s->info.mach = bfd_mach_x86_64;
413 s->info.print_insn = print_insn_i386;
414 s->info.cap_arch = CS_ARCH_X86;
415 s->info.cap_mode = CS_MODE_64;
416 s->info.cap_insn_unit = 1;
417 s->info.cap_insn_split = 8;
418#elif defined(_ARCH_PPC)
419 s->info.disassembler_options = (char *)"any";
420 s->info.print_insn = print_insn_ppc;
421 s->info.cap_arch = CS_ARCH_PPC;
422# ifdef _ARCH_PPC64
423 s->info.cap_mode = CS_MODE_64;
424# endif
425#elif defined(__riscv) && defined(CONFIG_RISCV_DIS)
426#if defined(_ILP32) || (__riscv_xlen == 32)
427 s->info.print_insn = print_insn_riscv32;
428#elif defined(_LP64)
429 s->info.print_insn = print_insn_riscv64;
430#else
431#error unsupported RISC-V ABI
432#endif
433#elif defined(__aarch64__) && defined(CONFIG_ARM_A64_DIS)
434 s->info.print_insn = print_insn_arm_a64;
435 s->info.cap_arch = CS_ARCH_ARM64;
436#elif defined(__alpha__)
437 s->info.print_insn = print_insn_alpha;
438#elif defined(__sparc__)
439 s->info.print_insn = print_insn_sparc;
440 s->info.mach = bfd_mach_sparc_v9b;
441#elif defined(__arm__)
442 /* TCG only generates code for arm mode. */
443 s->info.print_insn = print_insn_arm;
444 s->info.cap_arch = CS_ARCH_ARM;
445#elif defined(__MIPSEB__)
446 s->info.print_insn = print_insn_big_mips;
447#elif defined(__MIPSEL__)
448 s->info.print_insn = print_insn_little_mips;
449#elif defined(__m68k__)
450 s->info.print_insn = print_insn_m68k;
451#elif defined(__s390__)
452 s->info.print_insn = print_insn_s390;
453#elif defined(__hppa__)
454 s->info.print_insn = print_insn_hppa;
455#endif
456}
457
1d48474d 458/* Disassemble this for me please... (debugging). */
d49190c4 459void target_disas(FILE *out, CPUState *cpu, target_ulong code,
1d48474d 460 target_ulong size)
b9adb4a6 461{
c27004ec 462 target_ulong pc;
b9adb4a6 463 int count;
f4359b9f 464 CPUDebug s;
b9adb4a6 465
12b6e9b2
RH
466 initialize_debug_target(&s, cpu);
467 s.info.fprintf_func = fprintf;
468 s.info.stream = out;
f4359b9f
BS
469 s.info.buffer_vma = code;
470 s.info.buffer_length = size;
37b9de46 471
8ca80760
RH
472 if (s.info.cap_arch >= 0 && cap_disas_target(&s.info, code, size)) {
473 return;
474 }
475
2de295c5
PC
476 if (s.info.print_insn == NULL) {
477 s.info.print_insn = print_insn_od_target;
c46ffd57 478 }
c6105c0a 479
7e000c2e 480 for (pc = code; size > 0; pc += count, size -= count) {
fa15e030 481 fprintf(out, "0x" TARGET_FMT_lx ": ", pc);
2de295c5 482 count = s.info.print_insn(pc, &s.info);
c27004ec
FB
483 fprintf(out, "\n");
484 if (count < 0)
485 break;
754d00ae 486 if (size < count) {
487 fprintf(out,
488 "Disassembler disagrees with translator over instruction "
489 "decoding\n"
490 "Please report this to qemu-devel@nongnu.org\n");
491 break;
492 }
c27004ec
FB
493 }
494}
495
cbafa236
AB
496static int plugin_printf(FILE *stream, const char *fmt, ...)
497{
b71f3a68
RH
498 /* We abuse the FILE parameter to pass a GString. */
499 GString *s = (GString *)stream;
cbafa236 500 int initial_len = s->len;
b71f3a68 501 va_list va;
cbafa236
AB
502
503 va_start(va, fmt);
504 g_string_append_vprintf(s, fmt, va);
505 va_end(va);
506
507 return s->len - initial_len;
508}
509
510static void plugin_print_address(bfd_vma addr, struct disassemble_info *info)
511{
512 /* does nothing */
513}
514
515
516#ifdef CONFIG_CAPSTONE
517/* Disassemble a single instruction directly into plugin output */
518static
519bool cap_disas_plugin(disassemble_info *info, uint64_t pc, size_t size)
520{
b71f3a68
RH
521 uint8_t cap_buf[64];
522 const uint8_t *cbuf = cap_buf;
cbafa236 523 csh handle;
cbafa236
AB
524
525 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
526 return false;
527 }
cbafa236 528
b71f3a68
RH
529 assert(size < sizeof(cap_buf));
530 target_read_memory(pc, cap_buf, size, info);
cbafa236 531
b71f3a68
RH
532 if (cs_disasm_iter(handle, &cbuf, &size, &pc, cap_insn)) {
533 GString *s = (GString *)info->stream;
534 g_string_printf(s, "%s %s", cap_insn->mnemonic, cap_insn->op_str);
cbafa236
AB
535 }
536
537 cs_close(&handle);
538 return true;
539}
540#endif
541
542/*
543 * We should only be dissembling one instruction at a time here. If
544 * there is left over it usually indicates the front end has read more
545 * bytes than it needed.
546 */
547char *plugin_disas(CPUState *cpu, uint64_t addr, size_t size)
548{
cbafa236 549 CPUDebug s;
b71f3a68 550 GString *ds = g_string_new(NULL);
cbafa236 551
12b6e9b2
RH
552 initialize_debug_target(&s, cpu);
553 s.info.fprintf_func = plugin_printf;
b71f3a68 554 s.info.stream = (FILE *)ds; /* abuse this slot */
cbafa236
AB
555 s.info.buffer_vma = addr;
556 s.info.buffer_length = size;
557 s.info.print_address_func = plugin_print_address;
cbafa236
AB
558
559 if (s.info.cap_arch >= 0 && cap_disas_plugin(&s.info, addr, size)) {
b71f3a68
RH
560 ; /* done */
561 } else if (s.info.print_insn) {
562 s.info.print_insn(addr, &s.info);
563 } else {
564 ; /* cannot disassemble -- return empty string */
cbafa236
AB
565 }
566
b71f3a68
RH
567 /* Return the buffer, freeing the GString container. */
568 return g_string_free(ds, false);
cbafa236
AB
569}
570
c27004ec 571/* Disassemble this for me please... (debugging). */
4c389f6e 572void disas(FILE *out, void *code, unsigned long size)
c27004ec 573{
b0b0f1c9 574 uintptr_t pc;
c27004ec 575 int count;
f4359b9f 576 CPUDebug s;
c27004ec 577
12b6e9b2
RH
578 initialize_debug_host(&s);
579 s.info.fprintf_func = fprintf;
580 s.info.stream = out;
f4359b9f
BS
581 s.info.buffer = code;
582 s.info.buffer_vma = (uintptr_t)code;
583 s.info.buffer_length = size;
8ca80760 584
4c389f6e 585 if (s.info.cap_arch >= 0 && cap_disas_host(&s.info, code, size)) {
8ca80760
RH
586 return;
587 }
588
12b6e9b2
RH
589 if (s.info.print_insn == NULL) {
590 s.info.print_insn = print_insn_od_host;
c46ffd57 591 }
b0b0f1c9
SW
592 for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) {
593 fprintf(out, "0x%08" PRIxPTR ": ", pc);
12b6e9b2 594 count = s.info.print_insn(pc, &s.info);
e5ef4ec2
AB
595 fprintf(out, "\n");
596 if (count < 0) {
597 break;
598 }
b9adb4a6 599 }
e5ef4ec2 600
b9adb4a6
FB
601}
602
603/* Look up symbol for debugging purpose. Returns "" if unknown. */
c27004ec 604const char *lookup_symbol(target_ulong orig_addr)
b9adb4a6 605{
49918a75 606 const char *symbol = "";
e80cfcfc 607 struct syminfo *s;
3b46e624 608
e80cfcfc 609 for (s = syminfos; s; s = s->next) {
49918a75
PB
610 symbol = s->lookup_symbol(s, orig_addr);
611 if (symbol[0] != '\0') {
612 break;
613 }
b9adb4a6 614 }
49918a75
PB
615
616 return symbol;
b9adb4a6 617}
9307c4c1
FB
618
619#if !defined(CONFIG_USER_ONLY)
620
83c9089e 621#include "monitor/monitor.h"
3d2cfdf1 622
9307c4c1 623static int
b8d87208 624physical_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
a5f1b965 625 struct disassemble_info *info)
9307c4c1 626{
f2c6abc8 627 CPUDebug *s = container_of(info, CPUDebug, info);
6766ba50 628 MemTxResult res;
f2c6abc8 629
6766ba50
PMD
630 res = address_space_read(s->cpu->as, memaddr, MEMTXATTRS_UNSPECIFIED,
631 myaddr, length);
632 return res == MEMTX_OK ? 0 : EIO;
9307c4c1
FB
633}
634
1d48474d 635/* Disassembler for the monitor. */
d49190c4 636void monitor_disas(Monitor *mon, CPUState *cpu,
1d48474d 637 target_ulong pc, int nb_insn, int is_physical)
9307c4c1 638{
9307c4c1 639 int count, i;
f4359b9f 640 CPUDebug s;
9307c4c1 641
12b6e9b2
RH
642 initialize_debug_target(&s, cpu);
643 s.info.fprintf_func = qemu_fprintf;
644 if (is_physical) {
645 s.info.read_memory_func = physical_read_memory;
37b9de46 646 }
12b6e9b2 647 s.info.buffer_vma = pc;
37b9de46 648
8ca80760
RH
649 if (s.info.cap_arch >= 0 && cap_disas_monitor(&s.info, pc, nb_insn)) {
650 return;
651 }
652
37b9de46
PC
653 if (!s.info.print_insn) {
654 monitor_printf(mon, "0x" TARGET_FMT_lx
655 ": Asm output not supported on this arch\n", pc);
656 return;
657 }
9307c4c1
FB
658
659 for(i = 0; i < nb_insn; i++) {
376253ec 660 monitor_printf(mon, "0x" TARGET_FMT_lx ": ", pc);
2de295c5 661 count = s.info.print_insn(pc, &s.info);
376253ec 662 monitor_printf(mon, "\n");
9307c4c1
FB
663 if (count < 0)
664 break;
665 pc += count;
666 }
667}
668#endif