From patchwork Tue Mar 26 14:01:50 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Llu=C3=ADs_Vilanova?= X-Patchwork-Id: 231217 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 7C79D2C0082 for ; Wed, 27 Mar 2013 01:09:28 +1100 (EST) Received: from localhost ([::1]:44345 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UKUZ2-0001pn-4K for incoming@patchwork.ozlabs.org; Tue, 26 Mar 2013 10:09:24 -0400 Received: from eggs.gnu.org ([208.118.235.92]:36727) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UKURq-0008J8-0A for qemu-devel@nongnu.org; Tue, 26 Mar 2013 10:02:02 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UKURk-0008Bn-Fr for qemu-devel@nongnu.org; Tue, 26 Mar 2013 10:01:57 -0400 Received: from roura.ac.upc.es ([147.83.33.10]:37484) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UKURj-0008B6-VQ for qemu-devel@nongnu.org; Tue, 26 Mar 2013 10:01:52 -0400 Received: from gw.ac.upc.edu (gw.ac.upc.es [147.83.30.3]) by roura.ac.upc.es (8.13.8/8.13.8) with ESMTP id r2QE1pGL005220 for ; Tue, 26 Mar 2013 15:01:51 +0100 Received: from localhost (unknown [84.88.51.85]) by gw.ac.upc.edu (Postfix) with ESMTP id C50076B01C4 for ; Tue, 26 Mar 2013 15:01:50 +0100 (CET) From: =?utf-8?b?TGx1w61z?= Vilanova To: qemu-devel@nongnu.org Date: Tue, 26 Mar 2013 15:01:50 +0100 Message-Id: <20130326140150.4471.14513.stgit@fimbulvetr.bsc.es> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <20130326140021.4471.99597.stgit@fimbulvetr.bsc.es> References: <20130326140021.4471.99597.stgit@fimbulvetr.bsc.es> User-Agent: StGit/0.16 MIME-Version: 1.0 X-MIME-Autoconverted: from 8bit to quoted-printable by roura.ac.upc.es id r2QE1pGL005220 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x X-Received-From: 147.83.33.10 Subject: [Qemu-devel] [PATCH 16/22] instrument: Add commandline options to start with an instrumentation library X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add commandline options to control initial loading of dynamic instrumentation library. Signed-off-by: Lluís Vilanova --- 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 diff --git a/bsd-user/main.c b/bsd-user/main.c index cc84981..2facee0 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -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; diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c index 18b43f1..dbb6816 100644 --- a/bsd-user/syscall.c +++ b/bsd-user/syscall.c @@ -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 */ diff --git a/instrument/Makefile.objs b/instrument/Makefile.objs index ad9ca6d..9c7ea5c 100644 --- a/instrument/Makefile.objs +++ b/instrument/Makefile.objs @@ -64,6 +64,8 @@ endif ###################################################################### # Control code +target-obj-y += cmdline.o + target-obj-y += control.o common-obj-$(CONFIG_SOFTMMU) += hmp.o diff --git a/instrument/cmdline.c b/instrument/cmdline.c new file mode 100644 index 0000000..eda6b9c --- /dev/null +++ b/instrument/cmdline.c @@ -0,0 +1,94 @@ +/* + * Control dynamic trace instrumentation during program (de)initialization. + * + * Copyright (C) 2012 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 "instrument/cmdline.h" + +#include + +#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); +} diff --git a/instrument/cmdline.h b/instrument/cmdline.h new file mode 100644 index 0000000..23bee5e --- /dev/null +++ b/instrument/cmdline.h @@ -0,0 +1,41 @@ +/* + * Control dynamic trace instrumentation during program (de)initialization. + * + * Copyright (C) 2012 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. + */ + +#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 */ diff --git a/linux-user/main.c b/linux-user/main.c index 29845f9..5ef766e 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -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; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 19630ea..f35d421 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -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 diff --git a/qemu-options.hx b/qemu-options.hx index 797d992..7c7e35b 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2942,6 +2942,24 @@ the @var{simple} tracing backend. @end table ETEXI +DEF("instr", HAS_ARG, QEMU_OPTION_instr, + "-instr file=[,args=]\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) diff --git a/qmp-commands.hx b/qmp-commands.hx index f704221..d86d15c 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -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, }, diff --git a/vl.c b/vl.c index febd2ea..90a3b39 100644 --- a/vl.c +++ b/vl.c @@ -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);