qemu/plugins/api.c
<<
>>
Prefs
   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
  52void qemu_plugin_uninstall(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb)
  53{
  54    plugin_reset_uninstall(id, cb, false);
  55}
  56
  57void 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
  69void 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
  75void 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
  81void 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
  90void 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
  97void 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
 106void 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
 116void 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
 126void 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
 135void 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
 141void 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
 147void
 148qemu_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
 170size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb)
 171{
 172    return tb->n;
 173}
 174
 175uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb)
 176{
 177    return tb->vaddr;
 178}
 179
 180struct qemu_plugin_insn *
 181qemu_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
 196const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn)
 197{
 198    return insn->data->data;
 199}
 200
 201size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn)
 202{
 203    return insn->data->len;
 204}
 205
 206uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn)
 207{
 208    return insn->vaddr;
 209}
 210
 211void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn)
 212{
 213    return insn->haddr;
 214}
 215
 216char *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
 227unsigned qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info)
 228{
 229    return info & TRACE_MEM_SZ_SHIFT_MASK;
 230}
 231
 232bool qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info)
 233{
 234    return !!(info & TRACE_MEM_SE);
 235}
 236
 237bool qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info)
 238{
 239    return !!(info & TRACE_MEM_BE);
 240}
 241
 242bool 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
 252static __thread struct qemu_plugin_hwaddr hwaddr_info;
 253
 254struct 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
 270struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
 271                                                  uint64_t vaddr)
 272{
 273    return NULL;
 274}
 275#endif
 276
 277bool 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
 286uint64_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
 311static MachineState * get_ms(void)
 312{
 313    return MACHINE(qdev_get_machine());
 314}
 315#endif
 316
 317int 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
 326int 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 */
 338void qemu_plugin_outs(const char *string)
 339{
 340    qemu_log_mask(CPU_LOG_PLUGIN, "%s", string);
 341}
 342