From patchwork Tue Apr 16 13:51:27 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: 236968 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 6D6F32C00D8 for ; Tue, 16 Apr 2013 23:53:13 +1000 (EST) Received: from localhost ([::1]:38563 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1US6Jr-0006PM-Mu for incoming@patchwork.ozlabs.org; Tue, 16 Apr 2013 09:53:11 -0400 Received: from eggs.gnu.org ([208.118.235.92]:52322) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1US6JD-000654-Cm for qemu-devel@nongnu.org; Tue, 16 Apr 2013 09:52:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1US6ID-0003h7-KT for qemu-devel@nongnu.org; Tue, 16 Apr 2013 09:51:36 -0400 Received: from roura.ac.upc.es ([147.83.33.10]:44909) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1US6IC-0003gd-VD for qemu-devel@nongnu.org; Tue, 16 Apr 2013 09:51:29 -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 r3GDpSkZ030925 for ; Tue, 16 Apr 2013 15:51:28 +0200 Received: from localhost (unknown [84.88.51.85]) by gw.ac.upc.edu (Postfix) with ESMTP id E6E646B01C9 for ; Tue, 16 Apr 2013 15:51:27 +0200 (CEST) From: =?utf-8?b?TGx1w61z?= Vilanova To: qemu-devel@nongnu.org Date: Tue, 16 Apr 2013 15:51:27 +0200 Message-Id: <20130416135126.21588.39829.stgit@fimbulvetr.bsc.es> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <20130416134949.21588.80064.stgit@fimbulvetr.bsc.es> References: <20130416134949.21588.80064.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 r3GDpSkZ030925 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x X-Received-From: 147.83.33.10 Subject: [Qemu-devel] [PATCH v2 17/23] 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 | 25 +++++++++++ bsd-user/syscall.c | 5 ++ instrument/Makefile.objs | 2 + instrument/cmdline.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++ instrument/cmdline.h | 52 ++++++++++++++++++++++++ linux-user/main.c | 30 ++++++++++++++ linux-user/syscall.c | 4 ++ qemu-options.hx | 18 ++++++++ vl.c | 41 +++++++++++++++++++ 9 files changed, 278 insertions(+) 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..489168a 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-arg string\n" + " argument to dynamic trace instrumentation library (can be given multiple times)\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,9 @@ int main(int argc, char **argv) char **target_environ, **wrk; envlist_t *envlist = NULL; bsd_type = target_openbsd; + char *instrument_path = NULL; + int instrument_argc = 0; + char **instrument_argv = NULL; if (argc <= 1) usage(); @@ -852,6 +866,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-arg")) { + instr_parse_args(argv[optind++], &instrument_argc, &instrument_argv); +#endif } else { usage(); @@ -1135,6 +1157,9 @@ int main(int argc, char **argv) gdbserver_start (gdbstub_port); gdb_handlesig(env, 0); } + + instr_init(instrument_path, instrument_argc, instrument_argv); + 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 e3d4e9b..453330f 100644 --- a/instrument/Makefile.objs +++ b/instrument/Makefile.objs @@ -65,6 +65,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..0f52f60 --- /dev/null +++ b/instrument/cmdline.c @@ -0,0 +1,101 @@ +/* + * Control dynamic trace instrumentation during program (de)initialization. + * + * Copyright (C) 2012-2013 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; + + +void instr_parse_args(const char *args, int *argc, const char ***argv) +{ + *argv = realloc(*argv, sizeof(**argv) * (*argc + 1)); + (*argv)[*argc] = args; + (*argc)++; +} + +void instr_init(const char *path, int argc, const char **argv) +{ + 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(argc, argv); +#endif + return; + } + + InstrLoadError err = instr_load(path, argc, argv); + 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..b096793 --- /dev/null +++ b/instrument/cmdline.h @@ -0,0 +1,52 @@ +/* + * Control dynamic trace instrumentation during program (de)initialization. + * + * Copyright (C) 2012-2013 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_parse_args: + * @args: Input arguments. + * @argc: Output argument count. + * @argv: Output argument array. + * + * Adds element @args into the argument array. + */ +void instr_parse_args(const char *args, 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 */ diff --git a/linux-user/main.c b/linux-user/main.c index 4e92a0b..9216e69 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; @@ -3327,6 +3329,23 @@ static void handle_arg_reserved_va(const char *arg) } #endif +static const char *instrument_path; +#if defined(CONFIG_TRACE_INSTRUMENT_DYNAMIC) +static void handle_arg_instrument(const char *arg) +{ + instrument_path = arg; +} +#endif + +static int instrument_argc = 0; +static const char **instrument_argv = NULL; +#if defined(CONFIG_TRACE_INSTRUMENT) +static void handle_arg_instrument_arg(const char *arg) +{ + instr_parse_args(arg, &instrument_argc, &instrument_argv); +} +#endif + static void handle_arg_singlestep(const char *arg) { singlestep = 1; @@ -3378,6 +3397,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-arg", "QEMU_INSTR_ARGS", true, handle_arg_instrument_arg, + "string", "argument to dynamic trace instrumentation library (can be given multiple times)"}, +#endif {"d", "QEMU_LOG", true, handle_arg_log, "item[,...]", "enable logging of specified items " "(use '-d help' for a list of items)"}, @@ -4071,6 +4098,9 @@ int main(int argc, char **argv, char **envp) } gdb_handlesig(env, 0); } + + instr_init(instrument_path, instrument_argc, instrument_argv); + cpu_loop(env); /* never exits */ return 0; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1f07621..d55af6c 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -109,6 +109,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 | \ @@ -5248,6 +5250,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; @@ -7028,6 +7031,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 7cd6002..0f36c1c 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3021,6 +3021,24 @@ the @var{simple} tracing backend. @end table ETEXI +DEF("instr", HAS_ARG, QEMU_OPTION_instr, + "-instr file=[,arg=]\n" + " load an instrumentation library\n", + QEMU_ARCH_ALL) +STEXI +@item -instr file=@var{file}[,arg=@var{string}] +@findex -instr + +Load a dynamic trace instrumentation library. + +@table @option +@item file=@var{file} +Load the given dynamic trace instrumentation library. +@item arg=@var{string} +String argument passed as to the library's @code{qi_init} routine (can be given multiple times). +@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/vl.c b/vl.c index d694a90..e773bb4 100644 --- a/vl.c +++ b/vl.c @@ -163,6 +163,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" @@ -352,6 +353,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 = "arg", + .type = QEMU_OPT_STRING, + }, + { /* end of list */ } + }, +}; + static QemuOptsList qemu_option_rom_opts = { .name = "option-rom", .implied_opt_name = "romfile", @@ -2883,6 +2900,9 @@ int main(int argc, char **argv, char **envp) }; const char *trace_events = NULL; const char *trace_file = NULL; + const char *instrument_path = NULL; + int instrument_argc = 0; + const char **instrument_argv = NULL; atexit(qemu_run_exit_notifiers); error_set_progname(argv[0]); @@ -2908,6 +2928,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); @@ -3820,6 +3841,24 @@ 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); + } + const char * path = qemu_opt_get(opts, "file"); + if (path != NULL) { + instrument_path = path; + } + instr_parse_args(qemu_opt_get(opts, "arg"), + &instrument_argc, &instrument_argv); + break; + } case QEMU_OPTION_readconfig: { int ret = qemu_read_config_file(optarg); @@ -4414,6 +4453,8 @@ int main(int argc, char **argv, char **envp) } } + instr_init(instrument_path, instrument_argc, instrument_argv); + if (incoming) { Error *local_err = NULL; qemu_start_incoming_migration(incoming, &local_err);