@@ -9,6 +9,7 @@
/instrument-root.c
/instrument/generated-tcg-tracers.h
/instrument/generated-tcg-tracers.c
+/instrument/qemu-instr/events.h
/trace-events-all
/trace/generated-events.h
/trace/generated-events.c
@@ -193,6 +193,9 @@ trace-dtrace-root.o: trace-dtrace-root.dtrace
INSTRUMENT_HEADERS = instrument-root.h $(trace-events-subdirs:%=%/instrument.h)
INSTRUMENT_HEADERS += instrument/generated-tcg-tracers.h
+ifeq ($(TRACE_INSTRUMENT_BACKEND),instr-dynamic)
+INSTRUMENT_HEADERS += instrument/qemu-instr/events.h
+endif
INSTRUMENT_SOURCES = instrument-root.c $(trace-events-subdirs:%=%/instrument.c)
INSTRUMENT_SOURCES += instrument/generated-tcg-tracers.c
@@ -644,8 +647,13 @@ ifneq (,$(findstring qemu-ga,$(TOOLS)))
endif
endif
+install-includedir:
+ $(INSTALL_DIR) "$(DESTDIR)$(includedir)"
install: all $(if $(BUILD_DOCS),install-doc) install-datadir install-localstatedir
+ifeq ($(TRACE_INSTRUMENT_BACKEND),instr-dynamic)
+install: install-includedir
+endif
ifneq ($(TOOLS),)
$(call install-prog,$(subst qemu-ga,qemu-ga$(EXESUF),$(TOOLS)),$(DESTDIR)$(bindir))
endif
@@ -676,6 +684,12 @@ endif
for d in $(TARGET_DIRS); do \
$(MAKE) $(SUBDIR_MAKEFLAGS) TARGET_DIR=$$d/ -C $$d $@ || exit 1 ; \
done
+ifeq ($(TRACE_INSTRUMENT_BACKEND),instr-dynamic)
+ $(INSTALL_DIR) "$(DESTDIR)$(includedir)/qemu-instr"
+ $(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/types.h "$(DESTDIR)$(includedir)/qemu-instr/"
+ $(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/visibility-internal.h "$(DESTDIR)$(includedir)/qemu-instr/"
+ $(INSTALL_DATA) $(BUILD_DIR)/instrument/qemu-instr/events.h "$(DESTDIR)$(includedir)/qemu-instr/"
+endif
# various test targets
test speed: all
@@ -489,6 +489,8 @@ QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
QEMU_INCLUDES="-I. -I\$(SRC_PATH) -I\$(SRC_PATH)/accel/tcg -I\$(SRC_PATH)/include"
+QEMU_INCLUDES="$QEMU_INCLUDES -I\$(SRC_PATH)/instrument"
+QEMU_INCLUDES="$QEMU_INCLUDES -I\$(BUILD_DIR)/instrument"
if test "$debug_info" = "yes"; then
CFLAGS="-g $CFLAGS"
LDFLAGS="-g $LDFLAGS"
@@ -24,3 +24,17 @@ $(obj)/generated-tcg-tracers.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/
$< > $@,"GEN","$(patsubst %-timestamp,%,$@)")
target-obj-$(CONFIG_INSTRUMENT) += generated-tcg-tracers.o
+
+######################################################################
+# User interface
+
+$(obj)/qemu-instr/events.h: $(obj)/qemu-instr/events.h-timestamp
+ @cmp -s $< $@ || cp $< $@
+$(obj)/qemu-instr/events.h-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR)/config-host.mak $(tracetool-y)
+ @mkdir -p $(dir $@)
+ $(call quiet-command,$(TRACETOOL) \
+ --group=root \
+ --format=instr-api-h \
+ --backend=$(TRACE_INSTRUMENT_BACKEND) \
+ $(TRACETOOL_INSTR_STATIC) \
+ $< > $@,"GEN","$(patsubst %-timestamp,%,$@)")
new file mode 100644
@@ -0,0 +1,73 @@
+/*
+ * QI-specific types for instrumentation clients.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova <vilanova@ac.upc.edu>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QI__TYPES_H
+#define QI__TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * SECTION: types
+ * @section_id: qi-types
+ * @title: Common types
+ *
+ * Data of architecture-specific length is always passed as an #int64_t to
+ * provide binary compatibility between the instrumentation library and QEMU,
+ * regardless of the guest architecture being instrumented.
+ */
+
+/**
+ * QICPU:
+ *
+ * Opaque guest CPU pointer.
+ */
+typedef struct QICPU QICPU;
+
+/**
+ * QITCGv_cpu:
+ *
+ * TCG register with QICPU.
+ */
+typedef struct QITCGv_cpu_d *QITCGv_cpu;
+
+/**
+ * QITCGv:
+ *
+ * TCG register with data of architecture-specific length.
+ */
+typedef struct QITCGv_d *QITCGv;
+
+/**
+ * QITCGv_i32:
+ *
+ * TCG register with 32-bit data.
+ */
+typedef struct QITCGv_i32_d *QITCGv_i32;
+
+/**
+ * QITCGv_i64:
+ *
+ * TCG register with 64-bit data.
+ */
+typedef struct QITCGv_i64_d *QITCGv_i64;
+
+/**
+ * QITCGv_ptr:
+ *
+ * TCG register with pointer of architecture-specific length.
+ */
+typedef struct QITCGv_ptr_d *QITCGv_ptr;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QI__TYPES_H */
new file mode 100644
@@ -0,0 +1,58 @@
+/*
+ * Macros for symbol visibility.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova <vilanova@ac.upc.edu>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory of QEMU.
+ */
+
+#ifndef QI__VISIBILITY_INTERNAL_H
+#define QI__VISIBILITY_INTERNAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * SECTION:visibility
+ * @section_id: qi-visibility
+ * @title: Symbol visibility
+ *
+ * This code is taken from http://gcc.gnu.org/wiki/Visibility.
+ */
+
+/**
+ * QI_VPUBLIC:
+ *
+ * Make an element public to user's instrumentation code.
+ */
+
+/**
+ * QI_VLOCAL:
+ *
+ * Make an element not visible to user's instrumentation code.
+ */
+
+#if defined _WIN32 || defined __CYGWIN__
+ #ifdef __GNUC__
+ #define QI_VPUBLIC __attribute__ ((dllimport))
+ #else
+ #define QI_VPUBLIC __declspec(dllimport)
+ #endif
+ #define QI_VLOCAL
+#else
+ #if __GNUC__ >= 4
+ #define QI_VPUBLIC __attribute__ ((visibility ("default")))
+ #define QI_VLOCAL __attribute__ ((visibility ("hidden")))
+ #else
+ #define QI_VPUBLIC
+ #define QI_VLOCAL
+ #endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QI__VISIBILITY_INTERNAL_H */
@@ -277,6 +277,10 @@ class Event(object):
QI_TRACE_INSTRUMENT = "qi_event_%(name)s"
QI_TRACE_INSTRUMENT_TCG = QI_TRACE_INSTRUMENT + "_tcg"
+ QI_TRACE_NOP = QI_TRACE_INSTRUMENT + "_nop"
+ QI_TRACE_TRACE = QI_TRACE_INSTRUMENT + "_trace"
+ QI_TRACE_GEN = QI_TRACE_INSTRUMENT + "_gen_exec"
+ QI_TRACE_TRACEGEN = QI_TRACE_INSTRUMENT + "_trace_and_gen_exec"
def api(self, fmt=None):
if fmt is None:
@@ -65,3 +65,87 @@ def generate_instr_tcg_h(event, group):
args=event.args,
argnames=", ".join(event.args.names()),
argtypes=argtypes)
+
+
+##################################################
+# instr-tcg-c
+
+def generate_instr_tcg_c_begin(events, group):
+ out('#include "qemu-instr/events.h"',
+ '')
+
+def generate_instr_tcg_c(event, group):
+ if "tcg" in event.properties:
+ event = event.event_trans
+
+ iargs = tracetool.vcpu.transform_args("tcg_h", event.original)
+ api_args = iargs.transform(TCG_2_QI_TCG)
+
+ qtargs = ["(%s)%s" % (arg[0], arg[1])
+ for arg in event.args]
+ gargs = tracetool.vcpu.transform_args(
+ "tcg_helper_c", event.original, "wrapper")
+ qgargs = ["(%s)%s" % (arg[0], arg[1])
+ for arg in gargs]
+ qargs = ["(%s)%s" % (arg[0], arg[1])
+ for arg in iargs]
+
+ out('QI_VPUBLIC void %(nop)s(%(api_args)s)',
+ '{',
+ '}',
+ 'QI_VPUBLIC void %(trace)s(%(api_args)s)',
+ '{',
+ ' %(b_trace)s(%(qtargs)s);',
+ '}',
+ 'QI_VPUBLIC void %(gen)s(%(api_args)s)',
+ '{',
+ ' %(b_gen)s(%(qgargs)s);',
+ '}',
+ 'QI_VPUBLIC void %(trace_gen)s(%(api_args)s)',
+ '{',
+ ' %(b_trace_gen)s(%(qargs)s);',
+ '}',
+ 'void *%(qi_cb)s_cb = %(trace_gen)s;',
+ '',
+ api_args=api_args,
+ nop=event.api(event.QI_TRACE_NOP),
+ trace=event.api(event.QI_TRACE_TRACE),
+ b_trace=event.api(event.QEMU_TRACE_BACKEND),
+ gen=event.api(event.QI_TRACE_GEN),
+ b_gen="gen_helper_" + event.original.event_exec.api(event.QEMU_TRACE_BACKEND),
+ trace_gen=event.api(event.QI_TRACE_TRACEGEN),
+ b_trace_gen=event.original.api(event.QEMU_TRACE_TCG_BACKEND),
+ iargs=iargs,
+ qargs=", ".join(qargs),
+ qtargs=", ".join(qtargs),
+ qgargs=", ".join(qgargs),
+ qi_cb=event.original.api(event.QI_TRACE_INSTRUMENT_TCG))
+
+
+##################################################
+# instr-c
+
+def generate_instr_c_begin(events, group):
+ out('#include "qemu-instr/events.h"',
+ '')
+
+def generate_instr_c(event, group):
+ args = event.args.transform(TCG_2_QI_TCG)
+ qargs = ["(%s)%s" % (arg[0], arg[1])
+ for arg in event.args]
+ out('QI_VPUBLIC void %(nop)s(%(args)s)',
+ '{',
+ '}',
+ 'QI_VPUBLIC void %(trace)s(%(args)s)',
+ '{',
+ ' %(backend)s(%(qargs)s);',
+ '}',
+ 'void *%(qi_cb)s_cb = %(qi_trace)s;',
+ '',
+ args=args,
+ nop=event.api(event.QI_TRACE_NOP),
+ trace=event.api(event.QI_TRACE_TRACE),
+ backend=event.api(event.QEMU_TRACE_BACKEND),
+ qargs=", ".join(qargs),
+ qi_cb=event.api(event.QI_TRACE_INSTRUMENT),
+ qi_trace=event.api(event.QI_TRACE_TRACE))
@@ -32,3 +32,21 @@ def generate_instr_h(event, group):
out(' %(backend)s(%(argnames)s);',
backend=event.api(event.QEMU_TRACE_BACKEND),
argnames=", ".join(event.args.names()))
+
+
+##################################################
+# instr-tcg-c
+
+def generate_instr_tcg_c(event, group):
+ out('void *%(qi_cb)s_cb = %(qi_trace)s;',
+ qi_cb=event.api(event.QI_TRACE_INSTRUMENT_TCG),
+ qi_trace=event.api(event.QEMU_TRACE_TCG_BACKEND))
+
+
+##################################################
+# instr-c
+
+def generate_instr_c(event, group):
+ out('void *%(qi_cb)s_cb = %(qi_trace)s;',
+ qi_cb=event.api(event.QI_TRACE_INSTRUMENT),
+ qi_trace=event.api(event.QEMU_TRACE_BACKEND))
new file mode 100644
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+instrument/qemu-instr/events.h
+
+"""
+
+__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012-2017, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+from tracetool.transform import *
+import tracetool.vcpu
+
+
+def generate(events, backend, group):
+ # We won't be using any backend, because this code is only compiled in when
+ # dynamic instrumentation mode is enabled
+
+ out('/* This file is autogenerated by tracetool, do not edit. */',
+ '',
+ '#ifndef QI__EVENTS_H',
+ '#define QI__EVENTS_H',
+ '',
+ '#ifdef __cplusplus',
+ 'extern "C" {',
+ '#endif',
+ '',
+ '#include <stdbool.h>',
+ '#include <stdint.h>',
+ '#include <qemu-instr/types.h>',
+ '#include <qemu-instr/visibility-internal.h>',
+ '',
+ '')
+
+ for e in events:
+ if "tcg-trans" in e.properties:
+ args = tracetool.vcpu.transform_args("tcg_h", e.original)
+ args = args.transform(TCG_2_QI_TCG)
+ else:
+ args = e.args.transform(TCG_2_QI_TCG)
+ out('QI_VPUBLIC void %(nop)s(%(args)s);',
+ 'QI_VPUBLIC void %(trace)s(%(args)s);',
+ args=args,
+ nop=e.api(e.QI_TRACE_NOP),
+ trace=e.api(e.QI_TRACE_TRACE))
+ if "tcg-trans" in e.properties:
+ out('QI_VPUBLIC void %(gen)s(%(args)s);',
+ 'QI_VPUBLIC void %(trace_gen)s(%(args)s);',
+ args=args,
+ gen=e.api(e.QI_TRACE_GEN),
+ trace_gen=e.api(e.QI_TRACE_TRACEGEN))
+ out('')
+
+ out('#ifdef __cplusplus',
+ '}',
+ '#endif',
+ '',
+ '#endif /* QI__EVENTS_H */')
@@ -21,8 +21,7 @@ from tracetool.transform import *
def generate(events, backend, group):
events = [e for e in events
- if "tcg-trans" not in e.properties and
- "instrument" in e.properties]
+ if "tcg-trans" not in e.properties]
if group == "root":
header = "trace-root.h"
@@ -37,8 +36,6 @@ def generate(events, backend, group):
backend.generate_begin(events, group)
for e in events:
- out('void *%(qi_cb)s_cb = %(qi_trace)s;',
- qi_cb=e.api(e.QI_TRACE_INSTRUMENT),
- qi_trace=e.api(e.QEMU_TRACE_BACKEND))
+ backend.generate(e, group)
backend.generate_end(events, group)
@@ -20,8 +20,7 @@ from tracetool.transform import *
def generate(events, backend, group):
events = [e.original for e in events
- if "tcg-trans" in e.properties and
- "instrument" in e.properties]
+ if "tcg-trans" in e.properties]
out('/* This file is autogenerated by tracetool, do not edit. */',
'',
@@ -33,8 +32,6 @@ def generate(events, backend, group):
backend.generate_begin(events, group)
for e in events:
- out('void *%(qi_cb)s_cb = %(qi_trace)s;',
- qi_cb=e.api(e.QI_TRACE_INSTRUMENT_TCG),
- qi_trace=e.api(e.QEMU_TRACE_TCG_BACKEND))
+ backend.generate(e, group)
backend.generate_end(events, group)
@@ -75,7 +75,7 @@ def generate(events, backend, group):
' %(name)s(%(args_call)s);',
'}',
name_tcg="helper_%s_proxy" % e.api(e.QEMU_TRACE_BACKEND),
- name=e.api(e.QEMU_TRACE_NOCHECK),
+ name=e.api(e.QEMU_TRACE),
args_api=e_args_api,
args_call=", ".join(e_args_call.casted()),
)
@@ -137,6 +137,19 @@ TCG_2_TCG_HELPER_DECL = {
##################################################
+# host/tcg -> instrumentation-client tcg type
+
+def TCG_2_QI_TCG(type_):
+ if type_ == "TCGv_env":
+ return "QITCGv_cpu"
+ elif type_.startswith("TCGv"):
+ return "QI" + type_
+ elif type_.startswith("CPUState"):
+ return type_.replace("CPUState", "QICPU", 1)
+ else:
+ return type_
+
+##################################################
# host/tcg -> tcg temporal constant allocation
def _host_2_tcg_tmp_new(type_):
For each event, adds a set of public routines available to instrumentation clients: * qi_event_*_nop: Do nothing (to disable an instrumentation event). * qi_event_*_trace Trace event using QEMU's tracing system. Default for execution-time events. * qi_event_*_gen_exec Generate TCG code to raise the event at execution time. Only available for translation-time events. * qi_event_*_trace_and_gen_exec Combination of qi_event_*_trace and qi_event_*_gen_exec. Only available for translation-time events. Default for translation-time events. The functions are defined for all events, regardless of whether they are instrumented or disabled (used later). Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu> --- .gitignore | 1 Makefile | 14 +++++ configure | 2 + instrument/Makefile.objs | 14 +++++ instrument/qemu-instr/types.h | 73 +++++++++++++++++++++++ instrument/qemu-instr/visibility-internal.h | 58 +++++++++++++++++++ scripts/tracetool/__init__.py | 4 + scripts/tracetool/backend/instr_dynamic.py | 84 +++++++++++++++++++++++++++ scripts/tracetool/backend/instr_none.py | 18 ++++++ scripts/tracetool/format/instr_api_h.py | 65 +++++++++++++++++++++ scripts/tracetool/format/instr_c.py | 7 +- scripts/tracetool/format/instr_tcg_c.py | 7 +- scripts/tracetool/format/tcg_helper_c.py | 2 - scripts/tracetool/transform.py | 13 ++++ 14 files changed, 351 insertions(+), 11 deletions(-) create mode 100644 instrument/qemu-instr/types.h create mode 100644 instrument/qemu-instr/visibility-internal.h create mode 100644 scripts/tracetool/format/instr_api_h.py