| .. |
| Copyright (C) 2017, Emilio G. Cota <cota@braap.org> |
| Copyright (c) 2019, Linaro Limited |
| Written by Emilio Cota and Alex Bennée |
| |
| .. _TCG Plugins: |
| |
| QEMU TCG Plugins |
| ================ |
| |
| |
| Writing plugins |
| --------------- |
| |
| API versioning |
| ~~~~~~~~~~~~~~ |
| |
| This is a new feature for QEMU and it does allow people to develop |
| out-of-tree plugins that can be dynamically linked into a running QEMU |
| process. However the project reserves the right to change or break the |
| API should it need to do so. The best way to avoid this is to submit |
| your plugin upstream so they can be updated if/when the API changes. |
| |
| All plugins need to declare a symbol which exports the plugin API |
| version they were built against. This can be done simply by:: |
| |
| QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; |
| |
| The core code will refuse to load a plugin that doesn't export a |
| ``qemu_plugin_version`` symbol or if plugin version is outside of QEMU's |
| supported range of API versions. |
| |
| Additionally the ``qemu_info_t`` structure which is passed to the |
| ``qemu_plugin_install`` method of a plugin will detail the minimum and |
| current API versions supported by QEMU. The API version will be |
| incremented if new APIs are added. The minimum API version will be |
| incremented if existing APIs are changed or removed. |
| |
| Lifetime of the query handle |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Each callback provides an opaque anonymous information handle which |
| can usually be further queried to find out information about a |
| translation, instruction or operation. The handles themselves are only |
| valid during the lifetime of the callback so it is important that any |
| information that is needed is extracted during the callback and saved |
| by the plugin. |
| |
| Plugin life cycle |
| ~~~~~~~~~~~~~~~~~ |
| |
| First the plugin is loaded and the public qemu_plugin_install function |
| is called. The plugin will then register callbacks for various plugin |
| events. Generally plugins will register a handler for the *atexit* |
| if they want to dump a summary of collected information once the |
| program/system has finished running. |
| |
| When a registered event occurs the plugin callback is invoked. The |
| callbacks may provide additional information. In the case of a |
| translation event the plugin has an option to enumerate the |
| instructions in a block of instructions and optionally register |
| callbacks to some or all instructions when they are executed. |
| |
| There is also a facility to add inline instructions doing various operations, |
| like adding or storing an immediate value. It is also possible to execute a |
| callback conditionally, with condition being evaluated inline. All those inline |
| operations are associated to a ``scoreboard``, which is a thread-local storage |
| automatically expanded when new cores/threads are created and that can be |
| accessed/modified in a thread-safe way without any lock needed. Combining inline |
| operations and conditional callbacks offer a more efficient way to instrument |
| binaries, compared to classic callbacks. |
| |
| Finally when QEMU exits all the registered *atexit* callbacks are |
| invoked. |
| |
| Exposure of QEMU internals |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| The plugin architecture actively avoids leaking implementation details |
| about how QEMU's translation works to the plugins. While there are |
| conceptions such as translation time and translation blocks the |
| details are opaque to plugins. The plugin is able to query select |
| details of instructions and system configuration only through the |
| exported *qemu_plugin* functions. |
| |
| However the following assumptions can be made: |
| |
| Translation Blocks |
| ++++++++++++++++++ |
| |
| All code will go through a translation phase although not all |
| translations will be necessarily be executed. You need to instrument |
| actual executions to track what is happening. |
| |
| It is quite normal to see the same address translated multiple times. |
| If you want to track the code in system emulation you should examine |
| the underlying physical address (``qemu_plugin_insn_haddr``) to take |
| into account the effects of virtual memory although if the system does |
| paging this will change too. |
| |
| Not all instructions in a block will always execute so if its |
| important to track individual instruction execution you need to |
| instrument them directly. However asynchronous interrupts will not |
| change control flow mid-block. |
| |
| Instructions |
| ++++++++++++ |
| |
| Instruction instrumentation runs before the instruction executes. You |
| can be can be sure the instruction will be dispatched, but you can't |
| be sure it will complete. Generally this will be because of a |
| synchronous exception (e.g. SIGILL) triggered by the instruction |
| attempting to execute. If you want to be sure you will need to |
| instrument the next instruction as well. See the ``execlog.c`` plugin |
| for examples of how to track this and finalise details after execution. |
| |
| Memory Accesses |
| +++++++++++++++ |
| |
| Memory callbacks are called after a successful load or store. |
| Unsuccessful operations (i.e. faults) will not be visible to memory |
| instrumentation although the execution side effects can be observed |
| (e.g. entering a exception handler). |
| |
| System Idle and Resume States |
| +++++++++++++++++++++++++++++ |
| |
| The ``qemu_plugin_register_vcpu_idle_cb`` and |
| ``qemu_plugin_register_vcpu_resume_cb`` functions can be used to track |
| when CPUs go into and return from sleep states when waiting for |
| external I/O. Be aware though that these may occur less frequently |
| than in real HW due to the inefficiencies of emulation giving less |
| chance for the CPU to idle. |
| |
| Internals |
| --------- |
| |
| Locking |
| ~~~~~~~ |
| |
| We have to ensure we cannot deadlock, particularly under MTTCG. For |
| this we acquire a lock when called from plugin code. We also keep the |
| list of callbacks under RCU so that we do not have to hold the lock |
| when calling the callbacks. This is also for performance, since some |
| callbacks (e.g. memory access callbacks) might be called very |
| frequently. |
| |
| * A consequence of this is that we keep our own list of CPUs, so that |
| we do not have to worry about locking order wrt cpu_list_lock. |
| * Use a recursive lock, since we can get registration calls from |
| callbacks. |
| |
| As a result registering/unregistering callbacks is "slow", since it |
| takes a lock. But this is very infrequent; we want performance when |
| calling (or not calling) callbacks, not when registering them. Using |
| RCU is great for this. |
| |
| We support the uninstallation of a plugin at any time (e.g. from |
| plugin callbacks). This allows plugins to remove themselves if they no |
| longer want to instrument the code. This operation is asynchronous |
| which means callbacks may still occur after the uninstall operation is |
| requested. The plugin isn't completely uninstalled until the safe work |
| has executed while all vCPUs are quiescent. |
| |
| Plugin API |
| ========== |
| |
| The following API is generated from the inline documentation in |
| ``include/qemu/qemu-plugin.h``. Please ensure any updates to the API |
| include the full kernel-doc annotations. |
| |
| .. kernel-doc:: include/qemu/qemu-plugin.h |