xref: /qemu/plugins/api.c (revision 597639c4273d1433b0a47c8533b90ccce29f84e5)
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  *  qemu_plugin_register
12  *
13  * Which can then be passed back into the API to do additional things.
14  * As such all the public functions in here are exported in
15  * qemu-plugin.h.
16  *
17  * The general life-cycle of a plugin is:
18  *
19  *  - plugin is loaded, public qemu_plugin_install called
20  *    - the install func registers callbacks for events
21  *    - usually an atexit_cb is registered to dump info at the end
22  *  - when a registered event occurs the plugin is called
23  *     - some events pass additional info
24  *     - during translation the plugin can decide to instrument any
25  *       instruction
26  *  - when QEMU exits all the registered atexit callbacks are called
27  *
28  * Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
29  * Copyright (C) 2019, Linaro
30  *
31  * License: GNU GPL, version 2 or later.
32  *   See the COPYING file in the top-level directory.
33  *
34  * SPDX-License-Identifier: GPL-2.0-or-later
35  *
36  */
37 
38 #include "qemu/osdep.h"
39 #include "qemu/main-loop.h"
40 #include "qemu/plugin.h"
41 #include "qemu/log.h"
42 #include "system/memory.h"
43 #include "tcg/tcg.h"
44 #include "exec/gdbstub.h"
45 #include "exec/target_page.h"
46 #include "exec/translation-block.h"
47 #include "exec/translator.h"
48 #include "disas/disas.h"
49 #include "plugin.h"
50 
51 /* Uninstall and Reset handlers */
52 
qemu_plugin_uninstall(qemu_plugin_id_t id,qemu_plugin_simple_cb_t cb)53 void qemu_plugin_uninstall(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb)
54 {
55     plugin_reset_uninstall(id, cb, false);
56 }
57 
qemu_plugin_reset(qemu_plugin_id_t id,qemu_plugin_simple_cb_t cb)58 void qemu_plugin_reset(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb)
59 {
60     plugin_reset_uninstall(id, cb, true);
61 }
62 
63 /*
64  * Plugin Register Functions
65  *
66  * This allows the plugin to register callbacks for various events
67  * during the translation.
68  */
69 
qemu_plugin_register_vcpu_init_cb(qemu_plugin_id_t id,qemu_plugin_vcpu_simple_cb_t cb)70 void qemu_plugin_register_vcpu_init_cb(qemu_plugin_id_t id,
71                                        qemu_plugin_vcpu_simple_cb_t cb)
72 {
73     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_INIT, cb);
74 }
75 
qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id,qemu_plugin_vcpu_simple_cb_t cb)76 void qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id,
77                                        qemu_plugin_vcpu_simple_cb_t cb)
78 {
79     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_EXIT, cb);
80 }
81 
tb_is_mem_only(void)82 static bool tb_is_mem_only(void)
83 {
84     return tb_cflags(tcg_ctx->gen_tb) & CF_MEMI_ONLY;
85 }
86 
qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb * tb,qemu_plugin_vcpu_udata_cb_t cb,enum qemu_plugin_cb_flags flags,void * udata)87 void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
88                                           qemu_plugin_vcpu_udata_cb_t cb,
89                                           enum qemu_plugin_cb_flags flags,
90                                           void *udata)
91 {
92     if (!tb_is_mem_only()) {
93         plugin_register_dyn_cb__udata(&tb->cbs, cb, flags, udata);
94     }
95 }
96 
qemu_plugin_register_vcpu_tb_exec_cond_cb(struct qemu_plugin_tb * tb,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)97 void qemu_plugin_register_vcpu_tb_exec_cond_cb(struct qemu_plugin_tb *tb,
98                                                qemu_plugin_vcpu_udata_cb_t cb,
99                                                enum qemu_plugin_cb_flags flags,
100                                                enum qemu_plugin_cond cond,
101                                                qemu_plugin_u64 entry,
102                                                uint64_t imm,
103                                                void *udata)
104 {
105     if (cond == QEMU_PLUGIN_COND_NEVER || tb_is_mem_only()) {
106         return;
107     }
108     if (cond == QEMU_PLUGIN_COND_ALWAYS) {
109         qemu_plugin_register_vcpu_tb_exec_cb(tb, cb, flags, udata);
110         return;
111     }
112     plugin_register_dyn_cond_cb__udata(&tb->cbs, cb, flags,
113                                        cond, entry, imm, udata);
114 }
115 
qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(struct qemu_plugin_tb * tb,enum qemu_plugin_op op,qemu_plugin_u64 entry,uint64_t imm)116 void qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(
117     struct qemu_plugin_tb *tb,
118     enum qemu_plugin_op op,
119     qemu_plugin_u64 entry,
120     uint64_t imm)
121 {
122     if (!tb_is_mem_only()) {
123         plugin_register_inline_op_on_entry(&tb->cbs, 0, op, entry, imm);
124     }
125 }
126 
qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn * insn,qemu_plugin_vcpu_udata_cb_t cb,enum qemu_plugin_cb_flags flags,void * udata)127 void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
128                                             qemu_plugin_vcpu_udata_cb_t cb,
129                                             enum qemu_plugin_cb_flags flags,
130                                             void *udata)
131 {
132     if (!tb_is_mem_only()) {
133         plugin_register_dyn_cb__udata(&insn->insn_cbs, cb, flags, udata);
134     }
135 }
136 
qemu_plugin_register_vcpu_insn_exec_cond_cb(struct qemu_plugin_insn * insn,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)137 void qemu_plugin_register_vcpu_insn_exec_cond_cb(
138     struct qemu_plugin_insn *insn,
139     qemu_plugin_vcpu_udata_cb_t cb,
140     enum qemu_plugin_cb_flags flags,
141     enum qemu_plugin_cond cond,
142     qemu_plugin_u64 entry,
143     uint64_t imm,
144     void *udata)
145 {
146     if (cond == QEMU_PLUGIN_COND_NEVER || tb_is_mem_only()) {
147         return;
148     }
149     if (cond == QEMU_PLUGIN_COND_ALWAYS) {
150         qemu_plugin_register_vcpu_insn_exec_cb(insn, cb, flags, udata);
151         return;
152     }
153     plugin_register_dyn_cond_cb__udata(&insn->insn_cbs, cb, flags,
154                                        cond, entry, imm, udata);
155 }
156 
qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(struct qemu_plugin_insn * insn,enum qemu_plugin_op op,qemu_plugin_u64 entry,uint64_t imm)157 void qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(
158     struct qemu_plugin_insn *insn,
159     enum qemu_plugin_op op,
160     qemu_plugin_u64 entry,
161     uint64_t imm)
162 {
163     if (!tb_is_mem_only()) {
164         plugin_register_inline_op_on_entry(&insn->insn_cbs, 0, op, entry, imm);
165     }
166 }
167 
168 
169 /*
170  * We always plant memory instrumentation because they don't finalise until
171  * after the operation has complete.
172  */
qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn * insn,qemu_plugin_vcpu_mem_cb_t cb,enum qemu_plugin_cb_flags flags,enum qemu_plugin_mem_rw rw,void * udata)173 void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn,
174                                       qemu_plugin_vcpu_mem_cb_t cb,
175                                       enum qemu_plugin_cb_flags flags,
176                                       enum qemu_plugin_mem_rw rw,
177                                       void *udata)
178 {
179     plugin_register_vcpu_mem_cb(&insn->mem_cbs, cb, flags, rw, udata);
180 }
181 
qemu_plugin_register_vcpu_mem_inline_per_vcpu(struct qemu_plugin_insn * insn,enum qemu_plugin_mem_rw rw,enum qemu_plugin_op op,qemu_plugin_u64 entry,uint64_t imm)182 void qemu_plugin_register_vcpu_mem_inline_per_vcpu(
183     struct qemu_plugin_insn *insn,
184     enum qemu_plugin_mem_rw rw,
185     enum qemu_plugin_op op,
186     qemu_plugin_u64 entry,
187     uint64_t imm)
188 {
189     plugin_register_inline_op_on_entry(&insn->mem_cbs, rw, op, entry, imm);
190 }
191 
qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,qemu_plugin_vcpu_tb_trans_cb_t cb)192 void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,
193                                            qemu_plugin_vcpu_tb_trans_cb_t cb)
194 {
195     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_TB_TRANS, cb);
196 }
197 
qemu_plugin_register_vcpu_syscall_cb(qemu_plugin_id_t id,qemu_plugin_vcpu_syscall_cb_t cb)198 void qemu_plugin_register_vcpu_syscall_cb(qemu_plugin_id_t id,
199                                           qemu_plugin_vcpu_syscall_cb_t cb)
200 {
201     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL, cb);
202 }
203 
204 void
qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,qemu_plugin_vcpu_syscall_ret_cb_t cb)205 qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,
206                                          qemu_plugin_vcpu_syscall_ret_cb_t cb)
207 {
208     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL_RET, cb);
209 }
210 
211 /*
212  * Plugin Queries
213  *
214  * These are queries that the plugin can make to gauge information
215  * from our opaque data types. We do not want to leak internal details
216  * here just information useful to the plugin.
217  */
218 
219 /*
220  * Translation block information:
221  *
222  * A plugin can query the virtual address of the start of the block
223  * and the number of instructions in it. It can also get access to
224  * each translated instruction.
225  */
226 
qemu_plugin_tb_n_insns(const struct qemu_plugin_tb * tb)227 size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb)
228 {
229     return tb->n;
230 }
231 
qemu_plugin_tb_vaddr(const struct qemu_plugin_tb * tb)232 uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb)
233 {
234     const DisasContextBase *db = tcg_ctx->plugin_db;
235     return db->pc_first;
236 }
237 
238 struct qemu_plugin_insn *
qemu_plugin_tb_get_insn(const struct qemu_plugin_tb * tb,size_t idx)239 qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx)
240 {
241     if (unlikely(idx >= tb->n)) {
242         return NULL;
243     }
244     return g_ptr_array_index(tb->insns, idx);
245 }
246 
247 /*
248  * Instruction information
249  *
250  * These queries allow the plugin to retrieve information about each
251  * instruction being translated.
252  */
253 
qemu_plugin_insn_data(const struct qemu_plugin_insn * insn,void * dest,size_t len)254 size_t qemu_plugin_insn_data(const struct qemu_plugin_insn *insn,
255                              void *dest, size_t len)
256 {
257     const DisasContextBase *db = tcg_ctx->plugin_db;
258 
259     len = MIN(len, insn->len);
260     return translator_st(db, dest, insn->vaddr, len) ? len : 0;
261 }
262 
qemu_plugin_insn_size(const struct qemu_plugin_insn * insn)263 size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn)
264 {
265     return insn->len;
266 }
267 
qemu_plugin_insn_vaddr(const struct qemu_plugin_insn * insn)268 uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn)
269 {
270     return insn->vaddr;
271 }
272 
qemu_plugin_insn_haddr(const struct qemu_plugin_insn * insn)273 void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn)
274 {
275     const DisasContextBase *db = tcg_ctx->plugin_db;
276     vaddr page0_last = db->pc_first | ~qemu_target_page_mask();
277 
278     if (db->fake_insn) {
279         return NULL;
280     }
281 
282     /*
283      * ??? The return value is not intended for use of host memory,
284      * but as a proxy for address space and physical address.
285      * Thus we are only interested in the first byte and do not
286      * care about spanning pages.
287      */
288     if (insn->vaddr <= page0_last) {
289         if (db->host_addr[0] == NULL) {
290             return NULL;
291         }
292         return db->host_addr[0] + insn->vaddr - db->pc_first;
293     } else {
294         if (db->host_addr[1] == NULL) {
295             return NULL;
296         }
297         return db->host_addr[1] + insn->vaddr - (page0_last + 1);
298     }
299 }
300 
qemu_plugin_insn_disas(const struct qemu_plugin_insn * insn)301 char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn)
302 {
303     return plugin_disas(tcg_ctx->cpu, tcg_ctx->plugin_db,
304                         insn->vaddr, insn->len);
305 }
306 
qemu_plugin_insn_symbol(const struct qemu_plugin_insn * insn)307 const char *qemu_plugin_insn_symbol(const struct qemu_plugin_insn *insn)
308 {
309     const char *sym = lookup_symbol(insn->vaddr);
310     return sym[0] != 0 ? sym : NULL;
311 }
312 
313 /*
314  * The memory queries allow the plugin to query information about a
315  * memory access.
316  */
317 
qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info)318 unsigned qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info)
319 {
320     MemOp op = get_memop(info);
321     return op & MO_SIZE;
322 }
323 
qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info)324 bool qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info)
325 {
326     MemOp op = get_memop(info);
327     return op & MO_SIGN;
328 }
329 
qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info)330 bool qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info)
331 {
332     MemOp op = get_memop(info);
333     return (op & MO_BSWAP) == MO_BE;
334 }
335 
qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info)336 bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info)
337 {
338     return get_plugin_meminfo_rw(info) & QEMU_PLUGIN_MEM_W;
339 }
340 
qemu_plugin_mem_get_value(qemu_plugin_meminfo_t info)341 qemu_plugin_mem_value qemu_plugin_mem_get_value(qemu_plugin_meminfo_t info)
342 {
343     uint64_t low = current_cpu->neg.plugin_mem_value_low;
344     qemu_plugin_mem_value value;
345 
346     switch (qemu_plugin_mem_size_shift(info)) {
347     case 0:
348         value.type = QEMU_PLUGIN_MEM_VALUE_U8;
349         value.data.u8 = (uint8_t)low;
350         break;
351     case 1:
352         value.type = QEMU_PLUGIN_MEM_VALUE_U16;
353         value.data.u16 = (uint16_t)low;
354         break;
355     case 2:
356         value.type = QEMU_PLUGIN_MEM_VALUE_U32;
357         value.data.u32 = (uint32_t)low;
358         break;
359     case 3:
360         value.type = QEMU_PLUGIN_MEM_VALUE_U64;
361         value.data.u64 = low;
362         break;
363     case 4:
364         value.type = QEMU_PLUGIN_MEM_VALUE_U128;
365         value.data.u128.low = low;
366         value.data.u128.high = current_cpu->neg.plugin_mem_value_high;
367         break;
368     default:
369         g_assert_not_reached();
370     }
371     return value;
372 }
373 
qemu_plugin_num_vcpus(void)374 int qemu_plugin_num_vcpus(void)
375 {
376     return plugin_num_vcpus();
377 }
378 
379 /*
380  * Plugin output
381  */
qemu_plugin_outs(const char * string)382 void qemu_plugin_outs(const char *string)
383 {
384     qemu_log_mask(CPU_LOG_PLUGIN, "%s", string);
385 }
386 
qemu_plugin_bool_parse(const char * name,const char * value,bool * ret)387 bool qemu_plugin_bool_parse(const char *name, const char *value, bool *ret)
388 {
389     return name && value && qapi_bool_parse(name, value, ret, NULL);
390 }
391 
392 /*
393  * Create register handles.
394  *
395  * We need to create a handle for each register so the plugin
396  * infrastructure can call gdbstub to read a register. They are
397  * currently just a pointer encapsulation of the gdb_reg but in
398  * future may hold internal plugin state so its important plugin
399  * authors are not tempted to treat them as numbers.
400  *
401  * We also construct a result array with those handles and some
402  * ancillary data the plugin might find useful.
403  */
404 
create_register_handles(GArray * gdbstub_regs)405 static GArray *create_register_handles(GArray *gdbstub_regs)
406 {
407     GArray *find_data = g_array_new(true, true,
408                                     sizeof(qemu_plugin_reg_descriptor));
409 
410     for (int i = 0; i < gdbstub_regs->len; i++) {
411         GDBRegDesc *grd = &g_array_index(gdbstub_regs, GDBRegDesc, i);
412         qemu_plugin_reg_descriptor desc;
413 
414         /* skip "un-named" regs */
415         if (!grd->name) {
416             continue;
417         }
418 
419         /* Create a record for the plugin */
420         desc.handle = GINT_TO_POINTER(grd->gdb_reg + 1);
421         desc.name = g_intern_string(grd->name);
422         desc.feature = g_intern_string(grd->feature_name);
423         g_array_append_val(find_data, desc);
424     }
425 
426     return find_data;
427 }
428 
qemu_plugin_get_registers(void)429 GArray *qemu_plugin_get_registers(void)
430 {
431     g_assert(current_cpu);
432 
433     g_autoptr(GArray) regs = gdb_get_register_list(current_cpu);
434     return create_register_handles(regs);
435 }
436 
qemu_plugin_read_register(struct qemu_plugin_register * reg,GByteArray * buf)437 int qemu_plugin_read_register(struct qemu_plugin_register *reg, GByteArray *buf)
438 {
439     g_assert(current_cpu);
440 
441     if (qemu_plugin_get_cb_flags() == QEMU_PLUGIN_CB_NO_REGS) {
442         return -1;
443     }
444 
445     return gdb_read_register(current_cpu, buf, GPOINTER_TO_INT(reg) - 1);
446 }
447 
qemu_plugin_write_register(struct qemu_plugin_register * reg,GByteArray * buf)448 int qemu_plugin_write_register(struct qemu_plugin_register *reg,
449                                GByteArray *buf)
450 {
451     g_assert(current_cpu);
452 
453     if (buf->len == 0 || qemu_plugin_get_cb_flags() != QEMU_PLUGIN_CB_RW_REGS) {
454         return -1;
455     }
456 
457     return gdb_write_register(current_cpu, buf->data, GPOINTER_TO_INT(reg) - 1);
458 }
459 
qemu_plugin_read_memory_vaddr(uint64_t addr,GByteArray * data,size_t len)460 bool qemu_plugin_read_memory_vaddr(uint64_t addr, GByteArray *data, size_t len)
461 {
462     g_assert(current_cpu);
463 
464     if (len == 0) {
465         return false;
466     }
467 
468     g_byte_array_set_size(data, len);
469 
470     int result = cpu_memory_rw_debug(current_cpu, addr, data->data,
471                                      data->len, false);
472 
473     if (result < 0) {
474         return false;
475     }
476 
477     return true;
478 }
479 
qemu_plugin_write_memory_vaddr(uint64_t addr,GByteArray * data)480 bool qemu_plugin_write_memory_vaddr(uint64_t addr, GByteArray *data)
481 {
482     g_assert(current_cpu);
483 
484     if (data->len == 0) {
485         return false;
486     }
487 
488     int result = cpu_memory_rw_debug(current_cpu, addr, data->data,
489                                      data->len, true);
490 
491     if (result < 0) {
492         return false;
493     }
494 
495     return true;
496 }
497 
498 enum qemu_plugin_hwaddr_operation_result
qemu_plugin_read_memory_hwaddr(hwaddr addr,GByteArray * data,size_t len)499 qemu_plugin_read_memory_hwaddr(hwaddr addr, GByteArray *data, size_t len)
500 {
501 #ifdef CONFIG_SOFTMMU
502     if (len == 0) {
503         return QEMU_PLUGIN_HWADDR_OPERATION_ERROR;
504     }
505 
506     g_assert(current_cpu);
507 
508 
509     int as_idx = cpu_asidx_from_attrs(current_cpu, MEMTXATTRS_UNSPECIFIED);
510     AddressSpace *as = cpu_get_address_space(current_cpu, as_idx);
511 
512     if (as == NULL) {
513         return QEMU_PLUGIN_HWADDR_OPERATION_INVALID_ADDRESS_SPACE;
514     }
515 
516     g_byte_array_set_size(data, len);
517     MemTxResult res = address_space_rw(as, addr,
518                                        MEMTXATTRS_UNSPECIFIED, data->data,
519                                        data->len, false);
520 
521     switch (res) {
522     case MEMTX_OK:
523         return QEMU_PLUGIN_HWADDR_OPERATION_OK;
524     case MEMTX_ERROR:
525         return QEMU_PLUGIN_HWADDR_OPERATION_DEVICE_ERROR;
526     case MEMTX_DECODE_ERROR:
527         return QEMU_PLUGIN_HWADDR_OPERATION_INVALID_ADDRESS;
528     case MEMTX_ACCESS_ERROR:
529         return QEMU_PLUGIN_HWADDR_OPERATION_ACCESS_DENIED;
530     default:
531         return QEMU_PLUGIN_HWADDR_OPERATION_ERROR;
532     }
533 #else
534     return QEMU_PLUGIN_HWADDR_OPERATION_ERROR;
535 #endif
536 }
537 
538 enum qemu_plugin_hwaddr_operation_result
qemu_plugin_write_memory_hwaddr(hwaddr addr,GByteArray * data)539 qemu_plugin_write_memory_hwaddr(hwaddr addr, GByteArray *data)
540 {
541 #ifdef CONFIG_SOFTMMU
542     if (data->len == 0) {
543         return QEMU_PLUGIN_HWADDR_OPERATION_ERROR;
544     }
545 
546     g_assert(current_cpu);
547 
548     int as_idx = cpu_asidx_from_attrs(current_cpu, MEMTXATTRS_UNSPECIFIED);
549     AddressSpace *as = cpu_get_address_space(current_cpu, as_idx);
550 
551     if (as == NULL) {
552         return QEMU_PLUGIN_HWADDR_OPERATION_INVALID_ADDRESS_SPACE;
553     }
554 
555     MemTxResult res = address_space_rw(as, addr,
556                                        MEMTXATTRS_UNSPECIFIED, data->data,
557                                        data->len, true);
558     switch (res) {
559     case MEMTX_OK:
560         return QEMU_PLUGIN_HWADDR_OPERATION_OK;
561     case MEMTX_ERROR:
562         return QEMU_PLUGIN_HWADDR_OPERATION_DEVICE_ERROR;
563     case MEMTX_DECODE_ERROR:
564         return QEMU_PLUGIN_HWADDR_OPERATION_INVALID_ADDRESS;
565     case MEMTX_ACCESS_ERROR:
566         return QEMU_PLUGIN_HWADDR_OPERATION_ACCESS_DENIED;
567     default:
568         return QEMU_PLUGIN_HWADDR_OPERATION_ERROR;
569     }
570 #else
571     return QEMU_PLUGIN_HWADDR_OPERATION_ERROR;
572 #endif
573 }
574 
qemu_plugin_translate_vaddr(uint64_t vaddr,uint64_t * hwaddr)575 bool qemu_plugin_translate_vaddr(uint64_t vaddr, uint64_t *hwaddr)
576 {
577 #ifdef CONFIG_SOFTMMU
578     g_assert(current_cpu);
579 
580     uint64_t res = cpu_get_phys_page_debug(current_cpu, vaddr);
581 
582     if (res == (uint64_t)-1) {
583         return false;
584     }
585 
586     *hwaddr = res | (vaddr & ~TARGET_PAGE_MASK);
587 
588     return true;
589 #else
590     return false;
591 #endif
592 }
593 
qemu_plugin_scoreboard_new(size_t element_size)594 struct qemu_plugin_scoreboard *qemu_plugin_scoreboard_new(size_t element_size)
595 {
596     return plugin_scoreboard_new(element_size);
597 }
598 
qemu_plugin_scoreboard_free(struct qemu_plugin_scoreboard * score)599 void qemu_plugin_scoreboard_free(struct qemu_plugin_scoreboard *score)
600 {
601     plugin_scoreboard_free(score);
602 }
603 
qemu_plugin_scoreboard_find(struct qemu_plugin_scoreboard * score,unsigned int vcpu_index)604 void *qemu_plugin_scoreboard_find(struct qemu_plugin_scoreboard *score,
605                                   unsigned int vcpu_index)
606 {
607     g_assert(vcpu_index < qemu_plugin_num_vcpus());
608     /* we can't use g_array_index since entry size is not statically known */
609     char *base_ptr = score->data->data;
610     return base_ptr + vcpu_index * g_array_get_element_size(score->data);
611 }
612 
plugin_u64_address(qemu_plugin_u64 entry,unsigned int vcpu_index)613 static uint64_t *plugin_u64_address(qemu_plugin_u64 entry,
614                                     unsigned int vcpu_index)
615 {
616     char *ptr = qemu_plugin_scoreboard_find(entry.score, vcpu_index);
617     return (uint64_t *)(ptr + entry.offset);
618 }
619 
qemu_plugin_u64_add(qemu_plugin_u64 entry,unsigned int vcpu_index,uint64_t added)620 void qemu_plugin_u64_add(qemu_plugin_u64 entry, unsigned int vcpu_index,
621                          uint64_t added)
622 {
623     *plugin_u64_address(entry, vcpu_index) += added;
624 }
625 
qemu_plugin_u64_get(qemu_plugin_u64 entry,unsigned int vcpu_index)626 uint64_t qemu_plugin_u64_get(qemu_plugin_u64 entry,
627                              unsigned int vcpu_index)
628 {
629     return *plugin_u64_address(entry, vcpu_index);
630 }
631 
qemu_plugin_u64_set(qemu_plugin_u64 entry,unsigned int vcpu_index,uint64_t val)632 void qemu_plugin_u64_set(qemu_plugin_u64 entry, unsigned int vcpu_index,
633                          uint64_t val)
634 {
635     *plugin_u64_address(entry, vcpu_index) = val;
636 }
637 
qemu_plugin_u64_sum(qemu_plugin_u64 entry)638 uint64_t qemu_plugin_u64_sum(qemu_plugin_u64 entry)
639 {
640     uint64_t total = 0;
641     for (int i = 0, n = qemu_plugin_num_vcpus(); i < n; ++i) {
642         total += qemu_plugin_u64_get(entry, i);
643     }
644     return total;
645 }
646 
647