| 
									
										
										
										
											2003-04-29 20:41:16 +00:00
										 |  |  | /* General "disassemble this chunk" code.  Used for debugging. */ | 
					
						
							| 
									
										
										
										
											2016-01-29 17:50:05 +00:00
										 |  |  | #include "qemu/osdep.h"
 | 
					
						
							| 
									
										
										
										
											2019-04-17 21:18:04 +02:00
										 |  |  | #include "disas/dis-asm.h"
 | 
					
						
							| 
									
										
										
										
											2003-04-29 20:41:16 +00:00
										 |  |  | #include "elf.h"
 | 
					
						
							| 
									
										
										
										
											2019-04-17 21:18:03 +02:00
										 |  |  | #include "qemu/qemu-print.h"
 | 
					
						
							| 
									
										
										
										
											2003-04-29 20:41:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-10-27 21:13:58 +00:00
										 |  |  | #include "cpu.h"
 | 
					
						
							| 
									
										
										
										
											2012-10-24 11:12:21 +02:00
										 |  |  | #include "disas/disas.h"
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:41:12 -07:00
										 |  |  | #include "disas/capstone.h"
 | 
					
						
							| 
									
										
										
										
											2003-10-27 21:13:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  | typedef struct CPUDebug { | 
					
						
							|  |  |  |     struct disassemble_info info; | 
					
						
							| 
									
										
										
										
											2015-05-24 14:20:41 -07:00
										 |  |  |     CPUState *cpu; | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  | } CPUDebug; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-04-29 20:41:16 +00:00
										 |  |  | /* Filled in by elfload.c.  Simplistic, but will do for now. */ | 
					
						
							| 
									
										
										
										
											2004-12-19 23:18:01 +00:00
										 |  |  | struct syminfo *syminfos = NULL; | 
					
						
							| 
									
										
										
										
											2003-04-29 20:41:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-06-09 15:23:31 +00:00
										 |  |  | /* Get LENGTH bytes from info's buffer, at target address memaddr.
 | 
					
						
							|  |  |  |    Transfer them to myaddr.  */ | 
					
						
							|  |  |  | int | 
					
						
							| 
									
										
										
										
											2008-10-22 15:55:18 +00:00
										 |  |  | buffer_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length, | 
					
						
							|  |  |  |                    struct disassemble_info *info) | 
					
						
							| 
									
										
										
										
											2003-06-09 15:23:31 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2003-10-27 21:13:58 +00:00
										 |  |  |     if (memaddr < info->buffer_vma | 
					
						
							|  |  |  |         || memaddr + length > info->buffer_vma + info->buffer_length) | 
					
						
							|  |  |  |         /* Out of bounds.  Use EIO because GDB uses it.  */ | 
					
						
							|  |  |  |         return EIO; | 
					
						
							|  |  |  |     memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length); | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2003-06-09 15:23:31 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-10-27 21:13:58 +00:00
										 |  |  | /* Get LENGTH bytes from info's buffer, at target address memaddr.
 | 
					
						
							|  |  |  |    Transfer them to myaddr.  */ | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2005-01-03 23:35:10 +00:00
										 |  |  | target_read_memory (bfd_vma memaddr, | 
					
						
							|  |  |  |                     bfd_byte *myaddr, | 
					
						
							|  |  |  |                     int length, | 
					
						
							|  |  |  |                     struct disassemble_info *info) | 
					
						
							| 
									
										
										
										
											2003-10-27 21:13:58 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  |     CPUDebug *s = container_of(info, CPUDebug, info); | 
					
						
							| 
									
										
										
										
											2020-05-18 17:53:04 +02:00
										 |  |  |     int r; | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-18 17:53:04 +02:00
										 |  |  |     r = cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return r ? EIO : 0; | 
					
						
							| 
									
										
										
										
											2003-10-27 21:13:58 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-06-09 15:23:31 +00:00
										 |  |  | /* Print an error message.  We can assume that this is in response to
 | 
					
						
							|  |  |  |    an error return from buffer_read_memory.  */ | 
					
						
							|  |  |  | void | 
					
						
							| 
									
										
										
										
											2008-10-22 15:55:18 +00:00
										 |  |  | perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info) | 
					
						
							| 
									
										
										
										
											2003-06-09 15:23:31 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   if (status != EIO) | 
					
						
							|  |  |  |     /* Can't happen.  */ | 
					
						
							|  |  |  |     (*info->fprintf_func) (info->stream, "Unknown error %d\n", status); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     /* Actually, address between memaddr and memaddr + len was
 | 
					
						
							|  |  |  |        out of bounds.  */ | 
					
						
							|  |  |  |     (*info->fprintf_func) (info->stream, | 
					
						
							| 
									
										
										
										
											2006-06-25 18:15:32 +00:00
										 |  |  | 			   "Address 0x%" PRIx64 " is out of bounds.\n", memaddr); | 
					
						
							| 
									
										
										
										
											2003-06-09 15:23:31 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-09 05:12:04 +00:00
										 |  |  | /* This could be in a separate file, to save minuscule amounts of space
 | 
					
						
							| 
									
										
										
										
											2003-06-09 15:23:31 +00:00
										 |  |  |    in statically linked executables.  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Just print the address is hex.  This is included for completeness even
 | 
					
						
							|  |  |  |    though both GDB and objdump provide their own (to print symbolic | 
					
						
							|  |  |  |    addresses).  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							| 
									
										
										
										
											2008-10-22 15:55:18 +00:00
										 |  |  | generic_print_address (bfd_vma addr, struct disassemble_info *info) | 
					
						
							| 
									
										
										
										
											2003-06-09 15:23:31 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-06-25 18:15:32 +00:00
										 |  |  |     (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr); | 
					
						
							| 
									
										
										
										
											2003-06-09 15:23:31 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-25 04:55:55 +00:00
										 |  |  | /* Print address in hex, truncated to the width of a host virtual address. */ | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | generic_print_host_address(bfd_vma addr, struct disassemble_info *info) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint64_t mask = ~0ULL >> (64 - (sizeof(void *) * 8)); | 
					
						
							|  |  |  |     generic_print_address(addr & mask, info); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-06-09 15:23:31 +00:00
										 |  |  | /* Just return the given address.  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							| 
									
										
										
										
											2008-10-22 15:55:18 +00:00
										 |  |  | generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info) | 
					
						
							| 
									
										
										
										
											2003-06-09 15:23:31 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-29 02:12:51 +02:00
										 |  |  | bfd_vma bfd_getl64 (const bfd_byte *addr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   unsigned long long v; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   v = (unsigned long long) addr[0]; | 
					
						
							|  |  |  |   v |= (unsigned long long) addr[1] << 8; | 
					
						
							|  |  |  |   v |= (unsigned long long) addr[2] << 16; | 
					
						
							|  |  |  |   v |= (unsigned long long) addr[3] << 24; | 
					
						
							|  |  |  |   v |= (unsigned long long) addr[4] << 32; | 
					
						
							|  |  |  |   v |= (unsigned long long) addr[5] << 40; | 
					
						
							|  |  |  |   v |= (unsigned long long) addr[6] << 48; | 
					
						
							|  |  |  |   v |= (unsigned long long) addr[7] << 56; | 
					
						
							|  |  |  |   return (bfd_vma) v; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-06-09 15:23:31 +00:00
										 |  |  | bfd_vma bfd_getl32 (const bfd_byte *addr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   unsigned long v; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   v = (unsigned long) addr[0]; | 
					
						
							|  |  |  |   v |= (unsigned long) addr[1] << 8; | 
					
						
							|  |  |  |   v |= (unsigned long) addr[2] << 16; | 
					
						
							|  |  |  |   v |= (unsigned long) addr[3] << 24; | 
					
						
							|  |  |  |   return (bfd_vma) v; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bfd_vma bfd_getb32 (const bfd_byte *addr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   unsigned long v; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   v = (unsigned long) addr[0] << 24; | 
					
						
							|  |  |  |   v |= (unsigned long) addr[1] << 16; | 
					
						
							|  |  |  |   v |= (unsigned long) addr[2] << 8; | 
					
						
							|  |  |  |   v |= (unsigned long) addr[3]; | 
					
						
							|  |  |  |   return (bfd_vma) v; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-07-02 14:58:51 +00:00
										 |  |  | bfd_vma bfd_getl16 (const bfd_byte *addr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   unsigned long v; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   v = (unsigned long) addr[0]; | 
					
						
							|  |  |  |   v |= (unsigned long) addr[1] << 8; | 
					
						
							|  |  |  |   return (bfd_vma) v; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bfd_vma bfd_getb16 (const bfd_byte *addr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   unsigned long v; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   v = (unsigned long) addr[0] << 24; | 
					
						
							|  |  |  |   v |= (unsigned long) addr[1] << 16; | 
					
						
							|  |  |  |   return (bfd_vma) v; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-16 23:29:45 -07:00
										 |  |  | static int print_insn_objdump(bfd_vma pc, disassemble_info *info, | 
					
						
							|  |  |  |                               const char *prefix) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int i, n = info->buffer_length; | 
					
						
							|  |  |  |     uint8_t *buf = g_malloc(n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     info->read_memory_func(pc, buf, n, info); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (i = 0; i < n; ++i) { | 
					
						
							|  |  |  |         if (i % 32 == 0) { | 
					
						
							|  |  |  |             info->fprintf_func(info->stream, "\n%s: ", prefix); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         info->fprintf_func(info->stream, "%02x", buf[i]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     g_free(buf); | 
					
						
							|  |  |  |     return n; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int print_insn_od_host(bfd_vma pc, disassemble_info *info) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return print_insn_objdump(pc, info, "OBJD-H"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int print_insn_od_target(bfd_vma pc, disassemble_info *info) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return print_insn_objdump(pc, info, "OBJD-T"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:41:12 -07:00
										 |  |  | #ifdef CONFIG_CAPSTONE
 | 
					
						
							|  |  |  | /* Temporary storage for the capstone library.  This will be alloced via
 | 
					
						
							|  |  |  |    malloc with a size private to the library; thus there's no reason not | 
					
						
							|  |  |  |    to share this across calls and across host vs target disassembly.  */ | 
					
						
							|  |  |  | static __thread cs_insn *cap_insn; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Initialize the Capstone library.  */ | 
					
						
							|  |  |  | /* ??? It would be nice to cache this.  We would need one handle for the
 | 
					
						
							|  |  |  |    host and one for the target.  For most targets we can reset specific | 
					
						
							|  |  |  |    parameters via cs_option(CS_OPT_MODE, new_mode), but we cannot change | 
					
						
							|  |  |  |    CS_ARCH_* in this way.  Thus we would need to be able to close and | 
					
						
							|  |  |  |    re-open the target handle with a different arch for the target in order | 
					
						
							|  |  |  |    to handle AArch64 vs AArch32 mode switching.  */ | 
					
						
							|  |  |  | static cs_err cap_disas_start(disassemble_info *info, csh *handle) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     cs_mode cap_mode = info->cap_mode; | 
					
						
							|  |  |  |     cs_err err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cap_mode += (info->endian == BFD_ENDIAN_BIG ? CS_MODE_BIG_ENDIAN | 
					
						
							|  |  |  |                  : CS_MODE_LITTLE_ENDIAN); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     err = cs_open(info->cap_arch, cap_mode, handle); | 
					
						
							|  |  |  |     if (err != CS_ERR_OK) { | 
					
						
							|  |  |  |         return err; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* ??? There probably ought to be a better place to put this.  */ | 
					
						
							|  |  |  |     if (info->cap_arch == CS_ARCH_X86) { | 
					
						
							|  |  |  |         /* We don't care about errors (if for some reason the library
 | 
					
						
							|  |  |  |            is compiled without AT&T syntax); the user will just have | 
					
						
							|  |  |  |            to deal with the Intel syntax.  */ | 
					
						
							|  |  |  |         cs_option(*handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* "Disassemble" unknown insns as ".byte W,X,Y,Z".  */ | 
					
						
							|  |  |  |     cs_option(*handle, CS_OPT_SKIPDATA, CS_OPT_ON); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Allocate temp space for cs_disasm_iter.  */ | 
					
						
							|  |  |  |     if (cap_insn == NULL) { | 
					
						
							|  |  |  |         cap_insn = cs_malloc(*handle); | 
					
						
							|  |  |  |         if (cap_insn == NULL) { | 
					
						
							|  |  |  |             cs_close(handle); | 
					
						
							|  |  |  |             return CS_ERR_MEM; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return CS_ERR_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-07 13:19:18 +01:00
										 |  |  | static void cap_dump_insn_units(disassemble_info *info, cs_insn *insn, | 
					
						
							|  |  |  |                                 int i, int n) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     fprintf_function print = info->fprintf_func; | 
					
						
							|  |  |  |     FILE *stream = info->stream; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (info->cap_insn_unit) { | 
					
						
							|  |  |  |     case 4: | 
					
						
							|  |  |  |         if (info->endian == BFD_ENDIAN_BIG) { | 
					
						
							|  |  |  |             for (; i < n; i += 4) { | 
					
						
							|  |  |  |                 print(stream, " %08x", ldl_be_p(insn->bytes + i)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             for (; i < n; i += 4) { | 
					
						
							|  |  |  |                 print(stream, " %08x", ldl_le_p(insn->bytes + i)); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 2: | 
					
						
							|  |  |  |         if (info->endian == BFD_ENDIAN_BIG) { | 
					
						
							|  |  |  |             for (; i < n; i += 2) { | 
					
						
							|  |  |  |                 print(stream, " %04x", lduw_be_p(insn->bytes + i)); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             for (; i < n; i += 2) { | 
					
						
							|  |  |  |                 print(stream, " %04x", lduw_le_p(insn->bytes + i)); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         for (; i < n; i++) { | 
					
						
							|  |  |  |             print(stream, " %02x", insn->bytes[i]); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-13 18:51:33 +01:00
										 |  |  | static void cap_dump_insn(disassemble_info *info, cs_insn *insn, | 
					
						
							|  |  |  |                           const char *note) | 
					
						
							| 
									
										
										
										
											2017-11-07 13:19:18 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     fprintf_function print = info->fprintf_func; | 
					
						
							|  |  |  |     int i, n, split; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     print(info->stream, "0x%08" PRIx64 ": ", insn->address); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     n = insn->size; | 
					
						
							|  |  |  |     split = info->cap_insn_split; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Dump the first SPLIT bytes of the instruction.  */ | 
					
						
							|  |  |  |     cap_dump_insn_units(info, insn, 0, MIN(n, split)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Add padding up to SPLIT so that mnemonics line up.  */ | 
					
						
							|  |  |  |     if (n < split) { | 
					
						
							|  |  |  |         int width = (split - n) / info->cap_insn_unit; | 
					
						
							|  |  |  |         width *= (2 * info->cap_insn_unit + 1); | 
					
						
							|  |  |  |         print(info->stream, "%*s", width, ""); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Print the actual instruction.  */ | 
					
						
							| 
									
										
										
										
											2020-05-13 18:51:33 +01:00
										 |  |  |     print(info->stream, "  %-8s %s", insn->mnemonic, insn->op_str); | 
					
						
							|  |  |  |     if (note) { | 
					
						
							|  |  |  |         print(info->stream, "\t\t%s", note); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     print(info->stream, "\n"); | 
					
						
							| 
									
										
										
										
											2017-11-07 13:19:18 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Dump any remaining part of the insn on subsequent lines.  */ | 
					
						
							|  |  |  |     for (i = split; i < n; i += split) { | 
					
						
							|  |  |  |         print(info->stream, "0x%08" PRIx64 ": ", insn->address + i); | 
					
						
							|  |  |  |         cap_dump_insn_units(info, insn, i, MIN(n, i + split)); | 
					
						
							|  |  |  |         print(info->stream, "\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:41:12 -07:00
										 |  |  | /* Disassemble SIZE bytes at PC for the target.  */ | 
					
						
							|  |  |  | static bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint8_t cap_buf[1024]; | 
					
						
							|  |  |  |     csh handle; | 
					
						
							|  |  |  |     cs_insn *insn; | 
					
						
							|  |  |  |     size_t csize = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (cap_disas_start(info, &handle) != CS_ERR_OK) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     insn = cap_insn; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (1) { | 
					
						
							|  |  |  |         size_t tsize = MIN(sizeof(cap_buf) - csize, size); | 
					
						
							|  |  |  |         const uint8_t *cbuf = cap_buf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         target_read_memory(pc + csize, cap_buf + csize, tsize, info); | 
					
						
							|  |  |  |         csize += tsize; | 
					
						
							|  |  |  |         size -= tsize; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         while (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) { | 
					
						
							| 
									
										
										
										
											2020-05-13 18:51:33 +01:00
										 |  |  |             cap_dump_insn(info, insn, NULL); | 
					
						
							| 
									
										
										
										
											2017-09-14 09:41:12 -07:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* If the target memory is not consumed, go back for more... */ | 
					
						
							|  |  |  |         if (size != 0) { | 
					
						
							|  |  |  |             /* ... taking care to move any remaining fractional insn
 | 
					
						
							|  |  |  |                to the beginning of the buffer.  */ | 
					
						
							|  |  |  |             if (csize != 0) { | 
					
						
							|  |  |  |                 memmove(cap_buf, cbuf, csize); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Since the target memory is consumed, we should not have
 | 
					
						
							|  |  |  |            a remaining fractional insn.  */ | 
					
						
							|  |  |  |         if (csize != 0) { | 
					
						
							|  |  |  |             (*info->fprintf_func)(info->stream, | 
					
						
							|  |  |  |                 "Disassembler disagrees with translator " | 
					
						
							|  |  |  |                 "over instruction decoding\n" | 
					
						
							|  |  |  |                 "Please report this to qemu-devel@nongnu.org\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cs_close(&handle); | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Disassemble SIZE bytes at CODE for the host.  */ | 
					
						
							| 
									
										
										
										
											2020-05-13 18:51:33 +01:00
										 |  |  | static bool cap_disas_host(disassemble_info *info, void *code, size_t size, | 
					
						
							|  |  |  |                            const char *note) | 
					
						
							| 
									
										
										
										
											2017-09-14 09:41:12 -07:00
										 |  |  | { | 
					
						
							|  |  |  |     csh handle; | 
					
						
							|  |  |  |     const uint8_t *cbuf; | 
					
						
							|  |  |  |     cs_insn *insn; | 
					
						
							|  |  |  |     uint64_t pc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (cap_disas_start(info, &handle) != CS_ERR_OK) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     insn = cap_insn; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cbuf = code; | 
					
						
							|  |  |  |     pc = (uintptr_t)code; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (cs_disasm_iter(handle, &cbuf, &size, &pc, insn)) { | 
					
						
							| 
									
										
										
										
											2020-05-13 18:51:33 +01:00
										 |  |  |         cap_dump_insn(info, insn, note); | 
					
						
							|  |  |  |         note = NULL; | 
					
						
							| 
									
										
										
										
											2017-09-14 09:41:12 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (size != 0) { | 
					
						
							|  |  |  |         (*info->fprintf_func)(info->stream, | 
					
						
							|  |  |  |             "Disassembler disagrees with TCG over instruction encoding\n" | 
					
						
							|  |  |  |             "Please report this to qemu-devel@nongnu.org\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cs_close(&handle); | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if !defined(CONFIG_USER_ONLY)
 | 
					
						
							|  |  |  | /* Disassemble COUNT insns at PC for the target.  */ | 
					
						
							|  |  |  | static bool cap_disas_monitor(disassemble_info *info, uint64_t pc, int count) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint8_t cap_buf[32]; | 
					
						
							|  |  |  |     csh handle; | 
					
						
							|  |  |  |     cs_insn *insn; | 
					
						
							|  |  |  |     size_t csize = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (cap_disas_start(info, &handle) != CS_ERR_OK) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     insn = cap_insn; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (1) { | 
					
						
							|  |  |  |         /* We want to read memory for one insn, but generically we do not
 | 
					
						
							|  |  |  |            know how much memory that is.  We have a small buffer which is | 
					
						
							|  |  |  |            known to be sufficient for all supported targets.  Try to not | 
					
						
							|  |  |  |            read beyond the page, Just In Case.  For even more simplicity, | 
					
						
							|  |  |  |            ignore the actual target page size and use a 1k boundary.  If | 
					
						
							|  |  |  |            that turns out to be insufficient, we'll come back around the | 
					
						
							|  |  |  |            loop and read more.  */ | 
					
						
							|  |  |  |         uint64_t epc = QEMU_ALIGN_UP(pc + csize + 1, 1024); | 
					
						
							|  |  |  |         size_t tsize = MIN(sizeof(cap_buf) - csize, epc - pc); | 
					
						
							|  |  |  |         const uint8_t *cbuf = cap_buf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Make certain that we can make progress.  */ | 
					
						
							|  |  |  |         assert(tsize != 0); | 
					
						
							|  |  |  |         info->read_memory_func(pc, cap_buf + csize, tsize, info); | 
					
						
							|  |  |  |         csize += tsize; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) { | 
					
						
							| 
									
										
										
										
											2020-05-13 18:51:33 +01:00
										 |  |  |             cap_dump_insn(info, insn, NULL); | 
					
						
							| 
									
										
										
										
											2017-09-14 09:41:12 -07:00
										 |  |  |             if (--count <= 0) { | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         memmove(cap_buf, cbuf, csize); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cs_close(&handle); | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif /* !CONFIG_USER_ONLY */
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | # define cap_disas_target(i, p, s)  false
 | 
					
						
							| 
									
										
										
										
											2020-05-13 18:51:33 +01:00
										 |  |  | # define cap_disas_host(i, p, s, n)  false
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:41:12 -07:00
										 |  |  | # define cap_disas_monitor(i, p, c)  false
 | 
					
						
							| 
									
										
										
										
											2019-05-22 10:27:14 +01:00
										 |  |  | # define cap_disas_plugin(i, p, c) false
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:41:12 -07:00
										 |  |  | #endif /* CONFIG_CAPSTONE */
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 08:38:35 -07:00
										 |  |  | /* Disassemble this for me please... (debugging).  */ | 
					
						
							| 
									
										
										
										
											2015-05-24 14:20:41 -07:00
										 |  |  | void target_disas(FILE *out, CPUState *cpu, target_ulong code, | 
					
						
							| 
									
										
										
										
											2017-09-14 08:38:35 -07:00
										 |  |  |                   target_ulong size) | 
					
						
							| 
									
										
										
										
											2003-04-29 20:41:16 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-06-23 20:57:33 -07:00
										 |  |  |     CPUClass *cc = CPU_GET_CLASS(cpu); | 
					
						
							| 
									
										
										
										
											2005-01-03 23:35:10 +00:00
										 |  |  |     target_ulong pc; | 
					
						
							| 
									
										
										
										
											2003-04-29 20:41:16 +00:00
										 |  |  |     int count; | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  |     CPUDebug s; | 
					
						
							| 
									
										
										
										
											2003-04-29 20:41:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  |     INIT_DISASSEMBLE_INFO(s.info, out, fprintf); | 
					
						
							| 
									
										
										
										
											2003-04-29 20:41:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-24 14:20:41 -07:00
										 |  |  |     s.cpu = cpu; | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  |     s.info.read_memory_func = target_read_memory; | 
					
						
							|  |  |  |     s.info.buffer_vma = code; | 
					
						
							|  |  |  |     s.info.buffer_length = size; | 
					
						
							| 
									
										
										
										
											2015-07-05 13:50:32 -07:00
										 |  |  |     s.info.print_address_func = generic_print_address; | 
					
						
							| 
									
										
										
										
											2017-09-14 09:41:12 -07:00
										 |  |  |     s.info.cap_arch = -1; | 
					
						
							|  |  |  |     s.info.cap_mode = 0; | 
					
						
							| 
									
										
										
										
											2017-11-07 13:19:18 +01:00
										 |  |  |     s.info.cap_insn_unit = 4; | 
					
						
							|  |  |  |     s.info.cap_insn_split = 4; | 
					
						
							| 
									
										
										
										
											2005-01-03 23:35:10 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef TARGET_WORDS_BIGENDIAN
 | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  |     s.info.endian = BFD_ENDIAN_BIG; | 
					
						
							| 
									
										
										
										
											2005-01-03 23:35:10 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  |     s.info.endian = BFD_ENDIAN_LITTLE; | 
					
						
							| 
									
										
										
										
											2005-01-03 23:35:10 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2015-06-23 20:57:33 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (cc->disas_set_info) { | 
					
						
							|  |  |  |         cc->disas_set_info(cpu, &s.info); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:41:12 -07:00
										 |  |  |     if (s.info.cap_arch >= 0 && cap_disas_target(&s.info, code, size)) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-23 20:57:32 -07:00
										 |  |  |     if (s.info.print_insn == NULL) { | 
					
						
							|  |  |  |         s.info.print_insn = print_insn_od_target; | 
					
						
							| 
									
										
										
										
											2013-08-16 23:29:45 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2003-10-27 21:13:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-13 21:44:41 +00:00
										 |  |  |     for (pc = code; size > 0; pc += count, size -= count) { | 
					
						
							| 
									
										
										
										
											2005-01-31 23:32:31 +00:00
										 |  |  | 	fprintf(out, "0x" TARGET_FMT_lx ":  ", pc); | 
					
						
							| 
									
										
										
										
											2015-06-23 20:57:32 -07:00
										 |  |  | 	count = s.info.print_insn(pc, &s.info); | 
					
						
							| 
									
										
										
										
											2005-01-03 23:35:10 +00:00
										 |  |  | 	fprintf(out, "\n"); | 
					
						
							|  |  |  | 	if (count < 0) | 
					
						
							|  |  |  | 	    break; | 
					
						
							| 
									
										
										
										
											2009-04-21 22:26:22 +00:00
										 |  |  |         if (size < count) { | 
					
						
							|  |  |  |             fprintf(out, | 
					
						
							|  |  |  |                     "Disassembler disagrees with translator over instruction " | 
					
						
							|  |  |  |                     "decoding\n" | 
					
						
							|  |  |  |                     "Please report this to qemu-devel@nongnu.org\n"); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2005-01-03 23:35:10 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-22 10:27:14 +01:00
										 |  |  | static __thread GString plugin_disas_output; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int plugin_printf(FILE *stream, const char *fmt, ...) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     va_list va; | 
					
						
							|  |  |  |     GString *s = &plugin_disas_output; | 
					
						
							|  |  |  |     int initial_len = s->len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     va_start(va, fmt); | 
					
						
							|  |  |  |     g_string_append_vprintf(s, fmt, va); | 
					
						
							|  |  |  |     va_end(va); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return s->len - initial_len; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void plugin_print_address(bfd_vma addr, struct disassemble_info *info) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /* does nothing */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_CAPSTONE
 | 
					
						
							|  |  |  | /* Disassemble a single instruction directly into plugin output */ | 
					
						
							|  |  |  | static | 
					
						
							|  |  |  | bool cap_disas_plugin(disassemble_info *info, uint64_t pc, size_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint8_t cap_buf[1024]; | 
					
						
							|  |  |  |     csh handle; | 
					
						
							|  |  |  |     cs_insn *insn; | 
					
						
							|  |  |  |     size_t csize = 0; | 
					
						
							|  |  |  |     int count; | 
					
						
							|  |  |  |     GString *s = &plugin_disas_output; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (cap_disas_start(info, &handle) != CS_ERR_OK) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     insn = cap_insn; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     size_t tsize = MIN(sizeof(cap_buf) - csize, size); | 
					
						
							|  |  |  |     const uint8_t *cbuf = cap_buf; | 
					
						
							|  |  |  |     target_read_memory(pc, cap_buf, tsize, info); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     count = cs_disasm(handle, cbuf, size, 0, 1, &insn); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (count) { | 
					
						
							|  |  |  |         g_string_printf(s, "%s %s", insn->mnemonic, insn->op_str); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         g_string_printf(s, "cs_disasm failed"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cs_close(&handle); | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * We should only be dissembling one instruction at a time here. If | 
					
						
							|  |  |  |  * there is left over it usually indicates the front end has read more | 
					
						
							|  |  |  |  * bytes than it needed. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | char *plugin_disas(CPUState *cpu, uint64_t addr, size_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     CPUClass *cc = CPU_GET_CLASS(cpu); | 
					
						
							|  |  |  |     int count; | 
					
						
							|  |  |  |     CPUDebug s; | 
					
						
							|  |  |  |     GString *ds = g_string_set_size(&plugin_disas_output, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     g_assert(ds == &plugin_disas_output); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     INIT_DISASSEMBLE_INFO(s.info, NULL, plugin_printf); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s.cpu = cpu; | 
					
						
							|  |  |  |     s.info.read_memory_func = target_read_memory; | 
					
						
							|  |  |  |     s.info.buffer_vma = addr; | 
					
						
							|  |  |  |     s.info.buffer_length = size; | 
					
						
							|  |  |  |     s.info.print_address_func = plugin_print_address; | 
					
						
							|  |  |  |     s.info.cap_arch = -1; | 
					
						
							|  |  |  |     s.info.cap_mode = 0; | 
					
						
							|  |  |  |     s.info.cap_insn_unit = 4; | 
					
						
							|  |  |  |     s.info.cap_insn_split = 4; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef TARGET_WORDS_BIGENDIAN
 | 
					
						
							|  |  |  |     s.info.endian = BFD_ENDIAN_BIG; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     s.info.endian = BFD_ENDIAN_LITTLE; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (cc->disas_set_info) { | 
					
						
							|  |  |  |         cc->disas_set_info(cpu, &s.info); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (s.info.cap_arch >= 0 && cap_disas_plugin(&s.info, addr, size)) { | 
					
						
							|  |  |  |         return g_strdup(ds->str); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (s.info.print_insn == NULL) { | 
					
						
							|  |  |  |         s.info.print_insn = print_insn_od_target; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     count = s.info.print_insn(addr, &s.info); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* The decoder probably read more than it needed it's not critical */ | 
					
						
							|  |  |  |     if (count < size) { | 
					
						
							|  |  |  |         warn_report("%s: %zu bytes left over", __func__, size - count); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return g_strdup(ds->str); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-03 23:35:10 +00:00
										 |  |  | /* Disassemble this for me please... (debugging). */ | 
					
						
							| 
									
										
										
										
											2020-05-13 18:51:32 +01:00
										 |  |  | void disas(FILE *out, void *code, unsigned long size, const char *note) | 
					
						
							| 
									
										
										
										
											2005-01-03 23:35:10 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-04-12 15:44:35 +02:00
										 |  |  |     uintptr_t pc; | 
					
						
							| 
									
										
										
										
											2005-01-03 23:35:10 +00:00
										 |  |  |     int count; | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  |     CPUDebug s; | 
					
						
							| 
									
										
										
										
											2013-08-16 23:29:45 -07:00
										 |  |  |     int (*print_insn)(bfd_vma pc, disassemble_info *info) = NULL; | 
					
						
							| 
									
										
										
										
											2005-01-03 23:35:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  |     INIT_DISASSEMBLE_INFO(s.info, out, fprintf); | 
					
						
							|  |  |  |     s.info.print_address_func = generic_print_host_address; | 
					
						
							| 
									
										
										
										
											2005-01-03 23:35:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  |     s.info.buffer = code; | 
					
						
							|  |  |  |     s.info.buffer_vma = (uintptr_t)code; | 
					
						
							|  |  |  |     s.info.buffer_length = size; | 
					
						
							| 
									
										
										
										
											2017-09-14 09:41:12 -07:00
										 |  |  |     s.info.cap_arch = -1; | 
					
						
							|  |  |  |     s.info.cap_mode = 0; | 
					
						
							| 
									
										
										
										
											2017-11-07 13:19:18 +01:00
										 |  |  |     s.info.cap_insn_unit = 4; | 
					
						
							|  |  |  |     s.info.cap_insn_split = 4; | 
					
						
							| 
									
										
										
										
											2003-04-29 20:41:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-27 16:13:06 +02:00
										 |  |  | #ifdef HOST_WORDS_BIGENDIAN
 | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  |     s.info.endian = BFD_ENDIAN_BIG; | 
					
						
							| 
									
										
										
										
											2003-04-29 20:41:16 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  |     s.info.endian = BFD_ENDIAN_LITTLE; | 
					
						
							| 
									
										
										
										
											2003-04-29 20:41:16 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-10-05 20:03:53 +02:00
										 |  |  | #if defined(CONFIG_TCG_INTERPRETER)
 | 
					
						
							|  |  |  |     print_insn = print_insn_tci; | 
					
						
							|  |  |  | #elif defined(__i386__)
 | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  |     s.info.mach = bfd_mach_i386_i386; | 
					
						
							| 
									
										
										
										
											2005-01-03 23:35:10 +00:00
										 |  |  |     print_insn = print_insn_i386; | 
					
						
							| 
									
										
										
										
											2017-09-14 09:50:05 -07:00
										 |  |  |     s.info.cap_arch = CS_ARCH_X86; | 
					
						
							|  |  |  |     s.info.cap_mode = CS_MODE_32; | 
					
						
							| 
									
										
										
										
											2017-11-07 13:19:18 +01:00
										 |  |  |     s.info.cap_insn_unit = 1; | 
					
						
							|  |  |  |     s.info.cap_insn_split = 8; | 
					
						
							| 
									
										
										
										
											2004-03-17 23:46:04 +00:00
										 |  |  | #elif defined(__x86_64__)
 | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  |     s.info.mach = bfd_mach_x86_64; | 
					
						
							| 
									
										
										
										
											2005-01-03 23:35:10 +00:00
										 |  |  |     print_insn = print_insn_i386; | 
					
						
							| 
									
										
										
										
											2017-09-14 09:50:05 -07:00
										 |  |  |     s.info.cap_arch = CS_ARCH_X86; | 
					
						
							|  |  |  |     s.info.cap_mode = CS_MODE_64; | 
					
						
							| 
									
										
										
										
											2017-11-07 13:19:18 +01:00
										 |  |  |     s.info.cap_insn_unit = 1; | 
					
						
							|  |  |  |     s.info.cap_insn_split = 8; | 
					
						
							| 
									
										
										
										
											2009-01-14 18:39:49 +00:00
										 |  |  | #elif defined(_ARCH_PPC)
 | 
					
						
							| 
									
										
										
										
											2013-01-31 11:16:21 -08:00
										 |  |  |     s.info.disassembler_options = (char *)"any"; | 
					
						
							| 
									
										
										
										
											2005-01-03 23:35:10 +00:00
										 |  |  |     print_insn = print_insn_ppc; | 
					
						
							| 
									
										
										
										
											2017-09-14 10:38:40 -07:00
										 |  |  |     s.info.cap_arch = CS_ARCH_PPC; | 
					
						
							|  |  |  | # ifdef _ARCH_PPC64
 | 
					
						
							|  |  |  |     s.info.cap_mode = CS_MODE_64; | 
					
						
							|  |  |  | # endif
 | 
					
						
							| 
									
										
										
										
											2018-12-19 19:20:09 +00:00
										 |  |  | #elif defined(__riscv) && defined(CONFIG_RISCV_DIS)
 | 
					
						
							|  |  |  | #if defined(_ILP32) || (__riscv_xlen == 32)
 | 
					
						
							|  |  |  |     print_insn = print_insn_riscv32; | 
					
						
							|  |  |  | #elif defined(_LP64)
 | 
					
						
							|  |  |  |     print_insn = print_insn_riscv64; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #error unsupported RISC-V ABI
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-02-05 17:27:28 +00:00
										 |  |  | #elif defined(__aarch64__) && defined(CONFIG_ARM_A64_DIS)
 | 
					
						
							|  |  |  |     print_insn = print_insn_arm_a64; | 
					
						
							| 
									
										
										
										
											2017-09-14 09:51:06 -07:00
										 |  |  |     s.info.cap_arch = CS_ARCH_ARM64; | 
					
						
							| 
									
										
										
										
											2003-05-11 12:25:45 +00:00
										 |  |  | #elif defined(__alpha__)
 | 
					
						
							| 
									
										
										
										
											2005-01-03 23:35:10 +00:00
										 |  |  |     print_insn = print_insn_alpha; | 
					
						
							| 
									
										
										
										
											2003-06-09 15:23:31 +00:00
										 |  |  | #elif defined(__sparc__)
 | 
					
						
							| 
									
										
										
										
											2005-01-03 23:35:10 +00:00
										 |  |  |     print_insn = print_insn_sparc; | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  |     s.info.mach = bfd_mach_sparc_v9b; | 
					
						
							| 
									
										
										
										
											2007-09-16 21:08:06 +00:00
										 |  |  | #elif defined(__arm__)
 | 
					
						
							| 
									
										
										
										
											2005-01-03 23:35:10 +00:00
										 |  |  |     print_insn = print_insn_arm; | 
					
						
							| 
									
										
										
										
											2017-09-14 09:51:06 -07:00
										 |  |  |     s.info.cap_arch = CS_ARCH_ARM; | 
					
						
							|  |  |  |     /* TCG only generates code for arm mode.  */ | 
					
						
							| 
									
										
										
										
											2005-07-02 14:58:51 +00:00
										 |  |  | #elif defined(__MIPSEB__)
 | 
					
						
							|  |  |  |     print_insn = print_insn_big_mips; | 
					
						
							|  |  |  | #elif defined(__MIPSEL__)
 | 
					
						
							|  |  |  |     print_insn = print_insn_little_mips; | 
					
						
							| 
									
										
										
										
											2005-11-06 16:52:11 +00:00
										 |  |  | #elif defined(__m68k__)
 | 
					
						
							|  |  |  |     print_insn = print_insn_m68k; | 
					
						
							| 
									
										
										
										
											2007-07-31 23:44:21 +00:00
										 |  |  | #elif defined(__s390__)
 | 
					
						
							|  |  |  |     print_insn = print_insn_s390; | 
					
						
							| 
									
										
										
										
											2016-09-29 10:55:53 -07:00
										 |  |  | #elif defined(__hppa__)
 | 
					
						
							|  |  |  |     print_insn = print_insn_hppa; | 
					
						
							| 
									
										
										
										
											2003-04-29 20:41:16 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:41:12 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-13 18:51:33 +01:00
										 |  |  |     if (s.info.cap_arch >= 0 && cap_disas_host(&s.info, code, size, note)) { | 
					
						
							| 
									
										
										
										
											2017-09-14 09:41:12 -07:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-16 23:29:45 -07:00
										 |  |  |     if (print_insn == NULL) { | 
					
						
							|  |  |  |         print_insn = print_insn_od_host; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-04-12 15:44:35 +02:00
										 |  |  |     for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) { | 
					
						
							|  |  |  |         fprintf(out, "0x%08" PRIxPTR ":  ", pc); | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  |         count = print_insn(pc, &s.info); | 
					
						
							| 
									
										
										
										
											2020-05-13 18:51:32 +01:00
										 |  |  |         if (note) { | 
					
						
							|  |  |  |             fprintf(out, "\t\t%s", note); | 
					
						
							|  |  |  |             note = NULL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         fprintf(out, "\n"); | 
					
						
							|  |  |  |         if (count < 0) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2003-04-29 20:41:16 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-05-13 18:51:32 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-04-29 20:41:16 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Look up symbol for debugging purpose.  Returns "" if unknown. */ | 
					
						
							| 
									
										
										
										
											2005-01-03 23:35:10 +00:00
										 |  |  | const char *lookup_symbol(target_ulong orig_addr) | 
					
						
							| 
									
										
										
										
											2003-04-29 20:41:16 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-10-22 15:11:31 +00:00
										 |  |  |     const char *symbol = ""; | 
					
						
							| 
									
										
										
										
											2004-12-19 23:18:01 +00:00
										 |  |  |     struct syminfo *s; | 
					
						
							| 
									
										
										
										
											2007-09-17 08:09:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-12-19 23:18:01 +00:00
										 |  |  |     for (s = syminfos; s; s = s->next) { | 
					
						
							| 
									
										
										
										
											2008-10-22 15:11:31 +00:00
										 |  |  |         symbol = s->lookup_symbol(s, orig_addr); | 
					
						
							|  |  |  |         if (symbol[0] != '\0') { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2003-04-29 20:41:16 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-10-22 15:11:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return symbol; | 
					
						
							| 
									
										
										
										
											2003-04-29 20:41:16 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2004-04-04 12:57:25 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if !defined(CONFIG_USER_ONLY)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-17 18:19:49 +01:00
										 |  |  | #include "monitor/monitor.h"
 | 
					
						
							| 
									
										
										
										
											2004-08-01 21:49:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-04-04 12:57:25 +00:00
										 |  |  | static int | 
					
						
							| 
									
										
										
										
											2017-09-19 09:40:40 -05:00
										 |  |  | physical_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length, | 
					
						
							| 
									
										
										
										
											2008-08-17 20:21:51 +00:00
										 |  |  |                      struct disassemble_info *info) | 
					
						
							| 
									
										
										
										
											2004-04-04 12:57:25 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-12-14 13:30:49 +00:00
										 |  |  |     CPUDebug *s = container_of(info, CPUDebug, info); | 
					
						
							| 
									
										
										
										
											2020-05-18 17:53:04 +02:00
										 |  |  |     MemTxResult res; | 
					
						
							| 
									
										
										
										
											2018-12-14 13:30:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-18 17:53:04 +02:00
										 |  |  |     res = address_space_read(s->cpu->as, memaddr, MEMTXATTRS_UNSPECIFIED, | 
					
						
							|  |  |  |                              myaddr, length); | 
					
						
							|  |  |  |     return res == MEMTX_OK ? 0 : EIO; | 
					
						
							| 
									
										
										
										
											2004-04-04 12:57:25 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 08:38:35 -07:00
										 |  |  | /* Disassembler for the monitor.  */ | 
					
						
							| 
									
										
										
										
											2015-05-24 14:20:41 -07:00
										 |  |  | void monitor_disas(Monitor *mon, CPUState *cpu, | 
					
						
							| 
									
										
										
										
											2017-09-14 08:38:35 -07:00
										 |  |  |                    target_ulong pc, int nb_insn, int is_physical) | 
					
						
							| 
									
										
										
										
											2004-04-04 12:57:25 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-06-23 20:57:33 -07:00
										 |  |  |     CPUClass *cc = CPU_GET_CLASS(cpu); | 
					
						
							| 
									
										
										
										
											2004-04-04 12:57:25 +00:00
										 |  |  |     int count, i; | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  |     CPUDebug s; | 
					
						
							| 
									
										
										
										
											2004-04-04 12:57:25 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 21:18:03 +02:00
										 |  |  |     INIT_DISASSEMBLE_INFO(s.info, NULL, qemu_fprintf); | 
					
						
							| 
									
										
										
										
											2004-04-04 12:57:25 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-24 14:20:41 -07:00
										 |  |  |     s.cpu = cpu; | 
					
						
							| 
									
										
										
										
											2017-09-19 09:40:40 -05:00
										 |  |  |     s.info.read_memory_func | 
					
						
							|  |  |  |         = (is_physical ? physical_read_memory : target_read_memory); | 
					
						
							| 
									
										
										
										
											2015-07-05 13:50:32 -07:00
										 |  |  |     s.info.print_address_func = generic_print_address; | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  |     s.info.buffer_vma = pc; | 
					
						
							| 
									
										
										
										
											2017-09-14 09:41:12 -07:00
										 |  |  |     s.info.cap_arch = -1; | 
					
						
							|  |  |  |     s.info.cap_mode = 0; | 
					
						
							| 
									
										
										
										
											2017-11-07 13:19:18 +01:00
										 |  |  |     s.info.cap_insn_unit = 4; | 
					
						
							|  |  |  |     s.info.cap_insn_split = 4; | 
					
						
							| 
									
										
										
										
											2004-04-04 12:57:25 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef TARGET_WORDS_BIGENDIAN
 | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  |     s.info.endian = BFD_ENDIAN_BIG; | 
					
						
							| 
									
										
										
										
											2004-04-04 12:57:25 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2012-09-08 12:40:00 +00:00
										 |  |  |     s.info.endian = BFD_ENDIAN_LITTLE; | 
					
						
							| 
									
										
										
										
											2004-04-04 12:57:25 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2015-06-23 20:57:33 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (cc->disas_set_info) { | 
					
						
							|  |  |  |         cc->disas_set_info(cpu, &s.info); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:41:12 -07:00
										 |  |  |     if (s.info.cap_arch >= 0 && cap_disas_monitor(&s.info, pc, nb_insn)) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-23 20:57:33 -07:00
										 |  |  |     if (!s.info.print_insn) { | 
					
						
							|  |  |  |         monitor_printf(mon, "0x" TARGET_FMT_lx | 
					
						
							|  |  |  |                        ": Asm output not supported on this arch\n", pc); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2004-04-04 12:57:25 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for(i = 0; i < nb_insn; i++) { | 
					
						
							| 
									
										
										
										
											2009-03-05 23:01:23 +00:00
										 |  |  | 	monitor_printf(mon, "0x" TARGET_FMT_lx ":  ", pc); | 
					
						
							| 
									
										
										
										
											2015-06-23 20:57:32 -07:00
										 |  |  |         count = s.info.print_insn(pc, &s.info); | 
					
						
							| 
									
										
										
										
											2009-03-05 23:01:23 +00:00
										 |  |  | 	monitor_printf(mon, "\n"); | 
					
						
							| 
									
										
										
										
											2004-04-04 12:57:25 +00:00
										 |  |  | 	if (count < 0) | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  |         pc += count; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 |