1 /* 2 * Copyright (C) 2018, Emilio G. Cota <cota@braap.org> 3 * 4 * License: GNU GPL, version 2 or later. 5 * See the COPYING file in the top-level directory. 6 */ 7 #include <inttypes.h> 8 #include <assert.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <unistd.h> 12 #include <stdio.h> 13 #include <glib.h> 14 15 #include <qemu-plugin.h> 16 17 QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; 18 19 static uint64_t inline_mem_count; 20 static uint64_t cb_mem_count; 21 static uint64_t io_count; 22 static bool do_inline, do_callback; 23 static bool do_haddr; 24 static enum qemu_plugin_mem_rw rw = QEMU_PLUGIN_MEM_RW; 25 26 static void plugin_exit(qemu_plugin_id_t id, void *p) 27 { 28 g_autoptr(GString) out = g_string_new(""); 29 30 if (do_inline) { 31 g_string_printf(out, "inline mem accesses: %" PRIu64 "\n", inline_mem_count); 32 } 33 if (do_callback) { 34 g_string_append_printf(out, "callback mem accesses: %" PRIu64 "\n", cb_mem_count); 35 } 36 if (do_haddr) { 37 g_string_append_printf(out, "io accesses: %" PRIu64 "\n", io_count); 38 } 39 qemu_plugin_outs(out->str); 40 } 41 42 static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t meminfo, 43 uint64_t vaddr, void *udata) 44 { 45 if (do_haddr) { 46 struct qemu_plugin_hwaddr *hwaddr; 47 hwaddr = qemu_plugin_get_hwaddr(meminfo, vaddr); 48 if (qemu_plugin_hwaddr_is_io(hwaddr)) { 49 io_count++; 50 } else { 51 cb_mem_count++; 52 } 53 } else { 54 cb_mem_count++; 55 } 56 } 57 58 static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) 59 { 60 size_t n = qemu_plugin_tb_n_insns(tb); 61 size_t i; 62 63 for (i = 0; i < n; i++) { 64 struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i); 65 66 if (do_inline) { 67 qemu_plugin_register_vcpu_mem_inline(insn, rw, 68 QEMU_PLUGIN_INLINE_ADD_U64, 69 &inline_mem_count, 1); 70 } 71 if (do_callback) { 72 qemu_plugin_register_vcpu_mem_cb(insn, vcpu_mem, 73 QEMU_PLUGIN_CB_NO_REGS, 74 rw, NULL); 75 } 76 } 77 } 78 79 QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, 80 const qemu_info_t *info, 81 int argc, char **argv) 82 { 83 if (argc) { 84 if (argc >= 3) { 85 if (!strcmp(argv[2], "haddr")) { 86 do_haddr = true; 87 } 88 } 89 if (argc >= 2) { 90 const char *str = argv[1]; 91 92 if (!strcmp(str, "r")) { 93 rw = QEMU_PLUGIN_MEM_R; 94 } else if (!strcmp(str, "w")) { 95 rw = QEMU_PLUGIN_MEM_W; 96 } 97 } 98 if (!strcmp(argv[0], "inline")) { 99 do_inline = true; 100 do_callback = false; 101 } else if (!strcmp(argv[0], "both")) { 102 do_inline = true; 103 do_callback = true; 104 } else { 105 do_callback = true; 106 } 107 } 108 109 qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans); 110 qemu_plugin_register_atexit_cb(id, plugin_exit, NULL); 111 return 0; 112 } 113