Re: [Qemu-devel] [PATCH v6 03/22] instrument: Add generic library loader

2017-09-18 Thread Stefan Hajnoczi
On Wed, Sep 13, 2017 at 01:05:49PM +0300, Lluís Vilanova wrote:
> +#include 

Is it possible to use glib's portable gmodule API so this works on
Windows too?



[Qemu-devel] [PATCH v6 03/22] instrument: Add generic library loader

2017-09-13 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 MAINTAINERS  |1 
 Makefile.objs|4 +
 configure|3 +
 instrument/Makefile.objs |4 +
 instrument/cmdline.c |  128 +++
 instrument/cmdline.h |   51 ++
 instrument/load.c|  166 ++
 instrument/load.h|   88 
 stubs/Makefile.objs  |1 
 stubs/instrument.c   |   18 +
 10 files changed, 464 insertions(+)
 create mode 100644 instrument/Makefile.objs
 create mode 100644 instrument/cmdline.c
 create mode 100644 instrument/cmdline.h
 create mode 100644 instrument/load.c
 create mode 100644 instrument/load.h
 create mode 100644 stubs/instrument.c

diff --git a/MAINTAINERS b/MAINTAINERS
index fb0eaee06a..6c0b12a69a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1491,6 +1491,7 @@ M: Lluís Vilanova 
 M: Stefan Hajnoczi 
 S: Maintained
 F: docs/instrument.txt
+F: instrument/
 
 TPM
 S: Orphan
diff --git a/Makefile.objs b/Makefile.objs
index 24a4ea08b8..81a9218e14 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -97,6 +97,10 @@ version-obj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.o
 util-obj-y +=  trace/
 target-obj-y += trace/
 
+##
+# instrument
+target-obj-y += instrument/
+
 ##
 # guest agent
 
diff --git a/configure b/configure
index a21d1bceb9..5175151317 100755
--- a/configure
+++ b/configure
@@ -6025,6 +6025,9 @@ fi
 echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak
 
 if test "$instrument" = "yes"; then
+  LDFLAGS="-rdynamic $LDFLAGS"  # limit symbols available to clients
+  QEMU_CFLAGS="-fvisibility=hidden $QEMU_CFLAGS"
+  LIBS="-ldl $LIBS"
   echo "CONFIG_INSTRUMENT=y" >> $config_host_mak
 fi
 
diff --git a/instrument/Makefile.objs b/instrument/Makefile.objs
new file mode 100644
index 00..71994a4c85
--- /dev/null
+++ b/instrument/Makefile.objs
@@ -0,0 +1,4 @@
+# -*- mode: makefile -*-
+
+target-obj-$(CONFIG_INSTRUMENT) += cmdline.o
+target-obj-$(CONFIG_INSTRUMENT) += load.o
diff --git a/instrument/cmdline.c b/instrument/cmdline.c
new file mode 100644
index 00..da7a7cbceb
--- /dev/null
+++ b/instrument/cmdline.c
@@ -0,0 +1,128 @@
+/*
+ * Control instrumentation during program (de)initialization.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * 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 
+#include "instrument/cmdline.h"
+#include "instrument/load.h"
+#include "qemu/config-file.h"
+#include "qemu/error-report.h"
+
+
+QemuOptsList qemu_instr_opts = {
+.name = "instrument",
+.implied_opt_name = "file",
+.merge_lists = true,
+.head = QTAILQ_HEAD_INITIALIZER(qemu_instr_opts.head),
+.desc = {
+{
+.name = "file",
+.type = QEMU_OPT_STRING,
+},{
+.name = "arg",
+.type = QEMU_OPT_STRING,
+},
+{ /* end of list */ }
+},
+};
+
+void instr_opt_parse(const char *optarg, char **path,
+ int *argc, const char ***argv)
+{
+const char *arg;
+QemuOptsIter iter;
+QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("instrument"),
+ optarg, true);
+if (!opts) {
+exit(1);
+} else {
+#if !defined(CONFIG_INSTRUMENT)
+error_report("instrumentation not enabled on this build");
+exit(1);
+#endif
+}
+
+
+arg = qemu_opt_get(opts, "file");
+if (arg != NULL) {
+g_free(*path);
+*path = g_strdup(arg);
+}
+
+qemu_opt_iter_init(&iter, opts, "arg");
+while ((arg = qemu_opt_iter_next(&iter)) != NULL) {
+*argv = realloc(*argv, sizeof(**argv) * (*argc + 1));
+(*argv)[*argc] = g_strdup(arg);
+(*argc)++;
+}
+
+qemu_opts_del(opts);
+}
+
+void instr_init(const char *path, int argc, const char **argv)
+{
+#if defined(CONFIG_INSTRUMENT)
+InstrLoadError err;
+
+if (path == NULL) {
+return;
+}
+
+if (atexit(instr_fini) != 0) {
+fprintf(stderr, "error: atexit: %s\n", strerror(errno));
+abort();
+}
+
+const char *id = "cmdline";
+err = instr_load(path, argc, argv, &id);
+switch (err) {
+case INSTR_LOAD_OK:
+error_report("instrument: loaded library with ID '%s'", id);
+return;
+case INSTR_LOAD_TOO_MANY:
+error_report("instrument: tried to load too many libraries");
+break;
+case INSTR_LOAD_ID_EXISTS:
+g_assert_not_reached();
+break;
+case INSTR_LOAD_ERROR:
+error_report("instrument: library initialization returned non-zero");
+break;
+case INSTR_LOAD_DLERROR:
+error_report("instrument: error loading library: