qemu

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

core.c (15605B)


      1 /*
      2  * QEMU Plugin Core code
      3  *
      4  * This is the core code that deals with injecting instrumentation into the code
      5  *
      6  * Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
      7  * Copyright (C) 2019, Linaro
      8  *
      9  * License: GNU GPL, version 2 or later.
     10  *   See the COPYING file in the top-level directory.
     11  *
     12  * SPDX-License-Identifier: GPL-2.0-or-later
     13  */
     14 #include "qemu/osdep.h"
     15 #include "qemu/error-report.h"
     16 #include "qemu/config-file.h"
     17 #include "qapi/error.h"
     18 #include "qemu/lockable.h"
     19 #include "qemu/option.h"
     20 #include "qemu/rcu_queue.h"
     21 #include "qemu/xxhash.h"
     22 #include "qemu/rcu.h"
     23 #include "hw/core/cpu.h"
     24 #include "exec/cpu-common.h"
     25 
     26 #include "exec/exec-all.h"
     27 #include "exec/helper-proto.h"
     28 #include "tcg/tcg.h"
     29 #include "tcg/tcg-op.h"
     30 #include "plugin.h"
     31 #include "qemu/compiler.h"
     32 
     33 struct qemu_plugin_cb {
     34     struct qemu_plugin_ctx *ctx;
     35     union qemu_plugin_cb_sig f;
     36     void *udata;
     37     QLIST_ENTRY(qemu_plugin_cb) entry;
     38 };
     39 
     40 struct qemu_plugin_state plugin;
     41 
     42 struct qemu_plugin_ctx *plugin_id_to_ctx_locked(qemu_plugin_id_t id)
     43 {
     44     struct qemu_plugin_ctx *ctx;
     45     qemu_plugin_id_t *id_p;
     46 
     47     id_p = g_hash_table_lookup(plugin.id_ht, &id);
     48     ctx = container_of(id_p, struct qemu_plugin_ctx, id);
     49     if (ctx == NULL) {
     50         error_report("plugin: invalid plugin id %" PRIu64, id);
     51         abort();
     52     }
     53     return ctx;
     54 }
     55 
     56 static void plugin_cpu_update__async(CPUState *cpu, run_on_cpu_data data)
     57 {
     58     bitmap_copy(cpu->plugin_mask, &data.host_ulong, QEMU_PLUGIN_EV_MAX);
     59     tcg_flush_jmp_cache(cpu);
     60 }
     61 
     62 static void plugin_cpu_update__locked(gpointer k, gpointer v, gpointer udata)
     63 {
     64     CPUState *cpu = container_of(k, CPUState, cpu_index);
     65     run_on_cpu_data mask = RUN_ON_CPU_HOST_ULONG(*plugin.mask);
     66 
     67     if (cpu->created) {
     68         async_run_on_cpu(cpu, plugin_cpu_update__async, mask);
     69     } else {
     70         plugin_cpu_update__async(cpu, mask);
     71     }
     72 }
     73 
     74 void plugin_unregister_cb__locked(struct qemu_plugin_ctx *ctx,
     75                                   enum qemu_plugin_event ev)
     76 {
     77     struct qemu_plugin_cb *cb = ctx->callbacks[ev];
     78 
     79     if (cb == NULL) {
     80         return;
     81     }
     82     QLIST_REMOVE_RCU(cb, entry);
     83     g_free(cb);
     84     ctx->callbacks[ev] = NULL;
     85     if (QLIST_EMPTY_RCU(&plugin.cb_lists[ev])) {
     86         clear_bit(ev, plugin.mask);
     87         g_hash_table_foreach(plugin.cpu_ht, plugin_cpu_update__locked, NULL);
     88     }
     89 }
     90 
     91 /*
     92  * Disable CFI checks.
     93  * The callback function has been loaded from an external library so we do not
     94  * have type information
     95  */
     96 QEMU_DISABLE_CFI
     97 static void plugin_vcpu_cb__simple(CPUState *cpu, enum qemu_plugin_event ev)
     98 {
     99     struct qemu_plugin_cb *cb, *next;
    100 
    101     switch (ev) {
    102     case QEMU_PLUGIN_EV_VCPU_INIT:
    103     case QEMU_PLUGIN_EV_VCPU_EXIT:
    104     case QEMU_PLUGIN_EV_VCPU_IDLE:
    105     case QEMU_PLUGIN_EV_VCPU_RESUME:
    106         /* iterate safely; plugins might uninstall themselves at any time */
    107         QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
    108             qemu_plugin_vcpu_simple_cb_t func = cb->f.vcpu_simple;
    109 
    110             func(cb->ctx->id, cpu->cpu_index);
    111         }
    112         break;
    113     default:
    114         g_assert_not_reached();
    115     }
    116 }
    117 
    118 /*
    119  * Disable CFI checks.
    120  * The callback function has been loaded from an external library so we do not
    121  * have type information
    122  */
    123 QEMU_DISABLE_CFI
    124 static void plugin_cb__simple(enum qemu_plugin_event ev)
    125 {
    126     struct qemu_plugin_cb *cb, *next;
    127 
    128     switch (ev) {
    129     case QEMU_PLUGIN_EV_FLUSH:
    130         QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
    131             qemu_plugin_simple_cb_t func = cb->f.simple;
    132 
    133             func(cb->ctx->id);
    134         }
    135         break;
    136     default:
    137         g_assert_not_reached();
    138     }
    139 }
    140 
    141 /*
    142  * Disable CFI checks.
    143  * The callback function has been loaded from an external library so we do not
    144  * have type information
    145  */
    146 QEMU_DISABLE_CFI
    147 static void plugin_cb__udata(enum qemu_plugin_event ev)
    148 {
    149     struct qemu_plugin_cb *cb, *next;
    150 
    151     switch (ev) {
    152     case QEMU_PLUGIN_EV_ATEXIT:
    153         QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
    154             qemu_plugin_udata_cb_t func = cb->f.udata;
    155 
    156             func(cb->ctx->id, cb->udata);
    157         }
    158         break;
    159     default:
    160         g_assert_not_reached();
    161     }
    162 }
    163 
    164 static void
    165 do_plugin_register_cb(qemu_plugin_id_t id, enum qemu_plugin_event ev,
    166                       void *func, void *udata)
    167 {
    168     struct qemu_plugin_ctx *ctx;
    169 
    170     QEMU_LOCK_GUARD(&plugin.lock);
    171     ctx = plugin_id_to_ctx_locked(id);
    172     /* if the plugin is on its way out, ignore this request */
    173     if (unlikely(ctx->uninstalling)) {
    174         return;
    175     }
    176     if (func) {
    177         struct qemu_plugin_cb *cb = ctx->callbacks[ev];
    178 
    179         if (cb) {
    180             cb->f.generic = func;
    181             cb->udata = udata;
    182         } else {
    183             cb = g_new(struct qemu_plugin_cb, 1);
    184             cb->ctx = ctx;
    185             cb->f.generic = func;
    186             cb->udata = udata;
    187             ctx->callbacks[ev] = cb;
    188             QLIST_INSERT_HEAD_RCU(&plugin.cb_lists[ev], cb, entry);
    189             if (!test_bit(ev, plugin.mask)) {
    190                 set_bit(ev, plugin.mask);
    191                 g_hash_table_foreach(plugin.cpu_ht, plugin_cpu_update__locked,
    192                                      NULL);
    193             }
    194         }
    195     } else {
    196         plugin_unregister_cb__locked(ctx, ev);
    197     }
    198 }
    199 
    200 void plugin_register_cb(qemu_plugin_id_t id, enum qemu_plugin_event ev,
    201                         void *func)
    202 {
    203     do_plugin_register_cb(id, ev, func, NULL);
    204 }
    205 
    206 void
    207 plugin_register_cb_udata(qemu_plugin_id_t id, enum qemu_plugin_event ev,
    208                          void *func, void *udata)
    209 {
    210     do_plugin_register_cb(id, ev, func, udata);
    211 }
    212 
    213 void qemu_plugin_vcpu_init_hook(CPUState *cpu)
    214 {
    215     bool success;
    216 
    217     qemu_rec_mutex_lock(&plugin.lock);
    218     plugin_cpu_update__locked(&cpu->cpu_index, NULL, NULL);
    219     success = g_hash_table_insert(plugin.cpu_ht, &cpu->cpu_index,
    220                                   &cpu->cpu_index);
    221     g_assert(success);
    222     qemu_rec_mutex_unlock(&plugin.lock);
    223 
    224     plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_INIT);
    225 }
    226 
    227 void qemu_plugin_vcpu_exit_hook(CPUState *cpu)
    228 {
    229     bool success;
    230 
    231     plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_EXIT);
    232 
    233     qemu_rec_mutex_lock(&plugin.lock);
    234     success = g_hash_table_remove(plugin.cpu_ht, &cpu->cpu_index);
    235     g_assert(success);
    236     qemu_rec_mutex_unlock(&plugin.lock);
    237 }
    238 
    239 struct plugin_for_each_args {
    240     struct qemu_plugin_ctx *ctx;
    241     qemu_plugin_vcpu_simple_cb_t cb;
    242 };
    243 
    244 static void plugin_vcpu_for_each(gpointer k, gpointer v, gpointer udata)
    245 {
    246     struct plugin_for_each_args *args = udata;
    247     int cpu_index = *(int *)k;
    248 
    249     args->cb(args->ctx->id, cpu_index);
    250 }
    251 
    252 void qemu_plugin_vcpu_for_each(qemu_plugin_id_t id,
    253                                qemu_plugin_vcpu_simple_cb_t cb)
    254 {
    255     struct plugin_for_each_args args;
    256 
    257     if (cb == NULL) {
    258         return;
    259     }
    260     qemu_rec_mutex_lock(&plugin.lock);
    261     args.ctx = plugin_id_to_ctx_locked(id);
    262     args.cb = cb;
    263     g_hash_table_foreach(plugin.cpu_ht, plugin_vcpu_for_each, &args);
    264     qemu_rec_mutex_unlock(&plugin.lock);
    265 }
    266 
    267 /* Allocate and return a callback record */
    268 static struct qemu_plugin_dyn_cb *plugin_get_dyn_cb(GArray **arr)
    269 {
    270     GArray *cbs = *arr;
    271 
    272     if (!cbs) {
    273         cbs = g_array_sized_new(false, false,
    274                                 sizeof(struct qemu_plugin_dyn_cb), 1);
    275         *arr = cbs;
    276     }
    277 
    278     g_array_set_size(cbs, cbs->len + 1);
    279     return &g_array_index(cbs, struct qemu_plugin_dyn_cb, cbs->len - 1);
    280 }
    281 
    282 void plugin_register_inline_op(GArray **arr,
    283                                enum qemu_plugin_mem_rw rw,
    284                                enum qemu_plugin_op op, void *ptr,
    285                                uint64_t imm)
    286 {
    287     struct qemu_plugin_dyn_cb *dyn_cb;
    288 
    289     dyn_cb = plugin_get_dyn_cb(arr);
    290     dyn_cb->userp = ptr;
    291     dyn_cb->type = PLUGIN_CB_INLINE;
    292     dyn_cb->rw = rw;
    293     dyn_cb->inline_insn.op = op;
    294     dyn_cb->inline_insn.imm = imm;
    295 }
    296 
    297 void plugin_register_dyn_cb__udata(GArray **arr,
    298                                    qemu_plugin_vcpu_udata_cb_t cb,
    299                                    enum qemu_plugin_cb_flags flags,
    300                                    void *udata)
    301 {
    302     struct qemu_plugin_dyn_cb *dyn_cb = plugin_get_dyn_cb(arr);
    303 
    304     dyn_cb->userp = udata;
    305     /* Note flags are discarded as unused. */
    306     dyn_cb->f.vcpu_udata = cb;
    307     dyn_cb->type = PLUGIN_CB_REGULAR;
    308 }
    309 
    310 void plugin_register_vcpu_mem_cb(GArray **arr,
    311                                  void *cb,
    312                                  enum qemu_plugin_cb_flags flags,
    313                                  enum qemu_plugin_mem_rw rw,
    314                                  void *udata)
    315 {
    316     struct qemu_plugin_dyn_cb *dyn_cb;
    317 
    318     dyn_cb = plugin_get_dyn_cb(arr);
    319     dyn_cb->userp = udata;
    320     /* Note flags are discarded as unused. */
    321     dyn_cb->type = PLUGIN_CB_REGULAR;
    322     dyn_cb->rw = rw;
    323     dyn_cb->f.generic = cb;
    324 }
    325 
    326 /*
    327  * Disable CFI checks.
    328  * The callback function has been loaded from an external library so we do not
    329  * have type information
    330  */
    331 QEMU_DISABLE_CFI
    332 void qemu_plugin_tb_trans_cb(CPUState *cpu, struct qemu_plugin_tb *tb)
    333 {
    334     struct qemu_plugin_cb *cb, *next;
    335     enum qemu_plugin_event ev = QEMU_PLUGIN_EV_VCPU_TB_TRANS;
    336 
    337     /* no plugin_mask check here; caller should have checked */
    338 
    339     QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
    340         qemu_plugin_vcpu_tb_trans_cb_t func = cb->f.vcpu_tb_trans;
    341 
    342         func(cb->ctx->id, tb);
    343     }
    344 }
    345 
    346 /*
    347  * Disable CFI checks.
    348  * The callback function has been loaded from an external library so we do not
    349  * have type information
    350  */
    351 QEMU_DISABLE_CFI
    352 void
    353 qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1, uint64_t a2,
    354                          uint64_t a3, uint64_t a4, uint64_t a5,
    355                          uint64_t a6, uint64_t a7, uint64_t a8)
    356 {
    357     struct qemu_plugin_cb *cb, *next;
    358     enum qemu_plugin_event ev = QEMU_PLUGIN_EV_VCPU_SYSCALL;
    359 
    360     if (!test_bit(ev, cpu->plugin_mask)) {
    361         return;
    362     }
    363 
    364     QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
    365         qemu_plugin_vcpu_syscall_cb_t func = cb->f.vcpu_syscall;
    366 
    367         func(cb->ctx->id, cpu->cpu_index, num, a1, a2, a3, a4, a5, a6, a7, a8);
    368     }
    369 }
    370 
    371 /*
    372  * Disable CFI checks.
    373  * The callback function has been loaded from an external library so we do not
    374  * have type information
    375  */
    376 QEMU_DISABLE_CFI
    377 void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret)
    378 {
    379     struct qemu_plugin_cb *cb, *next;
    380     enum qemu_plugin_event ev = QEMU_PLUGIN_EV_VCPU_SYSCALL_RET;
    381 
    382     if (!test_bit(ev, cpu->plugin_mask)) {
    383         return;
    384     }
    385 
    386     QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
    387         qemu_plugin_vcpu_syscall_ret_cb_t func = cb->f.vcpu_syscall_ret;
    388 
    389         func(cb->ctx->id, cpu->cpu_index, num, ret);
    390     }
    391 }
    392 
    393 void qemu_plugin_vcpu_idle_cb(CPUState *cpu)
    394 {
    395     plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_IDLE);
    396 }
    397 
    398 void qemu_plugin_vcpu_resume_cb(CPUState *cpu)
    399 {
    400     plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_RESUME);
    401 }
    402 
    403 void qemu_plugin_register_vcpu_idle_cb(qemu_plugin_id_t id,
    404                                        qemu_plugin_vcpu_simple_cb_t cb)
    405 {
    406     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_IDLE, cb);
    407 }
    408 
    409 void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
    410                                          qemu_plugin_vcpu_simple_cb_t cb)
    411 {
    412     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_RESUME, cb);
    413 }
    414 
    415 void qemu_plugin_register_flush_cb(qemu_plugin_id_t id,
    416                                    qemu_plugin_simple_cb_t cb)
    417 {
    418     plugin_register_cb(id, QEMU_PLUGIN_EV_FLUSH, cb);
    419 }
    420 
    421 static bool free_dyn_cb_arr(void *p, uint32_t h, void *userp)
    422 {
    423     g_array_free((GArray *) p, true);
    424     return true;
    425 }
    426 
    427 void qemu_plugin_flush_cb(void)
    428 {
    429     qht_iter_remove(&plugin.dyn_cb_arr_ht, free_dyn_cb_arr, NULL);
    430     qht_reset(&plugin.dyn_cb_arr_ht);
    431 
    432     plugin_cb__simple(QEMU_PLUGIN_EV_FLUSH);
    433 }
    434 
    435 void exec_inline_op(struct qemu_plugin_dyn_cb *cb)
    436 {
    437     uint64_t *val = cb->userp;
    438 
    439     switch (cb->inline_insn.op) {
    440     case QEMU_PLUGIN_INLINE_ADD_U64:
    441         *val += cb->inline_insn.imm;
    442         break;
    443     default:
    444         g_assert_not_reached();
    445     }
    446 }
    447 
    448 void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
    449                              MemOpIdx oi, enum qemu_plugin_mem_rw rw)
    450 {
    451     GArray *arr = cpu->plugin_mem_cbs;
    452     size_t i;
    453 
    454     if (arr == NULL) {
    455         return;
    456     }
    457     for (i = 0; i < arr->len; i++) {
    458         struct qemu_plugin_dyn_cb *cb =
    459             &g_array_index(arr, struct qemu_plugin_dyn_cb, i);
    460 
    461         if (!(rw & cb->rw)) {
    462                 break;
    463         }
    464         switch (cb->type) {
    465         case PLUGIN_CB_REGULAR:
    466             cb->f.vcpu_mem(cpu->cpu_index, make_plugin_meminfo(oi, rw),
    467                            vaddr, cb->userp);
    468             break;
    469         case PLUGIN_CB_INLINE:
    470             exec_inline_op(cb);
    471             break;
    472         default:
    473             g_assert_not_reached();
    474         }
    475     }
    476 }
    477 
    478 void qemu_plugin_atexit_cb(void)
    479 {
    480     plugin_cb__udata(QEMU_PLUGIN_EV_ATEXIT);
    481 }
    482 
    483 void qemu_plugin_register_atexit_cb(qemu_plugin_id_t id,
    484                                     qemu_plugin_udata_cb_t cb,
    485                                     void *udata)
    486 {
    487     plugin_register_cb_udata(id, QEMU_PLUGIN_EV_ATEXIT, cb, udata);
    488 }
    489 
    490 /*
    491  * Handle exit from linux-user. Unlike the normal atexit() mechanism
    492  * we need to handle the clean-up manually as it's possible threads
    493  * are still running. We need to remove all callbacks from code
    494  * generation, flush the current translations and then we can safely
    495  * trigger the exit callbacks.
    496  */
    497 
    498 void qemu_plugin_user_exit(void)
    499 {
    500     enum qemu_plugin_event ev;
    501     CPUState *cpu;
    502 
    503     QEMU_LOCK_GUARD(&plugin.lock);
    504 
    505     start_exclusive();
    506 
    507     /* un-register all callbacks except the final AT_EXIT one */
    508     for (ev = 0; ev < QEMU_PLUGIN_EV_MAX; ev++) {
    509         if (ev != QEMU_PLUGIN_EV_ATEXIT) {
    510             struct qemu_plugin_ctx *ctx;
    511             QTAILQ_FOREACH(ctx, &plugin.ctxs, entry) {
    512                 plugin_unregister_cb__locked(ctx, ev);
    513             }
    514         }
    515     }
    516 
    517     tb_flush(current_cpu);
    518 
    519     CPU_FOREACH(cpu) {
    520         qemu_plugin_disable_mem_helpers(cpu);
    521     }
    522 
    523     end_exclusive();
    524 
    525     /* now it's safe to handle the exit case */
    526     qemu_plugin_atexit_cb();
    527 }
    528 
    529 /*
    530  * Helpers for *-user to ensure locks are sane across fork() events.
    531  */
    532 
    533 void qemu_plugin_user_prefork_lock(void)
    534 {
    535     qemu_rec_mutex_lock(&plugin.lock);
    536 }
    537 
    538 void qemu_plugin_user_postfork(bool is_child)
    539 {
    540     if (is_child) {
    541         /* should we just reset via plugin_init? */
    542         qemu_rec_mutex_init(&plugin.lock);
    543     } else {
    544         qemu_rec_mutex_unlock(&plugin.lock);
    545     }
    546 }
    547 
    548 
    549 /*
    550  * Call this function after longjmp'ing to the main loop. It's possible that the
    551  * last instruction of a TB might have used helpers, and therefore the
    552  * "disable" instruction will never execute because it ended up as dead code.
    553  */
    554 void qemu_plugin_disable_mem_helpers(CPUState *cpu)
    555 {
    556     cpu->plugin_mem_cbs = NULL;
    557 }
    558 
    559 static bool plugin_dyn_cb_arr_cmp(const void *ap, const void *bp)
    560 {
    561     return ap == bp;
    562 }
    563 
    564 static void __attribute__((__constructor__)) plugin_init(void)
    565 {
    566     int i;
    567 
    568     for (i = 0; i < QEMU_PLUGIN_EV_MAX; i++) {
    569         QLIST_INIT(&plugin.cb_lists[i]);
    570     }
    571     qemu_rec_mutex_init(&plugin.lock);
    572     plugin.id_ht = g_hash_table_new(g_int64_hash, g_int64_equal);
    573     plugin.cpu_ht = g_hash_table_new(g_int_hash, g_int_equal);
    574     QTAILQ_INIT(&plugin.ctxs);
    575     qht_init(&plugin.dyn_cb_arr_ht, plugin_dyn_cb_arr_cmp, 16,
    576              QHT_MODE_AUTO_RESIZE);
    577     atexit(qemu_plugin_atexit_cb);
    578 }