qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

api.c (11858B)


      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 "qemu/log.h"
     40 #include "tcg/tcg.h"
     41 #include "exec/exec-all.h"
     42 #include "exec/ram_addr.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 #else
     49 #include "qemu.h"
     50 #ifdef CONFIG_LINUX
     51 #include "loader.h"
     52 #endif
     53 #endif
     54 
     55 /* Uninstall and Reset handlers */
     56 
     57 void qemu_plugin_uninstall(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb)
     58 {
     59     plugin_reset_uninstall(id, cb, false);
     60 }
     61 
     62 void qemu_plugin_reset(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb)
     63 {
     64     plugin_reset_uninstall(id, cb, true);
     65 }
     66 
     67 /*
     68  * Plugin Register Functions
     69  *
     70  * This allows the plugin to register callbacks for various events
     71  * during the translation.
     72  */
     73 
     74 void qemu_plugin_register_vcpu_init_cb(qemu_plugin_id_t id,
     75                                        qemu_plugin_vcpu_simple_cb_t cb)
     76 {
     77     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_INIT, cb);
     78 }
     79 
     80 void qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id,
     81                                        qemu_plugin_vcpu_simple_cb_t cb)
     82 {
     83     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_EXIT, cb);
     84 }
     85 
     86 void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
     87                                           qemu_plugin_vcpu_udata_cb_t cb,
     88                                           enum qemu_plugin_cb_flags flags,
     89                                           void *udata)
     90 {
     91     if (!tb->mem_only) {
     92         plugin_register_dyn_cb__udata(&tb->cbs[PLUGIN_CB_REGULAR],
     93                                       cb, flags, udata);
     94     }
     95 }
     96 
     97 void qemu_plugin_register_vcpu_tb_exec_inline(struct qemu_plugin_tb *tb,
     98                                               enum qemu_plugin_op op,
     99                                               void *ptr, uint64_t imm)
    100 {
    101     if (!tb->mem_only) {
    102         plugin_register_inline_op(&tb->cbs[PLUGIN_CB_INLINE], 0, op, ptr, imm);
    103     }
    104 }
    105 
    106 void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
    107                                             qemu_plugin_vcpu_udata_cb_t cb,
    108                                             enum qemu_plugin_cb_flags flags,
    109                                             void *udata)
    110 {
    111     if (!insn->mem_only) {
    112         plugin_register_dyn_cb__udata(&insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR],
    113                                       cb, flags, udata);
    114     }
    115 }
    116 
    117 void qemu_plugin_register_vcpu_insn_exec_inline(struct qemu_plugin_insn *insn,
    118                                                 enum qemu_plugin_op op,
    119                                                 void *ptr, uint64_t imm)
    120 {
    121     if (!insn->mem_only) {
    122         plugin_register_inline_op(&insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_INLINE],
    123                                   0, op, ptr, imm);
    124     }
    125 }
    126 
    127 
    128 /*
    129  * We always plant memory instrumentation because they don't finalise until
    130  * after the operation has complete.
    131  */
    132 void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn,
    133                                       qemu_plugin_vcpu_mem_cb_t cb,
    134                                       enum qemu_plugin_cb_flags flags,
    135                                       enum qemu_plugin_mem_rw rw,
    136                                       void *udata)
    137 {
    138     plugin_register_vcpu_mem_cb(&insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR],
    139                                     cb, flags, rw, udata);
    140 }
    141 
    142 void qemu_plugin_register_vcpu_mem_inline(struct qemu_plugin_insn *insn,
    143                                           enum qemu_plugin_mem_rw rw,
    144                                           enum qemu_plugin_op op, void *ptr,
    145                                           uint64_t imm)
    146 {
    147     plugin_register_inline_op(&insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE],
    148                               rw, op, ptr, imm);
    149 }
    150 
    151 void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,
    152                                            qemu_plugin_vcpu_tb_trans_cb_t cb)
    153 {
    154     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_TB_TRANS, cb);
    155 }
    156 
    157 void qemu_plugin_register_vcpu_syscall_cb(qemu_plugin_id_t id,
    158                                           qemu_plugin_vcpu_syscall_cb_t cb)
    159 {
    160     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL, cb);
    161 }
    162 
    163 void
    164 qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,
    165                                          qemu_plugin_vcpu_syscall_ret_cb_t cb)
    166 {
    167     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL_RET, cb);
    168 }
    169 
    170 /*
    171  * Plugin Queries
    172  *
    173  * These are queries that the plugin can make to gauge information
    174  * from our opaque data types. We do not want to leak internal details
    175  * here just information useful to the plugin.
    176  */
    177 
    178 /*
    179  * Translation block information:
    180  *
    181  * A plugin can query the virtual address of the start of the block
    182  * and the number of instructions in it. It can also get access to
    183  * each translated instruction.
    184  */
    185 
    186 size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb)
    187 {
    188     return tb->n;
    189 }
    190 
    191 uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb)
    192 {
    193     return tb->vaddr;
    194 }
    195 
    196 struct qemu_plugin_insn *
    197 qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx)
    198 {
    199     struct qemu_plugin_insn *insn;
    200     if (unlikely(idx >= tb->n)) {
    201         return NULL;
    202     }
    203     insn = g_ptr_array_index(tb->insns, idx);
    204     insn->mem_only = tb->mem_only;
    205     return insn;
    206 }
    207 
    208 /*
    209  * Instruction information
    210  *
    211  * These queries allow the plugin to retrieve information about each
    212  * instruction being translated.
    213  */
    214 
    215 const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn)
    216 {
    217     return insn->data->data;
    218 }
    219 
    220 size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn)
    221 {
    222     return insn->data->len;
    223 }
    224 
    225 uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn)
    226 {
    227     return insn->vaddr;
    228 }
    229 
    230 void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn)
    231 {
    232     return insn->haddr;
    233 }
    234 
    235 char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn)
    236 {
    237     CPUState *cpu = current_cpu;
    238     return plugin_disas(cpu, insn->vaddr, insn->data->len);
    239 }
    240 
    241 const char *qemu_plugin_insn_symbol(const struct qemu_plugin_insn *insn)
    242 {
    243     const char *sym = lookup_symbol(insn->vaddr);
    244     return sym[0] != 0 ? sym : NULL;
    245 }
    246 
    247 /*
    248  * The memory queries allow the plugin to query information about a
    249  * memory access.
    250  */
    251 
    252 unsigned qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info)
    253 {
    254     MemOp op = get_memop(info);
    255     return op & MO_SIZE;
    256 }
    257 
    258 bool qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info)
    259 {
    260     MemOp op = get_memop(info);
    261     return op & MO_SIGN;
    262 }
    263 
    264 bool qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info)
    265 {
    266     MemOp op = get_memop(info);
    267     return (op & MO_BSWAP) == MO_BE;
    268 }
    269 
    270 bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info)
    271 {
    272     return get_plugin_meminfo_rw(info) & QEMU_PLUGIN_MEM_W;
    273 }
    274 
    275 /*
    276  * Virtual Memory queries
    277  */
    278 
    279 #ifdef CONFIG_SOFTMMU
    280 static __thread struct qemu_plugin_hwaddr hwaddr_info;
    281 #endif
    282 
    283 struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
    284                                                   uint64_t vaddr)
    285 {
    286 #ifdef CONFIG_SOFTMMU
    287     CPUState *cpu = current_cpu;
    288     unsigned int mmu_idx = get_mmuidx(info);
    289     enum qemu_plugin_mem_rw rw = get_plugin_meminfo_rw(info);
    290     hwaddr_info.is_store = (rw & QEMU_PLUGIN_MEM_W) != 0;
    291 
    292     assert(mmu_idx < NB_MMU_MODES);
    293 
    294     if (!tlb_plugin_lookup(cpu, vaddr, mmu_idx,
    295                            hwaddr_info.is_store, &hwaddr_info)) {
    296         error_report("invalid use of qemu_plugin_get_hwaddr");
    297         return NULL;
    298     }
    299 
    300     return &hwaddr_info;
    301 #else
    302     return NULL;
    303 #endif
    304 }
    305 
    306 bool qemu_plugin_hwaddr_is_io(const struct qemu_plugin_hwaddr *haddr)
    307 {
    308 #ifdef CONFIG_SOFTMMU
    309     return haddr->is_io;
    310 #else
    311     return false;
    312 #endif
    313 }
    314 
    315 uint64_t qemu_plugin_hwaddr_phys_addr(const struct qemu_plugin_hwaddr *haddr)
    316 {
    317 #ifdef CONFIG_SOFTMMU
    318     if (haddr) {
    319         if (!haddr->is_io) {
    320             RAMBlock *block;
    321             ram_addr_t offset;
    322             void *hostaddr = haddr->v.ram.hostaddr;
    323 
    324             block = qemu_ram_block_from_host(hostaddr, false, &offset);
    325             if (!block) {
    326                 error_report("Bad host ram pointer %p", haddr->v.ram.hostaddr);
    327                 abort();
    328             }
    329 
    330             return block->offset + offset + block->mr->addr;
    331         } else {
    332             MemoryRegionSection *mrs = haddr->v.io.section;
    333             return mrs->offset_within_address_space + haddr->v.io.offset;
    334         }
    335     }
    336 #endif
    337     return 0;
    338 }
    339 
    340 const char *qemu_plugin_hwaddr_device_name(const struct qemu_plugin_hwaddr *h)
    341 {
    342 #ifdef CONFIG_SOFTMMU
    343     if (h && h->is_io) {
    344         MemoryRegionSection *mrs = h->v.io.section;
    345         if (!mrs->mr->name) {
    346             unsigned long maddr = 0xffffffff & (uintptr_t) mrs->mr;
    347             g_autofree char *temp = g_strdup_printf("anon%08lx", maddr);
    348             return g_intern_string(temp);
    349         } else {
    350             return g_intern_string(mrs->mr->name);
    351         }
    352     } else {
    353         return g_intern_static_string("RAM");
    354     }
    355 #else
    356     return g_intern_static_string("Invalid");
    357 #endif
    358 }
    359 
    360 /*
    361  * Queries to the number and potential maximum number of vCPUs there
    362  * will be. This helps the plugin dimension per-vcpu arrays.
    363  */
    364 
    365 #ifndef CONFIG_USER_ONLY
    366 static MachineState * get_ms(void)
    367 {
    368     return MACHINE(qdev_get_machine());
    369 }
    370 #endif
    371 
    372 int qemu_plugin_n_vcpus(void)
    373 {
    374 #ifdef CONFIG_USER_ONLY
    375     return -1;
    376 #else
    377     return get_ms()->smp.cpus;
    378 #endif
    379 }
    380 
    381 int qemu_plugin_n_max_vcpus(void)
    382 {
    383 #ifdef CONFIG_USER_ONLY
    384     return -1;
    385 #else
    386     return get_ms()->smp.max_cpus;
    387 #endif
    388 }
    389 
    390 /*
    391  * Plugin output
    392  */
    393 void qemu_plugin_outs(const char *string)
    394 {
    395     qemu_log_mask(CPU_LOG_PLUGIN, "%s", string);
    396 }
    397 
    398 bool qemu_plugin_bool_parse(const char *name, const char *value, bool *ret)
    399 {
    400     return name && value && qapi_bool_parse(name, value, ret, NULL);
    401 }
    402 
    403 /*
    404  * Binary path, start and end locations
    405  */
    406 const char *qemu_plugin_path_to_binary(void)
    407 {
    408     char *path = NULL;
    409 #ifdef CONFIG_USER_ONLY
    410     TaskState *ts = (TaskState *) current_cpu->opaque;
    411     path = g_strdup(ts->bprm->filename);
    412 #endif
    413     return path;
    414 }
    415 
    416 uint64_t qemu_plugin_start_code(void)
    417 {
    418     uint64_t start = 0;
    419 #ifdef CONFIG_USER_ONLY
    420     TaskState *ts = (TaskState *) current_cpu->opaque;
    421     start = ts->info->start_code;
    422 #endif
    423     return start;
    424 }
    425 
    426 uint64_t qemu_plugin_end_code(void)
    427 {
    428     uint64_t end = 0;
    429 #ifdef CONFIG_USER_ONLY
    430     TaskState *ts = (TaskState *) current_cpu->opaque;
    431     end = ts->info->end_code;
    432 #endif
    433     return end;
    434 }
    435 
    436 uint64_t qemu_plugin_entry_code(void)
    437 {
    438     uint64_t entry = 0;
    439 #ifdef CONFIG_USER_ONLY
    440     TaskState *ts = (TaskState *) current_cpu->opaque;
    441     entry = ts->info->entry;
    442 #endif
    443     return entry;
    444 }