xref: /openbmc/qemu/plugins/api.c (revision 9b4b4e510bcb8b1c3c4789615dce3b520aa1f1d3)
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          plugin_register_dyn_cb__udata(&tb->cbs[PLUGIN_CB_REGULAR],
93                                        cb, flags, udata);
94      }
95  }
96  
97  void qemu_plugin_register_vcpu_tb_exec_inline(struct qemu_plugin_tb *tb,
98                                                enum qemu_plugin_op op,
99                                                void *ptr, uint64_t imm)
100  {
101      if (!tb->mem_only) {
102          plugin_register_inline_op(&tb->cbs[PLUGIN_CB_INLINE], 0, op, ptr, imm);
103      }
104  }
105  
106  void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
107                                              qemu_plugin_vcpu_udata_cb_t cb,
108                                              enum qemu_plugin_cb_flags flags,
109                                              void *udata)
110  {
111      if (!insn->mem_only) {
112          plugin_register_dyn_cb__udata(&insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR],
113                                        cb, flags, udata);
114      }
115  }
116  
117  void qemu_plugin_register_vcpu_insn_exec_inline(struct qemu_plugin_insn *insn,
118                                                  enum qemu_plugin_op op,
119                                                  void *ptr, uint64_t imm)
120  {
121      if (!insn->mem_only) {
122          plugin_register_inline_op(&insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_INLINE],
123                                    0, op, ptr, imm);
124      }
125  }
126  
127  
128  /*
129   * We always plant memory instrumentation because they don't finalise until
130   * after the operation has complete.
131   */
132  void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn,
133                                        qemu_plugin_vcpu_mem_cb_t cb,
134                                        enum qemu_plugin_cb_flags flags,
135                                        enum qemu_plugin_mem_rw rw,
136                                        void *udata)
137  {
138      plugin_register_vcpu_mem_cb(&insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR],
139                                      cb, flags, rw, udata);
140  }
141  
142  void qemu_plugin_register_vcpu_mem_inline(struct qemu_plugin_insn *insn,
143                                            enum qemu_plugin_mem_rw rw,
144                                            enum qemu_plugin_op op, void *ptr,
145                                            uint64_t imm)
146  {
147      plugin_register_inline_op(&insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE],
148                                rw, op, ptr, imm);
149  }
150  
151  void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,
152                                             qemu_plugin_vcpu_tb_trans_cb_t cb)
153  {
154      plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_TB_TRANS, cb);
155  }
156  
157  void qemu_plugin_register_vcpu_syscall_cb(qemu_plugin_id_t id,
158                                            qemu_plugin_vcpu_syscall_cb_t cb)
159  {
160      plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL, cb);
161  }
162  
163  void
164  qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,
165                                           qemu_plugin_vcpu_syscall_ret_cb_t cb)
166  {
167      plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL_RET, cb);
168  }
169  
170  /*
171   * Plugin Queries
172   *
173   * These are queries that the plugin can make to gauge information
174   * from our opaque data types. We do not want to leak internal details
175   * here just information useful to the plugin.
176   */
177  
178  /*
179   * Translation block information:
180   *
181   * A plugin can query the virtual address of the start of the block
182   * and the number of instructions in it. It can also get access to
183   * each translated instruction.
184   */
185  
186  size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb)
187  {
188      return tb->n;
189  }
190  
191  uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb)
192  {
193      return tb->vaddr;
194  }
195  
196  struct qemu_plugin_insn *
197  qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx)
198  {
199      struct qemu_plugin_insn *insn;
200      if (unlikely(idx >= tb->n)) {
201          return NULL;
202      }
203      insn = g_ptr_array_index(tb->insns, idx);
204      insn->mem_only = tb->mem_only;
205      return insn;
206  }
207  
208  /*
209   * Instruction information
210   *
211   * These queries allow the plugin to retrieve information about each
212   * instruction being translated.
213   */
214  
215  const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn)
216  {
217      return insn->data->data;
218  }
219  
220  size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn)
221  {
222      return insn->data->len;
223  }
224  
225  uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn)
226  {
227      return insn->vaddr;
228  }
229  
230  void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn)
231  {
232      return insn->haddr;
233  }
234  
235  char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn)
236  {
237      CPUState *cpu = current_cpu;
238      return plugin_disas(cpu, insn->vaddr, insn->data->len);
239  }
240  
241  const char *qemu_plugin_insn_symbol(const struct qemu_plugin_insn *insn)
242  {
243      const char *sym = lookup_symbol(insn->vaddr);
244      return sym[0] != 0 ? sym : NULL;
245  }
246  
247  /*
248   * The memory queries allow the plugin to query information about a
249   * memory access.
250   */
251  
252  unsigned qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info)
253  {
254      MemOp op = get_memop(info);
255      return op & MO_SIZE;
256  }
257  
258  bool qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info)
259  {
260      MemOp op = get_memop(info);
261      return op & MO_SIGN;
262  }
263  
264  bool qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info)
265  {
266      MemOp op = get_memop(info);
267      return (op & MO_BSWAP) == MO_BE;
268  }
269  
270  bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info)
271  {
272      return get_plugin_meminfo_rw(info) & QEMU_PLUGIN_MEM_W;
273  }
274  
275  /*
276   * Virtual Memory queries
277   */
278  
279  #ifdef CONFIG_SOFTMMU
280  static __thread struct qemu_plugin_hwaddr hwaddr_info;
281  #endif
282  
283  struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
284                                                    uint64_t vaddr)
285  {
286  #ifdef CONFIG_SOFTMMU
287      CPUState *cpu = current_cpu;
288      unsigned int mmu_idx = get_mmuidx(info);
289      enum qemu_plugin_mem_rw rw = get_plugin_meminfo_rw(info);
290      hwaddr_info.is_store = (rw & QEMU_PLUGIN_MEM_W) != 0;
291  
292      assert(mmu_idx < NB_MMU_MODES);
293  
294      if (!tlb_plugin_lookup(cpu, vaddr, mmu_idx,
295                             hwaddr_info.is_store, &hwaddr_info)) {
296          error_report("invalid use of qemu_plugin_get_hwaddr");
297          return NULL;
298      }
299  
300      return &hwaddr_info;
301  #else
302      return NULL;
303  #endif
304  }
305  
306  bool qemu_plugin_hwaddr_is_io(const struct qemu_plugin_hwaddr *haddr)
307  {
308  #ifdef CONFIG_SOFTMMU
309      return haddr->is_io;
310  #else
311      return false;
312  #endif
313  }
314  
315  uint64_t qemu_plugin_hwaddr_phys_addr(const struct qemu_plugin_hwaddr *haddr)
316  {
317  #ifdef CONFIG_SOFTMMU
318      if (haddr) {
319          return haddr->phys_addr;
320      }
321  #endif
322      return 0;
323  }
324  
325  const char *qemu_plugin_hwaddr_device_name(const struct qemu_plugin_hwaddr *h)
326  {
327  #ifdef CONFIG_SOFTMMU
328      if (h && h->is_io) {
329          MemoryRegion *mr = h->mr;
330          if (!mr->name) {
331              unsigned maddr = (uintptr_t)mr;
332              g_autofree char *temp = g_strdup_printf("anon%08x", maddr);
333              return g_intern_string(temp);
334          } else {
335              return g_intern_string(mr->name);
336          }
337      } else {
338          return g_intern_static_string("RAM");
339      }
340  #else
341      return g_intern_static_string("Invalid");
342  #endif
343  }
344  
345  /*
346   * Queries to the number and potential maximum number of vCPUs there
347   * will be. This helps the plugin dimension per-vcpu arrays.
348   */
349  
350  #ifndef CONFIG_USER_ONLY
351  static MachineState * get_ms(void)
352  {
353      return MACHINE(qdev_get_machine());
354  }
355  #endif
356  
357  int qemu_plugin_n_vcpus(void)
358  {
359  #ifdef CONFIG_USER_ONLY
360      return -1;
361  #else
362      return get_ms()->smp.cpus;
363  #endif
364  }
365  
366  int qemu_plugin_n_max_vcpus(void)
367  {
368  #ifdef CONFIG_USER_ONLY
369      return -1;
370  #else
371      return get_ms()->smp.max_cpus;
372  #endif
373  }
374  
375  /*
376   * Plugin output
377   */
378  void qemu_plugin_outs(const char *string)
379  {
380      qemu_log_mask(CPU_LOG_PLUGIN, "%s", string);
381  }
382  
383  bool qemu_plugin_bool_parse(const char *name, const char *value, bool *ret)
384  {
385      return name && value && qapi_bool_parse(name, value, ret, NULL);
386  }
387  
388  /*
389   * Binary path, start and end locations
390   */
391  const char *qemu_plugin_path_to_binary(void)
392  {
393      char *path = NULL;
394  #ifdef CONFIG_USER_ONLY
395      TaskState *ts = (TaskState *) current_cpu->opaque;
396      path = g_strdup(ts->bprm->filename);
397  #endif
398      return path;
399  }
400  
401  uint64_t qemu_plugin_start_code(void)
402  {
403      uint64_t start = 0;
404  #ifdef CONFIG_USER_ONLY
405      TaskState *ts = (TaskState *) current_cpu->opaque;
406      start = ts->info->start_code;
407  #endif
408      return start;
409  }
410  
411  uint64_t qemu_plugin_end_code(void)
412  {
413      uint64_t end = 0;
414  #ifdef CONFIG_USER_ONLY
415      TaskState *ts = (TaskState *) current_cpu->opaque;
416      end = ts->info->end_code;
417  #endif
418      return end;
419  }
420  
421  uint64_t qemu_plugin_entry_code(void)
422  {
423      uint64_t entry = 0;
424  #ifdef CONFIG_USER_ONLY
425      TaskState *ts = (TaskState *) current_cpu->opaque;
426      entry = ts->info->entry;
427  #endif
428      return entry;
429  }
430