@@ -33,6 +33,8 @@
#include "tcg.h"
#include "qemu/timer.h"
#include "qemu/envlist.h"
+#include "instrument/cmdline.h"
+
int singlestep;
#if defined(CONFIG_USE_GUEST_BASE)
@@ -688,6 +690,15 @@ static void usage(void)
#endif
"-bsd type select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n"
"\n"
+#if defined(CONFIG_TRACE_INSTRUMENT)
+ "Tracing options:\n"
+#if defined(CONFIG_TRACE_INSTRUMENT_DYNAMIC)
+ "-instr path load a dynamic trace instrumentation library\n"
+#endif
+ "-instr-args string\n"
+ " arguments to dynamic trace instrumentation library\n"
+ "\n"
+#endif
"Debug options:\n"
"-d item1[,...] enable logging of specified items\n"
" (use '-d help' for a list of log items)\n"
@@ -743,6 +754,8 @@ int main(int argc, char **argv)
char **target_environ, **wrk;
envlist_t *envlist = NULL;
bsd_type = target_openbsd;
+ char *instrument_path = NULL;
+ char *instrument_args = NULL;
if (argc <= 1)
usage();
@@ -852,6 +865,14 @@ int main(int argc, char **argv)
singlestep = 1;
} else if (!strcmp(r, "strace")) {
do_strace = 1;
+#if defined(CONFIG_TRACE_INSTRUMENT_DYNAMIC)
+ } else if (!strcmp(r, "instr")) {
+ instrument_path = argv[optind++];
+#endif
+#if defined(CONFIG_TRACE_INSTRUMENT)
+ } else if (!strcmp(r, "instr-args")) {
+ instrument_args = argv[optind++];
+#endif
} else
{
usage();
@@ -1135,6 +1156,9 @@ int main(int argc, char **argv)
gdbserver_start (gdbstub_port);
gdb_handlesig(env, 0);
}
+
+ instr_init(instrument_path, instrument_args);
+
cpu_loop(env);
/* never exits */
return 0;
@@ -35,6 +35,8 @@
#include "qemu.h"
#include "qemu-common.h"
+#include "instrument/cmdline.h"
+
//#define DEBUG
@@ -334,6 +336,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
_mcleanup();
#endif
gdb_exit(cpu_env, arg1);
+ instr_fini();
/* XXX: should free thread stack and CPU env */
_exit(arg1);
ret = 0; /* avoid warning */
@@ -429,6 +432,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
_mcleanup();
#endif
gdb_exit(cpu_env, arg1);
+ instr_fini();
/* XXX: should free thread stack and CPU env */
_exit(arg1);
ret = 0; /* avoid warning */
@@ -501,6 +505,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
_mcleanup();
#endif
gdb_exit(cpu_env, arg1);
+ instr_fini();
/* XXX: should free thread stack and CPU env */
_exit(arg1);
ret = 0; /* avoid warning */
@@ -64,6 +64,8 @@ endif
######################################################################
# Control code
+target-obj-y += cmdline.o
+
target-obj-y += control.o
common-obj-$(CONFIG_SOFTMMU) += hmp.o
new file mode 100644
@@ -0,0 +1,94 @@
+/*
+ * Control dynamic trace instrumentation during program (de)initialization.
+ *
+ * Copyright (C) 2012 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/cmdline.h"
+
+#include <dlfcn.h>
+
+#include "qemu-common.h"
+#include "instrument/control.h"
+
+#if defined(CONFIG_TRACE_INSTRUMENT_STATIC)
+#include "instrument/qemu-instr/events.h"
+#endif
+
+
+static bool loaded = false;
+
+
+void instr_init(const char *path, const char *args)
+{
+ if (atexit(instr_fini) != 0) {
+ fprintf(stderr, "error: atexit: %s\n", strerror(errno));
+ abort();
+ }
+
+ if (path == NULL) {
+#if defined(CONFIG_TRACE_INSTRUMENT_STATIC)
+ loaded = true;
+ qi_init(args);
+#endif
+ return;
+ }
+
+ InstrLoadError err = instr_load(path, args);
+ switch (err) {
+ case INSTR_LOAD_OK:
+ loaded = true;
+ return;
+ case INSTR_LOAD_UNAVAILABLE:
+ fprintf(stderr, "error: instrument: not available\n");
+ break;
+ case INSTR_LOAD_LOADED:
+ fprintf(stderr, "error: instrument: already loaded\n");
+ break;
+ case INSTR_LOAD_DL:
+#if defined(CONFIG_TRACE_INSTRUMENT_DYNAMIC)
+ fprintf(stderr, "error: instrument: error loading library: %s\n", dlerror());
+#else
+ abort();
+#endif
+ break;
+ }
+
+ exit(-1);
+}
+
+void instr_fini(void)
+{
+ if (!loaded) {
+ return;
+ }
+
+#if defined(CONFIG_TRACE_INSTRUMENT_STATIC)
+ qi_fini();
+ return;
+#endif
+
+ InstrUnloadError err = instr_unload();
+ switch (err) {
+ case INSTR_UNLOAD_OK:
+ return;
+ case INSTR_UNLOAD_UNAVAILABLE:
+ fprintf(stderr, "error: not available\n");
+ break;
+ case INSTR_UNLOAD_UNLOADED:
+ /* the user might have already unloaded it */
+ return;
+ case INSTR_UNLOAD_DL:
+#if defined(CONFIG_TRACE_INSTRUMENT_DYNAMIC)
+ fprintf(stderr, "error: error unloading library: %s\n", dlerror());
+#else
+ abort();
+#endif
+ break;
+ }
+
+ exit(-1);
+}
new file mode 100644
@@ -0,0 +1,41 @@
+/*
+ * Control dynamic trace instrumentation during program (de)initialization.
+ *
+ * Copyright (C) 2012 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__CMDLINE_H
+#define INSTRUMENT__CMDLINE_H
+
+/**
+ * instr_init:
+ * @path: Path to dynamic trace instrumentation library.
+ * @args: Arbitrary string to pass to the library's #qi_init routine.
+ *
+ * Load and initialize the given instrumentation library.
+ *
+ * Automatically installs #instr_fini as an atexit callback.
+ *
+ * If path is %NULL and we're running with static instrumentation, the library
+ * is not loaded but just initialized.
+ *
+ * Pre-condition: There is no library already loaded.
+ */
+void instr_init(const char *path, const char *args);
+
+/**
+ * instr_fini:
+ *
+ * Deinitialize and unload the current instrumentation library.
+ *
+ * If we're running with static instrumentation, the library is not unloaded but
+ * just deinitialized.
+ *
+ * Pre-condition: There is an already loaded library.
+ */
+void instr_fini(void);
+
+#endif /* INSTRUMENT__CMDLINE_H */
@@ -34,6 +34,8 @@
#include "qemu/timer.h"
#include "qemu/envlist.h"
#include "elf.h"
+#include "instrument/cmdline.h"
+
char *exec_path;
@@ -3242,6 +3244,22 @@ static void handle_arg_reserved_va(const char *arg)
}
#endif
+static const char *instrument_path = NULL;
+#if defined(CONFIG_TRACE_INSTRUMENT_DYNAMIC)
+static void handle_arg_instrument(const char *arg)
+{
+ instrument_path = arg;
+}
+#endif
+
+static const char *instrument_args = NULL;
+#if defined(CONFIG_TRACE_INSTRUMENT)
+static void handle_arg_instrument_args(const char *arg)
+{
+ instrument_args = arg;
+}
+#endif
+
static void handle_arg_singlestep(const char *arg)
{
singlestep = 1;
@@ -3293,6 +3311,14 @@ static const struct qemu_argument arg_table[] = {
{"R", "QEMU_RESERVED_VA", true, handle_arg_reserved_va,
"size", "reserve 'size' bytes for guest virtual address space"},
#endif
+#if defined(CONFIG_TRACE_INSTRUMENT_DYNAMIC)
+ {"instr", "QEMU_INSTR", true, handle_arg_instrument,
+ "path", "load a dynamic trace instrumentation library"},
+#endif
+#if defined(CONFIG_TRACE_INSTRUMENT)
+ {"instr-args", "QEMU_INSTR_ARGS", true, handle_arg_instrument_args,
+ "string", "arguments to dynamic trace instrumentation library"},
+#endif
{"d", "QEMU_LOG", true, handle_arg_log,
"item[,...]", "enable logging of specified items "
"(use '-d help' for a list of items)"},
@@ -3978,6 +4004,9 @@ int main(int argc, char **argv, char **envp)
}
gdb_handlesig(env, 0);
}
+
+ instr_init(instrument_path, instrument_args);
+
cpu_loop(env);
/* never exits */
return 0;
@@ -106,6 +106,8 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
#include "cpu-uname.h"
#include "qemu.h"
+#include "instrument/cmdline.h"
+
#if defined(CONFIG_USE_NPTL)
#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
@@ -5230,6 +5232,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
_mcleanup();
#endif
gdb_exit(cpu_env, arg1);
+ instr_fini();
_exit(arg1);
ret = 0; /* avoid warning */
break;
@@ -7001,6 +7004,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
_mcleanup();
#endif
gdb_exit(cpu_env, arg1);
+ instr_fini();
ret = get_errno(exit_group(arg1));
break;
#endif
@@ -2942,6 +2942,24 @@ the @var{simple} tracing backend.
@end table
ETEXI
+DEF("instr", HAS_ARG, QEMU_OPTION_instr,
+ "-instr file=<file>[,args=<string>]\n"
+ " load an instrumentation library\n",
+ QEMU_ARCH_ALL)
+STEXI
+@item -instr file=@var{file}[,args=@var{args}]
+@findex -instr
+
+Load a dynamic trace instrumentation library.
+
+@table @option
+@item file=@var{file}
+Load the given dynamic trace instrumentation library.
+@item args=@var{string}
+An arbitrary string passed as the argument to the library's @code{qi_init} routine.
+@end table
+ETEXI
+
HXCOMM Internal use
DEF("qtest", HAS_ARG, QEMU_OPTION_qtest, "", QEMU_ARCH_ALL)
DEF("qtest-log", HAS_ARG, QEMU_OPTION_qtest_log, "", QEMU_ARCH_ALL)
@@ -1519,6 +1519,7 @@ Load a dynamic instrumentation library.
Arguments:
- path: path to the dynamic instrumentation library
+- args: arguments to the dynamic instrumentation library
Example:
@@ -1529,8 +1530,8 @@ EQMP
{
.name = "instr-load",
- .args_type = "path:s",
- .params = "path",
+ .args_type = "path:F,args:s?",
+ .params = "path args",
.mhandler.cmd_new = qmp_marshal_input_instr_load,
},
@@ -162,6 +162,7 @@ int main(int argc, char **argv)
#include "trace.h"
#include "trace/control.h"
+#include "instrument/cmdline.h"
#include "qemu/queue.h"
#include "sysemu/cpus.h"
#include "sysemu/arch_init.h"
@@ -349,6 +350,22 @@ static QemuOptsList qemu_trace_opts = {
},
};
+static QemuOptsList qemu_instr_opts = {
+ .name = "instr",
+ .implied_opt_name = "instr",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_instr_opts.head),
+ .desc = {
+ {
+ .name = "file",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "args",
+ .type = QEMU_OPT_STRING,
+ },
+ { /* end of list */ }
+ },
+};
+
static QemuOptsList qemu_option_rom_opts = {
.name = "option-rom",
.implied_opt_name = "romfile",
@@ -2837,6 +2854,8 @@ int main(int argc, char **argv, char **envp)
};
const char *trace_events = NULL;
const char *trace_file = NULL;
+ const char *instrument_path = NULL;
+ const char *instrument_args = NULL;
atexit(qemu_run_exit_notifiers);
error_set_progname(argv[0]);
@@ -2862,6 +2881,7 @@ int main(int argc, char **argv, char **envp)
qemu_add_opts(&qemu_global_opts);
qemu_add_opts(&qemu_mon_opts);
qemu_add_opts(&qemu_trace_opts);
+ qemu_add_opts(&qemu_instr_opts);
qemu_add_opts(&qemu_option_rom_opts);
qemu_add_opts(&qemu_machine_opts);
qemu_add_opts(&qemu_boot_opts);
@@ -3747,6 +3767,20 @@ int main(int argc, char **argv, char **envp)
trace_file = qemu_opt_get(opts, "file");
break;
}
+ case QEMU_OPTION_instr:
+ {
+ olist = qemu_find_opts("instr");
+ if (!olist) {
+ exit(1);
+ }
+ opts = qemu_opts_parse(olist, optarg, 0);
+ if (!opts) {
+ exit(1);
+ }
+ instrument_path = qemu_opt_get(opts, "file");
+ instrument_args = qemu_opt_get(opts, "args");
+ break;
+ }
case QEMU_OPTION_readconfig:
{
int ret = qemu_read_config_file(optarg);
@@ -4334,6 +4368,8 @@ int main(int argc, char **argv, char **envp)
}
}
+ instr_init(instrument_path, instrument_args);
+
if (incoming) {
Error *local_err = NULL;
qemu_start_incoming_migration(incoming, &local_err);
Add commandline options to control initial loading of dynamic instrumentation library. Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu> --- bsd-user/main.c | 24 ++++++++++++ bsd-user/syscall.c | 5 ++ instrument/Makefile.objs | 2 + instrument/cmdline.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++ instrument/cmdline.h | 41 ++++++++++++++++++++ linux-user/main.c | 29 ++++++++++++++ linux-user/syscall.c | 4 ++ qemu-options.hx | 18 +++++++++ qmp-commands.hx | 5 +- vl.c | 36 ++++++++++++++++++ 10 files changed, 256 insertions(+), 2 deletions(-) create mode 100644 instrument/cmdline.c create mode 100644 instrument/cmdline.h