@@ -439,3 +439,12 @@ If the translating vCPU has address 0xc1 and code is later executed by vCPU
baz_trans cpu=0xc1 a=0xd3
// at guest code execution
baz_exec cpu=0xc2 a=0xd3
+
+=== "instrument" ===
+
+When compiling QEMU with trace instrumentation enabled, the "instrument"
+property lets you provide your own implementation for that trace event. This
+implementation can override and/or wrap the backend-specific tracing code
+(regardless of the tracing backend).
+
+See "docs/instrumentation.txt" for more information.
new file mode 100644
@@ -0,0 +1,264 @@
+= Trace instrumentation =
+
+== Introduction ==
+
+Trace instrumentation allows users to execute their own code when QEMU raises
+one of its tracing events (see "docs/devel/tracing.txt"). This is more efficient
+than instrumenting events with the "dtrace" backend, since the user will run
+native instrumentation code and has more options to interact with the dynamic
+tracing and instrumentation facilities of QEMU.
+
+When applied to guest code events (i.e., those with the "guest_" prefix, like
+guest memory accesses), this turns QEMU into a fairly efficient and guest
+architecture-agnostic dynamic binary instrumentation framework. It works on all
+QEMU-supported architectures, as well as works in both 'user' (standalone
+application) and 'system' (full-system emulation) modes.
+
+Look at the headers installed by QEMU on the "qemu-instr" directory for further
+information beyond this document.
+
+
+== Selecting the events to instrument ==
+
+You must first select which events must be instrumentable before compiling QEMU
+by prefixing them with the "instrument" property, and removing the "disable"
+property if it is present.
+
+To get the full list of files defining events:
+
+ find /path/to/qemu-source -name trace-events
+
+To avoid modifying QEMU's sources, you can pass the "--with-instrument-events"
+argument to configure with one event name per line.
+
+
+== Instrumenting guest code ==
+
+QEMU emulates all guest instructions when executing in TCG mode (as opposed to
+using native hardware virtualization with KVM). Instructions are decompiled and
+translated into the intermediate TCG language. Then, the TCG compiler translates
+TCG code into the native host code that QEMU will execute.
+
+All events relating to guest code are named "guest_*". In addition, all events
+with the "tcg" property (see "docs/devel/tracing.txt") can be instrumented at
+two levels:
+
+* Translation
+
+ Raised when generating TCG code (e.g., translate a memory access instruction
+ from the guest).
+
+ Note: This level only exists for events with the "tcg" property.
+
+* Execution
+
+ Raised when executing the native host code generated by the TCG compiler
+ (e.g., execute a memory access instruction from the guest).
+
+ Note: All events without the "tcg" property are raised at execution time
+ (e.g., CPU hotplug).
+
+Note: Events with the "tcg" property (e.g., 'guest_mem_before') are internally
+ translated into two events to differentiate the translation and execution
+ levels (e.g., 'guest_mem_before_trans' and 'guest_mem_before_exec').
+
+Note: All guest events have a "Mode" and "Target" line describing when they are
+ available (e.g., TCG, KVM, etc.).
+
+
+== Setting instrumentation callbacks ==
+
+Function qi_ctrl_event_set() in "qemu-instr/control.h" can be used to set the
+instrumentation callback on each event to a user-specified function. Header
+"qemu-instr/events.h" provides the event identifiers and some pre-defined
+callbacks:
+
+* QI_EVENT_${EVENT}
+
+ Event identifier, passed to functions in "qemu-instr/control.h".
+
+* qi_event_${event}_nop
+
+ Do nothing.
+
+* qi_event_${event}_trace
+
+ Trace the event using whatever tracing backend QEMU has been configured with.
+
+* qi_event_${event}_gen_exec
+
+ Generate TCG code to raise the corresponding event when the TCG-generated code
+ is executed. Otherwise, the event will not be instrumented at execution time,
+ resulting in zero-overhead when executing the guest code.
+
+ Only available for translation-time events.
+
+* qi_event_${event}_trace_and_gen_exec
+
+ Combines 'qi_event_${event}_trace' and 'qi_event_${event}_gen_exec' in a
+ single call.
+
+ Only available for translation-time events.
+
+
+== Loading an instrumentation library ==
+
+There are two ways two load an instrumentation library:
+
+* Using the command-line "-instr" argument.
+
+* Using the "instr-load" and "instr-unload" commands in the HMP and QMP
+ interfaces.
+
+
+=== Example ===
+
+1. Configure QEMU with the selected events to instrument:
+
+ # instrument guest_cpu_enter and guest_mem_before
+ cat >/tmp/my-events <<EOF
+ guest_cpu_enter
+ guest_mem_before
+ EOF
+ mkdir -p /path/to/qemu-build
+ cd /path/to/qemu-build
+ /path/to/qemu-source/configure \
+ --enable-trace-instrument \
+ --with-instrument-events=/tmp/my-events \
+ --prefix=/path/to/qemu-install
+
+2. Build and install QEMU:
+
+ make install
+
+3. Create the "Makefile" to build the instrumentation library:
+
+ mkdir -p /tmp/my-instrument
+
+ cat > /tmp/my-instrument/Makefile <<EOF
+ QEMU_PATH=/tmp/qemu-install/
+
+ CFLAGS += -g
+ CFLAGS += -O3
+ CFLAGS += -Werror -Wall
+ CFLAGS += -I$(QEMU_PATH)/include
+
+ all: libtrace-instrument.la
+
+ libtrace-instrument.la: instrument.lo
+ libtool --mode=link --tag=CC $(CC) -module -rpath /usr/local/lib -o $@ $^
+
+ %.lo: %.c
+ libtool --mode=compile --tag=CC $(CC) $(CFLAGS) -c $^
+
+ clean:
+ $(RM) -f *.o *.so *.lo
+ $(RM) -Rf .libs
+ EOF
+
+4. Write your instrumentation library:
+
+ cat > /tmp/my-instrument/instrument.c <<EOF
+ #include <stdio.h>
+ #include <assert.h>
+
+ #include <qemu-instr/events.h> /* get event declarations */
+ #include <qemu-instr/control.h> /* manipulate events */
+
+ /* as documented in QEMU's event description */
+ struct mem_info {
+ uint8_t size_shift : 2;
+ bool sign_extend: 1;
+ uint8_t endianness : 1;
+ bool store : 1;
+ };
+
+ /* the address for the memory access is not known at translation time */
+ void guest_mem_before_trans(QICPU *cpu, QITCGv_cpu tcg_cpu,
+ QITCGv vaddr, uint8_t info)
+ {
+ struct mem_info *mi = (struct mem_info*)&info;
+ qi_event_guest_mem_before_trans_trace(cpu, tcg_cpu, vaddr, info);
+ if (mi->store) {
+ /* generate at execution time only for memory writes */
+ qi_event_guest_mem_before_trans_gen_exec(cpu, tcg_cpu, vaddr, info);
+ }
+ }
+
+ /* called when QEMU executes a memory access */
+ void guest_mem_before_exec(QICPU *cpu, uint64_t vaddr, uint8_t info)
+ {
+ struct mem_info *mi = (struct mem_info*)&info;
+ if (mi->store) {
+ /* if called by TCG code, we'll only get writes (see above) */
+ qi_event_guest_mem_before_exec_trace(cpu, vaddr, info);
+ }
+ }
+
+ /* called every time QEMU hotplugs a CPU */
+ void guest_cpu_enter(QICPU *cpu)
+ {
+ /* call the original tracing routine */
+ qi_event_guest_cpu_enter_trace(cpu);
+
+ /* disable instrumentation and tracing after the first call */
+ static bool found = false;
+ if (found) {
+ QIEvent *ev = QI_EVENT_GUEST_CPU_ENTER;
+ qi_ctrl_event_set(ev, NULL);
+ qi_trace_event_set_state_dynamic(ev, false);
+ } else {
+ found = true;
+ }
+ }
+
+
+ /* mandatory initialization callback */
+ void qi_init(int argc, const char **argv)
+ {
+ int i;
+ printf("init!\n");
+ printf(" argc :: %d\n", argc);
+ for (i = 0; i < argc; i++) {
+ printf(" -> %s\n", argv[i]);
+ }
+
+ /* instrument and trace events */
+ QIEvent *ev;
+
+ ev = QI_EVENT_GUEST_CPU_ENTER;
+ qi_ctrl_event_set(ev, guest_cpu_enter);
+ qi_trace_event_set_state_dynamic(ev, true);
+
+ ev = QI_EVENT_GUEST_MEM_BEFORE_TRANS;
+ qi_ctrl_event_set(ev, guest_mem_before_trans);
+ qi_trace_event_set_state_dynamic(ev, true);
+
+ ev = QI_EVENT_GUEST_MEM_BEFORE_EXEC;
+ qi_ctrl_event_set(ev, guest_mem_before_exec);
+ qi_trace_event_set_state_dynamic(ev, true);
+ }
+
+ /* mandatory finalization callback */
+ void qi_fini(void)
+ {
+ fprintf(stderr, "fini!\n");
+
+ /* ensure all tracing is disabled */
+ qi_trace_event_set_state_dynamic(QI_EVENT_GUEST_CPU_ENTER, false);
+ qi_trace_event_set_state_dynamic(QI_EVENT_GUEST_MEM_BEFORE_TRANS, false);
+ qi_trace_event_set_state_dynamic(QI_EVENT_GUEST_MEM_BEFORE_EXEC, false);
+
+ /* instrumentation callbacks are automatically reset by QEMU */
+ }
+ EOF
+
+5. Compile the instrumentation library:
+
+ make -C /tmp/my-instrument
+
+6. Start QEMU with the instrumentation library:
+
+ /tmp/qemu-install/bin/qemu-system-x86_64 \
+ -instr file=/tmp/my-dinstrument/.libs/libtrace-instrument.so, \
+ arg=foo,arg=bar
Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu> --- docs/devel/tracing.txt | 9 ++ docs/instrumentation.txt | 264 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 273 insertions(+) create mode 100644 docs/instrumentation.txt