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 50 /* Uninstall and Reset handlers */ 51 52 void qemu_plugin_uninstall(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb) 53 { 54 plugin_reset_uninstall(id, cb, false); 55 } 56 57 void qemu_plugin_reset(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb) 58 { 59 plugin_reset_uninstall(id, cb, true); 60 } 61 62 /* 63 * Plugin Register Functions 64 * 65 * This allows the plugin to register callbacks for various events 66 * during the translation. 67 */ 68 69 void qemu_plugin_register_vcpu_init_cb(qemu_plugin_id_t id, 70 qemu_plugin_vcpu_simple_cb_t cb) 71 { 72 plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_INIT, cb); 73 } 74 75 void qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id, 76 qemu_plugin_vcpu_simple_cb_t cb) 77 { 78 plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_EXIT, cb); 79 } 80 81 void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb, 82 qemu_plugin_vcpu_udata_cb_t cb, 83 enum qemu_plugin_cb_flags flags, 84 void *udata) 85 { 86 plugin_register_dyn_cb__udata(&tb->cbs[PLUGIN_CB_REGULAR], 87 cb, flags, udata); 88 } 89 90 void qemu_plugin_register_vcpu_tb_exec_inline(struct qemu_plugin_tb *tb, 91 enum qemu_plugin_op op, 92 void *ptr, uint64_t imm) 93 { 94 plugin_register_inline_op(&tb->cbs[PLUGIN_CB_INLINE], 0, op, ptr, imm); 95 } 96 97 void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn, 98 qemu_plugin_vcpu_udata_cb_t cb, 99 enum qemu_plugin_cb_flags flags, 100 void *udata) 101 { 102 plugin_register_dyn_cb__udata(&insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR], 103 cb, flags, udata); 104 } 105 106 void qemu_plugin_register_vcpu_insn_exec_inline(struct qemu_plugin_insn *insn, 107 enum qemu_plugin_op op, 108 void *ptr, uint64_t imm) 109 { 110 plugin_register_inline_op(&insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_INLINE], 111 0, op, ptr, imm); 112 } 113 114 115 116 void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn, 117 qemu_plugin_vcpu_mem_cb_t cb, 118 enum qemu_plugin_cb_flags flags, 119 enum qemu_plugin_mem_rw rw, 120 void *udata) 121 { 122 plugin_register_vcpu_mem_cb(&insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR], 123 cb, flags, rw, udata); 124 } 125 126 void qemu_plugin_register_vcpu_mem_inline(struct qemu_plugin_insn *insn, 127 enum qemu_plugin_mem_rw rw, 128 enum qemu_plugin_op op, void *ptr, 129 uint64_t imm) 130 { 131 plugin_register_inline_op(&insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE], 132 rw, op, ptr, imm); 133 } 134 135 void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id, 136 qemu_plugin_vcpu_tb_trans_cb_t cb) 137 { 138 plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_TB_TRANS, cb); 139 } 140 141 void qemu_plugin_register_vcpu_syscall_cb(qemu_plugin_id_t id, 142 qemu_plugin_vcpu_syscall_cb_t cb) 143 { 144 plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL, cb); 145 } 146 147 void 148 qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id, 149 qemu_plugin_vcpu_syscall_ret_cb_t cb) 150 { 151 plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL_RET, cb); 152 } 153 154 /* 155 * Plugin Queries 156 * 157 * These are queries that the plugin can make to gauge information 158 * from our opaque data types. We do not want to leak internal details 159 * here just information useful to the plugin. 160 */ 161 162 /* 163 * Translation block information: 164 * 165 * A plugin can query the virtual address of the start of the block 166 * and the number of instructions in it. It can also get access to 167 * each translated instruction. 168 */ 169 170 size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb) 171 { 172 return tb->n; 173 } 174 175 uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb) 176 { 177 return tb->vaddr; 178 } 179 180 struct qemu_plugin_insn * 181 qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx) 182 { 183 if (unlikely(idx >= tb->n)) { 184 return NULL; 185 } 186 return g_ptr_array_index(tb->insns, idx); 187 } 188 189 /* 190 * Instruction information 191 * 192 * These queries allow the plugin to retrieve information about each 193 * instruction being translated. 194 */ 195 196 const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn) 197 { 198 return insn->data->data; 199 } 200 201 size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn) 202 { 203 return insn->data->len; 204 } 205 206 uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn) 207 { 208 return insn->vaddr; 209 } 210 211 void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn) 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); 220 } 221 222 /* 223 * The memory queries allow the plugin to query information about a 224 * memory access. 225 */ 226 227 unsigned qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info) 228 { 229 return info & TRACE_MEM_SZ_SHIFT_MASK; 230 } 231 232 bool qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info) 233 { 234 return !!(info & TRACE_MEM_SE); 235 } 236 237 bool qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info) 238 { 239 return !!(info & TRACE_MEM_BE); 240 } 241 242 bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info) 243 { 244 return !!(info & TRACE_MEM_ST); 245 } 246 247 /* 248 * Virtual Memory queries 249 */ 250 251 #ifdef CONFIG_SOFTMMU 252 static __thread struct qemu_plugin_hwaddr hwaddr_info; 253 254 struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info, 255 uint64_t vaddr) 256 { 257 CPUState *cpu = current_cpu; 258 unsigned int mmu_idx = info >> TRACE_MEM_MMU_SHIFT; 259 hwaddr_info.is_store = info & TRACE_MEM_ST; 260 261 if (!tlb_plugin_lookup(cpu, vaddr, mmu_idx, 262 info & TRACE_MEM_ST, &hwaddr_info)) { 263 error_report("invalid use of qemu_plugin_get_hwaddr"); 264 return NULL; 265 } 266 267 return &hwaddr_info; 268 } 269 #else 270 struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info, 271 uint64_t vaddr) 272 { 273 return NULL; 274 } 275 #endif 276 277 bool qemu_plugin_hwaddr_is_io(struct qemu_plugin_hwaddr *hwaddr) 278 { 279 #ifdef CONFIG_SOFTMMU 280 return hwaddr->is_io; 281 #else 282 return false; 283 #endif 284 } 285 286 uint64_t qemu_plugin_hwaddr_device_offset(const struct qemu_plugin_hwaddr *haddr) 287 { 288 #ifdef CONFIG_SOFTMMU 289 if (haddr) { 290 if (!haddr->is_io) { 291 ram_addr_t ram_addr = qemu_ram_addr_from_host((void *) haddr->v.ram.hostaddr); 292 if (ram_addr == RAM_ADDR_INVALID) { 293 error_report("Bad ram pointer %"PRIx64"", haddr->v.ram.hostaddr); 294 abort(); 295 } 296 return ram_addr; 297 } else { 298 return haddr->v.io.offset; 299 } 300 } 301 #endif 302 return 0; 303 } 304 305 /* 306 * Queries to the number and potential maximum number of vCPUs there 307 * will be. This helps the plugin dimension per-vcpu arrays. 308 */ 309 310 #ifndef CONFIG_USER_ONLY 311 static MachineState * get_ms(void) 312 { 313 return MACHINE(qdev_get_machine()); 314 } 315 #endif 316 317 int qemu_plugin_n_vcpus(void) 318 { 319 #ifdef CONFIG_USER_ONLY 320 return -1; 321 #else 322 return get_ms()->smp.cpus; 323 #endif 324 } 325 326 int qemu_plugin_n_max_vcpus(void) 327 { 328 #ifdef CONFIG_USER_ONLY 329 return -1; 330 #else 331 return get_ms()->smp.max_cpus; 332 #endif 333 } 334 335 /* 336 * Plugin output 337 */ 338 void qemu_plugin_outs(const char *string) 339 { 340 qemu_log_mask(CPU_LOG_PLUGIN, "%s", string); 341 } 342