qemu/include/qemu/plugin.h
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2017, 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#ifndef QEMU_PLUGIN_H
   8#define QEMU_PLUGIN_H
   9
  10#include "qemu/config-file.h"
  11#include "qemu/qemu-plugin.h"
  12#include "qemu/error-report.h"
  13#include "qemu/queue.h"
  14#include "qemu/option.h"
  15
  16/*
  17 * Events that plugins can subscribe to.
  18 */
  19enum qemu_plugin_event {
  20    QEMU_PLUGIN_EV_VCPU_INIT,
  21    QEMU_PLUGIN_EV_VCPU_EXIT,
  22    QEMU_PLUGIN_EV_VCPU_TB_TRANS,
  23    QEMU_PLUGIN_EV_VCPU_IDLE,
  24    QEMU_PLUGIN_EV_VCPU_RESUME,
  25    QEMU_PLUGIN_EV_VCPU_SYSCALL,
  26    QEMU_PLUGIN_EV_VCPU_SYSCALL_RET,
  27    QEMU_PLUGIN_EV_FLUSH,
  28    QEMU_PLUGIN_EV_ATEXIT,
  29    QEMU_PLUGIN_EV_MAX, /* total number of plugin events we support */
  30};
  31
  32/*
  33 * Option parsing/processing.
  34 * Note that we can load an arbitrary number of plugins.
  35 */
  36struct qemu_plugin_desc;
  37typedef QTAILQ_HEAD(, qemu_plugin_desc) QemuPluginList;
  38
  39#ifdef CONFIG_PLUGIN
  40extern QemuOptsList qemu_plugin_opts;
  41
  42static inline void qemu_plugin_add_opts(void)
  43{
  44    qemu_add_opts(&qemu_plugin_opts);
  45}
  46
  47void qemu_plugin_opt_parse(const char *optarg, QemuPluginList *head);
  48int qemu_plugin_load_list(QemuPluginList *head, Error **errp);
  49
  50union qemu_plugin_cb_sig {
  51    qemu_plugin_simple_cb_t          simple;
  52    qemu_plugin_udata_cb_t           udata;
  53    qemu_plugin_vcpu_simple_cb_t     vcpu_simple;
  54    qemu_plugin_vcpu_udata_cb_t      vcpu_udata;
  55    qemu_plugin_vcpu_tb_trans_cb_t   vcpu_tb_trans;
  56    qemu_plugin_vcpu_mem_cb_t        vcpu_mem;
  57    qemu_plugin_vcpu_syscall_cb_t    vcpu_syscall;
  58    qemu_plugin_vcpu_syscall_ret_cb_t vcpu_syscall_ret;
  59    void *generic;
  60};
  61
  62enum plugin_dyn_cb_type {
  63    PLUGIN_CB_INSN,
  64    PLUGIN_CB_MEM,
  65    PLUGIN_N_CB_TYPES,
  66};
  67
  68enum plugin_dyn_cb_subtype {
  69    PLUGIN_CB_REGULAR,
  70    PLUGIN_CB_INLINE,
  71    PLUGIN_N_CB_SUBTYPES,
  72};
  73
  74/*
  75 * A dynamic callback has an insertion point that is determined at run-time.
  76 * Usually the insertion point is somewhere in the code cache; think for
  77 * instance of a callback to be called upon the execution of a particular TB.
  78 */
  79struct qemu_plugin_dyn_cb {
  80    union qemu_plugin_cb_sig f;
  81    void *userp;
  82    unsigned tcg_flags;
  83    enum plugin_dyn_cb_subtype type;
  84    /* @rw applies to mem callbacks only (both regular and inline) */
  85    enum qemu_plugin_mem_rw rw;
  86    /* fields specific to each dyn_cb type go here */
  87    union {
  88        struct {
  89            enum qemu_plugin_op op;
  90            uint64_t imm;
  91        } inline_insn;
  92    };
  93};
  94
  95/* Internal context for instrumenting an instruction */
  96struct qemu_plugin_insn {
  97    GByteArray *data;
  98    uint64_t vaddr;
  99    void *haddr;
 100    GArray *cbs[PLUGIN_N_CB_TYPES][PLUGIN_N_CB_SUBTYPES];
 101    bool calls_helpers;
 102    bool mem_helper;
 103    bool mem_only;
 104};
 105
 106/*
 107 * qemu_plugin_insn allocate and cleanup functions. We don't expect to
 108 * cleanup many of these structures. They are reused for each fresh
 109 * translation.
 110 */
 111
 112static inline void qemu_plugin_insn_cleanup_fn(gpointer data)
 113{
 114    struct qemu_plugin_insn *insn = (struct qemu_plugin_insn *) data;
 115    g_byte_array_free(insn->data, true);
 116}
 117
 118static inline struct qemu_plugin_insn *qemu_plugin_insn_alloc(void)
 119{
 120    int i, j;
 121    struct qemu_plugin_insn *insn = g_new0(struct qemu_plugin_insn, 1);
 122    insn->data = g_byte_array_sized_new(4);
 123
 124    for (i = 0; i < PLUGIN_N_CB_TYPES; i++) {
 125        for (j = 0; j < PLUGIN_N_CB_SUBTYPES; j++) {
 126            insn->cbs[i][j] = g_array_new(false, false,
 127                                          sizeof(struct qemu_plugin_dyn_cb));
 128        }
 129    }
 130    return insn;
 131}
 132
 133/* Internal context for this TranslationBlock */
 134struct qemu_plugin_tb {
 135    GPtrArray *insns;
 136    size_t n;
 137    uint64_t vaddr;
 138    uint64_t vaddr2;
 139    void *haddr1;
 140    void *haddr2;
 141    bool mem_only;
 142    GArray *cbs[PLUGIN_N_CB_SUBTYPES];
 143};
 144
 145/**
 146 * qemu_plugin_tb_insn_get(): get next plugin record for translation.
 147 *
 148 */
 149static inline
 150struct qemu_plugin_insn *qemu_plugin_tb_insn_get(struct qemu_plugin_tb *tb)
 151{
 152    struct qemu_plugin_insn *insn;
 153    int i, j;
 154
 155    if (unlikely(tb->n == tb->insns->len)) {
 156        struct qemu_plugin_insn *new_insn = qemu_plugin_insn_alloc();
 157        g_ptr_array_add(tb->insns, new_insn);
 158    }
 159    insn = g_ptr_array_index(tb->insns, tb->n++);
 160    g_byte_array_set_size(insn->data, 0);
 161    insn->calls_helpers = false;
 162    insn->mem_helper = false;
 163
 164    for (i = 0; i < PLUGIN_N_CB_TYPES; i++) {
 165        for (j = 0; j < PLUGIN_N_CB_SUBTYPES; j++) {
 166            g_array_set_size(insn->cbs[i][j], 0);
 167        }
 168    }
 169
 170    return insn;
 171}
 172
 173void qemu_plugin_vcpu_init_hook(CPUState *cpu);
 174void qemu_plugin_vcpu_exit_hook(CPUState *cpu);
 175void qemu_plugin_tb_trans_cb(CPUState *cpu, struct qemu_plugin_tb *tb);
 176void qemu_plugin_vcpu_idle_cb(CPUState *cpu);
 177void qemu_plugin_vcpu_resume_cb(CPUState *cpu);
 178void
 179qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1,
 180                         uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5,
 181                         uint64_t a6, uint64_t a7, uint64_t a8);
 182void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret);
 183
 184void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr, uint32_t meminfo);
 185
 186void qemu_plugin_flush_cb(void);
 187
 188void qemu_plugin_atexit_cb(void);
 189
 190void qemu_plugin_add_dyn_cb_arr(GArray *arr);
 191
 192void qemu_plugin_disable_mem_helpers(CPUState *cpu);
 193
 194#else /* !CONFIG_PLUGIN */
 195
 196static inline void qemu_plugin_add_opts(void)
 197{ }
 198
 199static inline void qemu_plugin_opt_parse(const char *optarg,
 200                                         QemuPluginList *head)
 201{
 202    error_report("plugin interface not enabled in this build");
 203    exit(1);
 204}
 205
 206static inline int qemu_plugin_load_list(QemuPluginList *head, Error **errp)
 207{
 208    return 0;
 209}
 210
 211static inline void qemu_plugin_vcpu_init_hook(CPUState *cpu)
 212{ }
 213
 214static inline void qemu_plugin_vcpu_exit_hook(CPUState *cpu)
 215{ }
 216
 217static inline void qemu_plugin_tb_trans_cb(CPUState *cpu,
 218                                           struct qemu_plugin_tb *tb)
 219{ }
 220
 221static inline void qemu_plugin_vcpu_idle_cb(CPUState *cpu)
 222{ }
 223
 224static inline void qemu_plugin_vcpu_resume_cb(CPUState *cpu)
 225{ }
 226
 227static inline void
 228qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1, uint64_t a2,
 229                         uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6,
 230                         uint64_t a7, uint64_t a8)
 231{ }
 232
 233static inline
 234void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret)
 235{ }
 236
 237static inline void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
 238                                           uint32_t meminfo)
 239{ }
 240
 241static inline void qemu_plugin_flush_cb(void)
 242{ }
 243
 244static inline void qemu_plugin_atexit_cb(void)
 245{ }
 246
 247static inline
 248void qemu_plugin_add_dyn_cb_arr(GArray *arr)
 249{ }
 250
 251static inline void qemu_plugin_disable_mem_helpers(CPUState *cpu)
 252{ }
 253
 254#endif /* !CONFIG_PLUGIN */
 255
 256#endif /* QEMU_PLUGIN_H */
 257