xref: /openbmc/qemu/plugins/api.c (revision c006147122dede4440c027142ce3025f64e199c0)
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  *
12  * Which can then be passed back into the API to do additional things.
13  * As such all the public functions in here are exported in
14  * qemu-plugin.h.
15  *
16  * The general life-cycle of a plugin is:
17  *
18  *  - plugin is loaded, public qemu_plugin_install called
19  *    - the install func registers callbacks for events
20  *    - usually an atexit_cb is registered to dump info at the end
21  *  - when a registered event occurs the plugin is called
22  *     - some events pass additional info
23  *     - during translation the plugin can decide to instrument any
24  *       instruction
25  *  - when QEMU exits all the registered atexit callbacks are called
26  *
27  * Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
28  * Copyright (C) 2019, Linaro
29  *
30  * License: GNU GPL, version 2 or later.
31  *   See the COPYING file in the top-level directory.
32  *
33  * SPDX-License-Identifier: GPL-2.0-or-later
34  *
35  */
36 
37 #include "qemu/osdep.h"
38 #include "qemu/plugin.h"
39 #include "qemu/log.h"
40 #include "tcg/tcg.h"
41 #include "exec/exec-all.h"
42 #include "exec/ram_addr.h"
43 #include "disas/disas.h"
44 #include "plugin.h"
45 #ifndef CONFIG_USER_ONLY
46 #include "qemu/plugin-memory.h"
47 #include "hw/boards.h"
48 #else
49 #include "qemu.h"
50 #ifdef CONFIG_LINUX
51 #include "loader.h"
52 #endif
53 #endif
54 
55 /* Uninstall and Reset handlers */
56 
57 void qemu_plugin_uninstall(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb)
58 {
59     plugin_reset_uninstall(id, cb, false);
60 }
61 
62 void qemu_plugin_reset(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb)
63 {
64     plugin_reset_uninstall(id, cb, true);
65 }
66 
67 /*
68  * Plugin Register Functions
69  *
70  * This allows the plugin to register callbacks for various events
71  * during the translation.
72  */
73 
74 void qemu_plugin_register_vcpu_init_cb(qemu_plugin_id_t id,
75                                        qemu_plugin_vcpu_simple_cb_t cb)
76 {
77     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_INIT, cb);
78 }
79 
80 void qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id,
81                                        qemu_plugin_vcpu_simple_cb_t cb)
82 {
83     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_EXIT, cb);
84 }
85 
86 void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
87                                           qemu_plugin_vcpu_udata_cb_t cb,
88                                           enum qemu_plugin_cb_flags flags,
89                                           void *udata)
90 {
91     if (!tb->mem_only) {
92         int index = flags == QEMU_PLUGIN_CB_R_REGS ||
93                     flags == QEMU_PLUGIN_CB_RW_REGS ?
94                     PLUGIN_CB_REGULAR_R : PLUGIN_CB_REGULAR;
95 
96         plugin_register_dyn_cb__udata(&tb->cbs[index],
97                                       cb, flags, udata);
98     }
99 }
100 
101 void qemu_plugin_register_vcpu_tb_exec_inline(struct qemu_plugin_tb *tb,
102                                               enum qemu_plugin_op op,
103                                               void *ptr, uint64_t imm)
104 {
105     if (!tb->mem_only) {
106         plugin_register_inline_op(&tb->cbs[PLUGIN_CB_INLINE], 0, op, ptr, imm);
107     }
108 }
109 
110 void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
111                                             qemu_plugin_vcpu_udata_cb_t cb,
112                                             enum qemu_plugin_cb_flags flags,
113                                             void *udata)
114 {
115     if (!insn->mem_only) {
116         int index = flags == QEMU_PLUGIN_CB_R_REGS ||
117                     flags == QEMU_PLUGIN_CB_RW_REGS ?
118                     PLUGIN_CB_REGULAR_R : PLUGIN_CB_REGULAR;
119 
120         plugin_register_dyn_cb__udata(&insn->cbs[PLUGIN_CB_INSN][index],
121                                       cb, flags, udata);
122     }
123 }
124 
125 void qemu_plugin_register_vcpu_insn_exec_inline(struct qemu_plugin_insn *insn,
126                                                 enum qemu_plugin_op op,
127                                                 void *ptr, uint64_t imm)
128 {
129     if (!insn->mem_only) {
130         plugin_register_inline_op(&insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_INLINE],
131                                   0, op, ptr, imm);
132     }
133 }
134 
135 
136 /*
137  * We always plant memory instrumentation because they don't finalise until
138  * after the operation has complete.
139  */
140 void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn,
141                                       qemu_plugin_vcpu_mem_cb_t cb,
142                                       enum qemu_plugin_cb_flags flags,
143                                       enum qemu_plugin_mem_rw rw,
144                                       void *udata)
145 {
146     plugin_register_vcpu_mem_cb(&insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR],
147                                     cb, flags, rw, udata);
148 }
149 
150 void qemu_plugin_register_vcpu_mem_inline(struct qemu_plugin_insn *insn,
151                                           enum qemu_plugin_mem_rw rw,
152                                           enum qemu_plugin_op op, void *ptr,
153                                           uint64_t imm)
154 {
155     plugin_register_inline_op(&insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE],
156                               rw, op, ptr, imm);
157 }
158 
159 void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,
160                                            qemu_plugin_vcpu_tb_trans_cb_t cb)
161 {
162     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_TB_TRANS, cb);
163 }
164 
165 void qemu_plugin_register_vcpu_syscall_cb(qemu_plugin_id_t id,
166                                           qemu_plugin_vcpu_syscall_cb_t cb)
167 {
168     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL, cb);
169 }
170 
171 void
172 qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,
173                                          qemu_plugin_vcpu_syscall_ret_cb_t cb)
174 {
175     plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL_RET, cb);
176 }
177 
178 /*
179  * Plugin Queries
180  *
181  * These are queries that the plugin can make to gauge information
182  * from our opaque data types. We do not want to leak internal details
183  * here just information useful to the plugin.
184  */
185 
186 /*
187  * Translation block information:
188  *
189  * A plugin can query the virtual address of the start of the block
190  * and the number of instructions in it. It can also get access to
191  * each translated instruction.
192  */
193 
194 size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb)
195 {
196     return tb->n;
197 }
198 
199 uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb)
200 {
201     return tb->vaddr;
202 }
203 
204 struct qemu_plugin_insn *
205 qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx)
206 {
207     struct qemu_plugin_insn *insn;
208     if (unlikely(idx >= tb->n)) {
209         return NULL;
210     }
211     insn = g_ptr_array_index(tb->insns, idx);
212     insn->mem_only = tb->mem_only;
213     return insn;
214 }
215 
216 /*
217  * Instruction information
218  *
219  * These queries allow the plugin to retrieve information about each
220  * instruction being translated.
221  */
222 
223 const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn)
224 {
225     return insn->data->data;
226 }
227 
228 size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn)
229 {
230     return insn->data->len;
231 }
232 
233 uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn)
234 {
235     return insn->vaddr;
236 }
237 
238 void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn)
239 {
240     return insn->haddr;
241 }
242 
243 char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn)
244 {
245     CPUState *cpu = current_cpu;
246     return plugin_disas(cpu, insn->vaddr, insn->data->len);
247 }
248 
249 const char *qemu_plugin_insn_symbol(const struct qemu_plugin_insn *insn)
250 {
251     const char *sym = lookup_symbol(insn->vaddr);
252     return sym[0] != 0 ? sym : NULL;
253 }
254 
255 /*
256  * The memory queries allow the plugin to query information about a
257  * memory access.
258  */
259 
260 unsigned qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info)
261 {
262     MemOp op = get_memop(info);
263     return op & MO_SIZE;
264 }
265 
266 bool qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info)
267 {
268     MemOp op = get_memop(info);
269     return op & MO_SIGN;
270 }
271 
272 bool qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info)
273 {
274     MemOp op = get_memop(info);
275     return (op & MO_BSWAP) == MO_BE;
276 }
277 
278 bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info)
279 {
280     return get_plugin_meminfo_rw(info) & QEMU_PLUGIN_MEM_W;
281 }
282 
283 /*
284  * Virtual Memory queries
285  */
286 
287 #ifdef CONFIG_SOFTMMU
288 static __thread struct qemu_plugin_hwaddr hwaddr_info;
289 #endif
290 
291 struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
292                                                   uint64_t vaddr)
293 {
294 #ifdef CONFIG_SOFTMMU
295     CPUState *cpu = current_cpu;
296     unsigned int mmu_idx = get_mmuidx(info);
297     enum qemu_plugin_mem_rw rw = get_plugin_meminfo_rw(info);
298     hwaddr_info.is_store = (rw & QEMU_PLUGIN_MEM_W) != 0;
299 
300     assert(mmu_idx < NB_MMU_MODES);
301 
302     if (!tlb_plugin_lookup(cpu, vaddr, mmu_idx,
303                            hwaddr_info.is_store, &hwaddr_info)) {
304         error_report("invalid use of qemu_plugin_get_hwaddr");
305         return NULL;
306     }
307 
308     return &hwaddr_info;
309 #else
310     return NULL;
311 #endif
312 }
313 
314 bool qemu_plugin_hwaddr_is_io(const struct qemu_plugin_hwaddr *haddr)
315 {
316 #ifdef CONFIG_SOFTMMU
317     return haddr->is_io;
318 #else
319     return false;
320 #endif
321 }
322 
323 uint64_t qemu_plugin_hwaddr_phys_addr(const struct qemu_plugin_hwaddr *haddr)
324 {
325 #ifdef CONFIG_SOFTMMU
326     if (haddr) {
327         return haddr->phys_addr;
328     }
329 #endif
330     return 0;
331 }
332 
333 const char *qemu_plugin_hwaddr_device_name(const struct qemu_plugin_hwaddr *h)
334 {
335 #ifdef CONFIG_SOFTMMU
336     if (h && h->is_io) {
337         MemoryRegion *mr = h->mr;
338         if (!mr->name) {
339             unsigned maddr = (uintptr_t)mr;
340             g_autofree char *temp = g_strdup_printf("anon%08x", maddr);
341             return g_intern_string(temp);
342         } else {
343             return g_intern_string(mr->name);
344         }
345     } else {
346         return g_intern_static_string("RAM");
347     }
348 #else
349     return g_intern_static_string("Invalid");
350 #endif
351 }
352 
353 int qemu_plugin_num_vcpus(void)
354 {
355     return plugin_num_vcpus();
356 }
357 
358 /*
359  * Plugin output
360  */
361 void qemu_plugin_outs(const char *string)
362 {
363     qemu_log_mask(CPU_LOG_PLUGIN, "%s", string);
364 }
365 
366 bool qemu_plugin_bool_parse(const char *name, const char *value, bool *ret)
367 {
368     return name && value && qapi_bool_parse(name, value, ret, NULL);
369 }
370 
371 /*
372  * Binary path, start and end locations
373  */
374 const char *qemu_plugin_path_to_binary(void)
375 {
376     char *path = NULL;
377 #ifdef CONFIG_USER_ONLY
378     TaskState *ts = (TaskState *) current_cpu->opaque;
379     path = g_strdup(ts->bprm->filename);
380 #endif
381     return path;
382 }
383 
384 uint64_t qemu_plugin_start_code(void)
385 {
386     uint64_t start = 0;
387 #ifdef CONFIG_USER_ONLY
388     TaskState *ts = (TaskState *) current_cpu->opaque;
389     start = ts->info->start_code;
390 #endif
391     return start;
392 }
393 
394 uint64_t qemu_plugin_end_code(void)
395 {
396     uint64_t end = 0;
397 #ifdef CONFIG_USER_ONLY
398     TaskState *ts = (TaskState *) current_cpu->opaque;
399     end = ts->info->end_code;
400 #endif
401     return end;
402 }
403 
404 uint64_t qemu_plugin_entry_code(void)
405 {
406     uint64_t entry = 0;
407 #ifdef CONFIG_USER_ONLY
408     TaskState *ts = (TaskState *) current_cpu->opaque;
409     entry = ts->info->entry;
410 #endif
411     return entry;
412 }
413