@@ -688,6 +688,7 @@ 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) $(SRC_PATH)/instrument/qemu-instr/control.h "$(DESTDIR)$(includedir)/qemu-instr/"
$(INSTALL_DATA) $(BUILD_DIR)/instrument/qemu-instr/events.h "$(DESTDIR)$(includedir)/qemu-instr/"
endif
@@ -6019,10 +6019,14 @@ QEMU_INCLUDES="-I\$(SRC_PATH)/tcg $QEMU_INCLUDES"
echo "TRACE_INSTRUMENT_BACKEND=instr-$trace_instrument_backend" >> $config_host_mak
if test "$trace_instrument" = "yes"; then
echo "CONFIG_INSTRUMENT=y" >> $config_host_mak
+ libs_qga="-ldl $libs_qga"
+ LDFLAGS="-rdynamic $LDFLAGS"
fi
if test -n "$instrument_events"; then
echo "CONFIG_INSTRUMENT_EVENTS=$instrument_events" >> $config_host_mak
fi
+# code requiring it is always compiled-in
+LIBS="-ldl $LIBS"
##########################################
echo "TOOLS=$tools" >> $config_host_mak
@@ -38,3 +38,8 @@ $(obj)/qemu-instr/events.h-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR)
--backend=$(TRACE_INSTRUMENT_BACKEND) \
$(TRACETOOL_INSTR_STATIC) \
$< > $@,"GEN","$(patsubst %-timestamp,%,$@)")
+
+######################################################################
+# Control code
+
+target-obj-y += control.o
new file mode 100644
@@ -0,0 +1,316 @@
+/*
+ * Interface for controlling dynamic trace instrumentation.
+ *
+ * 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.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+
+#include <dlfcn.h>
+#include "instrument/control.h"
+#include "qemu/thread.h"
+#include "qemu-instr/control.h"
+#include "qemu/error-report.h"
+
+
+typedef int64_t HandleID;
+
+typedef struct Handle
+{
+ HandleID id;
+ void *dlhandle;
+ void (*init)(int, const char **);
+ void (*fini)(void);
+ QSLIST_ENTRY(Handle) list;
+} Handle;
+
+HandleID handle_last_id;
+QSLIST_HEAD(, Handle) handles = QSLIST_HEAD_INITIALIZER(handles);
+static QemuMutex instr_lock;
+
+
+static Handle *handle_get(void)
+{
+ Handle *res = g_malloc0(sizeof(Handle));
+ res->id = handle_last_id++;
+ QSLIST_INSERT_HEAD(&handles, res, list);
+ return res;
+}
+
+static bool handle_put(HandleID id)
+{
+ Handle *prev = NULL;
+ Handle *handle;
+ QSLIST_FOREACH(handle, &handles, list) {
+ if (handle->id == id) {
+ break;
+ }
+ prev = handle;
+ }
+ if (handle == NULL) {
+ return false;
+ } else {
+ if (prev == NULL) {
+ QSLIST_REMOVE_HEAD(&handles, list);
+ } else {
+ QSLIST_REMOVE_AFTER(prev, list);
+ }
+ g_free(handle);
+ return true;
+ }
+}
+
+#if defined(CONFIG_INSTRUMENT)
+static Handle *handle_find(HandleID id)
+{
+ Handle *handle;
+ QSLIST_FOREACH(handle, &handles, list) {
+ if (handle->id == id) {
+ return handle;
+ }
+ }
+ return NULL;
+}
+#endif
+
+static bool instr_available(void)
+{
+#if defined(CONFIG_INSTRUMENT)
+ return true;
+#else
+ return false;
+#endif
+}
+
+InstrLoadError instr_load(const char * path, int argc, const char ** argv,
+ int64_t *handle_id)
+{
+ InstrLoadError res;
+
+ qemu_rec_mutex_lock(&instr_lock);
+
+ *handle_id = -1;
+ if (!instr_available()) {
+ res = INSTR_LOAD_UNAVAILABLE;
+ goto out;
+ }
+
+ if (!QSLIST_EMPTY(&handles) > 0) {
+ /* XXX: This is in fact a hard-coded limit, but there's no reason why a
+ * real multi-library implementation should fail with something like
+ * "too many open libraries".
+ */
+ res = INSTR_LOAD_UNAVAILABLE;
+ goto out;
+ }
+
+ Handle * handle = handle_get();
+ handle->dlhandle = dlopen(path, RTLD_NOW);
+ if (handle->dlhandle == NULL) {
+ goto err;
+ }
+
+ handle->init = dlsym(handle->dlhandle, "qi_init");
+ if (handle->init == NULL) {
+ goto err;
+ }
+ handle->fini = dlsym(handle->dlhandle, "qi_fini");
+ if (handle->fini == NULL) {
+ goto err;
+ }
+
+ handle->init(argc, argv);
+
+ *handle_id = handle->id;
+ res = INSTR_LOAD_OK;
+ goto out;
+
+err:
+ handle_put(handle->id);
+ res = INSTR_LOAD_ERROR;
+out:
+ qemu_rec_mutex_unlock(&instr_lock);
+ return res;
+}
+
+static inline bool instr_event_is_instrument(TraceEvent *ev)
+{
+#if defined(CONFIG_INSTRUMENT)
+ return ev->is_instr;
+#else
+ return false;
+#endif
+}
+
+InstrUnloadError instr_unload(int64_t handle_id)
+{
+ InstrLoadError res;
+
+ qemu_rec_mutex_lock(&instr_lock);
+
+ if (!instr_available()) {
+ res = INSTR_UNLOAD_UNAVAILABLE;
+ goto out;
+ }
+
+#if defined(CONFIG_INSTRUMENT)
+ Handle *handle = handle_find(handle_id);
+ if (handle == NULL) {
+ res = INSTR_UNLOAD_INVALID;
+ goto out;
+ }
+
+ handle->fini();
+
+ TraceEventIter iter;
+ TraceEvent *ev = NULL;
+ trace_event_iter_init(&iter, NULL);
+ while ((ev = trace_event_iter_next(&iter)) != NULL) {
+ if (instr_event_is_instrument(ev)) {
+ *ev->instr_cb = ev->instr_cb_default;
+ }
+ }
+
+ /* this should never fail */
+ if (dlclose(handle->dlhandle) < 0) {
+ res = INSTR_UNLOAD_ERROR;
+ } else {
+ res = INSTR_UNLOAD_OK;
+ }
+ handle_put(handle->id);
+#endif
+
+out:
+ qemu_rec_mutex_unlock(&instr_lock);
+ return res;
+}
+
+InstrUnloadError instr_unload_all(void)
+{
+ InstrUnloadError res = INSTR_UNLOAD_OK;
+
+ qemu_rec_mutex_lock(&instr_lock);
+ while (true) {
+ Handle *handle = QSLIST_FIRST(&handles);
+ if (handle == NULL) {
+ break;
+ } else {
+ res = instr_unload(handle->id);
+ if (res != INSTR_UNLOAD_OK) {
+ break;
+ }
+ }
+ }
+ qemu_rec_mutex_unlock(&instr_lock);
+
+ return res;
+}
+
+void qi_ctrl_event_set(QIEvent *ev, void *cb)
+{
+ TraceEvent *tev = (TraceEvent *)ev;
+
+ if (unlikely(tev == NULL)) {
+ error_report("qi_ctrl_event_set: event is NULL");
+ return;
+ }
+
+#if defined(CONFIG_INSTRUMENT)
+ if (unlikely(!tev->is_instr)) {
+ error_report("qi_ctrl_event_set: event is not instrumentable");
+ return;
+ }
+
+ if (cb == NULL) {
+ *tev->instr_cb = tev->instr_cb_default;
+ } else {
+ *tev->instr_cb = cb;
+ }
+#else
+ assert(false);
+#endif /* defined(CONFIG_INSTRUMENT) */
+}
+
+bool qi_trace_event_get_state_static(QIEvent *ev)
+{
+ if (unlikely(ev == NULL)) {
+ error_report("qi_trace_event_get_state_static: event is NULL");
+ return false;
+ }
+ return trace_event_get_state_static((TraceEvent *)ev);
+}
+
+bool qi_trace_event_get_state_dynamic(QIEvent *ev)
+{
+ if (unlikely(ev == NULL)) {
+ error_report("qi_trace_event_get_state_dynamic: event is NULL");
+ return false;
+ }
+ return trace_event_get_state_dynamic((TraceEvent *)ev);
+}
+
+bool qi_trace_event_get_vcpu_state_dynamic(QICPU *vcpu, QIEvent *ev)
+{
+ TraceEvent *tev = (TraceEvent *)ev;
+
+ if (unlikely(vcpu == NULL)) {
+ error_report("qi_trace_event_get_vcpu_state_dynamic: vcpu is NULL");
+ return false;
+ }
+ if (unlikely(tev == NULL)) {
+ error_report("qi_trace_event_get_vcpu_state_dynamic: event is NULL");
+ return false;
+ }
+ if (unlikely(!trace_event_is_vcpu(tev))) {
+ error_report("qi_trace_event_get_vcpu_state_dynamic: event does not have 'vcpu' property");
+ return false;
+ }
+ return trace_event_get_vcpu_state_dynamic((CPUState *)vcpu, tev);
+}
+
+void qi_trace_event_set_state_dynamic(QIEvent *ev, bool state)
+{
+ TraceEvent *tev = (TraceEvent *)ev;
+
+ if (unlikely(tev == NULL)) {
+ error_report("qi_trace_event_set_state_dynamic: event is NULL");
+ return;
+ }
+ if (unlikely(!trace_event_get_state_static(tev))) {
+ error_report("qi_trace_event_set_state_dynamic: event is statically disabled");
+ return;
+ }
+ trace_event_set_state_dynamic(tev, state);
+}
+
+void qi_trace_event_set_vcpu_state_dynamic(QICPU *vcpu, QIEvent *ev, bool state)
+{
+ TraceEvent *tev = (TraceEvent *)ev;
+
+ if (unlikely(vcpu == NULL)) {
+ error_report("qi_trace_event_set_vcpu_state_dynamic: vcpu is NULL");
+ return;
+ }
+ if (unlikely(tev == NULL)) {
+ error_report("qi_trace_event_set_vcpu_state_dynamic: event is NULL");
+ return;
+ }
+ if (unlikely(!trace_event_is_vcpu(tev))) {
+ error_report("qi_trace_event_set_vcpu_state_dynamic: event does not have 'vcpu' property");
+ return;
+ }
+ if (unlikely(!trace_event_get_state_static(tev))) {
+ error_report("qi_trace_event_set_vcpu_state_dynamic: event is statically disabled");
+ return;
+ }
+ trace_event_set_vcpu_state_dynamic((CPUState *)vcpu, tev, state);
+}
+
+static void __attribute__((constructor)) instr_lock_init(void)
+{
+ qemu_rec_mutex_init(&instr_lock);
+}
new file mode 100644
@@ -0,0 +1,86 @@
+/*
+ * Interface for controlling dynamic trace instrumentation.
+ *
+ * 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 INSTRUMENT__CONTROL_H
+#define INSTRUMENT__CONTROL_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "qapi-types.h"
+#include "trace/control.h"
+
+
+/**
+ * InstrLoadError:
+ * @INSTR_LOAD_OK: Correctly loaded.
+ * @INSTR_LOAD_UNAVAILABLE: Service not available.
+ * @INSTR_LOAD_ERROR: Error with libdl (see dlerror).
+ *
+ * Error codes for instr_load().
+ *
+ * Warning: Keep in sync with #InstrLoadCode
+ */
+typedef enum {
+ INSTR_LOAD_OK,
+ INSTR_LOAD_UNAVAILABLE,
+ INSTR_LOAD_ERROR,
+} InstrLoadError;
+
+/**
+ * InstrUnloadError:
+ * @INSTR_UNLOAD_OK: Correctly unloaded.
+ * @INSTR_UNLOAD_UNAVAILABLE: Service not available.
+ * @INSTR_UNLOAD_INVALID: Invalid handle.
+ * @INSTR_UNLOAD_ERROR: Error with libdl (see dlerror).
+ *
+ * Error codes for instr_unload().
+ *
+ * Warning: Keep in sync with #InstrUnloadCode
+ */
+typedef enum {
+ INSTR_UNLOAD_OK,
+ INSTR_UNLOAD_UNAVAILABLE,
+ INSTR_UNLOAD_INVALID,
+ INSTR_UNLOAD_ERROR,
+} InstrUnloadError;
+
+/**
+ * instr_load:
+ * @path: Path to the shared library to load.
+ * @argc: Number of arguments passed to the initialization function of the library.
+ * @argv: Arguments passed to the initialization function of the library.
+ * @handle: Instrumentation library handle (undefined in case of error).
+ *
+ * Load a dynamic trace instrumentation library.
+ *
+ * Returns: Whether the library could be loaded.
+ */
+InstrLoadError instr_load(const char * path, int argc, const char ** argv,
+ int64_t *handle);
+
+/**
+ * instr_unload:
+ * @handle: Instrumentation library handle returned by instr_load().
+ *
+ * Unload the given instrumentation library.
+ *
+ * Returns: Whether the library could be unloaded.
+ */
+InstrUnloadError instr_unload(int64_t handle);
+
+/**
+ * instr_unload_all:
+ *
+ * Unload all instrumentation libraries.
+ *
+ * Returns: Whether any library could not be unloaded.
+ */
+InstrUnloadError instr_unload_all(void);
+
+#endif /* INSTRUMENT__CONTROL_H */
new file mode 100644
@@ -0,0 +1,128 @@
+/*
+ * Interface for controlling the state of events.
+ *
+ * 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__CONTROL_H
+#define QI__CONTROL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include <qemu-instr/types.h>
+#include <qemu-instr/visibility-internal.h>
+
+
+/**
+ * SECTION:control
+ * @section_id: qi-control
+ * @title: Event control API for QEMU event instrumentation
+ */
+
+/**
+ * qi_ctrl_event_set:
+ * @ev: Event descriptor.
+ * @cb: Pointer to instrumentation callback.
+ *
+ * Set the instrumentation callback for the given event.
+ *
+ * @cb can also be set to #NULL to restore the default callback.
+ */
+QI_VPUBLIC void qi_ctrl_event_set(QIEvent *ev, void *cb);
+
+/**
+ * qi_trace_event_get_state:
+ * @ev: Event identifier name.
+ *
+ * Get the tracing state of an event (both static and dynamic).
+ *
+ * If the event has the disabled property, the check will have no performance
+ * impact.
+ */
+#define qi_trace_event_get_state(ev) \
+ ((ev ##_ENABLED) && qi_trace_event_get_state_dynamic(ev))
+
+/**
+ * qi_trace_event_get_vcpu_state:
+ * @vcpu: Target vCPU.
+ * @ev: Event identifier name.
+ *
+ * Get the tracing state of an event (both static and dynamic) for the given
+ * vCPU.
+ *
+ * If the event has the disabled property, the check will have no performance
+ * impact.
+ */
+#define qi_trace_event_get_vcpu_state(vcpu, ev) \
+ ((ev ##_ENABLED) && \
+ qi_trace_event_get_vcpu_state_dynamic(vcpu, ev))
+
+/**
+ * qi_trace_event_get_state_static:
+ * @ev: Event identifier.
+ *
+ * Get the static tracing state of an event.
+ *
+ * Use the define 'QI_EVENT_${EVENT}_ENABLED' for compile-time checks (it will
+ * be set to 1 or 0 according to the presence of the disabled property).
+ */
+QI_VPUBLIC bool qi_trace_event_get_state_static(QIEvent *ev);
+
+/**
+ * qi_trace_event_get_state_dynamic:
+ * @ev: Event identifier.
+ *
+ * Get the dynamic tracing state of an event.
+ */
+QI_VPUBLIC bool qi_trace_event_get_state_dynamic(QIEvent *ev);
+
+/**
+ * qi_trace_event_get_vcpu_state_dynamic:
+ * @vcpu: Target vCPU.
+ * @ev: Event identifier.
+ *
+ * Get the dynamic tracing state of an event for the given vCPU.
+ */
+QI_VPUBLIC bool qi_trace_event_get_vcpu_state_dynamic(QICPU *vcpu,
+ QIEvent *ev);
+
+/**
+ * qi_trace_event_set_state_dynamic:
+ * @ev: Event identifier.
+ * @state: Target tracing state.
+ *
+ * Set the dynamic tracing state of an event.
+ *
+ * Pre-condition: qi_trace_event_get_state_static(ev) == true
+ */
+QI_VPUBLIC void qi_trace_event_set_state_dynamic(QIEvent *ev, bool state);
+
+/**
+ * qi_trace_event_set_vcpu_state_dynamic:
+ * @vcpu: Target vCPU.
+ * @ev: Event identifier.
+ * @state: Target tracing state.
+ *
+ * Set the dynamic tracing state of an event for the given vCPU.
+ *
+ * Pre-condition: qi_trace_event_get_state_static(ev) == true
+ *
+ * Note: Changes for execution-time events with the 'tcg' property will not be
+ * propagated until the next TB is executed (iff executing in TCG mode).
+ */
+QI_VPUBLIC void qi_trace_event_set_vcpu_state_dynamic(QICPU *vcpu,
+ QIEvent *ev, bool state);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QI__CONTROL_H */
@@ -25,6 +25,14 @@ extern "C" {
*/
/**
+ * QIEvent:
+ *
+ * Opaque structure defining an instrumentation event.
+ */
+struct QIEvent;
+typedef struct QIEvent QIEvent;
+
+/**
* QICPU:
*
* Opaque guest CPU pointer.
@@ -90,7 +90,8 @@ def generate_instr_tcg_c(event, group):
qargs = ["(%s)%s" % (arg[0], arg[1])
for arg in iargs]
- out('QI_VPUBLIC void %(nop)s(%(api_args)s)',
+ out('QIEvent *%(qevent)s = (QIEvent *)&%(tevent)s;',
+ 'QI_VPUBLIC void %(nop)s(%(api_args)s)',
'{',
'}',
'QI_VPUBLIC void %(trace)s(%(api_args)s)',
@@ -99,7 +100,10 @@ def generate_instr_tcg_c(event, group):
'}',
'QI_VPUBLIC void %(gen)s(%(api_args)s)',
'{',
+ # does not exist when event is disabled
+ '#if %(teventu)s_ENABLED',
' %(b_gen)s(%(qgargs)s);',
+ '#endif',
'}',
'QI_VPUBLIC void %(trace_gen)s(%(api_args)s)',
'{',
@@ -107,6 +111,9 @@ def generate_instr_tcg_c(event, group):
'}',
'void *%(qi_cb)s_cb = %(trace_gen)s;',
'',
+ qevent=event.api(event.QI_TRACE_INSTRUMENT).upper(),
+ tevent=event.api(event.QEMU_EVENT),
+ teventu=event.api(event.QEMU_TRACE).upper(),
api_args=api_args,
nop=event.api(event.QI_TRACE_NOP),
trace=event.api(event.QI_TRACE_TRACE),
@@ -133,7 +140,8 @@ 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)',
+ out('QIEvent *%(qevent)s = (QIEvent *)&%(tevent)s;',
+ 'QI_VPUBLIC void %(nop)s(%(args)s)',
'{',
'}',
'QI_VPUBLIC void %(trace)s(%(args)s)',
@@ -142,6 +150,8 @@ def generate_instr_c(event, group):
'}',
'void *%(qi_cb)s_cb = %(qi_trace)s;',
'',
+ qevent=event.api(event.QI_TRACE_INSTRUMENT).upper(),
+ tevent=event.api(event.QEMU_EVENT),
args=args,
nop=event.api(event.QI_TRACE_NOP),
trace=event.api(event.QI_TRACE_TRACE),
@@ -6,7 +6,7 @@ trace/generated-tracers.c
"""
__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
-__copyright__ = "Copyright 2012-2014, 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"
@@ -39,18 +39,49 @@ def generate(events, backend, group):
vcpu_id = 0
else:
vcpu_id = "TRACE_VCPU_EVENT_NONE"
+
+ if "instrument" in e.properties:
+ is_instr = "true"
+ out('#if defined(CONFIG_INSTRUMENT)')
+ if "tcg-trans" in e.properties:
+ instr_cb = e.original.api(e.QI_TRACE_INSTRUMENT_TCG) + "_cb"
+ instr_cb_default = e.api(e.QI_TRACE_TRACEGEN)
+ out('static void *_tmp__%(name1)s;',
+ 'extern void *%(name1)s __attribute__((weak, alias("_tmp__%(name1)s")));',
+ name1=instr_cb)
+ else:
+ instr_cb = e.api(e.QI_TRACE_INSTRUMENT) + "_cb"
+ instr_cb_default = e.api(e.QI_TRACE_TRACE)
+ out('static void _tmp__%(name2)s(void) {};',
+ 'void %(name2)s(void) __attribute__((weak, alias("_tmp__%(name2)s")));',
+ '#endif',
+ name2=instr_cb_default)
+ instr_cb = "&" + instr_cb
+ else:
+ is_instr = "false"
+ instr_cb = "NULL"
+ instr_cb_default = "NULL"
+
out('TraceEvent %(event)s = {',
' .id = 0,',
' .vcpu_id = %(vcpu_id)s,',
' .name = \"%(name)s\",',
' .sstate = %(sstate)s,',
- ' .dstate = &%(dstate)s ',
+ ' .dstate = &%(dstate)s,',
+ '#if defined(CONFIG_INSTRUMENT)',
+ ' .is_instr = %(is_instr)s,',
+ ' .instr_cb = %(instr_cb)s,',
+ ' .instr_cb_default = %(instr_cb_default)s,',
+ '#endif',
'};',
event = e.api(e.QEMU_EVENT),
vcpu_id = vcpu_id,
name = e.name,
sstate = "TRACE_%s_ENABLED" % e.name.upper(),
- dstate = e.api(e.QEMU_DSTATE))
+ dstate = e.api(e.QEMU_DSTATE),
+ is_instr=is_instr,
+ instr_cb=instr_cb,
+ instr_cb_default=instr_cb_default)
out('TraceEvent *%(group)s_trace_events[] = {',
group = group.lower())
@@ -40,13 +40,24 @@ def generate(events, backend, group):
'')
for e in events:
+ if "disable" in e.properties:
+ enabled = 0
+ else:
+ enabled = 1
+
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);',
+
+ out('#define %(qeventu)s_ENABLED %(enabled)d',
+ 'extern QI_VPUBLIC QIEvent *%(event)s;',
+ 'QI_VPUBLIC void %(nop)s(%(args)s);',
'QI_VPUBLIC void %(trace)s(%(args)s);',
+ qeventu=e.api(e.QI_TRACE_INSTRUMENT).upper(),
+ enabled=enabled,
+ event=e.api(e.QI_TRACE_INSTRUMENT).upper(),
args=args,
nop=e.api(e.QI_TRACE_NOP),
trace=e.api(e.QI_TRACE_TRACE))
@@ -1,7 +1,7 @@
/*
* Interface for configuring and controlling the state of tracing events.
*
- * Copyright (C) 2012-2016 Lluís Vilanova <vilanova@ac.upc.edu>
+ * 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.
@@ -23,6 +23,9 @@
* @name: Event name.
* @sstate: Static tracing state.
* @dstate: Dynamic tracing state
+ * @is_instr: Whether the event is instrumentable.
+ * @instr_cb: Current instrumentation callback.
+ * @instr_cb_default: Default instrumentation callback.
*
* Interpretation of @dstate depends on whether the event has the 'vcpu'
* property:
@@ -37,6 +40,11 @@ typedef struct TraceEvent {
const char * name;
const bool sstate;
uint16_t *dstate;
+#if defined(CONFIG_INSTRUMENT)
+ bool is_instr;
+ void **instr_cb;
+ void *instr_cb_default;
+#endif
} TraceEvent;
void trace_event_set_state_dynamic_init(TraceEvent *ev, bool state);
Adds public and internal APIs to control event instrumentation. It also adds an event object (QI_EVENT_${NAME}) and define to know if it's staically enabled (QI_EVENT_${NAME}_ENABLED). Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu> --- Makefile | 1 configure | 4 instrument/Makefile.objs | 5 instrument/control.c | 316 ++++++++++++++++++++++++++++ instrument/control.h | 86 ++++++++ instrument/qemu-instr/control.h | 128 +++++++++++ instrument/qemu-instr/types.h | 8 + scripts/tracetool/backend/instr_dynamic.py | 14 + scripts/tracetool/format/c.py | 37 +++ scripts/tracetool/format/instr_api_h.py | 13 + trace/event-internal.h | 10 + 11 files changed, 615 insertions(+), 7 deletions(-) create mode 100644 instrument/control.c create mode 100644 instrument/control.h create mode 100644 instrument/qemu-instr/control.h