1 /* 2 * QEMU Plugin API 3 * 4 * This provides the API that is available to the plugins to interact 5 * with QEMU. We have to be careful not to expose internal details of 6 * how QEMU works so we abstract out things like translation and 7 * instructions to anonymous data types: 8 * 9 * qemu_plugin_tb 10 * qemu_plugin_insn 11 * 12 * Which can then be passed back into the API to do additional things. 13 * As such all the public functions in here are exported in 14 * qemu-plugin.h. 15 * 16 * The general life-cycle of a plugin is: 17 * 18 * - plugin is loaded, public qemu_plugin_install called 19 * - the install func registers callbacks for events 20 * - usually an atexit_cb is registered to dump info at the end 21 * - when a registered event occurs the plugin is called 22 * - some events pass additional info 23 * - during translation the plugin can decide to instrument any 24 * instruction 25 * - when QEMU exits all the registered atexit callbacks are called 26 * 27 * Copyright (C) 2017, Emilio G. Cota <cota@braap.org> 28 * Copyright (C) 2019, Linaro 29 * 30 * License: GNU GPL, version 2 or later. 31 * See the COPYING file in the top-level directory. 32 * 33 * SPDX-License-Identifier: GPL-2.0-or-later 34 * 35 */ 36 37 #include "qemu/osdep.h" 38 #include "qemu/plugin.h" 39 #include "cpu.h" 40 #include "sysemu/sysemu.h" 41 #include "tcg/tcg.h" 42 #include "exec/exec-all.h" 43 #include "disas/disas.h" 44 #include "plugin.h" 45 #ifndef CONFIG_USER_ONLY 46 #include "qemu/plugin-memory.h" 47 #include "hw/boards.h" 48 #endif 49 #include "trace/mem.h" 50 51 /* Uninstall and Reset handlers */ 52 53 void qemu_plugin_uninstall(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb) 54 { 55 plugin_reset_uninstall(id, cb, false); 56 } 57 58 void qemu_plugin_reset(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb) 59 { 60 plugin_reset_uninstall(id, cb, true); 61 } 62 63 /* 64 * Plugin Register Functions 65 * 66 * This allows the plugin to register callbacks for various events 67 * during the translation. 68 */ 69 70 void qemu_plugin_register_vcpu_init_cb(qemu_plugin_id_t id, 71 qemu_plugin_vcpu_simple_cb_t cb) 72 { 73 plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_INIT, cb); 74 } 75 76 void qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id, 77 qemu_plugin_vcpu_simple_cb_t cb) 78 { 79 plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_EXIT, cb); 80 } 81 82 void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb, 83 qemu_plugin_vcpu_udata_cb_t cb, 84 enum qemu_plugin_cb_flags flags, 85 void *udata) 86 { 87 plugin_register_dyn_cb__udata(&tb->cbs[PLUGIN_CB_REGULAR], 88 cb, flags, udata); 89 } 90 91 void qemu_plugin_register_vcpu_tb_exec_inline(struct qemu_plugin_tb *tb, 92 enum qemu_plugin_op op, 93 void *ptr, uint64_t imm) 94 { 95 plugin_register_inline_op(&tb->cbs[PLUGIN_CB_INLINE], 0, op, ptr, imm); 96 } 97 98 void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn, 99 qemu_plugin_vcpu_udata_cb_t cb, 100 enum qemu_plugin_cb_flags flags, 101 void *udata) 102 { 103 plugin_register_dyn_cb__udata(&insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR], 104 cb, flags, udata); 105 } 106 107 void qemu_plugin_register_vcpu_insn_exec_inline(struct qemu_plugin_insn *insn, 108 enum qemu_plugin_op op, 109 void *ptr, uint64_t imm) 110 { 111 plugin_register_inline_op(&insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_INLINE], 112 0, op, ptr, imm); 113 } 114 115 116 117 void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn, 118 qemu_plugin_vcpu_mem_cb_t cb, 119 enum qemu_plugin_cb_flags flags, 120 enum qemu_plugin_mem_rw rw, 121 void *udata) 122 { 123 plugin_register_vcpu_mem_cb(&insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR], 124 cb, flags, rw, udata); 125 } 126 127 void qemu_plugin_register_vcpu_mem_inline(struct qemu_plugin_insn *insn, 128 enum qemu_plugin_mem_rw rw, 129 enum qemu_plugin_op op, void *ptr, 130 uint64_t imm) 131 { 132 plugin_register_inline_op(&insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE], 133 rw, op, ptr, imm); 134 } 135 136 void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id, 137 qemu_plugin_vcpu_tb_trans_cb_t cb) 138 { 139 plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_TB_TRANS, cb); 140 } 141 142 void qemu_plugin_register_vcpu_syscall_cb(qemu_plugin_id_t id, 143 qemu_plugin_vcpu_syscall_cb_t cb) 144 { 145 plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL, cb); 146 } 147 148 void 149 qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id, 150 qemu_plugin_vcpu_syscall_ret_cb_t cb) 151 { 152 plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL_RET, cb); 153 } 154 155 /* 156 * Plugin Queries 157 * 158 * These are queries that the plugin can make to gauge information 159 * from our opaque data types. We do not want to leak internal details 160 * here just information useful to the plugin. 161 */ 162 163 /* 164 * Translation block information: 165 * 166 * A plugin can query the virtual address of the start of the block 167 * and the number of instructions in it. It can also get access to 168 * each translated instruction. 169 */ 170 171 size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb) 172 { 173 return tb->n; 174 } 175 176 uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb) 177 { 178 return tb->vaddr; 179 } 180 181 struct qemu_plugin_insn * 182 qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx) 183 { 184 if (unlikely(idx >= tb->n)) { 185 return NULL; 186 } 187 return g_ptr_array_index(tb->insns, idx); 188 } 189 190 /* 191 * Instruction information 192 * 193 * These queries allow the plugin to retrieve information about each 194 * instruction being translated. 195 */ 196 197 const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn) 198 { 199 return insn->data->data; 200 } 201 202 size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn) 203 { 204 return insn->data->len; 205 } 206 207 uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn) 208 { 209 return insn->vaddr; 210 } 211 212 void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn) 213 { 214 return insn->haddr; 215 } 216 217 char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn) 218 { 219 CPUState *cpu = current_cpu; 220 return plugin_disas(cpu, insn->vaddr, insn->data->len); 221 } 222 223 /* 224 * The memory queries allow the plugin to query information about a 225 * memory access. 226 */ 227 228 unsigned qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info) 229 { 230 return info & TRACE_MEM_SZ_SHIFT_MASK; 231 } 232 233 bool qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info) 234 { 235 return !!(info & TRACE_MEM_SE); 236 } 237 238 bool qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info) 239 { 240 return !!(info & TRACE_MEM_BE); 241 } 242 243 bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info) 244 { 245 return !!(info & TRACE_MEM_ST); 246 } 247 248 /* 249 * Virtual Memory queries 250 */ 251 252 #ifdef CONFIG_SOFTMMU 253 static __thread struct qemu_plugin_hwaddr hwaddr_info; 254 255 struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info, 256 uint64_t vaddr) 257 { 258 CPUState *cpu = current_cpu; 259 unsigned int mmu_idx = info >> TRACE_MEM_MMU_SHIFT; 260 hwaddr_info.is_store = info & TRACE_MEM_ST; 261 262 if (!tlb_plugin_lookup(cpu, vaddr, mmu_idx, 263 info & TRACE_MEM_ST, &hwaddr_info)) { 264 error_report("invalid use of qemu_plugin_get_hwaddr"); 265 return NULL; 266 } 267 268 return &hwaddr_info; 269 } 270 #else 271 struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info, 272 uint64_t vaddr) 273 { 274 return NULL; 275 } 276 #endif 277 278 bool qemu_plugin_hwaddr_is_io(struct qemu_plugin_hwaddr *hwaddr) 279 { 280 #ifdef CONFIG_SOFTMMU 281 return hwaddr->is_io; 282 #else 283 return false; 284 #endif 285 } 286 287 uint64_t qemu_plugin_hwaddr_device_offset(const struct qemu_plugin_hwaddr *haddr) 288 { 289 #ifdef CONFIG_SOFTMMU 290 if (haddr) { 291 if (!haddr->is_io) { 292 ram_addr_t ram_addr = qemu_ram_addr_from_host((void *) haddr->v.ram.hostaddr); 293 if (ram_addr == RAM_ADDR_INVALID) { 294 error_report("Bad ram pointer %"PRIx64"", haddr->v.ram.hostaddr); 295 abort(); 296 } 297 return ram_addr; 298 } else { 299 return haddr->v.io.offset; 300 } 301 } 302 #endif 303 return 0; 304 } 305 306 /* 307 * Queries to the number and potential maximum number of vCPUs there 308 * will be. This helps the plugin dimension per-vcpu arrays. 309 */ 310 311 #ifndef CONFIG_USER_ONLY 312 static MachineState * get_ms(void) 313 { 314 return MACHINE(qdev_get_machine()); 315 } 316 #endif 317 318 int qemu_plugin_n_vcpus(void) 319 { 320 #ifdef CONFIG_USER_ONLY 321 return -1; 322 #else 323 return get_ms()->smp.cpus; 324 #endif 325 } 326 327 int qemu_plugin_n_max_vcpus(void) 328 { 329 #ifdef CONFIG_USER_ONLY 330 return -1; 331 #else 332 return get_ms()->smp.max_cpus; 333 #endif 334 } 335 336 /* 337 * Plugin output 338 */ 339 void qemu_plugin_outs(const char *string) 340 { 341 qemu_log_mask(CPU_LOG_PLUGIN, "%s", string); 342 } 343