Signed-off-by: Lluís Vilanova <vilan...@ac.upc.edu> --- instrument/Makefile.objs | 1 instrument/cmdline.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++ instrument/cmdline.h | 58 +++++++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 instrument/cmdline.c create mode 100644 instrument/cmdline.h
diff --git a/instrument/Makefile.objs b/instrument/Makefile.objs index 244936aa8c..aa6db29ff4 100644 --- a/instrument/Makefile.objs +++ b/instrument/Makefile.objs @@ -43,3 +43,4 @@ $(obj)/qemu-instr/events.h-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR) # Control code target-obj-y += control.o +target-obj-y += cmdline.o diff --git a/instrument/cmdline.c b/instrument/cmdline.c new file mode 100644 index 0000000000..e0c0e9ce1b --- /dev/null +++ b/instrument/cmdline.c @@ -0,0 +1,117 @@ +/* + * Control dynamic trace instrumentation during program (de)initialization. + * + * Copyright (C) 2012-2017 Lluís Vilanova <vilan...@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 <dlfcn.h> +#include "instrument/cmdline.h" +#include "instrument/control.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) +{ + InstrLoadError err; + int64_t handle; + + if (path == NULL) { + return; + } + + if (atexit(instr_fini) != 0) { + fprintf(stderr, "error: atexit: %s\n", strerror(errno)); + abort(); + } + + err = instr_load(path, argc, argv, &handle); + switch (err) { + case INSTR_LOAD_OK: + return; + case INSTR_LOAD_UNAVAILABLE: + error_report("instrument: not available"); + break; + case INSTR_LOAD_ERROR: + error_report("instrument: error loading library: %s", dlerror()); + break; + } + + exit(1); +} + +void instr_fini(void) +{ + InstrUnloadError err = instr_unload_all(); + + switch (err) { + case INSTR_UNLOAD_OK: + return; + case INSTR_UNLOAD_UNAVAILABLE: + error_report("instrument: not available"); + break; + case INSTR_UNLOAD_INVALID: + /* the user might have already unloaded it */ + return; + case INSTR_UNLOAD_ERROR: + error_report("instrument: error unloading library: %s", dlerror()); + break; + } + + exit(1); +} diff --git a/instrument/cmdline.h b/instrument/cmdline.h new file mode 100644 index 0000000000..c5eebf8b58 --- /dev/null +++ b/instrument/cmdline.h @@ -0,0 +1,58 @@ +/* + * Control dynamic trace instrumentation during program (de)initialization. + * + * Copyright (C) 2012-2017 Lluís Vilanova <vilan...@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 + + +/** + * Definition of QEMU options describing instrumentation subsystem + * configuration. + */ +extern QemuOptsList qemu_instr_opts; + +/** + * instr_opt_parse: + * @optarg: A string argument of --instrument command line argument + * + * Initialize instrument subsystem. + */ +void instr_opt_parse(const char *optarg, char **path, + int *argc, const char ***argv); + +/** + * instr_init: + * @path: Path to dynamic trace instrumentation library. + * @argc: Number of arguments to the library's #qi_init routine. + * @argv: Arguments 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, int argc, const char **argv); + +/** + * 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 */