2 * Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
4 * License: GNU GPL, version 2 or later.
5 * See the COPYING file in the top-level directory.
10 #include "qemu/config-file.h"
11 #include "qemu/qemu-plugin.h"
12 #include "qemu/error-report.h"
13 #include "qemu/queue.h"
14 #include "qemu/option.h"
15 #include "qemu/plugin-event.h"
16 #include "exec/memopidx.h"
17 #include "hw/core/cpu.h"
20 * Option parsing/processing.
21 * Note that we can load an arbitrary number of plugins.
23 struct qemu_plugin_desc
;
24 typedef QTAILQ_HEAD(, qemu_plugin_desc
) QemuPluginList
;
27 * Construct a qemu_plugin_meminfo_t.
29 static inline qemu_plugin_meminfo_t
30 make_plugin_meminfo(MemOpIdx oi
, enum qemu_plugin_mem_rw rw
)
32 return oi
| (rw
<< 16);
36 * Extract the memory operation direction from a qemu_plugin_meminfo_t.
37 * Other portions may be extracted via get_memop and get_mmuidx.
39 static inline enum qemu_plugin_mem_rw
40 get_plugin_meminfo_rw(qemu_plugin_meminfo_t i
)
46 extern QemuOptsList qemu_plugin_opts
;
48 static inline void qemu_plugin_add_opts(void)
50 qemu_add_opts(&qemu_plugin_opts
);
53 void qemu_plugin_opt_parse(const char *optstr
, QemuPluginList
*head
);
54 int qemu_plugin_load_list(QemuPluginList
*head
, Error
**errp
);
56 union qemu_plugin_cb_sig
{
57 qemu_plugin_simple_cb_t simple
;
58 qemu_plugin_udata_cb_t udata
;
59 qemu_plugin_vcpu_simple_cb_t vcpu_simple
;
60 qemu_plugin_vcpu_udata_cb_t vcpu_udata
;
61 qemu_plugin_vcpu_tb_trans_cb_t vcpu_tb_trans
;
62 qemu_plugin_vcpu_mem_cb_t vcpu_mem
;
63 qemu_plugin_vcpu_syscall_cb_t vcpu_syscall
;
64 qemu_plugin_vcpu_syscall_ret_cb_t vcpu_syscall_ret
;
68 enum plugin_dyn_cb_type
{
74 enum plugin_dyn_cb_subtype
{
82 * A dynamic callback has an insertion point that is determined at run-time.
83 * Usually the insertion point is somewhere in the code cache; think for
84 * instance of a callback to be called upon the execution of a particular TB.
86 struct qemu_plugin_dyn_cb
{
87 union qemu_plugin_cb_sig f
;
89 enum plugin_dyn_cb_subtype type
;
90 /* @rw applies to mem callbacks only (both regular and inline) */
91 enum qemu_plugin_mem_rw rw
;
92 /* fields specific to each dyn_cb type go here */
95 qemu_plugin_u64 entry
;
96 enum qemu_plugin_op op
;
102 /* Internal context for instrumenting an instruction */
103 struct qemu_plugin_insn
{
107 GArray
*cbs
[PLUGIN_N_CB_TYPES
][PLUGIN_N_CB_SUBTYPES
];
110 /* if set, the instruction calls helpers that might access guest memory */
116 /* A scoreboard is an array of values, indexed by vcpu_index */
117 struct qemu_plugin_scoreboard
{
119 QLIST_ENTRY(qemu_plugin_scoreboard
) entry
;
123 * qemu_plugin_insn allocate and cleanup functions. We don't expect to
124 * cleanup many of these structures. They are reused for each fresh
128 static inline void qemu_plugin_insn_cleanup_fn(gpointer data
)
130 struct qemu_plugin_insn
*insn
= (struct qemu_plugin_insn
*) data
;
131 g_byte_array_free(insn
->data
, true);
134 static inline struct qemu_plugin_insn
*qemu_plugin_insn_alloc(void)
137 struct qemu_plugin_insn
*insn
= g_new0(struct qemu_plugin_insn
, 1);
138 insn
->data
= g_byte_array_sized_new(4);
140 for (i
= 0; i
< PLUGIN_N_CB_TYPES
; i
++) {
141 for (j
= 0; j
< PLUGIN_N_CB_SUBTYPES
; j
++) {
142 insn
->cbs
[i
][j
] = g_array_new(false, false,
143 sizeof(struct qemu_plugin_dyn_cb
));
149 /* Internal context for this TranslationBlock */
150 struct qemu_plugin_tb
{
159 /* if set, the TB calls helpers that might access guest memory */
162 GArray
*cbs
[PLUGIN_N_CB_SUBTYPES
];
166 * qemu_plugin_tb_insn_get(): get next plugin record for translation.
167 * @tb: the internal tb context
168 * @pc: address of instruction
171 struct qemu_plugin_insn
*qemu_plugin_tb_insn_get(struct qemu_plugin_tb
*tb
,
174 struct qemu_plugin_insn
*insn
;
177 if (unlikely(tb
->n
== tb
->insns
->len
)) {
178 struct qemu_plugin_insn
*new_insn
= qemu_plugin_insn_alloc();
179 g_ptr_array_add(tb
->insns
, new_insn
);
181 insn
= g_ptr_array_index(tb
->insns
, tb
->n
++);
182 g_byte_array_set_size(insn
->data
, 0);
183 insn
->calls_helpers
= false;
184 insn
->mem_helper
= false;
187 for (i
= 0; i
< PLUGIN_N_CB_TYPES
; i
++) {
188 for (j
= 0; j
< PLUGIN_N_CB_SUBTYPES
; j
++) {
189 g_array_set_size(insn
->cbs
[i
][j
], 0);
197 * struct CPUPluginState - per-CPU state for plugins
198 * @event_mask: plugin event bitmap. Modified only via async work.
200 struct CPUPluginState
{
201 DECLARE_BITMAP(event_mask
, QEMU_PLUGIN_EV_MAX
);
205 * qemu_plugin_create_vcpu_state: allocate plugin state
207 CPUPluginState
*qemu_plugin_create_vcpu_state(void);
209 void qemu_plugin_vcpu_init_hook(CPUState
*cpu
);
210 void qemu_plugin_vcpu_exit_hook(CPUState
*cpu
);
211 void qemu_plugin_tb_trans_cb(CPUState
*cpu
, struct qemu_plugin_tb
*tb
);
212 void qemu_plugin_vcpu_idle_cb(CPUState
*cpu
);
213 void qemu_plugin_vcpu_resume_cb(CPUState
*cpu
);
215 qemu_plugin_vcpu_syscall(CPUState
*cpu
, int64_t num
, uint64_t a1
,
216 uint64_t a2
, uint64_t a3
, uint64_t a4
, uint64_t a5
,
217 uint64_t a6
, uint64_t a7
, uint64_t a8
);
218 void qemu_plugin_vcpu_syscall_ret(CPUState
*cpu
, int64_t num
, int64_t ret
);
220 void qemu_plugin_vcpu_mem_cb(CPUState
*cpu
, uint64_t vaddr
,
221 MemOpIdx oi
, enum qemu_plugin_mem_rw rw
);
223 void qemu_plugin_flush_cb(void);
225 void qemu_plugin_atexit_cb(void);
227 void qemu_plugin_add_dyn_cb_arr(GArray
*arr
);
229 static inline void qemu_plugin_disable_mem_helpers(CPUState
*cpu
)
231 cpu
->plugin_mem_cbs
= NULL
;
235 * qemu_plugin_user_exit(): clean-up callbacks before calling exit callbacks
237 * This is a user-mode only helper that ensure we have fully cleared
238 * callbacks from all threads before calling the exit callbacks. This
239 * is so the plugins themselves don't have to jump through hoops to
240 * guard against race conditions.
242 void qemu_plugin_user_exit(void);
245 * qemu_plugin_user_prefork_lock(): take plugin lock before forking
247 * This is a user-mode only helper to take the internal plugin lock
248 * before a fork event. This is ensure a consistent lock state
250 void qemu_plugin_user_prefork_lock(void);
253 * qemu_plugin_user_postfork(): reset the plugin lock
254 * @is_child: is this thread the child
256 * This user-mode only helper resets the lock state after a fork so we
257 * can continue using the plugin interface.
259 void qemu_plugin_user_postfork(bool is_child
);
261 #else /* !CONFIG_PLUGIN */
263 static inline void qemu_plugin_add_opts(void)
266 static inline void qemu_plugin_opt_parse(const char *optstr
,
267 QemuPluginList
*head
)
269 error_report("plugin interface not enabled in this build");
273 static inline int qemu_plugin_load_list(QemuPluginList
*head
, Error
**errp
)
278 static inline void qemu_plugin_vcpu_init_hook(CPUState
*cpu
)
281 static inline void qemu_plugin_vcpu_exit_hook(CPUState
*cpu
)
284 static inline void qemu_plugin_tb_trans_cb(CPUState
*cpu
,
285 struct qemu_plugin_tb
*tb
)
288 static inline void qemu_plugin_vcpu_idle_cb(CPUState
*cpu
)
291 static inline void qemu_plugin_vcpu_resume_cb(CPUState
*cpu
)
295 qemu_plugin_vcpu_syscall(CPUState
*cpu
, int64_t num
, uint64_t a1
, uint64_t a2
,
296 uint64_t a3
, uint64_t a4
, uint64_t a5
, uint64_t a6
,
297 uint64_t a7
, uint64_t a8
)
301 void qemu_plugin_vcpu_syscall_ret(CPUState
*cpu
, int64_t num
, int64_t ret
)
304 static inline void qemu_plugin_vcpu_mem_cb(CPUState
*cpu
, uint64_t vaddr
,
306 enum qemu_plugin_mem_rw rw
)
309 static inline void qemu_plugin_flush_cb(void)
312 static inline void qemu_plugin_atexit_cb(void)
316 void qemu_plugin_add_dyn_cb_arr(GArray
*arr
)
319 static inline void qemu_plugin_disable_mem_helpers(CPUState
*cpu
)
322 static inline void qemu_plugin_user_exit(void)
325 static inline void qemu_plugin_user_prefork_lock(void)
328 static inline void qemu_plugin_user_postfork(bool is_child
)
331 #endif /* !CONFIG_PLUGIN */
333 #endif /* QEMU_PLUGIN_H */