disas.c (10982B)
1/* General "disassemble this chunk" code. Used for debugging. */ 2#include "qemu/osdep.h" 3#include "disas/dis-asm.h" 4#include "elf.h" 5#include "qemu/qemu-print.h" 6 7#include "disas/disas.h" 8#include "disas/capstone.h" 9 10typedef struct CPUDebug { 11 struct disassemble_info info; 12 CPUState *cpu; 13} CPUDebug; 14 15/* Filled in by elfload.c. Simplistic, but will do for now. */ 16struct syminfo *syminfos = NULL; 17 18/* 19 * Get LENGTH bytes from info's buffer, at host address memaddr. 20 * Transfer them to myaddr. 21 */ 22static int host_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length, 23 struct disassemble_info *info) 24{ 25 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 } 30 memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length); 31 return 0; 32} 33 34/* 35 * Get LENGTH bytes from info's buffer, at target address memaddr. 36 * Transfer them to myaddr. 37 */ 38static int target_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length, 39 struct disassemble_info *info) 40{ 41 CPUDebug *s = container_of(info, CPUDebug, info); 42 int r = cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0); 43 return r ? EIO : 0; 44} 45 46/* 47 * Print an error message. We can assume that this is in response to 48 * an error return from {host,target}_read_memory. 49 */ 50static void perror_memory(int status, bfd_vma memaddr, 51 struct disassemble_info *info) 52{ 53 if (status != EIO) { 54 /* Can't happen. */ 55 info->fprintf_func(info->stream, "Unknown error %d\n", status); 56 } else { 57 /* Address between memaddr and memaddr + len was out of bounds. */ 58 info->fprintf_func(info->stream, 59 "Address 0x%" PRIx64 " is out of bounds.\n", 60 memaddr); 61 } 62} 63 64/* Print address in hex. */ 65static void print_address(bfd_vma addr, struct disassemble_info *info) 66{ 67 info->fprintf_func(info->stream, "0x%" PRIx64, addr); 68} 69 70/* Print address in hex, truncated to the width of a host virtual address. */ 71static void host_print_address(bfd_vma addr, struct disassemble_info *info) 72{ 73 print_address((uintptr_t)addr, info); 74} 75 76/* Stub prevents some fruitless earching in optabs disassemblers. */ 77static int symbol_at_address(bfd_vma addr, struct disassemble_info *info) 78{ 79 return 1; 80} 81 82static int print_insn_objdump(bfd_vma pc, disassemble_info *info, 83 const char *prefix) 84{ 85 int i, n = info->buffer_length; 86 uint8_t *buf = g_malloc(n); 87 88 info->read_memory_func(pc, buf, n, info); 89 90 for (i = 0; i < n; ++i) { 91 if (i % 32 == 0) { 92 info->fprintf_func(info->stream, "\n%s: ", prefix); 93 } 94 info->fprintf_func(info->stream, "%02x", buf[i]); 95 } 96 97 g_free(buf); 98 return n; 99} 100 101static int print_insn_od_host(bfd_vma pc, disassemble_info *info) 102{ 103 return print_insn_objdump(pc, info, "OBJD-H"); 104} 105 106static int print_insn_od_target(bfd_vma pc, disassemble_info *info) 107{ 108 return print_insn_objdump(pc, info, "OBJD-T"); 109} 110 111static void initialize_debug(CPUDebug *s) 112{ 113 memset(s, 0, sizeof(*s)); 114 s->info.arch = bfd_arch_unknown; 115 s->info.cap_arch = -1; 116 s->info.cap_insn_unit = 4; 117 s->info.cap_insn_split = 4; 118 s->info.memory_error_func = perror_memory; 119 s->info.symbol_at_address_func = symbol_at_address; 120} 121 122static void initialize_debug_target(CPUDebug *s, CPUState *cpu) 123{ 124 initialize_debug(s); 125 126 s->cpu = cpu; 127 s->info.read_memory_func = target_read_memory; 128 s->info.print_address_func = print_address; 129#ifdef TARGET_WORDS_BIGENDIAN 130 s->info.endian = BFD_ENDIAN_BIG; 131#else 132 s->info.endian = BFD_ENDIAN_LITTLE; 133#endif 134 135 CPUClass *cc = CPU_GET_CLASS(cpu); 136 if (cc->disas_set_info) { 137 cc->disas_set_info(cpu, &s->info); 138 } 139} 140 141static void initialize_debug_host(CPUDebug *s) 142{ 143 initialize_debug(s); 144 145 s->info.read_memory_func = host_read_memory; 146 s->info.print_address_func = host_print_address; 147#ifdef HOST_WORDS_BIGENDIAN 148 s->info.endian = BFD_ENDIAN_BIG; 149#else 150 s->info.endian = BFD_ENDIAN_LITTLE; 151#endif 152#if defined(CONFIG_TCG_INTERPRETER) 153 s->info.print_insn = print_insn_tci; 154#elif defined(__i386__) 155 s->info.mach = bfd_mach_i386_i386; 156 s->info.print_insn = print_insn_i386; 157 s->info.cap_arch = CS_ARCH_X86; 158 s->info.cap_mode = CS_MODE_32; 159 s->info.cap_insn_unit = 1; 160 s->info.cap_insn_split = 8; 161#elif defined(__x86_64__) 162 s->info.mach = bfd_mach_x86_64; 163 s->info.print_insn = print_insn_i386; 164 s->info.cap_arch = CS_ARCH_X86; 165 s->info.cap_mode = CS_MODE_64; 166 s->info.cap_insn_unit = 1; 167 s->info.cap_insn_split = 8; 168#elif defined(_ARCH_PPC) 169 s->info.disassembler_options = (char *)"any"; 170 s->info.print_insn = print_insn_ppc; 171 s->info.cap_arch = CS_ARCH_PPC; 172# ifdef _ARCH_PPC64 173 s->info.cap_mode = CS_MODE_64; 174# endif 175#elif defined(__riscv) && defined(CONFIG_RISCV_DIS) 176#if defined(_ILP32) || (__riscv_xlen == 32) 177 s->info.print_insn = print_insn_riscv32; 178#elif defined(_LP64) 179 s->info.print_insn = print_insn_riscv64; 180#else 181#error unsupported RISC-V ABI 182#endif 183#elif defined(__aarch64__) 184 s->info.cap_arch = CS_ARCH_ARM64; 185# ifdef CONFIG_ARM_A64_DIS 186 s->info.print_insn = print_insn_arm_a64; 187# endif 188#elif defined(__alpha__) 189 s->info.print_insn = print_insn_alpha; 190#elif defined(__sparc__) 191 s->info.print_insn = print_insn_sparc; 192 s->info.mach = bfd_mach_sparc_v9b; 193#elif defined(__arm__) 194 /* TCG only generates code for arm mode. */ 195 s->info.print_insn = print_insn_arm; 196 s->info.cap_arch = CS_ARCH_ARM; 197#elif defined(__MIPSEB__) 198 s->info.print_insn = print_insn_big_mips; 199#elif defined(__MIPSEL__) 200 s->info.print_insn = print_insn_little_mips; 201#elif defined(__m68k__) 202 s->info.print_insn = print_insn_m68k; 203#elif defined(__s390__) 204 s->info.print_insn = print_insn_s390; 205 s->info.cap_arch = CS_ARCH_SYSZ; 206 s->info.cap_insn_unit = 2; 207 s->info.cap_insn_split = 6; 208#elif defined(__hppa__) 209 s->info.print_insn = print_insn_hppa; 210#endif 211} 212 213/* Disassemble this for me please... (debugging). */ 214void target_disas(FILE *out, CPUState *cpu, target_ulong code, 215 target_ulong size) 216{ 217 target_ulong pc; 218 int count; 219 CPUDebug s; 220 221 initialize_debug_target(&s, cpu); 222 s.info.fprintf_func = fprintf; 223 s.info.stream = out; 224 s.info.buffer_vma = code; 225 s.info.buffer_length = size; 226 227 if (s.info.cap_arch >= 0 && cap_disas_target(&s.info, code, size)) { 228 return; 229 } 230 231 if (s.info.print_insn == NULL) { 232 s.info.print_insn = print_insn_od_target; 233 } 234 235 for (pc = code; size > 0; pc += count, size -= count) { 236 fprintf(out, "0x" TARGET_FMT_lx ": ", pc); 237 count = s.info.print_insn(pc, &s.info); 238 fprintf(out, "\n"); 239 if (count < 0) 240 break; 241 if (size < count) { 242 fprintf(out, 243 "Disassembler disagrees with translator over instruction " 244 "decoding\n" 245 "Please report this to qemu-devel@nongnu.org\n"); 246 break; 247 } 248 } 249} 250 251static int plugin_printf(FILE *stream, const char *fmt, ...) 252{ 253 /* We abuse the FILE parameter to pass a GString. */ 254 GString *s = (GString *)stream; 255 int initial_len = s->len; 256 va_list va; 257 258 va_start(va, fmt); 259 g_string_append_vprintf(s, fmt, va); 260 va_end(va); 261 262 return s->len - initial_len; 263} 264 265static void plugin_print_address(bfd_vma addr, struct disassemble_info *info) 266{ 267 /* does nothing */ 268} 269 270 271/* 272 * We should only be dissembling one instruction at a time here. If 273 * there is left over it usually indicates the front end has read more 274 * bytes than it needed. 275 */ 276char *plugin_disas(CPUState *cpu, uint64_t addr, size_t size) 277{ 278 CPUDebug s; 279 GString *ds = g_string_new(NULL); 280 281 initialize_debug_target(&s, cpu); 282 s.info.fprintf_func = plugin_printf; 283 s.info.stream = (FILE *)ds; /* abuse this slot */ 284 s.info.buffer_vma = addr; 285 s.info.buffer_length = size; 286 s.info.print_address_func = plugin_print_address; 287 288 if (s.info.cap_arch >= 0 && cap_disas_plugin(&s.info, addr, size)) { 289 ; /* done */ 290 } else if (s.info.print_insn) { 291 s.info.print_insn(addr, &s.info); 292 } else { 293 ; /* cannot disassemble -- return empty string */ 294 } 295 296 /* Return the buffer, freeing the GString container. */ 297 return g_string_free(ds, false); 298} 299 300/* Disassemble this for me please... (debugging). */ 301void disas(FILE *out, const void *code, unsigned long size) 302{ 303 uintptr_t pc; 304 int count; 305 CPUDebug s; 306 307 initialize_debug_host(&s); 308 s.info.fprintf_func = fprintf; 309 s.info.stream = out; 310 s.info.buffer = code; 311 s.info.buffer_vma = (uintptr_t)code; 312 s.info.buffer_length = size; 313 314 if (s.info.cap_arch >= 0 && cap_disas_host(&s.info, code, size)) { 315 return; 316 } 317 318 if (s.info.print_insn == NULL) { 319 s.info.print_insn = print_insn_od_host; 320 } 321 for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) { 322 fprintf(out, "0x%08" PRIxPTR ": ", pc); 323 count = s.info.print_insn(pc, &s.info); 324 fprintf(out, "\n"); 325 if (count < 0) { 326 break; 327 } 328 } 329 330} 331 332/* Look up symbol for debugging purpose. Returns "" if unknown. */ 333const char *lookup_symbol(target_ulong orig_addr) 334{ 335 const char *symbol = ""; 336 struct syminfo *s; 337 338 for (s = syminfos; s; s = s->next) { 339 symbol = s->lookup_symbol(s, orig_addr); 340 if (symbol[0] != '\0') { 341 break; 342 } 343 } 344 345 return symbol; 346} 347 348#if !defined(CONFIG_USER_ONLY) 349 350#include "monitor/monitor.h" 351 352static int 353physical_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length, 354 struct disassemble_info *info) 355{ 356 CPUDebug *s = container_of(info, CPUDebug, info); 357 MemTxResult res; 358 359 res = address_space_read(s->cpu->as, memaddr, MEMTXATTRS_UNSPECIFIED, 360 myaddr, length); 361 return res == MEMTX_OK ? 0 : EIO; 362} 363 364/* Disassembler for the monitor. */ 365void monitor_disas(Monitor *mon, CPUState *cpu, 366 target_ulong pc, int nb_insn, int is_physical) 367{ 368 int count, i; 369 CPUDebug s; 370 371 initialize_debug_target(&s, cpu); 372 s.info.fprintf_func = qemu_fprintf; 373 if (is_physical) { 374 s.info.read_memory_func = physical_read_memory; 375 } 376 s.info.buffer_vma = pc; 377 378 if (s.info.cap_arch >= 0 && cap_disas_monitor(&s.info, pc, nb_insn)) { 379 return; 380 } 381 382 if (!s.info.print_insn) { 383 monitor_printf(mon, "0x" TARGET_FMT_lx 384 ": Asm output not supported on this arch\n", pc); 385 return; 386 } 387 388 for(i = 0; i < nb_insn; i++) { 389 monitor_printf(mon, "0x" TARGET_FMT_lx ": ", pc); 390 count = s.info.print_insn(pc, &s.info); 391 monitor_printf(mon, "\n"); 392 if (count < 0) 393 break; 394 pc += count; 395 } 396} 397#endif