Signed-off-by: Lluís Vilanova <vilan...@ac.upc.edu> --- instrument/Makefile.objs | 1 instrument/load.h | 4 ++ instrument/qmp.c | 88 ++++++++++++++++++++++++++++++++++++++++++ qapi-schema.json | 3 + qapi/instrument.json | 96 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 192 insertions(+) create mode 100644 instrument/qmp.c create mode 100644 qapi/instrument.json
diff --git a/instrument/Makefile.objs b/instrument/Makefile.objs index 5ea5c77245..13a8f60431 100644 --- a/instrument/Makefile.objs +++ b/instrument/Makefile.objs @@ -2,3 +2,4 @@ target-obj-y += cmdline.o target-obj-$(CONFIG_INSTRUMENT) += load.o +target-obj-y += qmp.o diff --git a/instrument/load.h b/instrument/load.h index 2ddb2c6c19..f8a02e6849 100644 --- a/instrument/load.h +++ b/instrument/load.h @@ -25,6 +25,8 @@ * @INSTR_LOAD_DLERROR: Error with libdl (see dlerror). * * Error codes for instr_load(). + * + * NOTE: Keep in sync with QAPI's #InstrLoadCode. */ typedef enum { INSTR_LOAD_OK, @@ -40,6 +42,8 @@ typedef enum { * @INSTR_UNLOAD_DLERROR: Error with libdl (see dlerror). * * Error codes for instr_unload(). + * + * NOTE: Keep in sync with QAPI's #InstrUnloadCode. */ typedef enum { INSTR_UNLOAD_OK, diff --git a/instrument/qmp.c b/instrument/qmp.c new file mode 100644 index 0000000000..c36960c12f --- /dev/null +++ b/instrument/qmp.c @@ -0,0 +1,88 @@ +/* + * QMP interface for instrumentation control commands. + * + * 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 "qemu-common.h" +#include "qapi/qmp/qerror.h" +#include "qmp-commands.h" + +#include <dlfcn.h> + +#include "instrument/load.h" + + + +InstrLoadResult *qmp_instr_load(const char * path, + bool have_args, strList * args, + Error **errp) +{ + InstrLoadResult *res = g_malloc0(sizeof(*res)); + +#if defined(CONFIG_INSTRUMENT) + int argc = 0; + const char **argv = NULL; + + strList *entry = have_args ? args : NULL; + while (entry != NULL) { + argv = realloc(argv, sizeof(*argv) * (argc + 1)); + argv[argc] = entry->value; + argc++; + entry = entry->next; + } + + InstrLoadError code = instr_load(path, argc, argv, &res->handle); + switch (code) { + case INSTR_LOAD_OK: + res->code = INSTR_LOAD_CODE_OK; + res->has_handle = true; + break; + case INSTR_LOAD_TOO_MANY: + res->code = INSTR_LOAD_CODE_TOO_MANY; + break; + case INSTR_LOAD_ERROR: + res->code = INSTR_LOAD_CODE_ERROR; + break; + case INSTR_LOAD_DLERROR: + res->has_msg = true; + res->msg = dlerror(); + res->code = INSTR_LOAD_CODE_DLERROR; + break; + } +#else + res->code = INSTR_LOAD_CODE_UNAVAILABLE; +#endif + + return res; +} + +InstrUnloadResult *qmp_instr_unload(int64_t handle, Error **errp) +{ + InstrUnloadResult *res = g_malloc0(sizeof(*res)); + +#if defined(CONFIG_INSTRUMENT) + InstrUnloadError code = instr_unload(handle); + switch (code) { + case INSTR_UNLOAD_OK: + res->code = INSTR_UNLOAD_CODE_OK; + break; + case INSTR_UNLOAD_INVALID: + res->code = INSTR_UNLOAD_CODE_INVALID; + break; + case INSTR_UNLOAD_DLERROR: + res->has_msg = true; + res->msg = dlerror(); + break; + res->code = INSTR_UNLOAD_CODE_DLERROR; + } +#else + res->code = INSTR_UNLOAD_CODE_UNAVAILABLE; +#endif + + return res; +} diff --git a/qapi-schema.json b/qapi-schema.json index 802ea53d00..5e343be9ff 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -90,6 +90,9 @@ # QAPI introspection { 'include': 'qapi/introspect.json' } +# Instrumentation commands +{ 'include': 'qapi/instrument.json' } + ## # = QMP commands ## diff --git a/qapi/instrument.json b/qapi/instrument.json new file mode 100644 index 0000000000..ea63fae309 --- /dev/null +++ b/qapi/instrument.json @@ -0,0 +1,96 @@ +# *-*- Mode: Python -*-* +# +# QAPI instrumentation control commands. +# +# 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. + +## +# @InstrLoadCode: +# +# Result code of an 'instr-load' command. +# +# @ok: Correctly loaded. +# @too-many: Tried to load too many instrumentation libraries. +# @error: The library's main() function returned a non-zero value. +# @dlerror: Error with libdl (see 'msg'). +# @unavailable: Service not available. +# +# Since: 2.11 +## +{ 'enum': 'InstrLoadCode', + 'data': [ 'ok', 'too-many', 'error', 'dlerror', 'unavailable' ] } + +## +# @InstrLoadResult: +# +# Result of an 'instr-load' command. +# +# @code: Result code. +# @msg: Additional error message (for human consumption only; present only in +# case of error). +# @handle: Instrumentation library identifier (present only if successful). +# +# Since: 2.11 +## +{ 'struct': 'InstrLoadResult', + 'data': { 'code': 'InstrLoadCode', '*msg': 'str', '*handle': 'int' } } + +## +# @instr-load: +# +# Load an instrumentation library. +# +# @path: path to the dynamic instrumentation library +# @args: arguments to the dynamic instrumentation library +# +# Since: 2.11 +## +{ 'command': 'instr-load', + 'data': { 'path': 'str', '*args': ['str'] }, + 'returns': 'InstrLoadResult' } + + +## +# @InstrUnloadCode: +# +# Result code of an 'instr-unload' command. +# +# @ok: Correctly unloaded. +# @invalid: Invalid handle. +# @dlerror: Error with libdl (see 'msg'). +# @unavailable: Service not available. +# +# Since: 2.11 +## +{ 'enum': 'InstrUnloadCode', + 'data': [ 'ok', 'invalid', 'dlerror', 'unavailable' ] } + +## +# @InstrUnloadResult: +# +# Result of an 'instr-unload' command. +# +# @code: Result code. +# @msg: Additional error message (for human consumption only; present only in +# case of error). +# +# Since: 2.11 +## +{ 'struct': 'InstrUnloadResult', + 'data': { 'code': 'InstrUnloadCode', '*msg': 'str' } } + +## +# @instr-unload: +# +# Unload an instrumentation library. +# +# @handle: Instrumentation library identifier (see #InstrLoadResult). +# +# Since: 2.11 +## +{ 'command': 'instr-unload', + 'data': { 'handle': 'int' }, + 'returns': 'InstrUnloadResult' }