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 "tcg/tcg.h"
  40#include "exec/exec-all.h"
  41#include "exec/ram_addr.h"
  42#include "disas/disas.h"
  43#include "plugin.h"
  44#ifndef CONFIG_USER_ONLY
  45#include "qemu/plugin-memory.h"
  46#include "hw/boards.h"
  47#endif
  48#include "trace/mem.h"
  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    if (!tb->mem_only) {
  87        plugin_register_dyn_cb__udata(&tb->cbs[PLUGIN_CB_REGULAR],
  88                                      cb, flags, udata);
  89    }
  90}
  91
  92void qemu_plugin_register_vcpu_tb_exec_inline(struct qemu_plugin_tb *tb,
  93                                              enum qemu_plugin_op op,
  94                                              void *ptr, uint64_t imm)
  95{
  96    if (!tb->mem_only) {
  97        plugin_register_inline_op(&tb->cbs[PLUGIN_CB_INLINE], 0, op, ptr, imm);
  98    }
  99}
 100
 101void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
 102                                            qemu_plugin_vcpu_udata_cb_t cb,
 103                                            enum qemu_plugin_cb_flags flags,
 104                                            void *udata)
 105{
 106    if (!insn->mem_only) {
 107        plugin_register_dyn_cb__udata(&insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR],
 108                                      cb, flags, udata);
 109    }
 110}
 111
 112void qemu_plugin_register_vcpu_insn_exec_inline(struct qemu_plugin_insn *insn,
 113                                                enum qemu_plugin_op op,
 114                                                void *ptr, uint64_t imm)
 115{
 116    if (!insn->mem_only) {
 117        plugin_register_inline_op(&insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_INLINE],
 118                                  0, op, ptr, imm);
 119    }
 120}
 121
 122
 123/*
 124 * We always plant memory instrumentation because they don't finalise until
 125 * after the operation has complete.
 126 */
 127void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn,
 128                                      qemu_plugin_vcpu_mem_cb_t cb,
 129                                      enum qemu_plugin_cb_flags flags,
 130                                      enum qemu_plugin_mem_rw rw,
 131                                      void *udata)
 132{
 133    plugin_register_vcpu_mem_cb(&insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR],
 134                                    cb, flags, rw, udata);
 135}
 136
 137void qemu_plugin_register_vcpu_mem_inline(struct qemu_plugin_insn *insn,
 138                                          enum qemu_plugin_mem_rw rw,
 139                                          enum qemu_plugin_op op, void *ptr,
 140                                          uint64_t imm)
 141{
 142    plugin_register_inline_op(&insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE],
 143                              rw, op, ptr, imm);
 144}
 145
 146void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,
 147                                           qemu_plugin_vcpu_tb_trans_cb_t cb)
 148{
 149    plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_TB_TRANS, cb);
 150}
 151
 152void qemu_plugin_register_vcpu_syscall_cb(qemu_plugin_id_t id,
 153                                          qemu_plugin_vcpu_syscall_cb_t cb)
 154{
 155    plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL, cb);
 156}
 157
 158void
 159qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,
 160                                         qemu_plugin_vcpu_syscall_ret_cb_t cb)
 161{
 162    plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL_RET, cb);
 163}
 164
 165/*
 166 * Plugin Queries
 167 *
 168 * These are queries that the plugin can make to gauge information
 169 * from our opaque data types. We do not want to leak internal details
 170 * here just information useful to the plugin.
 171 */
 172
 173/*
 174 * Translation block information:
 175 *
 176 * A plugin can query the virtual address of the start of the block
 177 * and the number of instructions in it. It can also get access to
 178 * each translated instruction.
 179 */
 180
 181size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb)
 182{
 183    return tb->n;
 184}
 185
 186uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb)
 187{
 188    return tb->vaddr;
 189}
 190
 191struct qemu_plugin_insn *
 192qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx)
 193{
 194    struct qemu_plugin_insn *insn;
 195    if (unlikely(idx >= tb->n)) {
 196        return NULL;
 197    }
 198    insn = g_ptr_array_index(tb->insns, idx);
 199    insn->mem_only = tb->mem_only;
 200    return insn;
 201}
 202
 203/*
 204 * Instruction information
 205 *
 206 * These queries allow the plugin to retrieve information about each
 207 * instruction being translated.
 208 */
 209
 210const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn)
 211{
 212    return insn->data->data;
 213}
 214
 215size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn)
 216{
 217    return insn->data->len;
 218}
 219
 220uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn)
 221{
 222    return insn->vaddr;
 223}
 224
 225void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn)
 226{
 227    return insn->haddr;
 228}
 229
 230char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn)
 231{
 232    CPUState *cpu = current_cpu;
 233    return plugin_disas(cpu, insn->vaddr, insn->data->len);
 234}
 235
 236const char *qemu_plugin_insn_symbol(const struct qemu_plugin_insn *insn)
 237{
 238    const char *sym = lookup_symbol(insn->vaddr);
 239    return sym[0] != 0 ? sym : NULL;
 240}
 241
 242/*
 243 * The memory queries allow the plugin to query information about a
 244 * memory access.
 245 */
 246
 247unsigned qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info)
 248{
 249    return info & TRACE_MEM_SZ_SHIFT_MASK;
 250}
 251
 252bool qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info)
 253{
 254    return !!(info & TRACE_MEM_SE);
 255}
 256
 257bool qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info)
 258{
 259    return !!(info & TRACE_MEM_BE);
 260}
 261
 262bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info)
 263{
 264    return !!(info & TRACE_MEM_ST);
 265}
 266
 267/*
 268 * Virtual Memory queries
 269 */
 270
 271#ifdef CONFIG_SOFTMMU
 272static __thread struct qemu_plugin_hwaddr hwaddr_info;
 273#endif
 274
 275struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
 276                                                  uint64_t vaddr)
 277{
 278#ifdef CONFIG_SOFTMMU
 279    CPUState *cpu = current_cpu;
 280    unsigned int mmu_idx = info >> TRACE_MEM_MMU_SHIFT;
 281    hwaddr_info.is_store = info & TRACE_MEM_ST;
 282
 283    if (!tlb_plugin_lookup(cpu, vaddr, mmu_idx,
 284                           info & TRACE_MEM_ST, &hwaddr_info)) {
 285        error_report("invalid use of qemu_plugin_get_hwaddr");
 286        return NULL;
 287    }
 288
 289    return &hwaddr_info;
 290#else
 291    return NULL;
 292#endif
 293}
 294
 295bool qemu_plugin_hwaddr_is_io(const struct qemu_plugin_hwaddr *haddr)
 296{
 297#ifdef CONFIG_SOFTMMU
 298    return haddr->is_io;
 299#else
 300    return false;
 301#endif
 302}
 303
 304uint64_t qemu_plugin_hwaddr_phys_addr(const struct qemu_plugin_hwaddr *haddr)
 305{
 306#ifdef CONFIG_SOFTMMU
 307    if (haddr) {
 308        if (!haddr->is_io) {
 309            RAMBlock *block;
 310            ram_addr_t offset;
 311            void *hostaddr = haddr->v.ram.hostaddr;
 312
 313            block = qemu_ram_block_from_host(hostaddr, false, &offset);
 314            if (!block) {
 315                error_report("Bad host ram pointer %p", haddr->v.ram.hostaddr);
 316                abort();
 317            }
 318
 319            return block->offset + offset + block->mr->addr;
 320        } else {
 321            MemoryRegionSection *mrs = haddr->v.io.section;
 322            return mrs->offset_within_address_space + haddr->v.io.offset;
 323        }
 324    }
 325#endif
 326    return 0;
 327}
 328
 329const char *qemu_plugin_hwaddr_device_name(const struct qemu_plugin_hwaddr *h)
 330{
 331#ifdef CONFIG_SOFTMMU
 332    if (h && h->is_io) {
 333        MemoryRegionSection *mrs = h->v.io.section;
 334        if (!mrs->mr->name) {
 335            unsigned long maddr = 0xffffffff & (uintptr_t) mrs->mr;
 336            g_autofree char *temp = g_strdup_printf("anon%08lx", maddr);
 337            return g_intern_string(temp);
 338        } else {
 339            return g_intern_string(mrs->mr->name);
 340        }
 341    } else {
 342        return g_intern_static_string("RAM");
 343    }
 344#else
 345    return g_intern_static_string("Invalid");
 346#endif
 347}
 348
 349/*
 350 * Queries to the number and potential maximum number of vCPUs there
 351 * will be. This helps the plugin dimension per-vcpu arrays.
 352 */
 353
 354#ifndef CONFIG_USER_ONLY
 355static MachineState * get_ms(void)
 356{
 357    return MACHINE(qdev_get_machine());
 358}
 359#endif
 360
 361int qemu_plugin_n_vcpus(void)
 362{
 363#ifdef CONFIG_USER_ONLY
 364    return -1;
 365#else
 366    return get_ms()->smp.cpus;
 367#endif
 368}
 369
 370int qemu_plugin_n_max_vcpus(void)
 371{
 372#ifdef CONFIG_USER_ONLY
 373    return -1;
 374#else
 375    return get_ms()->smp.max_cpus;
 376#endif
 377}
 378
 379/*
 380 * Plugin output
 381 */
 382void qemu_plugin_outs(const char *string)
 383{
 384    qemu_log_mask(CPU_LOG_PLUGIN, "%s", string);
 385}
 386