qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

plugin: add qemu_plugin_insn_disas helper

Give the plugins access to the QEMU dissasembler so they don't have to
re-invent the wheel. We generate a warning when there are spare bytes
in the decode buffer. This is usually due to the front end loading in
more bytes than decoded.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

+130 -1
+110
disas.c
··· 418 418 # define cap_disas_target(i, p, s) false 419 419 # define cap_disas_host(i, p, s) false 420 420 # define cap_disas_monitor(i, p, c) false 421 + # define cap_disas_plugin(i, p, c) false 421 422 #endif /* CONFIG_CAPSTONE */ 422 423 423 424 /* Disassemble this for me please... (debugging). */ ··· 473 474 break; 474 475 } 475 476 } 477 + } 478 + 479 + static __thread GString plugin_disas_output; 480 + 481 + static int plugin_printf(FILE *stream, const char *fmt, ...) 482 + { 483 + va_list va; 484 + GString *s = &plugin_disas_output; 485 + int initial_len = s->len; 486 + 487 + va_start(va, fmt); 488 + g_string_append_vprintf(s, fmt, va); 489 + va_end(va); 490 + 491 + return s->len - initial_len; 492 + } 493 + 494 + static void plugin_print_address(bfd_vma addr, struct disassemble_info *info) 495 + { 496 + /* does nothing */ 497 + } 498 + 499 + 500 + #ifdef CONFIG_CAPSTONE 501 + /* Disassemble a single instruction directly into plugin output */ 502 + static 503 + bool cap_disas_plugin(disassemble_info *info, uint64_t pc, size_t size) 504 + { 505 + uint8_t cap_buf[1024]; 506 + csh handle; 507 + cs_insn *insn; 508 + size_t csize = 0; 509 + int count; 510 + GString *s = &plugin_disas_output; 511 + 512 + if (cap_disas_start(info, &handle) != CS_ERR_OK) { 513 + return false; 514 + } 515 + insn = cap_insn; 516 + 517 + size_t tsize = MIN(sizeof(cap_buf) - csize, size); 518 + const uint8_t *cbuf = cap_buf; 519 + target_read_memory(pc, cap_buf, tsize, info); 520 + 521 + count = cs_disasm(handle, cbuf, size, 0, 1, &insn); 522 + 523 + if (count) { 524 + g_string_printf(s, "%s %s", insn->mnemonic, insn->op_str); 525 + } else { 526 + g_string_printf(s, "cs_disasm failed"); 527 + } 528 + 529 + cs_close(&handle); 530 + return true; 531 + } 532 + #endif 533 + 534 + /* 535 + * We should only be dissembling one instruction at a time here. If 536 + * there is left over it usually indicates the front end has read more 537 + * bytes than it needed. 538 + */ 539 + char *plugin_disas(CPUState *cpu, uint64_t addr, size_t size) 540 + { 541 + CPUClass *cc = CPU_GET_CLASS(cpu); 542 + int count; 543 + CPUDebug s; 544 + GString *ds = g_string_set_size(&plugin_disas_output, 0); 545 + 546 + g_assert(ds == &plugin_disas_output); 547 + 548 + INIT_DISASSEMBLE_INFO(s.info, NULL, plugin_printf); 549 + 550 + s.cpu = cpu; 551 + s.info.read_memory_func = target_read_memory; 552 + s.info.buffer_vma = addr; 553 + s.info.buffer_length = size; 554 + s.info.print_address_func = plugin_print_address; 555 + s.info.cap_arch = -1; 556 + s.info.cap_mode = 0; 557 + s.info.cap_insn_unit = 4; 558 + s.info.cap_insn_split = 4; 559 + 560 + #ifdef TARGET_WORDS_BIGENDIAN 561 + s.info.endian = BFD_ENDIAN_BIG; 562 + #else 563 + s.info.endian = BFD_ENDIAN_LITTLE; 564 + #endif 565 + 566 + if (cc->disas_set_info) { 567 + cc->disas_set_info(cpu, &s.info); 568 + } 569 + 570 + if (s.info.cap_arch >= 0 && cap_disas_plugin(&s.info, addr, size)) { 571 + return g_strdup(ds->str); 572 + } 573 + 574 + if (s.info.print_insn == NULL) { 575 + s.info.print_insn = print_insn_od_target; 576 + } 577 + 578 + count = s.info.print_insn(addr, &s.info); 579 + 580 + /* The decoder probably read more than it needed it's not critical */ 581 + if (count < size) { 582 + warn_report("%s: %zu bytes left over", __func__, size - count); 583 + } 584 + 585 + return g_strdup(ds->str); 476 586 } 477 587 478 588 /* Disassemble this for me please... (debugging). */
+2
include/disas/disas.h
··· 14 14 void monitor_disas(Monitor *mon, CPUState *cpu, 15 15 target_ulong pc, int nb_insn, int is_physical); 16 16 17 + char *plugin_disas(CPUState *cpu, uint64_t addr, size_t size); 18 + 17 19 /* Look up symbol for debugging purpose. Returns "" if unknown. */ 18 20 const char *lookup_symbol(target_ulong orig_addr); 19 21 #endif
+9
include/qemu/qemu-plugin.h
··· 352 352 353 353 354 354 /** 355 + * qemu_plugin_insn_disas() - return disassembly string for instruction 356 + * @insn: instruction reference 357 + * 358 + * Returns an allocated string containing the disassembly 359 + */ 360 + 361 + char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn); 362 + 363 + /** 355 364 * qemu_plugin_vcpu_for_each() - iterate over the existing vCPU 356 365 * @id: plugin ID 357 366 * @cb: callback function
+8 -1
plugins/api.c
··· 39 39 #include "cpu.h" 40 40 #include "sysemu/sysemu.h" 41 41 #include "tcg/tcg.h" 42 - #include "trace/mem-internal.h" /* mem_info macros */ 42 + #include "exec/exec-all.h" 43 + #include "disas/disas.h" 43 44 #include "plugin.h" 44 45 #ifndef CONFIG_USER_ONLY 45 46 #include "qemu/plugin-memory.h" ··· 210 211 void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn) 211 212 { 212 213 return insn->haddr; 214 + } 215 + 216 + char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn) 217 + { 218 + CPUState *cpu = current_cpu; 219 + return plugin_disas(cpu, insn->vaddr, insn->data->len); 213 220 } 214 221 215 222 /*
+1
plugins/qemu-plugins.symbols
··· 25 25 qemu_plugin_insn_size; 26 26 qemu_plugin_insn_vaddr; 27 27 qemu_plugin_insn_haddr; 28 + qemu_plugin_insn_disas; 28 29 qemu_plugin_mem_size_shift; 29 30 qemu_plugin_mem_is_sign_extended; 30 31 qemu_plugin_mem_is_big_endian;