Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/810737/?format=api
{ "id": 810737, "url": "http://patchwork.ozlabs.org/api/patches/810737/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/150471928780.24907.14047559834166839201.stgit@frigg.lan/", "project": { "id": 14, "url": "http://patchwork.ozlabs.org/api/projects/14/?format=api", "name": "QEMU Development", "link_name": "qemu-devel", "list_id": "qemu-devel.nongnu.org", "list_email": "qemu-devel@nongnu.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<150471928780.24907.14047559834166839201.stgit@frigg.lan>", "list_archive_url": null, "date": "2017-09-06T17:34:48", "name": "[v4,03/20] instrument: Add generic library loader", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "5e65d6cb734b0eb842ccf31de4de1724c7f18866", "submitter": { "id": 9099, "url": "http://patchwork.ozlabs.org/api/people/9099/?format=api", "name": "Lluís Vilanova", "email": "vilanova@ac.upc.edu" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/150471928780.24907.14047559834166839201.stgit@frigg.lan/mbox/", "series": [ { "id": 1859, "url": "http://patchwork.ozlabs.org/api/series/1859/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=1859", "date": "2017-09-06T17:22:41", "name": "instrument: Add basic event instrumentation", "version": 4, "mbox": "http://patchwork.ozlabs.org/series/1859/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/810737/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/810737/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org", "Authentication-Results": "ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=nongnu.org\n\t(client-ip=2001:4830:134:3::11; helo=lists.gnu.org;\n\tenvelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n\treceiver=<UNKNOWN>)", "Received": [ "from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11])\n\t(using TLSv1 with cipher AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xnW263nYDz9t2d\n\tfor <incoming@patchwork.ozlabs.org>;\n\tThu, 7 Sep 2017 03:35:26 +1000 (AEST)", "from localhost ([::1]:37288 helo=lists.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.71) (envelope-from\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>)\n\tid 1dpeEW-0003PI-JO\n\tfor incoming@patchwork.ozlabs.org; Wed, 06 Sep 2017 13:35:24 -0400", "from eggs.gnu.org ([2001:4830:134:3::10]:38410)\n\tby lists.gnu.org with esmtp (Exim 4.71)\n\t(envelope-from <vilanova@ac.upc.edu>) id 1dpeEB-0003Ox-IR\n\tfor qemu-devel@nongnu.org; Wed, 06 Sep 2017 13:35:05 -0400", "from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)\n\t(envelope-from <vilanova@ac.upc.edu>) id 1dpeE8-0006YW-Ch\n\tfor qemu-devel@nongnu.org; Wed, 06 Sep 2017 13:35:03 -0400", "from roura.ac.upc.es ([147.83.33.10]:40325)\n\tby eggs.gnu.org with esmtp (Exim 4.71)\n\t(envelope-from <vilanova@ac.upc.edu>) id 1dpeE7-0006Y2-OF\n\tfor qemu-devel@nongnu.org; Wed, 06 Sep 2017 13:35:00 -0400", "from correu-1.ac.upc.es (correu-1.ac.upc.es [147.83.30.91])\n\tby roura.ac.upc.es (8.13.8/8.13.8) with ESMTP id v86HYteU003993;\n\tWed, 6 Sep 2017 19:34:55 +0200", "from localhost (unknown [31.210.187.58])\n\tby correu-1.ac.upc.es (Postfix) with ESMTPSA id D7E7D8AF;\n\tWed, 6 Sep 2017 19:34:49 +0200 (CEST)" ], "From": "=?utf-8?b?TGx1w61z?= Vilanova <vilanova@ac.upc.edu>", "To": "qemu-devel@nongnu.org", "Date": "Wed, 6 Sep 2017 20:34:48 +0300", "Message-Id": "<150471928780.24907.14047559834166839201.stgit@frigg.lan>", "X-Mailer": "git-send-email 2.14.1", "In-Reply-To": "<150471856141.24907.274176769201097378.stgit@frigg.lan>", "References": "<150471856141.24907.274176769201097378.stgit@frigg.lan>", "User-Agent": "StGit/0.17.1-dirty", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=\"utf-8\"", "Content-Transfer-Encoding": "quoted-printable", "X-MIME-Autoconverted": "from 8bit to quoted-printable by roura.ac.upc.es id\n\tv86HYteU003993", "X-detected-operating-system": "by eggs.gnu.org: GNU/Linux 2.6.x [fuzzy]", "X-Received-From": "147.83.33.10", "Subject": "[Qemu-devel] [PATCH v4 03/20] instrument: Add generic library loader", "X-BeenThere": "qemu-devel@nongnu.org", "X-Mailman-Version": "2.1.21", "Precedence": "list", "List-Id": "<qemu-devel.nongnu.org>", "List-Unsubscribe": "<https://lists.nongnu.org/mailman/options/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>", "List-Archive": "<http://lists.nongnu.org/archive/html/qemu-devel/>", "List-Post": "<mailto:qemu-devel@nongnu.org>", "List-Help": "<mailto:qemu-devel-request@nongnu.org?subject=help>", "List-Subscribe": "<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=subscribe>", "Cc": "\"Emilio G. Cota\" <cota@braap.org>, =?utf-8?q?Llu=C3=ADs_Vilanova?=\n\t<vilanova@ac.upc.edu>, \tStefan Hajnoczi <stefanha@redhat.com>", "Errors-To": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org", "Sender": "\"Qemu-devel\"\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>" }, "content": "Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>\n---\n MAINTAINERS | 1 \n Makefile.objs | 4 +\n configure | 2 +\n instrument/Makefile.objs | 4 +\n instrument/cmdline.c | 124 ++++++++++++++++++++++++++++++++\n instrument/cmdline.h | 49 +++++++++++++\n instrument/load.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++\n instrument/load.h | 83 ++++++++++++++++++++++\n 8 files changed, 443 insertions(+)\n create mode 100644 instrument/Makefile.objs\n create mode 100644 instrument/cmdline.c\n create mode 100644 instrument/cmdline.h\n create mode 100644 instrument/load.c\n create mode 100644 instrument/load.h", "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex edb313c632..edd2c49078 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -1485,6 +1485,7 @@ M: Lluís Vilanova <vilanova@ac.upc.edu>\n M: Stefan Hajnoczi <stefanha@redhat.com>\n S: Maintained\n F: docs/instrument.txt\n+F: instrument/\n \n Checkpatch\n S: Odd Fixes\ndiff --git a/Makefile.objs b/Makefile.objs\nindex 24a4ea08b8..81a9218e14 100644\n--- a/Makefile.objs\n+++ b/Makefile.objs\n@@ -97,6 +97,10 @@ version-obj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.o\n util-obj-y += trace/\n target-obj-y += trace/\n \n+######################################################################\n+# instrument\n+target-obj-y += instrument/\n+\n ######################################################################\n # guest agent\n \ndiff --git a/configure b/configure\nindex 80dcc91c98..05bd7b1950 100755\n--- a/configure\n+++ b/configure\n@@ -6034,6 +6034,8 @@ fi\n echo \"CONFIG_TRACE_FILE=$trace_file\" >> $config_host_mak\n \n if test \"$instrument\" = \"yes\"; then\n+ LDFLAGS=\"-rdynamic $LDFLAGS\" # limit symbols available to clients\n+ LIBS=\"-ldl $LIBS\"\n echo \"CONFIG_INSTRUMENT=y\" >> $config_host_mak\n fi\n \ndiff --git a/instrument/Makefile.objs b/instrument/Makefile.objs\nnew file mode 100644\nindex 0000000000..5ea5c77245\n--- /dev/null\n+++ b/instrument/Makefile.objs\n@@ -0,0 +1,4 @@\n+# -*- mode: makefile -*-\n+\n+target-obj-y += cmdline.o\n+target-obj-$(CONFIG_INSTRUMENT) += load.o\ndiff --git a/instrument/cmdline.c b/instrument/cmdline.c\nnew file mode 100644\nindex 0000000000..ec87f96c72\n--- /dev/null\n+++ b/instrument/cmdline.c\n@@ -0,0 +1,124 @@\n+/*\n+ * Control instrumentation during program (de)initialization.\n+ *\n+ * Copyright (C) 2012-2017 Lluís Vilanova <vilanova@ac.upc.edu>\n+ *\n+ * This work is licensed under the terms of the GNU GPL, version 2 or later.\n+ * See the COPYING file in the top-level directory.\n+ */\n+\n+#include \"qemu/osdep.h\"\n+#include <dlfcn.h>\n+#include \"instrument/cmdline.h\"\n+#include \"instrument/load.h\"\n+#include \"qemu/config-file.h\"\n+#include \"qemu/error-report.h\"\n+\n+\n+QemuOptsList qemu_instr_opts = {\n+ .name = \"instrument\",\n+ .implied_opt_name = \"file\",\n+ .merge_lists = true,\n+ .head = QTAILQ_HEAD_INITIALIZER(qemu_instr_opts.head),\n+ .desc = {\n+ {\n+ .name = \"file\",\n+ .type = QEMU_OPT_STRING,\n+ },{\n+ .name = \"arg\",\n+ .type = QEMU_OPT_STRING,\n+ },\n+ { /* end of list */ }\n+ },\n+};\n+\n+void instr_opt_parse(const char *optarg, char **path,\n+ int *argc, const char ***argv)\n+{\n+ const char *arg;\n+ QemuOptsIter iter;\n+ QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts(\"instrument\"),\n+ optarg, true);\n+ if (!opts) {\n+ exit(1);\n+ } else {\n+#if !defined(CONFIG_INSTRUMENT)\n+ error_report(\"instrumentation not enabled on this build\");\n+ exit(1);\n+#endif\n+ }\n+\n+\n+ arg = qemu_opt_get(opts, \"file\");\n+ if (arg != NULL) {\n+ g_free(*path);\n+ *path = g_strdup(arg);\n+ }\n+\n+ qemu_opt_iter_init(&iter, opts, \"arg\");\n+ while ((arg = qemu_opt_iter_next(&iter)) != NULL) {\n+ *argv = realloc(*argv, sizeof(**argv) * (*argc + 1));\n+ (*argv)[*argc] = g_strdup(arg);\n+ (*argc)++;\n+ }\n+\n+ qemu_opts_del(opts);\n+}\n+\n+void instr_init(const char *path, int argc, const char **argv)\n+{\n+#if defined(CONFIG_INSTRUMENT)\n+ InstrLoadError err;\n+ int64_t handle;\n+\n+ if (path == NULL) {\n+ return;\n+ }\n+\n+ if (atexit(instr_fini) != 0) {\n+ fprintf(stderr, \"error: atexit: %s\\n\", strerror(errno));\n+ abort();\n+ }\n+\n+ err = instr_load(path, argc, argv, &handle);\n+ switch (err) {\n+ case INSTR_LOAD_OK:\n+ return;\n+ case INSTR_LOAD_TOO_MANY:\n+ error_report(\"instrument: tried to load too many libraries\");\n+ break;\n+ case INSTR_LOAD_ERROR:\n+ error_report(\"instrument: library initialization returned non-zero\");\n+ break;\n+ case INSTR_LOAD_DLERROR:\n+ error_report(\"instrument: error loading library: %s\", dlerror());\n+ break;\n+ }\n+#else\n+ error_report(\"instrument: not available\");\n+#endif\n+\n+ exit(1);\n+}\n+\n+void instr_fini(void)\n+{\n+#if defined(CONFIG_INSTRUMENT)\n+ InstrUnloadError err = instr_unload_all();\n+\n+ switch (err) {\n+ case INSTR_UNLOAD_OK:\n+ return;\n+ case INSTR_UNLOAD_INVALID:\n+ /* the user might have already unloaded it */\n+ return;\n+ case INSTR_UNLOAD_DLERROR:\n+ error_report(\"instrument: error unloading library: %s\", dlerror());\n+ break;\n+ }\n+#else\n+ error_report(\"instrument: not available\");\n+#endif\n+\n+ exit(1);\n+}\ndiff --git a/instrument/cmdline.h b/instrument/cmdline.h\nnew file mode 100644\nindex 0000000000..e6ea08c3e3\n--- /dev/null\n+++ b/instrument/cmdline.h\n@@ -0,0 +1,49 @@\n+/*\n+ * Control instrumentation during program (de)initialization.\n+ *\n+ * Copyright (C) 2012-2017 Lluís Vilanova <vilanova@ac.upc.edu>\n+ *\n+ * This work is licensed under the terms of the GNU GPL, version 2 or later.\n+ * See the COPYING file in the top-level directory.\n+ */\n+\n+#ifndef INSTRUMENT__CMDLINE_H\n+#define INSTRUMENT__CMDLINE_H\n+\n+\n+/**\n+ * Definition of QEMU options describing instrumentation subsystem\n+ * configuration.\n+ */\n+extern QemuOptsList qemu_instr_opts;\n+\n+/**\n+ * instr_opt_parse:\n+ * @optarg: A string argument of --instrument command line argument\n+ *\n+ * Initialize instrument subsystem.\n+ */\n+void instr_opt_parse(const char *optarg, char **path,\n+ int *argc, const char ***argv);\n+\n+/**\n+ * instr_init:\n+ * @path: Path to dynamic trace instrumentation library.\n+ * @argc: Number of arguments to the library's #qi_init routine.\n+ * @argv: Arguments to the library's #qi_init routine.\n+ *\n+ * Load and initialize the given instrumentation library. Calls exit() if the\n+ * library's initialization function returns a non-zero value.\n+ *\n+ * Installs instr_fini() as an atexit() callback.\n+ */\n+void instr_init(const char *path, int argc, const char **argv);\n+\n+/**\n+ * instr_fini:\n+ *\n+ * Deinitialize and unload all instrumentation libraries.\n+ */\n+void instr_fini(void);\n+\n+#endif /* INSTRUMENT__CMDLINE_H */\ndiff --git a/instrument/load.c b/instrument/load.c\nnew file mode 100644\nindex 0000000000..a57401102a\n--- /dev/null\n+++ b/instrument/load.c\n@@ -0,0 +1,176 @@\n+/*\n+ * Interface for (un)loading instrumentation libraries.\n+ *\n+ * Copyright (C) 2012-2017 Lluís Vilanova <vilanova@ac.upc.edu>\n+ *\n+ * This work is licensed under the terms of the GNU GPL, version 2 or later.\n+ * See the COPYING file in the top-level directory.\n+ */\n+\n+#include \"qemu/osdep.h\"\n+#include \"qemu-common.h\"\n+\n+#include <dlfcn.h>\n+#include \"instrument/load.h\"\n+#include \"qemu/config-file.h\"\n+#include \"qemu/error-report.h\"\n+\n+\n+typedef int64_t InstrHandleID;\n+\n+typedef struct InstrHandle\n+{\n+ InstrHandleID id;\n+ void *dlhandle;\n+ QSLIST_ENTRY(InstrHandle) list;\n+} InstrHandle;\n+\n+\n+static InstrHandleID handle_last_id;\n+static QSLIST_HEAD(, InstrHandle) handles = QSLIST_HEAD_INITIALIZER(handles);\n+static QemuMutex instr_lock;\n+\n+\n+static InstrHandle *handle_get(void)\n+{\n+ InstrHandle *res = g_malloc0(sizeof(InstrHandle));\n+ res->id = handle_last_id++;\n+ QSLIST_INSERT_HEAD(&handles, res, list);\n+ return res;\n+}\n+\n+static bool handle_put(InstrHandleID id)\n+{\n+ InstrHandle *prev = NULL;\n+ InstrHandle *handle;\n+ QSLIST_FOREACH(handle, &handles, list) {\n+ if (handle->id == id) {\n+ break;\n+ }\n+ prev = handle;\n+ }\n+ if (handle == NULL) {\n+ return false;\n+ } else {\n+ if (prev == NULL) {\n+ QSLIST_REMOVE_HEAD(&handles, list);\n+ } else {\n+ QSLIST_REMOVE_AFTER(prev, list);\n+ }\n+ g_free(handle);\n+ return true;\n+ }\n+}\n+\n+static InstrHandle *handle_find(InstrHandleID id)\n+{\n+ InstrHandle *handle;\n+ QSLIST_FOREACH(handle, &handles, list) {\n+ if (handle->id == id) {\n+ return handle;\n+ }\n+ }\n+ return NULL;\n+}\n+\n+InstrLoadError instr_load(const char * path, int argc, const char ** argv,\n+ int64_t *handle_id)\n+{\n+ InstrLoadError res;\n+ InstrHandle * handle;\n+ int (*main_cb)(int, const char **);\n+ int main_res;\n+\n+ qemu_rec_mutex_lock(&instr_lock);\n+\n+ *handle_id = -1;\n+\n+ if (!QSLIST_EMPTY(&handles) > 0) {\n+ /* XXX: This is in fact a hard-coded limit, but there's no reason why a\n+ * real multi-library implementation should fail.\n+ */\n+ res = INSTR_LOAD_TOO_MANY;\n+ goto out;\n+ }\n+\n+ handle = handle_get();\n+ handle->dlhandle = dlopen(path, RTLD_NOW);\n+ if (handle->dlhandle == NULL) {\n+ res = INSTR_LOAD_DLERROR;\n+ goto err;\n+ }\n+\n+ main_cb = dlsym(handle->dlhandle, \"main\");\n+ if (main_cb == NULL) {\n+ res = INSTR_LOAD_DLERROR;\n+ goto err;\n+ }\n+\n+ main_res = main_cb(argc, argv);\n+\n+ if (main_res != 0) {\n+ res = INSTR_LOAD_ERROR;\n+ goto err;\n+ }\n+\n+ *handle_id = handle->id;\n+ res = INSTR_LOAD_OK;\n+ goto out;\n+\n+err:\n+ handle_put(handle->id);\n+out:\n+ qemu_rec_mutex_unlock(&instr_lock);\n+ return res;\n+}\n+\n+InstrUnloadError instr_unload(int64_t handle_id)\n+{\n+ InstrLoadError res;\n+\n+ qemu_rec_mutex_lock(&instr_lock);\n+\n+ InstrHandle *handle = handle_find(handle_id);\n+ if (handle == NULL) {\n+ res = INSTR_UNLOAD_INVALID;\n+ goto out;\n+ }\n+\n+ /* this should never fail */\n+ if (dlclose(handle->dlhandle) < 0) {\n+ res = INSTR_UNLOAD_DLERROR;\n+ } else {\n+ res = INSTR_UNLOAD_OK;\n+ }\n+ handle_put(handle->id);\n+\n+out:\n+ qemu_rec_mutex_unlock(&instr_lock);\n+ return res;\n+}\n+\n+InstrUnloadError instr_unload_all(void)\n+{\n+ InstrUnloadError res = INSTR_UNLOAD_OK;\n+\n+ qemu_rec_mutex_lock(&instr_lock);\n+ while (true) {\n+ InstrHandle *handle = QSLIST_FIRST(&handles);\n+ if (handle == NULL) {\n+ break;\n+ } else {\n+ res = instr_unload(handle->id);\n+ if (res != INSTR_UNLOAD_OK) {\n+ break;\n+ }\n+ }\n+ }\n+ qemu_rec_mutex_unlock(&instr_lock);\n+\n+ return res;\n+}\n+\n+static void __attribute__((constructor)) instr_lock_init(void)\n+{\n+ qemu_rec_mutex_init(&instr_lock);\n+}\ndiff --git a/instrument/load.h b/instrument/load.h\nnew file mode 100644\nindex 0000000000..2ddb2c6c19\n--- /dev/null\n+++ b/instrument/load.h\n@@ -0,0 +1,83 @@\n+/*\n+ * Interface for (un)loading instrumentation libraries.\n+ *\n+ * Copyright (C) 2012-2017 Lluís Vilanova <vilanova@ac.upc.edu>\n+ *\n+ * This work is licensed under the terms of the GNU GPL, version 2 or later.\n+ * See the COPYING file in the top-level directory.\n+ */\n+\n+\n+#ifndef INSTRUMENT_LOAD_H\n+#define INSTRUMENT_LOAD_H\n+\n+#include \"qemu/osdep.h\"\n+\n+#include \"qemu/queue.h\"\n+#include \"qemu/thread.h\"\n+\n+\n+/**\n+ * InstrLoadError:\n+ * @INSTR_LOAD_OK: Correctly loaded.\n+ * @INSTR_LOAD_TOO_MANY: Tried to load too many instrumentation libraries.\n+ * @INSTR_LOAD_ERROR: The library's main() function returned a non-zero value.\n+ * @INSTR_LOAD_DLERROR: Error with libdl (see dlerror).\n+ *\n+ * Error codes for instr_load().\n+ */\n+typedef enum {\n+ INSTR_LOAD_OK,\n+ INSTR_LOAD_TOO_MANY,\n+ INSTR_LOAD_ERROR,\n+ INSTR_LOAD_DLERROR,\n+} InstrLoadError;\n+\n+/**\n+ * InstrUnloadError:\n+ * @INSTR_UNLOAD_OK: Correctly unloaded.\n+ * @INSTR_UNLOAD_INVALID: Invalid handle.\n+ * @INSTR_UNLOAD_DLERROR: Error with libdl (see dlerror).\n+ *\n+ * Error codes for instr_unload().\n+ */\n+typedef enum {\n+ INSTR_UNLOAD_OK,\n+ INSTR_UNLOAD_INVALID,\n+ INSTR_UNLOAD_DLERROR,\n+} InstrUnloadError;\n+\n+/**\n+ * instr_load:\n+ * @path: Path to the shared library to load.\n+ * @argc: Number of arguments passed to the initialization function of the library.\n+ * @argv: Arguments passed to the initialization function of the library.\n+ * @handle: Instrumentation library handle (undefined in case of error).\n+ *\n+ * Load a dynamic trace instrumentation library.\n+ *\n+ * Returns: Whether the library could be loaded.\n+ */\n+InstrLoadError instr_load(const char * path, int argc, const char ** argv,\n+ int64_t *handle);\n+\n+/**\n+ * instr_unload:\n+ * @handle: Instrumentation library handle returned by instr_load().\n+ *\n+ * Unload the given instrumentation library.\n+ *\n+ * Returns: Whether the library could be unloaded.\n+ */\n+InstrUnloadError instr_unload(int64_t handle);\n+\n+/**\n+ * instr_unload_all:\n+ *\n+ * Unload all instrumentation libraries.\n+ *\n+ * Returns: Whether any library could not be unloaded.\n+ */\n+InstrUnloadError instr_unload_all(void);\n+\n+#endif /* INSTRUMENT_LOAD_H */\n", "prefixes": [ "v4", "03/20" ] }