#include "qemu/error-report.h"
#include "qemu/config-file.h"
#include "qapi/error.h"
+#include "qemu/lockable.h"
#include "qemu/option.h"
#include "qemu/rcu_queue.h"
#include "qemu/qht.h"
#include "qemu/bitmap.h"
+#include "qemu/cacheinfo.h"
#include "qemu/xxhash.h"
#include "qemu/plugin.h"
+#include "qemu/memalign.h"
#include "hw/core/cpu.h"
-#include "cpu.h"
-#include "exec/exec-all.h"
+#include "exec/tb-flush.h"
#ifndef CONFIG_USER_ONLY
#include "hw/boards.h"
#endif
+#include "qemu/compiler.h"
#include "plugin.h"
{
struct qemu_plugin_parse_arg *arg = opaque;
struct qemu_plugin_desc *p;
+ bool is_on;
+ char *fullarg;
if (strcmp(name, "file") == 0) {
if (strcmp(value, "") == 0) {
QTAILQ_INSERT_TAIL(arg->head, p, entry);
}
arg->curr = p;
- } else if (strcmp(name, "arg") == 0) {
+ } else {
if (arg->curr == NULL) {
error_setg(errp, "missing earlier '-plugin file=' option");
return 1;
}
+
+ if (g_strcmp0(name, "arg") == 0 &&
+ !qapi_bool_parse(name, value, &is_on, NULL)) {
+ if (strchr(value, '=') == NULL) {
+ /* Will treat arg="argname" as "argname=on" */
+ fullarg = g_strdup_printf("%s=%s", value, "on");
+ } else {
+ fullarg = g_strdup_printf("%s", value);
+ }
+ warn_report("using 'arg=%s' is deprecated", value);
+ error_printf("Please use '%s' directly\n", fullarg);
+ } else {
+ fullarg = g_strdup_printf("%s=%s", name, value);
+ }
+
p = arg->curr;
p->argc++;
p->argv = g_realloc_n(p->argv, p->argc, sizeof(char *));
- p->argv[p->argc - 1] = g_strdup(value);
- } else {
- error_setg(errp, "-plugin: unexpected parameter '%s'; ignored", name);
+ p->argv[p->argc - 1] = fullarg;
}
+
return 0;
}
-void qemu_plugin_opt_parse(const char *optarg, QemuPluginList *head)
+void qemu_plugin_opt_parse(const char *optstr, QemuPluginList *head)
{
struct qemu_plugin_parse_arg arg;
QemuOpts *opts;
- opts = qemu_opts_parse_noisily(qemu_find_opts("plugin"), optarg, true);
+ opts = qemu_opts_parse_noisily(qemu_find_opts("plugin"), optstr, true);
if (opts == NULL) {
exit(1);
}
return x * UINT64_C(2685821657736338717);
}
-static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info)
+/*
+ * Disable CFI checks.
+ * The install and version functions have been loaded from an external library
+ * so we do not have type information
+ */
+QEMU_DISABLE_CFI
+static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info, Error **errp)
{
qemu_plugin_install_func_t install;
struct qemu_plugin_ctx *ctx;
ctx->handle = g_module_open(desc->path, G_MODULE_BIND_LOCAL);
if (ctx->handle == NULL) {
- error_report("%s: %s", __func__, g_module_error());
+ error_setg(errp, "Could not load plugin %s: %s", desc->path, g_module_error());
goto err_dlopen;
}
if (!g_module_symbol(ctx->handle, "qemu_plugin_install", &sym)) {
- error_report("%s: %s", __func__, g_module_error());
+ error_setg(errp, "Could not load plugin %s: %s", desc->path, g_module_error());
goto err_symbol;
}
install = (qemu_plugin_install_func_t) sym;
/* symbol was found; it could be NULL though */
if (install == NULL) {
- error_report("%s: %s: qemu_plugin_install is NULL",
- __func__, desc->path);
+ error_setg(errp, "Could not load plugin %s: qemu_plugin_install is NULL",
+ desc->path);
goto err_symbol;
}
+ if (!g_module_symbol(ctx->handle, "qemu_plugin_version", &sym)) {
+ error_setg(errp, "Could not load plugin %s: plugin does not declare API version %s",
+ desc->path, g_module_error());
+ goto err_symbol;
+ } else {
+ int version = *(int *)sym;
+ if (version < QEMU_PLUGIN_MIN_VERSION) {
+ error_setg(errp, "Could not load plugin %s: plugin requires API version %d, but "
+ "this QEMU supports only a minimum version of %d",
+ desc->path, version, QEMU_PLUGIN_MIN_VERSION);
+ goto err_symbol;
+ } else if (version > QEMU_PLUGIN_VERSION) {
+ error_setg(errp, "Could not load plugin %s: plugin requires API version %d, but "
+ "this QEMU supports only up to version %d",
+ desc->path, version, QEMU_PLUGIN_VERSION);
+ goto err_symbol;
+ }
+ }
+
qemu_rec_mutex_lock(&plugin.lock);
/* find an unused random id with &ctx as the seed */
rc = install(ctx->id, info, desc->argc, desc->argv);
ctx->installing = false;
if (rc) {
- error_report("%s: qemu_plugin_install returned error code %d",
- __func__, rc);
+ error_setg(errp, "Could not load plugin %s: qemu_plugin_install returned error code %d",
+ desc->path, rc);
/*
* we cannot rely on the plugin doing its own cleanup, so
* call a full uninstall if the plugin did not yet call it.
return rc;
err_symbol:
+ g_module_close(ctx->handle);
err_dlopen:
qemu_vfree(ctx);
return 1;
* Note: the descriptor of each successfully installed plugin is removed
* from the list given by @head.
*/
-int qemu_plugin_load_list(QemuPluginList *head)
+int qemu_plugin_load_list(QemuPluginList *head, Error **errp)
{
struct qemu_plugin_desc *desc, *next;
g_autofree qemu_info_t *info = g_new0(qemu_info_t, 1);
info->target_name = TARGET_NAME;
+ info->version.min = QEMU_PLUGIN_MIN_VERSION;
+ info->version.cur = QEMU_PLUGIN_VERSION;
#ifndef CONFIG_USER_ONLY
MachineState *ms = MACHINE(qdev_get_machine());
info->system_emulation = true;
QTAILQ_FOREACH_SAFE(desc, head, entry, next) {
int err;
- err = plugin_load(desc, info);
+ err = plugin_load(desc, info, errp);
if (err) {
return err;
}
struct qemu_plugin_reset_data *data;
struct qemu_plugin_ctx *ctx;
- qemu_rec_mutex_lock(&plugin.lock);
- ctx = plugin_id_to_ctx_locked(id);
- if (ctx->uninstalling || (reset && ctx->resetting)) {
- qemu_rec_mutex_unlock(&plugin.lock);
- return;
+ WITH_QEMU_LOCK_GUARD(&plugin.lock) {
+ ctx = plugin_id_to_ctx_locked(id);
+ if (ctx->uninstalling || (reset && ctx->resetting)) {
+ return;
+ }
+ ctx->resetting = reset;
+ ctx->uninstalling = !reset;
}
- ctx->resetting = reset;
- ctx->uninstalling = !reset;
- qemu_rec_mutex_unlock(&plugin.lock);
data = g_new(struct qemu_plugin_reset_data, 1);
data->ctx = ctx;