@@ -599,6 +599,10 @@ ifdef CONFIG_VIRTFS
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DATA) fsdev/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1"
endif
+ifdef CONFIG_INSTRUMENT
+ $(INSTALL_DIR) "$(DESTDIR)$(includedir)/qemu-instr/"
+ $(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/control.h "$(DESTDIR)$(includedir)/qemu-instr/"
+endif
install-datadir:
$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)"
@@ -6030,6 +6030,7 @@ if test "$instrument" = "yes"; then
LIBS="-ldl $LIBS"
echo "CONFIG_INSTRUMENT=y" >> $config_host_mak
fi
+QEMU_INCLUDES="-I\$(SRC_PATH)/instrument $QEMU_INCLUDES"
if test "$rdma" = "yes" ; then
echo "CONFIG_RDMA=y" >> $config_host_mak
@@ -111,4 +111,23 @@
#define GCC_FMT_ATTR(n, m)
#endif
+/*
+ * Export symbol to dlopen()'ed libraries'.
+ *
+ * This code is taken from http://gcc.gnu.org/wiki/Visibility.
+ */
+#if defined _WIN32 || defined __CYGWIN__
+ #ifdef __GNUC__
+ #define SYM_PUBLIC __attribute__ ((dllimport))
+ #else
+ #define SYM_PUBLIC __declspec(dllimport)
+ #endif
+#else
+ #if __GNUC__ >= 4
+ #define SYM_PUBLIC __attribute__ ((visibility("default")))
+ #else
+ #define SYM_PUBLIC
+ #endif
+#endif
+
#endif /* COMPILER_H */
@@ -3,3 +3,4 @@
target-obj-$(CONFIG_INSTRUMENT) += cmdline.o
target-obj-$(CONFIG_INSTRUMENT) += load.o
target-obj-$(CONFIG_INSTRUMENT) += qmp.o
+target-obj-$(CONFIG_INSTRUMENT) += control.o
new file mode 100644
@@ -0,0 +1,28 @@
+/*
+ * Control instrumentation during program (de)initialization.
+ *
+ * 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 "instrument/control.h"
+#include "instrument/error.h"
+#include "instrument/events.h"
+#include "instrument/load.h"
+#include "instrument/qemu-instr/control.h"
+#include "qemu/compiler.h"
+
+__thread InstrState instr_cur_state;
+
+
+qi_fini_fn instr_event__fini_fn;
+void *instr_event__fini_data;
+
+SYM_PUBLIC void qi_set_fini(qi_fini_fn fn, void *data)
+{
+ ERROR_IF(!instr_get_state(), "called outside instrumentation");
+ instr_set_event(fini_fn, fn);
+ instr_set_event(fini_data, data);
+}
new file mode 100644
@@ -0,0 +1,44 @@
+/*
+ * Control instrumentation during program (de)initialization.
+ *
+ * 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
+
+
+/**
+ * InstrState:
+ * @INSTR_STATE_DISABLE: Intrumentation API not available.
+ * @INSTR_STATE_ENABLE: Intrumentation API available.
+ *
+ * Instrumentation state of current host thread. Used to ensure instrumentation
+ * clients use QEMU's API only in expected points.
+ */
+typedef enum {
+ INSTR_STATE_DISABLE,
+ INSTR_STATE_ENABLE,
+} InstrState;
+
+/**
+ * instr_set_state:
+ *
+ * Set the instrumentation state of the current host thread.
+ */
+static inline void instr_set_state(InstrState state);
+
+/**
+ * instr_get_state:
+ *
+ * Get the instrumentation state of the current host thread.
+ */
+static inline InstrState instr_get_state(void);
+
+
+#include "instrument/control.inc.h"
+
+#endif /* INSTRUMENT__CONTROL_H */
new file mode 100644
@@ -0,0 +1,25 @@
+/*
+ * Control instrumentation during program (de)initialization.
+ *
+ * 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/atomic.h"
+#include "qemu/compiler.h"
+#include <stdbool.h>
+
+
+extern __thread InstrState instr_cur_state;
+
+static inline void instr_set_state(InstrState state)
+{
+ atomic_store_release(&instr_cur_state, state);
+}
+
+static inline InstrState instr_get_state(void)
+{
+ return atomic_load_acquire(&instr_cur_state);
+}
new file mode 100644
@@ -0,0 +1,28 @@
+/*
+ * Helpers for controlling errors in instrumentation libraries.
+ *
+ * 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_ERROR_H
+#define INSTRUMENT_ERROR_H
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+
+
+#define _ERROR(msg, args...) \
+ do { \
+ error_report("%s:" msg, __func__, ##args); \
+ } while (0)
+
+#define ERROR_IF(cond, msg, args...) \
+ if (unlikely(cond)) { \
+ _ERROR(msg, ##args); \
+ return; \
+ }
+
+#endif /* INSTRUMENT_ERROR_H */
new file mode 100644
@@ -0,0 +1,37 @@
+/*
+ * Internal API for triggering instrumentation events.
+ *
+ * Copyright (C) 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__EVENTS_H
+#define INSTRUMENT__EVENTS_H
+
+#include "instrument/qemu-instr/control.h"
+
+/**
+ * instr_get_event:
+ *
+ * Get value set by instrumentation library.
+ */
+#define instr_get_event(name) \
+ atomic_load_acquire(&instr_event__ ## name)
+
+/**
+ * instr_get_event:
+ *
+ * Set value from instrumentation library.
+ */
+#define instr_set_event(name, fn) \
+ atomic_store_release(&instr_event__ ## name, fn)
+
+
+extern qi_fini_fn instr_event__fini_fn;
+extern void *instr_event__fini_data;
+
+#include "instrument/events.inc.h"
+
+#endif /* INSTRUMENT__EVENTS_H */
new file mode 100644
@@ -0,0 +1,11 @@
+/*
+ * Internal API for triggering instrumentation events.
+ *
+ * Copyright (C) 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.
+ */
+
+
+
@@ -11,6 +11,8 @@
#include "qemu-common.h"
#include <dlfcn.h>
+#include "instrument/control.h"
+#include "instrument/events.h"
#include "instrument/load.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"
@@ -96,8 +98,11 @@ InstrLoadError instr_load(const char *path, int argc, const char **argv,
res = INSTR_LOAD_DLERROR;
goto err;
}
+ instr_set_event(fini_fn, NULL);
+ instr_set_state(INSTR_STATE_ENABLE);
main_res = main_cb(argc, argv);
+ instr_set_state(INSTR_STATE_DISABLE);
if (main_res != 0) {
res = INSTR_LOAD_ERROR;
@@ -126,6 +131,14 @@ InstrUnloadError instr_unload(const char *id)
goto out;
}
+ qi_fini_fn fini_fn = instr_get_event(fini_fn);
+ if (fini_fn) {
+ void *fini_data = instr_get_event(fini_data);
+ fini_fn(fini_data);
+ }
+
+ instr_set_event(fini_fn, NULL);
+
/* this should never fail */
if (dlclose(handle->dlhandle) < 0) {
res = INSTR_UNLOAD_DLERROR;
new file mode 100644
@@ -0,0 +1,46 @@
+/*
+ * Main instrumentation interface for QEMU.
+ *
+ * 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>
+
+
+/**
+ * SECTION:control
+ * @section_id: qi-control
+ * @title: Event control API for QEMU event instrumentation
+ */
+
+typedef void (*qi_fini_fn)(void *arg);
+
+/**
+ * qi_set_fini:
+ * @fn: Finalization function.
+ * @data: Argument to pass to the finalization function.
+ *
+ * Set the function to call when finalizing (unloading) the instrumentation
+ * library.
+ *
+ * NOTE: Calls to printf() might not be shown if the library is unloaded when
+ * QEMU terminates.
+ */
+void qi_set_fini(qi_fini_fn fn, void *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QI__CONTROL_H */
@@ -10,6 +10,7 @@
#include "qemu/osdep.h"
#include "instrument/cmdline.h"
+#include "instrument/control.h"
#include "qapi/error.h"
#include "qapi/qmp/qerror.h"
@@ -38,3 +39,6 @@ void qmp_instr_unload(const char *id, Error **errp)
{
error_setg(errp, QERR_UNSUPPORTED);
}
+
+
+__thread InstrState instr_cur_state;
Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu> --- Makefile | 4 +++ configure | 1 + include/qemu/compiler.h | 19 ++++++++++++++++ instrument/Makefile.objs | 1 + instrument/control.c | 28 ++++++++++++++++++++++++ instrument/control.h | 44 +++++++++++++++++++++++++++++++++++++ instrument/control.inc.h | 25 +++++++++++++++++++++ instrument/error.h | 28 ++++++++++++++++++++++++ instrument/events.h | 37 +++++++++++++++++++++++++++++++ instrument/events.inc.h | 11 +++++++++ instrument/load.c | 13 +++++++++++ instrument/qemu-instr/control.h | 46 +++++++++++++++++++++++++++++++++++++++ stubs/instrument.c | 4 +++ 13 files changed, 261 insertions(+) create mode 100644 instrument/control.c create mode 100644 instrument/control.h create mode 100644 instrument/control.inc.h create mode 100644 instrument/error.h create mode 100644 instrument/events.h create mode 100644 instrument/events.inc.h create mode 100644 instrument/qemu-instr/control.h