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