xref: /qemu/plugins/core.c (revision 597639c4273d1433b0a47c8533b90ccce29f84e5)
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/lockable.h"
16 #include "qemu/option.h"
17 #include "qemu/plugin.h"
18 #include "qemu/qemu-plugin.h"
19 #include "qemu/queue.h"
20 #include "qemu/rcu_queue.h"
21 #include "qemu/rcu.h"
22 #include "exec/tb-flush.h"
23 #include "tcg/tcg-op-common.h"
24 #include "plugin.h"
25 
26 struct qemu_plugin_cb {
27     struct qemu_plugin_ctx *ctx;
28     union qemu_plugin_cb_sig f;
29     void *udata;
30     QLIST_ENTRY(qemu_plugin_cb) entry;
31 };
32 
33 struct qemu_plugin_state plugin;
34 
plugin_id_to_ctx_locked(qemu_plugin_id_t id)35 struct qemu_plugin_ctx *plugin_id_to_ctx_locked(qemu_plugin_id_t id)
36 {
37     struct qemu_plugin_ctx *ctx;
38     qemu_plugin_id_t *id_p;
39 
40     id_p = g_hash_table_lookup(plugin.id_ht, &id);
41     ctx = container_of(id_p, struct qemu_plugin_ctx, id);
42     if (ctx == NULL) {
43         error_report("plugin: invalid plugin id %" PRIu64, id);
44         abort();
45     }
46     return ctx;
47 }
48 
plugin_cpu_update__async(CPUState * cpu,run_on_cpu_data data)49 static void plugin_cpu_update__async(CPUState *cpu, run_on_cpu_data data)
50 {
51     bitmap_copy(cpu->plugin_state->event_mask,
52                 &data.host_ulong, QEMU_PLUGIN_EV_MAX);
53     tcg_flush_jmp_cache(cpu);
54 }
55 
plugin_cpu_update__locked(gpointer k,gpointer v,gpointer udata)56 static void plugin_cpu_update__locked(gpointer k, gpointer v, gpointer udata)
57 {
58     CPUState *cpu = container_of(k, CPUState, cpu_index);
59     run_on_cpu_data mask = RUN_ON_CPU_HOST_ULONG(*plugin.mask);
60 
61     async_run_on_cpu(cpu, plugin_cpu_update__async, mask);
62 }
63 
plugin_unregister_cb__locked(struct qemu_plugin_ctx * ctx,enum qemu_plugin_event ev)64 void plugin_unregister_cb__locked(struct qemu_plugin_ctx *ctx,
65                                   enum qemu_plugin_event ev)
66 {
67     struct qemu_plugin_cb *cb = ctx->callbacks[ev];
68 
69     if (cb == NULL) {
70         return;
71     }
72     QLIST_REMOVE_RCU(cb, entry);
73     g_free(cb);
74     ctx->callbacks[ev] = NULL;
75     if (QLIST_EMPTY_RCU(&plugin.cb_lists[ev])) {
76         clear_bit(ev, plugin.mask);
77         g_hash_table_foreach(plugin.cpu_ht, plugin_cpu_update__locked, NULL);
78     }
79 }
80 
81 /*
82  * Disable CFI checks.
83  * The callback function has been loaded from an external library so we do not
84  * have type information
85  */
86 QEMU_DISABLE_CFI
plugin_vcpu_cb__simple(CPUState * cpu,enum qemu_plugin_event ev)87 static void plugin_vcpu_cb__simple(CPUState *cpu, enum qemu_plugin_event ev)
88 {
89     struct qemu_plugin_cb *cb, *next;
90 
91     switch (ev) {
92     case QEMU_PLUGIN_EV_VCPU_INIT:
93     case QEMU_PLUGIN_EV_VCPU_EXIT:
94     case QEMU_PLUGIN_EV_VCPU_IDLE:
95     case QEMU_PLUGIN_EV_VCPU_RESUME:
96         /* iterate safely; plugins might uninstall themselves at any time */
97         QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
98             qemu_plugin_vcpu_simple_cb_t func = cb->f.vcpu_simple;
99 
100             func(cb->ctx->id, cpu->cpu_index);
101         }
102         break;
103     default:
104         g_assert_not_reached();
105     }
106 }
107 
108 /*
109  * Disable CFI checks.
110  * The callback function has been loaded from an external library so we do not
111  * have type information
112  */
113 QEMU_DISABLE_CFI
plugin_cb__simple(enum qemu_plugin_event ev)114 static void plugin_cb__simple(enum qemu_plugin_event ev)
115 {
116     struct qemu_plugin_cb *cb, *next;
117 
118     switch (ev) {
119     case QEMU_PLUGIN_EV_FLUSH:
120         QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
121             qemu_plugin_simple_cb_t func = cb->f.simple;
122 
123             func(cb->ctx->id);
124         }
125         break;
126     default:
127         g_assert_not_reached();
128     }
129 }
130 
131 /*
132  * Disable CFI checks.
133  * The callback function has been loaded from an external library so we do not
134  * have type information
135  */
136 QEMU_DISABLE_CFI
plugin_cb__udata(enum qemu_plugin_event ev)137 static void plugin_cb__udata(enum qemu_plugin_event ev)
138 {
139     struct qemu_plugin_cb *cb, *next;
140 
141     switch (ev) {
142     case QEMU_PLUGIN_EV_ATEXIT:
143         QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
144             qemu_plugin_udata_cb_t func = cb->f.udata;
145 
146             func(cb->ctx->id, cb->udata);
147         }
148         break;
149     default:
150         g_assert_not_reached();
151     }
152 }
153 
154 static void
do_plugin_register_cb(qemu_plugin_id_t id,enum qemu_plugin_event ev,void * func,void * udata)155 do_plugin_register_cb(qemu_plugin_id_t id, enum qemu_plugin_event ev,
156                       void *func, void *udata)
157 {
158     struct qemu_plugin_ctx *ctx;
159 
160     QEMU_LOCK_GUARD(&plugin.lock);
161     ctx = plugin_id_to_ctx_locked(id);
162     /* if the plugin is on its way out, ignore this request */
163     if (unlikely(ctx->uninstalling)) {
164         return;
165     }
166     if (func) {
167         struct qemu_plugin_cb *cb = ctx->callbacks[ev];
168 
169         if (cb) {
170             cb->f.generic = func;
171             cb->udata = udata;
172         } else {
173             cb = g_new(struct qemu_plugin_cb, 1);
174             cb->ctx = ctx;
175             cb->f.generic = func;
176             cb->udata = udata;
177             ctx->callbacks[ev] = cb;
178             QLIST_INSERT_HEAD_RCU(&plugin.cb_lists[ev], cb, entry);
179             if (!test_bit(ev, plugin.mask)) {
180                 set_bit(ev, plugin.mask);
181                 g_hash_table_foreach(plugin.cpu_ht, plugin_cpu_update__locked,
182                                      NULL);
183             }
184         }
185     } else {
186         plugin_unregister_cb__locked(ctx, ev);
187     }
188 }
189 
plugin_register_cb(qemu_plugin_id_t id,enum qemu_plugin_event ev,void * func)190 void plugin_register_cb(qemu_plugin_id_t id, enum qemu_plugin_event ev,
191                         void *func)
192 {
193     do_plugin_register_cb(id, ev, func, NULL);
194 }
195 
196 void
plugin_register_cb_udata(qemu_plugin_id_t id,enum qemu_plugin_event ev,void * func,void * udata)197 plugin_register_cb_udata(qemu_plugin_id_t id, enum qemu_plugin_event ev,
198                          void *func, void *udata)
199 {
200     do_plugin_register_cb(id, ev, func, udata);
201 }
202 
qemu_plugin_create_vcpu_state(void)203 CPUPluginState *qemu_plugin_create_vcpu_state(void)
204 {
205     return g_new0(CPUPluginState, 1);
206 }
207 
plugin_grow_scoreboards__locked(CPUState * cpu)208 static void plugin_grow_scoreboards__locked(CPUState *cpu)
209 {
210     size_t scoreboard_size = plugin.scoreboard_alloc_size;
211     bool need_realloc = false;
212 
213     if (cpu->cpu_index < scoreboard_size) {
214         return;
215     }
216 
217     while (cpu->cpu_index >= scoreboard_size) {
218         scoreboard_size *= 2;
219         need_realloc = true;
220     }
221 
222     if (!need_realloc) {
223         return;
224     }
225 
226     if (QLIST_EMPTY(&plugin.scoreboards)) {
227         /* just update size for future scoreboards */
228         plugin.scoreboard_alloc_size = scoreboard_size;
229         return;
230     }
231 
232     /*
233      * A scoreboard creation/deletion might be in progress. If a new vcpu is
234      * initialized at the same time, we are safe, as the new
235      * plugin.scoreboard_alloc_size was not yet written.
236      */
237     qemu_rec_mutex_unlock(&plugin.lock);
238 
239     /* cpus must be stopped, as tb might still use an existing scoreboard. */
240     start_exclusive();
241     /* re-acquire lock */
242     qemu_rec_mutex_lock(&plugin.lock);
243     /* in case another vcpu is created between unlock and exclusive section. */
244     if (scoreboard_size > plugin.scoreboard_alloc_size) {
245         struct qemu_plugin_scoreboard *score;
246         QLIST_FOREACH(score, &plugin.scoreboards, entry) {
247             g_array_set_size(score->data, scoreboard_size);
248         }
249         plugin.scoreboard_alloc_size = scoreboard_size;
250         /* force all tb to be flushed, as scoreboard pointers were changed. */
251         tb_flush(cpu);
252     }
253     end_exclusive();
254 }
255 
qemu_plugin_vcpu_init__async(CPUState * cpu,run_on_cpu_data unused)256 static void qemu_plugin_vcpu_init__async(CPUState *cpu, run_on_cpu_data unused)
257 {
258     bool success;
259 
260     assert(cpu->cpu_index != UNASSIGNED_CPU_INDEX);
261     qemu_rec_mutex_lock(&plugin.lock);
262     plugin.num_vcpus = MAX(plugin.num_vcpus, cpu->cpu_index + 1);
263     plugin_cpu_update__locked(&cpu->cpu_index, NULL, NULL);
264     success = g_hash_table_insert(plugin.cpu_ht, &cpu->cpu_index,
265                                   &cpu->cpu_index);
266     g_assert(success);
267     plugin_grow_scoreboards__locked(cpu);
268     qemu_rec_mutex_unlock(&plugin.lock);
269 
270     qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
271     plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_INIT);
272     qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
273 }
274 
qemu_plugin_vcpu_init_hook(CPUState * cpu)275 void qemu_plugin_vcpu_init_hook(CPUState *cpu)
276 {
277     /* Plugin initialization must wait until the cpu start executing code */
278     async_run_on_cpu(cpu, qemu_plugin_vcpu_init__async, RUN_ON_CPU_NULL);
279 }
280 
qemu_plugin_vcpu_exit_hook(CPUState * cpu)281 void qemu_plugin_vcpu_exit_hook(CPUState *cpu)
282 {
283     bool success;
284 
285     qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
286     plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_EXIT);
287     qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
288 
289     assert(cpu->cpu_index != UNASSIGNED_CPU_INDEX);
290     qemu_rec_mutex_lock(&plugin.lock);
291     success = g_hash_table_remove(plugin.cpu_ht, &cpu->cpu_index);
292     g_assert(success);
293     qemu_rec_mutex_unlock(&plugin.lock);
294 }
295 
296 struct plugin_for_each_args {
297     struct qemu_plugin_ctx *ctx;
298     qemu_plugin_vcpu_simple_cb_t cb;
299 };
300 
plugin_vcpu_for_each(gpointer k,gpointer v,gpointer udata)301 static void plugin_vcpu_for_each(gpointer k, gpointer v, gpointer udata)
302 {
303     struct plugin_for_each_args *args = udata;
304     int cpu_index = *(int *)k;
305 
306     args->cb(args->ctx->id, cpu_index);
307 }
308 
qemu_plugin_vcpu_for_each(qemu_plugin_id_t id,qemu_plugin_vcpu_simple_cb_t cb)309 void qemu_plugin_vcpu_for_each(qemu_plugin_id_t id,
310                                qemu_plugin_vcpu_simple_cb_t cb)
311 {
312     struct plugin_for_each_args args;
313 
314     if (cb == NULL) {
315         return;
316     }
317     qemu_rec_mutex_lock(&plugin.lock);
318     args.ctx = plugin_id_to_ctx_locked(id);
319     args.cb = cb;
320     g_hash_table_foreach(plugin.cpu_ht, plugin_vcpu_for_each, &args);
321     qemu_rec_mutex_unlock(&plugin.lock);
322 }
323 
324 /* Allocate and return a callback record */
plugin_get_dyn_cb(GArray ** arr)325 static struct qemu_plugin_dyn_cb *plugin_get_dyn_cb(GArray **arr)
326 {
327     GArray *cbs = *arr;
328 
329     if (!cbs) {
330         cbs = g_array_sized_new(false, true,
331                                 sizeof(struct qemu_plugin_dyn_cb), 1);
332         *arr = cbs;
333     }
334 
335     g_array_set_size(cbs, cbs->len + 1);
336     return &g_array_index(cbs, struct qemu_plugin_dyn_cb, cbs->len - 1);
337 }
338 
op_to_cb_type(enum qemu_plugin_op op)339 static enum plugin_dyn_cb_type op_to_cb_type(enum qemu_plugin_op op)
340 {
341     switch (op) {
342     case QEMU_PLUGIN_INLINE_ADD_U64:
343         return PLUGIN_CB_INLINE_ADD_U64;
344     case QEMU_PLUGIN_INLINE_STORE_U64:
345         return PLUGIN_CB_INLINE_STORE_U64;
346     default:
347         g_assert_not_reached();
348     }
349 }
350 
plugin_register_inline_op_on_entry(GArray ** arr,enum qemu_plugin_mem_rw rw,enum qemu_plugin_op op,qemu_plugin_u64 entry,uint64_t imm)351 void plugin_register_inline_op_on_entry(GArray **arr,
352                                         enum qemu_plugin_mem_rw rw,
353                                         enum qemu_plugin_op op,
354                                         qemu_plugin_u64 entry,
355                                         uint64_t imm)
356 {
357     struct qemu_plugin_dyn_cb *dyn_cb;
358 
359     struct qemu_plugin_inline_cb inline_cb = { .rw = rw,
360                                                .entry = entry,
361                                                .imm = imm };
362     dyn_cb = plugin_get_dyn_cb(arr);
363     dyn_cb->type = op_to_cb_type(op);
364     dyn_cb->inline_insn = inline_cb;
365 }
366 
plugin_register_dyn_cb__udata(GArray ** arr,qemu_plugin_vcpu_udata_cb_t cb,enum qemu_plugin_cb_flags flags,void * udata)367 void plugin_register_dyn_cb__udata(GArray **arr,
368                                    qemu_plugin_vcpu_udata_cb_t cb,
369                                    enum qemu_plugin_cb_flags flags,
370                                    void *udata)
371 {
372     static TCGHelperInfo info[3] = {
373         [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG,
374         [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG,
375         [QEMU_PLUGIN_CB_RW_REGS].flags = 0,
376         /*
377          * Match qemu_plugin_vcpu_udata_cb_t:
378          *   void (*)(uint32_t, void *)
379          */
380         [0 ... 2].typemask = (dh_typemask(void, 0) |
381                               dh_typemask(i32, 1) |
382                               dh_typemask(ptr, 2))
383     };
384     assert((unsigned)flags < ARRAY_SIZE(info));
385 
386     struct qemu_plugin_dyn_cb *dyn_cb = plugin_get_dyn_cb(arr);
387     struct qemu_plugin_regular_cb regular_cb = { .f.vcpu_udata = cb,
388                                                  .userp = udata,
389                                                  .info = &info[flags] };
390     dyn_cb->type = PLUGIN_CB_REGULAR;
391     dyn_cb->regular = regular_cb;
392 }
393 
plugin_register_dyn_cond_cb__udata(GArray ** arr,qemu_plugin_vcpu_udata_cb_t cb,enum qemu_plugin_cb_flags flags,enum qemu_plugin_cond cond,qemu_plugin_u64 entry,uint64_t imm,void * udata)394 void plugin_register_dyn_cond_cb__udata(GArray **arr,
395                                         qemu_plugin_vcpu_udata_cb_t cb,
396                                         enum qemu_plugin_cb_flags flags,
397                                         enum qemu_plugin_cond cond,
398                                         qemu_plugin_u64 entry,
399                                         uint64_t imm,
400                                         void *udata)
401 {
402     static TCGHelperInfo info[3] = {
403         [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG,
404         [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG,
405         [QEMU_PLUGIN_CB_RW_REGS].flags = 0,
406         /*
407          * Match qemu_plugin_vcpu_udata_cb_t:
408          *   void (*)(uint32_t, void *)
409          */
410         [0 ... 2].typemask = (dh_typemask(void, 0) |
411                               dh_typemask(i32, 1) |
412                               dh_typemask(ptr, 2))
413     };
414     assert((unsigned)flags < ARRAY_SIZE(info));
415 
416     struct qemu_plugin_dyn_cb *dyn_cb = plugin_get_dyn_cb(arr);
417     struct qemu_plugin_conditional_cb cond_cb = { .userp = udata,
418                                                   .f.vcpu_udata = cb,
419                                                   .cond = cond,
420                                                   .entry = entry,
421                                                   .imm = imm,
422                                                   .info = &info[flags] };
423     dyn_cb->type = PLUGIN_CB_COND;
424     dyn_cb->cond = cond_cb;
425 }
426 
plugin_register_vcpu_mem_cb(GArray ** arr,void * cb,enum qemu_plugin_cb_flags flags,enum qemu_plugin_mem_rw rw,void * udata)427 void plugin_register_vcpu_mem_cb(GArray **arr,
428                                  void *cb,
429                                  enum qemu_plugin_cb_flags flags,
430                                  enum qemu_plugin_mem_rw rw,
431                                  void *udata)
432 {
433     /*
434      * Expect that the underlying type for enum qemu_plugin_meminfo_t
435      * is either int32_t or uint32_t, aka int or unsigned int.
436      */
437     QEMU_BUILD_BUG_ON(
438         !__builtin_types_compatible_p(qemu_plugin_meminfo_t, uint32_t) &&
439         !__builtin_types_compatible_p(qemu_plugin_meminfo_t, int32_t));
440 
441     static TCGHelperInfo info[3] = {
442         [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG,
443         [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG,
444         [QEMU_PLUGIN_CB_RW_REGS].flags = 0,
445         /*
446          * Match qemu_plugin_vcpu_mem_cb_t:
447          *   void (*)(uint32_t, qemu_plugin_meminfo_t, uint64_t, void *)
448          */
449         [0 ... 2].typemask =
450             (dh_typemask(void, 0) |
451              dh_typemask(i32, 1) |
452              (__builtin_types_compatible_p(qemu_plugin_meminfo_t, uint32_t)
453               ? dh_typemask(i32, 2) : dh_typemask(s32, 2)) |
454              dh_typemask(i64, 3) |
455              dh_typemask(ptr, 4))
456     };
457     assert((unsigned)flags < ARRAY_SIZE(info));
458 
459     struct qemu_plugin_dyn_cb *dyn_cb = plugin_get_dyn_cb(arr);
460     struct qemu_plugin_regular_cb regular_cb = { .userp = udata,
461                                                  .rw = rw,
462                                                  .f.vcpu_mem = cb,
463                                                  .info = &info[flags] };
464     dyn_cb->type = PLUGIN_CB_MEM_REGULAR;
465     dyn_cb->regular = regular_cb;
466 }
467 
468 /*
469  * Disable CFI checks.
470  * The callback function has been loaded from an external library so we do not
471  * have type information
472  */
473 QEMU_DISABLE_CFI
qemu_plugin_tb_trans_cb(CPUState * cpu,struct qemu_plugin_tb * tb)474 void qemu_plugin_tb_trans_cb(CPUState *cpu, struct qemu_plugin_tb *tb)
475 {
476     struct qemu_plugin_cb *cb, *next;
477     enum qemu_plugin_event ev = QEMU_PLUGIN_EV_VCPU_TB_TRANS;
478 
479     /* no plugin_state->event_mask check here; caller should have checked */
480 
481     QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
482         qemu_plugin_vcpu_tb_trans_cb_t func = cb->f.vcpu_tb_trans;
483 
484         qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
485         func(cb->ctx->id, tb);
486         qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
487     }
488 }
489 
490 /*
491  * Disable CFI checks.
492  * The callback function has been loaded from an external library so we do not
493  * have type information
494  */
495 QEMU_DISABLE_CFI
496 void
qemu_plugin_vcpu_syscall(CPUState * cpu,int64_t num,uint64_t a1,uint64_t a2,uint64_t a3,uint64_t a4,uint64_t a5,uint64_t a6,uint64_t a7,uint64_t a8)497 qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1, uint64_t a2,
498                          uint64_t a3, uint64_t a4, uint64_t a5,
499                          uint64_t a6, uint64_t a7, uint64_t a8)
500 {
501     struct qemu_plugin_cb *cb, *next;
502     enum qemu_plugin_event ev = QEMU_PLUGIN_EV_VCPU_SYSCALL;
503 
504     if (!test_bit(ev, cpu->plugin_state->event_mask)) {
505         return;
506     }
507 
508     QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
509         qemu_plugin_vcpu_syscall_cb_t func = cb->f.vcpu_syscall;
510 
511         qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
512         func(cb->ctx->id, cpu->cpu_index, num, a1, a2, a3, a4, a5, a6, a7, a8);
513         qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
514     }
515 }
516 
517 /*
518  * Disable CFI checks.
519  * The callback function has been loaded from an external library so we do not
520  * have type information
521  */
522 QEMU_DISABLE_CFI
qemu_plugin_vcpu_syscall_ret(CPUState * cpu,int64_t num,int64_t ret)523 void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret)
524 {
525     struct qemu_plugin_cb *cb, *next;
526     enum qemu_plugin_event ev = QEMU_PLUGIN_EV_VCPU_SYSCALL_RET;
527 
528     if (!test_bit(ev, cpu->plugin_state->event_mask)) {
529         return;
530     }
531 
532     QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
533         qemu_plugin_vcpu_syscall_ret_cb_t func = cb->f.vcpu_syscall_ret;
534 
535         qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
536         func(cb->ctx->id, cpu->cpu_index, num, ret);
537         qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
538     }
539 }
540 
qemu_plugin_vcpu_idle_cb(CPUState * cpu)541 void qemu_plugin_vcpu_idle_cb(CPUState *cpu)
542 {
543     /* idle and resume cb may be called before init, ignore in this case */
544     if (cpu->cpu_index < plugin.num_vcpus) {
545         qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
546         plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_IDLE);
547         qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
548     }
549 }
550 
qemu_plugin_vcpu_resume_cb(CPUState * cpu)551 void qemu_plugin_vcpu_resume_cb(CPUState *cpu)
552 {
553     if (cpu->cpu_index < plugin.num_vcpus) {
554         qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
555         plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_RESUME);
556         qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
557     }
558 }
559 
qemu_plugin_register_vcpu_idle_cb(qemu_plugin_id_t id,qemu_plugin_vcpu_simple_cb_t cb)560 void qemu_plugin_register_vcpu_idle_cb(qemu_plugin_id_t id,
561                                        qemu_plugin_vcpu_simple_cb_t cb)
562 {
563     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_IDLE, cb);
564 }
565 
qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,qemu_plugin_vcpu_simple_cb_t cb)566 void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
567                                          qemu_plugin_vcpu_simple_cb_t cb)
568 {
569     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_RESUME, cb);
570 }
571 
qemu_plugin_register_flush_cb(qemu_plugin_id_t id,qemu_plugin_simple_cb_t cb)572 void qemu_plugin_register_flush_cb(qemu_plugin_id_t id,
573                                    qemu_plugin_simple_cb_t cb)
574 {
575     plugin_register_cb(id, QEMU_PLUGIN_EV_FLUSH, cb);
576 }
577 
free_dyn_cb_arr(void * p,uint32_t h,void * userp)578 static bool free_dyn_cb_arr(void *p, uint32_t h, void *userp)
579 {
580     g_array_free((GArray *) p, true);
581     return true;
582 }
583 
qemu_plugin_flush_cb(void)584 void qemu_plugin_flush_cb(void)
585 {
586     qht_iter_remove(&plugin.dyn_cb_arr_ht, free_dyn_cb_arr, NULL);
587     qht_reset(&plugin.dyn_cb_arr_ht);
588 
589     plugin_cb__simple(QEMU_PLUGIN_EV_FLUSH);
590 }
591 
exec_inline_op(enum plugin_dyn_cb_type type,struct qemu_plugin_inline_cb * cb,int cpu_index)592 void exec_inline_op(enum plugin_dyn_cb_type type,
593                     struct qemu_plugin_inline_cb *cb,
594                     int cpu_index)
595 {
596     char *ptr = cb->entry.score->data->data;
597     size_t elem_size = g_array_get_element_size(
598         cb->entry.score->data);
599     size_t offset = cb->entry.offset;
600     uint64_t *val = (uint64_t *)(ptr + offset + cpu_index * elem_size);
601 
602     switch (type) {
603     case PLUGIN_CB_INLINE_ADD_U64:
604         *val += cb->imm;
605         break;
606     case PLUGIN_CB_INLINE_STORE_U64:
607         *val = cb->imm;
608         break;
609     default:
610         g_assert_not_reached();
611     }
612 }
613 
qemu_plugin_vcpu_mem_cb(CPUState * cpu,uint64_t vaddr,uint64_t value_low,uint64_t value_high,MemOpIdx oi,enum qemu_plugin_mem_rw rw)614 void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
615                              uint64_t value_low,
616                              uint64_t value_high,
617                              MemOpIdx oi, enum qemu_plugin_mem_rw rw)
618 {
619     GArray *arr = cpu->neg.plugin_mem_cbs;
620     size_t i;
621 
622     if (arr == NULL) {
623         return;
624     }
625 
626     cpu->neg.plugin_mem_value_low = value_low;
627     cpu->neg.plugin_mem_value_high = value_high;
628 
629     for (i = 0; i < arr->len; i++) {
630         struct qemu_plugin_dyn_cb *cb =
631             &g_array_index(arr, struct qemu_plugin_dyn_cb, i);
632 
633         switch (cb->type) {
634         case PLUGIN_CB_MEM_REGULAR:
635             if (rw & cb->regular.rw) {
636                 qemu_plugin_set_cb_flags(cpu,
637                     tcg_call_to_qemu_plugin_cb_flags(cb->regular.info->flags));
638 
639                 cb->regular.f.vcpu_mem(cpu->cpu_index,
640                                        make_plugin_meminfo(oi, rw),
641                                        vaddr, cb->regular.userp);
642                 qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
643             }
644             break;
645         case PLUGIN_CB_INLINE_ADD_U64:
646         case PLUGIN_CB_INLINE_STORE_U64:
647             if (rw & cb->inline_insn.rw) {
648                 exec_inline_op(cb->type, &cb->inline_insn, cpu->cpu_index);
649             }
650             break;
651         default:
652             g_assert_not_reached();
653         }
654     }
655 }
656 
qemu_plugin_atexit_cb(void)657 void qemu_plugin_atexit_cb(void)
658 {
659     plugin_cb__udata(QEMU_PLUGIN_EV_ATEXIT);
660 }
661 
qemu_plugin_register_atexit_cb(qemu_plugin_id_t id,qemu_plugin_udata_cb_t cb,void * udata)662 void qemu_plugin_register_atexit_cb(qemu_plugin_id_t id,
663                                     qemu_plugin_udata_cb_t cb,
664                                     void *udata)
665 {
666     plugin_register_cb_udata(id, QEMU_PLUGIN_EV_ATEXIT, cb, udata);
667 }
668 
669 /*
670  * Handle exit from linux-user. Unlike the normal atexit() mechanism
671  * we need to handle the clean-up manually as it's possible threads
672  * are still running. We need to remove all callbacks from code
673  * generation, flush the current translations and then we can safely
674  * trigger the exit callbacks.
675  */
676 
qemu_plugin_user_exit(void)677 void qemu_plugin_user_exit(void)
678 {
679     enum qemu_plugin_event ev;
680     CPUState *cpu;
681 
682     /*
683      * Locking order: we must acquire locks in an order that is consistent
684      * with the one in fork_start(). That is:
685      * - start_exclusive(), which acquires qemu_cpu_list_lock,
686      *   must be called before acquiring plugin.lock.
687      * - tb_flush(), which acquires mmap_lock(), must be called
688      *   while plugin.lock is not held.
689      */
690     start_exclusive();
691 
692     qemu_rec_mutex_lock(&plugin.lock);
693     /* un-register all callbacks except the final AT_EXIT one */
694     for (ev = 0; ev < QEMU_PLUGIN_EV_MAX; ev++) {
695         if (ev != QEMU_PLUGIN_EV_ATEXIT) {
696             struct qemu_plugin_cb *cb, *next;
697 
698             QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
699                 plugin_unregister_cb__locked(cb->ctx, ev);
700             }
701         }
702     }
703     CPU_FOREACH(cpu) {
704         qemu_plugin_disable_mem_helpers(cpu);
705     }
706     qemu_rec_mutex_unlock(&plugin.lock);
707 
708     tb_flush(current_cpu);
709     end_exclusive();
710 
711     /* now it's safe to handle the exit case */
712     qemu_plugin_atexit_cb();
713 }
714 
715 /*
716  * Helpers for *-user to ensure locks are sane across fork() events.
717  */
718 
qemu_plugin_user_prefork_lock(void)719 void qemu_plugin_user_prefork_lock(void)
720 {
721     qemu_rec_mutex_lock(&plugin.lock);
722 }
723 
qemu_plugin_user_postfork(bool is_child)724 void qemu_plugin_user_postfork(bool is_child)
725 {
726     if (is_child) {
727         /* should we just reset via plugin_init? */
728         qemu_rec_mutex_init(&plugin.lock);
729     } else {
730         qemu_rec_mutex_unlock(&plugin.lock);
731     }
732 }
733 
plugin_dyn_cb_arr_cmp(const void * ap,const void * bp)734 static bool plugin_dyn_cb_arr_cmp(const void *ap, const void *bp)
735 {
736     return ap == bp;
737 }
738 
plugin_init(void)739 static void __attribute__((__constructor__)) plugin_init(void)
740 {
741     int i;
742 
743     for (i = 0; i < QEMU_PLUGIN_EV_MAX; i++) {
744         QLIST_INIT(&plugin.cb_lists[i]);
745     }
746     qemu_rec_mutex_init(&plugin.lock);
747     plugin.id_ht = g_hash_table_new(g_int64_hash, g_int64_equal);
748     plugin.cpu_ht = g_hash_table_new(g_int_hash, g_int_equal);
749     QLIST_INIT(&plugin.scoreboards);
750     plugin.scoreboard_alloc_size = 16; /* avoid frequent reallocation */
751     QTAILQ_INIT(&plugin.ctxs);
752     qht_init(&plugin.dyn_cb_arr_ht, plugin_dyn_cb_arr_cmp, 16,
753              QHT_MODE_AUTO_RESIZE);
754     atexit(qemu_plugin_atexit_cb);
755 }
756 
plugin_num_vcpus(void)757 int plugin_num_vcpus(void)
758 {
759     return plugin.num_vcpus;
760 }
761 
plugin_scoreboard_new(size_t element_size)762 struct qemu_plugin_scoreboard *plugin_scoreboard_new(size_t element_size)
763 {
764     struct qemu_plugin_scoreboard *score =
765         g_malloc0(sizeof(struct qemu_plugin_scoreboard));
766     score->data = g_array_new(FALSE, TRUE, element_size);
767     g_array_set_size(score->data, plugin.scoreboard_alloc_size);
768 
769     qemu_rec_mutex_lock(&plugin.lock);
770     QLIST_INSERT_HEAD(&plugin.scoreboards, score, entry);
771     qemu_rec_mutex_unlock(&plugin.lock);
772 
773     return score;
774 }
775 
plugin_scoreboard_free(struct qemu_plugin_scoreboard * score)776 void plugin_scoreboard_free(struct qemu_plugin_scoreboard *score)
777 {
778     qemu_rec_mutex_lock(&plugin.lock);
779     QLIST_REMOVE(score, entry);
780     qemu_rec_mutex_unlock(&plugin.lock);
781 
782     g_array_free(score->data, TRUE);
783     g_free(score);
784 }
785 
tcg_call_to_qemu_plugin_cb_flags(int flags)786 enum qemu_plugin_cb_flags tcg_call_to_qemu_plugin_cb_flags(int flags)
787 {
788     if (flags & TCG_CALL_NO_RWG) {
789         return QEMU_PLUGIN_CB_NO_REGS;
790     } else if (flags & TCG_CALL_NO_WG) {
791         return QEMU_PLUGIN_CB_R_REGS;
792     } else {
793         return QEMU_PLUGIN_CB_RW_REGS;
794     }
795 }
796