From: Kevin Wolf <kwolf@redhat.com>
To: qemu-devel@nongnu.org
Cc: kwolf@redhat.com, armbru@redhat.com, qemu-block@nongnu.org,
dgilbert@redhat.com
Subject: [Qemu-devel] [RFC PATCH 09/10] monitor: Split out monitor/hmp.c
Date: Fri, 7 Jun 2019 15:54:29 +0200 [thread overview]
Message-ID: <20190607135430.22149-10-kwolf@redhat.com> (raw)
In-Reply-To: <20190607135430.22149-1-kwolf@redhat.com>
Move HMP infrastructure from monitor/misc.c to monitor/hmp.c. This is
code that can be shared for all targets, so compile it only once.
The amount of function and particularly extern variables in
monitor_int.h is probably a bit larger than it needs to be, but this way
no non-trivial code modifications are needed. The interfaces between HMP
and the monitor core can be cleaned up later.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
include/monitor/monitor.h | 1 +
monitor/monitor_int.h | 31 +
monitor/hmp.c | 1351 +++++++++++++++++++++++++++++++++++++
monitor/misc.c | 1338 +-----------------------------------
monitor/Makefile.objs | 2 +-
5 files changed, 1390 insertions(+), 1333 deletions(-)
create mode 100644 monitor/hmp.c
diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 7bbab05320..8547529e49 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -22,6 +22,7 @@ bool monitor_cur_is_qmp(void);
void monitor_init_globals(void);
void monitor_init(Chardev *chr, int flags);
void monitor_init_qmp(Chardev *chr, int flags);
+void monitor_init_hmp(Chardev *chr, int flags);
void monitor_cleanup(void);
int monitor_suspend(Monitor *mon);
diff --git a/monitor/monitor_int.h b/monitor/monitor_int.h
index 487618392f..8c5d95f942 100644
--- a/monitor/monitor_int.h
+++ b/monitor/monitor_int.h
@@ -27,6 +27,7 @@
#include "qemu-common.h"
#include "monitor/monitor.h"
+#include "qemu/cutils.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/json-parser.h"
@@ -153,6 +154,29 @@ static inline bool monitor_is_qmp(const Monitor *mon)
return (mon->flags & MONITOR_USE_CONTROL);
}
+/**
+ * Is @name in the '|' separated list of names @list?
+ */
+static inline int compare_cmd(const char *name, const char *list)
+{
+ const char *p, *pstart;
+ int len;
+ len = strlen(name);
+ p = list;
+ for(;;) {
+ pstart = p;
+ p = qemu_strchrnul(p, '|');
+ if ((p - pstart) == len && !memcmp(pstart, name, len)) {
+ return 1;
+ }
+ if (*p == '\0') {
+ break;
+ }
+ p++;
+ }
+ return 0;
+}
+
typedef QTAILQ_HEAD(MonitorList, Monitor) MonitorList;
extern IOThread *mon_iothread;
extern QEMUBH *qmp_dispatcher_bh;
@@ -161,6 +185,8 @@ extern QemuMutex monitor_lock;
extern MonitorList mon_list;
extern int mon_refcount;
+extern mon_cmd_t mon_cmds[];
+
int monitor_puts(Monitor *mon, const char *str);
void monitor_data_init(Monitor *mon, int flags, bool skip_flush,
bool use_io_thread);
@@ -172,4 +198,9 @@ void qmp_send_response(MonitorQMP *mon, const QDict *rsp);
void monitor_data_destroy_qmp(MonitorQMP *mon);
void monitor_qmp_bh_dispatcher(void *data);
+void monitor_data_init_hmp(MonitorHMP *mon, int flags, bool skip_flush);
+int get_monitor_def(int64_t *pval, const char *name);
+void help_cmd(Monitor *mon, const char *name);
+void handle_hmp_command(MonitorHMP *mon, const char *cmdline);
+
#endif
diff --git a/monitor/hmp.c b/monitor/hmp.c
new file mode 100644
index 0000000000..2bc464a7fc
--- /dev/null
+++ b/monitor/hmp.c
@@ -0,0 +1,1351 @@
+/*
+ * QEMU monitor
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "monitor_int.h"
+
+#include "qapi/error.h"
+#include "qapi/qmp/qnum.h"
+
+#include "qemu/config-file.h"
+#include "qemu/log.h"
+#include "qemu/option.h"
+#include "qemu/units.h"
+#include "sysemu/block-backend.h"
+#include "sysemu/sysemu.h"
+
+#include "trace-root.h"
+
+static int get_str(char *buf, int buf_size, const char **pp)
+{
+ const char *p;
+ char *q;
+ int c;
+
+ q = buf;
+ p = *pp;
+ while (qemu_isspace(*p)) {
+ p++;
+ }
+ if (*p == '\0') {
+ fail:
+ *q = '\0';
+ *pp = p;
+ return -1;
+ }
+ if (*p == '\"') {
+ p++;
+ while (*p != '\0' && *p != '\"') {
+ if (*p == '\\') {
+ p++;
+ c = *p++;
+ switch (c) {
+ case 'n':
+ c = '\n';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case '\\':
+ case '\'':
+ case '\"':
+ break;
+ default:
+ printf("unsupported escape code: '\\%c'\n", c);
+ goto fail;
+ }
+ if ((q - buf) < buf_size - 1) {
+ *q++ = c;
+ }
+ } else {
+ if ((q - buf) < buf_size - 1) {
+ *q++ = *p;
+ }
+ p++;
+ }
+ }
+ if (*p != '\"') {
+ printf("unterminated string\n");
+ goto fail;
+ }
+ p++;
+ } else {
+ while (*p != '\0' && !qemu_isspace(*p)) {
+ if ((q - buf) < buf_size - 1) {
+ *q++ = *p;
+ }
+ p++;
+ }
+ }
+ *q = '\0';
+ *pp = p;
+ return 0;
+}
+
+#define MAX_ARGS 16
+
+static void free_cmdline_args(char **args, int nb_args)
+{
+ int i;
+
+ assert(nb_args <= MAX_ARGS);
+
+ for (i = 0; i < nb_args; i++) {
+ g_free(args[i]);
+ }
+
+}
+
+/*
+ * Parse the command line to get valid args.
+ * @cmdline: command line to be parsed.
+ * @pnb_args: location to store the number of args, must NOT be NULL.
+ * @args: location to store the args, which should be freed by caller, must
+ * NOT be NULL.
+ *
+ * Returns 0 on success, negative on failure.
+ *
+ * NOTE: this parser is an approximate form of the real command parser. Number
+ * of args have a limit of MAX_ARGS. If cmdline contains more, it will
+ * return with failure.
+ */
+static int parse_cmdline(const char *cmdline,
+ int *pnb_args, char **args)
+{
+ const char *p;
+ int nb_args, ret;
+ char buf[1024];
+
+ p = cmdline;
+ nb_args = 0;
+ for (;;) {
+ while (qemu_isspace(*p)) {
+ p++;
+ }
+ if (*p == '\0') {
+ break;
+ }
+ if (nb_args >= MAX_ARGS) {
+ goto fail;
+ }
+ ret = get_str(buf, sizeof(buf), &p);
+ if (ret < 0) {
+ goto fail;
+ }
+ args[nb_args] = g_strdup(buf);
+ nb_args++;
+ }
+ *pnb_args = nb_args;
+ return 0;
+
+ fail:
+ free_cmdline_args(args, nb_args);
+ return -1;
+}
+
+/*
+ * Can command @cmd be executed in preconfig state?
+ */
+static bool cmd_can_preconfig(const mon_cmd_t *cmd)
+{
+ if (!cmd->flags) {
+ return false;
+ }
+
+ return strchr(cmd->flags, 'p');
+}
+
+static void help_cmd_dump_one(Monitor *mon,
+ const mon_cmd_t *cmd,
+ char **prefix_args,
+ int prefix_args_nb)
+{
+ int i;
+
+ if (runstate_check(RUN_STATE_PRECONFIG) && !cmd_can_preconfig(cmd)) {
+ return;
+ }
+
+ for (i = 0; i < prefix_args_nb; i++) {
+ monitor_printf(mon, "%s ", prefix_args[i]);
+ }
+ monitor_printf(mon, "%s %s -- %s\n", cmd->name, cmd->params, cmd->help);
+}
+
+/* @args[@arg_index] is the valid command need to find in @cmds */
+static void help_cmd_dump(Monitor *mon, const mon_cmd_t *cmds,
+ char **args, int nb_args, int arg_index)
+{
+ const mon_cmd_t *cmd;
+ size_t i;
+
+ /* No valid arg need to compare with, dump all in *cmds */
+ if (arg_index >= nb_args) {
+ for (cmd = cmds; cmd->name != NULL; cmd++) {
+ help_cmd_dump_one(mon, cmd, args, arg_index);
+ }
+ return;
+ }
+
+ /* Find one entry to dump */
+ for (cmd = cmds; cmd->name != NULL; cmd++) {
+ if (compare_cmd(args[arg_index], cmd->name) &&
+ ((!runstate_check(RUN_STATE_PRECONFIG) ||
+ cmd_can_preconfig(cmd)))) {
+ if (cmd->sub_table) {
+ /* continue with next arg */
+ help_cmd_dump(mon, cmd->sub_table,
+ args, nb_args, arg_index + 1);
+ } else {
+ help_cmd_dump_one(mon, cmd, args, arg_index);
+ }
+ return;
+ }
+ }
+
+ /* Command not found */
+ monitor_printf(mon, "unknown command: '");
+ for (i = 0; i <= arg_index; i++) {
+ monitor_printf(mon, "%s%s", args[i], i == arg_index ? "'\n" : " ");
+ }
+}
+
+void help_cmd(Monitor *mon, const char *name)
+{
+ MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
+ char *args[MAX_ARGS];
+ int nb_args = 0;
+
+ /* 1. parse user input */
+ if (name) {
+ /* special case for log, directly dump and return */
+ if (!strcmp(name, "log")) {
+ const QEMULogItem *item;
+ monitor_printf(mon, "Log items (comma separated):\n");
+ monitor_printf(mon, "%-10s %s\n", "none", "remove all logs");
+ for (item = qemu_log_items; item->mask != 0; item++) {
+ monitor_printf(mon, "%-10s %s\n", item->name, item->help);
+ }
+ return;
+ }
+
+ if (parse_cmdline(name, &nb_args, args) < 0) {
+ return;
+ }
+ }
+
+ /* 2. dump the contents according to parsed args */
+ help_cmd_dump(mon, hmp_mon->cmd_table, args, nb_args, 0);
+
+ free_cmdline_args(args, nb_args);
+}
+
+/*******************************************************************/
+
+static const char *pch;
+static sigjmp_buf expr_env;
+
+static void GCC_FMT_ATTR(2, 3) QEMU_NORETURN
+expr_error(Monitor *mon, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ monitor_vprintf(mon, fmt, ap);
+ monitor_printf(mon, "\n");
+ va_end(ap);
+ siglongjmp(expr_env, 1);
+}
+
+static void next(void)
+{
+ if (*pch != '\0') {
+ pch++;
+ while (qemu_isspace(*pch))
+ pch++;
+ }
+}
+
+static int64_t expr_sum(Monitor *mon);
+
+static int64_t expr_unary(Monitor *mon)
+{
+ int64_t n;
+ char *p;
+ int ret;
+
+ switch(*pch) {
+ case '+':
+ next();
+ n = expr_unary(mon);
+ break;
+ case '-':
+ next();
+ n = -expr_unary(mon);
+ break;
+ case '~':
+ next();
+ n = ~expr_unary(mon);
+ break;
+ case '(':
+ next();
+ n = expr_sum(mon);
+ if (*pch != ')') {
+ expr_error(mon, "')' expected");
+ }
+ next();
+ break;
+ case '\'':
+ pch++;
+ if (*pch == '\0')
+ expr_error(mon, "character constant expected");
+ n = *pch;
+ pch++;
+ if (*pch != '\'')
+ expr_error(mon, "missing terminating \' character");
+ next();
+ break;
+ case '$':
+ {
+ char buf[128], *q;
+ int64_t reg = 0;
+
+ pch++;
+ q = buf;
+ while ((*pch >= 'a' && *pch <= 'z') ||
+ (*pch >= 'A' && *pch <= 'Z') ||
+ (*pch >= '0' && *pch <= '9') ||
+ *pch == '_' || *pch == '.') {
+ if ((q - buf) < sizeof(buf) - 1)
+ *q++ = *pch;
+ pch++;
+ }
+ while (qemu_isspace(*pch))
+ pch++;
+ *q = 0;
+ ret = get_monitor_def(®, buf);
+ if (ret < 0)
+ expr_error(mon, "unknown register");
+ n = reg;
+ }
+ break;
+ case '\0':
+ expr_error(mon, "unexpected end of expression");
+ n = 0;
+ break;
+ default:
+ errno = 0;
+ n = strtoull(pch, &p, 0);
+ if (errno == ERANGE) {
+ expr_error(mon, "number too large");
+ }
+ if (pch == p) {
+ expr_error(mon, "invalid char '%c' in expression", *p);
+ }
+ pch = p;
+ while (qemu_isspace(*pch))
+ pch++;
+ break;
+ }
+ return n;
+}
+
+static int64_t expr_prod(Monitor *mon)
+{
+ int64_t val, val2;
+ int op;
+
+ val = expr_unary(mon);
+ for(;;) {
+ op = *pch;
+ if (op != '*' && op != '/' && op != '%')
+ break;
+ next();
+ val2 = expr_unary(mon);
+ switch(op) {
+ default:
+ case '*':
+ val *= val2;
+ break;
+ case '/':
+ case '%':
+ if (val2 == 0)
+ expr_error(mon, "division by zero");
+ if (op == '/')
+ val /= val2;
+ else
+ val %= val2;
+ break;
+ }
+ }
+ return val;
+}
+
+static int64_t expr_logic(Monitor *mon)
+{
+ int64_t val, val2;
+ int op;
+
+ val = expr_prod(mon);
+ for(;;) {
+ op = *pch;
+ if (op != '&' && op != '|' && op != '^')
+ break;
+ next();
+ val2 = expr_prod(mon);
+ switch(op) {
+ default:
+ case '&':
+ val &= val2;
+ break;
+ case '|':
+ val |= val2;
+ break;
+ case '^':
+ val ^= val2;
+ break;
+ }
+ }
+ return val;
+}
+
+static int64_t expr_sum(Monitor *mon)
+{
+ int64_t val, val2;
+ int op;
+
+ val = expr_logic(mon);
+ for(;;) {
+ op = *pch;
+ if (op != '+' && op != '-')
+ break;
+ next();
+ val2 = expr_logic(mon);
+ if (op == '+')
+ val += val2;
+ else
+ val -= val2;
+ }
+ return val;
+}
+
+static int get_expr(Monitor *mon, int64_t *pval, const char **pp)
+{
+ pch = *pp;
+ if (sigsetjmp(expr_env, 0)) {
+ *pp = pch;
+ return -1;
+ }
+ while (qemu_isspace(*pch))
+ pch++;
+ *pval = expr_sum(mon);
+ *pp = pch;
+ return 0;
+}
+
+static int get_double(Monitor *mon, double *pval, const char **pp)
+{
+ const char *p = *pp;
+ char *tailp;
+ double d;
+
+ d = strtod(p, &tailp);
+ if (tailp == p) {
+ monitor_printf(mon, "Number expected\n");
+ return -1;
+ }
+ if (d != d || d - d != 0) {
+ /* NaN or infinity */
+ monitor_printf(mon, "Bad number\n");
+ return -1;
+ }
+ *pval = d;
+ *pp = tailp;
+ return 0;
+}
+
+/*
+ * Store the command-name in cmdname, and return a pointer to
+ * the remaining of the command string.
+ */
+static const char *get_command_name(const char *cmdline,
+ char *cmdname, size_t nlen)
+{
+ size_t len;
+ const char *p, *pstart;
+
+ p = cmdline;
+ while (qemu_isspace(*p))
+ p++;
+ if (*p == '\0')
+ return NULL;
+ pstart = p;
+ while (*p != '\0' && *p != '/' && !qemu_isspace(*p))
+ p++;
+ len = p - pstart;
+ if (len > nlen - 1)
+ len = nlen - 1;
+ memcpy(cmdname, pstart, len);
+ cmdname[len] = '\0';
+ return p;
+}
+
+/**
+ * Read key of 'type' into 'key' and return the current
+ * 'type' pointer.
+ */
+static char *key_get_info(const char *type, char **key)
+{
+ size_t len;
+ char *p, *str;
+
+ if (*type == ',')
+ type++;
+
+ p = strchr(type, ':');
+ if (!p) {
+ *key = NULL;
+ return NULL;
+ }
+ len = p - type;
+
+ str = g_malloc(len + 1);
+ memcpy(str, type, len);
+ str[len] = '\0';
+
+ *key = str;
+ return ++p;
+}
+
+static int default_fmt_format = 'x';
+static int default_fmt_size = 4;
+
+static int is_valid_option(const char *c, const char *typestr)
+{
+ char option[3];
+
+ option[0] = '-';
+ option[1] = *c;
+ option[2] = '\0';
+
+ typestr = strstr(typestr, option);
+ return (typestr != NULL);
+}
+
+static const mon_cmd_t *search_dispatch_table(const mon_cmd_t *disp_table,
+ const char *cmdname)
+{
+ const mon_cmd_t *cmd;
+
+ for (cmd = disp_table; cmd->name != NULL; cmd++) {
+ if (compare_cmd(cmdname, cmd->name)) {
+ return cmd;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Parse command name from @cmdp according to command table @table.
+ * If blank, return NULL.
+ * Else, if no valid command can be found, report to @mon, and return
+ * NULL.
+ * Else, change @cmdp to point right behind the name, and return its
+ * command table entry.
+ * Do not assume the return value points into @table! It doesn't when
+ * the command is found in a sub-command table.
+ */
+static const mon_cmd_t *monitor_parse_command(MonitorHMP *hmp_mon,
+ const char *cmdp_start,
+ const char **cmdp,
+ mon_cmd_t *table)
+{
+ Monitor *mon = &hmp_mon->common;
+ const char *p;
+ const mon_cmd_t *cmd;
+ char cmdname[256];
+
+ /* extract the command name */
+ p = get_command_name(*cmdp, cmdname, sizeof(cmdname));
+ if (!p) {
+ return NULL;
+ }
+
+ cmd = search_dispatch_table(table, cmdname);
+ if (!cmd) {
+ monitor_printf(mon, "unknown command: '%.*s'\n",
+ (int)(p - cmdp_start), cmdp_start);
+ return NULL;
+ }
+ if (runstate_check(RUN_STATE_PRECONFIG) && !cmd_can_preconfig(cmd)) {
+ monitor_printf(mon, "Command '%.*s' not available with -preconfig "
+ "until after exit_preconfig.\n",
+ (int)(p - cmdp_start), cmdp_start);
+ return NULL;
+ }
+
+ /* filter out following useless space */
+ while (qemu_isspace(*p)) {
+ p++;
+ }
+
+ *cmdp = p;
+ /* search sub command */
+ if (cmd->sub_table != NULL && *p != '\0') {
+ return monitor_parse_command(hmp_mon, cmdp_start, cmdp, cmd->sub_table);
+ }
+
+ return cmd;
+}
+
+/*
+ * Parse arguments for @cmd.
+ * If it can't be parsed, report to @mon, and return NULL.
+ * Else, insert command arguments into a QDict, and return it.
+ * Note: On success, caller has to free the QDict structure.
+ */
+static QDict *monitor_parse_arguments(Monitor *mon,
+ const char **endp,
+ const mon_cmd_t *cmd)
+{
+ const char *typestr;
+ char *key;
+ int c;
+ const char *p = *endp;
+ char buf[1024];
+ QDict *qdict = qdict_new();
+
+ /* parse the parameters */
+ typestr = cmd->args_type;
+ for(;;) {
+ typestr = key_get_info(typestr, &key);
+ if (!typestr) {
+ break;
+ }
+ c = *typestr;
+ typestr++;
+ switch(c) {
+ case 'F':
+ case 'B':
+ case 's':
+ {
+ int ret;
+
+ while (qemu_isspace(*p))
+ p++;
+ if (*typestr == '?') {
+ typestr++;
+ if (*p == '\0') {
+ /* no optional string: NULL argument */
+ break;
+ }
+ }
+ ret = get_str(buf, sizeof(buf), &p);
+ if (ret < 0) {
+ switch(c) {
+ case 'F':
+ monitor_printf(mon, "%s: filename expected\n",
+ cmd->name);
+ break;
+ case 'B':
+ monitor_printf(mon, "%s: block device name expected\n",
+ cmd->name);
+ break;
+ default:
+ monitor_printf(mon, "%s: string expected\n", cmd->name);
+ break;
+ }
+ goto fail;
+ }
+ qdict_put_str(qdict, key, buf);
+ }
+ break;
+ case 'O':
+ {
+ QemuOptsList *opts_list;
+ QemuOpts *opts;
+
+ opts_list = qemu_find_opts(key);
+ if (!opts_list || opts_list->desc->name) {
+ goto bad_type;
+ }
+ while (qemu_isspace(*p)) {
+ p++;
+ }
+ if (!*p) {
+ break;
+ }
+ if (get_str(buf, sizeof(buf), &p) < 0) {
+ goto fail;
+ }
+ opts = qemu_opts_parse_noisily(opts_list, buf, true);
+ if (!opts) {
+ goto fail;
+ }
+ qemu_opts_to_qdict(opts, qdict);
+ qemu_opts_del(opts);
+ }
+ break;
+ case '/':
+ {
+ int count, format, size;
+
+ while (qemu_isspace(*p))
+ p++;
+ if (*p == '/') {
+ /* format found */
+ p++;
+ count = 1;
+ if (qemu_isdigit(*p)) {
+ count = 0;
+ while (qemu_isdigit(*p)) {
+ count = count * 10 + (*p - '0');
+ p++;
+ }
+ }
+ size = -1;
+ format = -1;
+ for(;;) {
+ switch(*p) {
+ case 'o':
+ case 'd':
+ case 'u':
+ case 'x':
+ case 'i':
+ case 'c':
+ format = *p++;
+ break;
+ case 'b':
+ size = 1;
+ p++;
+ break;
+ case 'h':
+ size = 2;
+ p++;
+ break;
+ case 'w':
+ size = 4;
+ p++;
+ break;
+ case 'g':
+ case 'L':
+ size = 8;
+ p++;
+ break;
+ default:
+ goto next;
+ }
+ }
+ next:
+ if (*p != '\0' && !qemu_isspace(*p)) {
+ monitor_printf(mon, "invalid char in format: '%c'\n",
+ *p);
+ goto fail;
+ }
+ if (format < 0) {
+ format = default_fmt_format;
+ }
+ if (format != 'i') {
+ /* for 'i', not specifying a size gives -1 as size */
+ if (size < 0) {
+ size = default_fmt_size;
+ }
+ default_fmt_size = size;
+ }
+ default_fmt_format = format;
+ } else {
+ count = 1;
+ format = default_fmt_format;
+ if (format != 'i') {
+ size = default_fmt_size;
+ } else {
+ size = -1;
+ }
+ }
+ qdict_put_int(qdict, "count", count);
+ qdict_put_int(qdict, "format", format);
+ qdict_put_int(qdict, "size", size);
+ }
+ break;
+ case 'i':
+ case 'l':
+ case 'M':
+ {
+ int64_t val;
+
+ while (qemu_isspace(*p))
+ p++;
+ if (*typestr == '?' || *typestr == '.') {
+ if (*typestr == '?') {
+ if (*p == '\0') {
+ typestr++;
+ break;
+ }
+ } else {
+ if (*p == '.') {
+ p++;
+ while (qemu_isspace(*p)) {
+ p++;
+ }
+ } else {
+ typestr++;
+ break;
+ }
+ }
+ typestr++;
+ }
+ if (get_expr(mon, &val, &p))
+ goto fail;
+ /* Check if 'i' is greater than 32-bit */
+ if ((c == 'i') && ((val >> 32) & 0xffffffff)) {
+ monitor_printf(mon, "\'%s\' has failed: ", cmd->name);
+ monitor_printf(mon, "integer is for 32-bit values\n");
+ goto fail;
+ } else if (c == 'M') {
+ if (val < 0) {
+ monitor_printf(mon, "enter a positive value\n");
+ goto fail;
+ }
+ val *= MiB;
+ }
+ qdict_put_int(qdict, key, val);
+ }
+ break;
+ case 'o':
+ {
+ int ret;
+ uint64_t val;
+ const char *end;
+
+ while (qemu_isspace(*p)) {
+ p++;
+ }
+ if (*typestr == '?') {
+ typestr++;
+ if (*p == '\0') {
+ break;
+ }
+ }
+ ret = qemu_strtosz_MiB(p, &end, &val);
+ if (ret < 0 || val > INT64_MAX) {
+ monitor_printf(mon, "invalid size\n");
+ goto fail;
+ }
+ qdict_put_int(qdict, key, val);
+ p = end;
+ }
+ break;
+ case 'T':
+ {
+ double val;
+
+ while (qemu_isspace(*p)) {
+ p++;
+ }
+ if (*typestr == '?') {
+ typestr++;
+ if (*p == '\0') {
+ break;
+ }
+ }
+ if (get_double(mon, &val, &p) < 0) {
+ goto fail;
+ }
+ if (p[0] && p[1] == 's') {
+ switch (*p) {
+ case 'm':
+ val /= 1e3; p += 2; break;
+ case 'u':
+ val /= 1e6; p += 2; break;
+ case 'n':
+ val /= 1e9; p += 2; break;
+ }
+ }
+ if (*p && !qemu_isspace(*p)) {
+ monitor_printf(mon, "Unknown unit suffix\n");
+ goto fail;
+ }
+ qdict_put(qdict, key, qnum_from_double(val));
+ }
+ break;
+ case 'b':
+ {
+ const char *beg;
+ bool val;
+
+ while (qemu_isspace(*p)) {
+ p++;
+ }
+ beg = p;
+ while (qemu_isgraph(*p)) {
+ p++;
+ }
+ if (p - beg == 2 && !memcmp(beg, "on", p - beg)) {
+ val = true;
+ } else if (p - beg == 3 && !memcmp(beg, "off", p - beg)) {
+ val = false;
+ } else {
+ monitor_printf(mon, "Expected 'on' or 'off'\n");
+ goto fail;
+ }
+ qdict_put_bool(qdict, key, val);
+ }
+ break;
+ case '-':
+ {
+ const char *tmp = p;
+ int skip_key = 0;
+ /* option */
+
+ c = *typestr++;
+ if (c == '\0')
+ goto bad_type;
+ while (qemu_isspace(*p))
+ p++;
+ if (*p == '-') {
+ p++;
+ if(c != *p) {
+ if(!is_valid_option(p, typestr)) {
+ monitor_printf(mon, "%s: unsupported option -%c\n",
+ cmd->name, *p);
+ goto fail;
+ } else {
+ skip_key = 1;
+ }
+ }
+ if(skip_key) {
+ p = tmp;
+ } else {
+ /* has option */
+ p++;
+ qdict_put_bool(qdict, key, true);
+ }
+ }
+ }
+ break;
+ case 'S':
+ {
+ /* package all remaining string */
+ int len;
+
+ while (qemu_isspace(*p)) {
+ p++;
+ }
+ if (*typestr == '?') {
+ typestr++;
+ if (*p == '\0') {
+ /* no remaining string: NULL argument */
+ break;
+ }
+ }
+ len = strlen(p);
+ if (len <= 0) {
+ monitor_printf(mon, "%s: string expected\n",
+ cmd->name);
+ goto fail;
+ }
+ qdict_put_str(qdict, key, p);
+ p += len;
+ }
+ break;
+ default:
+ bad_type:
+ monitor_printf(mon, "%s: unknown type '%c'\n", cmd->name, c);
+ goto fail;
+ }
+ g_free(key);
+ key = NULL;
+ }
+ /* check that all arguments were parsed */
+ while (qemu_isspace(*p))
+ p++;
+ if (*p != '\0') {
+ monitor_printf(mon, "%s: extraneous characters at the end of line\n",
+ cmd->name);
+ goto fail;
+ }
+
+ return qdict;
+
+fail:
+ qobject_unref(qdict);
+ g_free(key);
+ return NULL;
+}
+
+void handle_hmp_command(MonitorHMP *mon, const char *cmdline)
+{
+ QDict *qdict;
+ const mon_cmd_t *cmd;
+ const char *cmd_start = cmdline;
+
+ trace_handle_hmp_command(mon, cmdline);
+
+ cmd = monitor_parse_command(mon, cmdline, &cmdline, mon->cmd_table);
+ if (!cmd) {
+ return;
+ }
+
+ qdict = monitor_parse_arguments(&mon->common, &cmdline, cmd);
+ if (!qdict) {
+ while (cmdline > cmd_start && qemu_isspace(cmdline[-1])) {
+ cmdline--;
+ }
+ monitor_printf(&mon->common, "Try \"help %.*s\" for more information\n",
+ (int)(cmdline - cmd_start), cmd_start);
+ return;
+ }
+
+ cmd->cmd(&mon->common, qdict);
+ qobject_unref(qdict);
+}
+
+static void cmd_completion(MonitorHMP *mon, const char *name, const char *list)
+{
+ const char *p, *pstart;
+ char cmd[128];
+ int len;
+
+ p = list;
+ for(;;) {
+ pstart = p;
+ p = qemu_strchrnul(p, '|');
+ len = p - pstart;
+ if (len > sizeof(cmd) - 2)
+ len = sizeof(cmd) - 2;
+ memcpy(cmd, pstart, len);
+ cmd[len] = '\0';
+ if (name[0] == '\0' || !strncmp(name, cmd, strlen(name))) {
+ readline_add_completion(mon->rs, cmd);
+ }
+ if (*p == '\0')
+ break;
+ p++;
+ }
+}
+
+static void file_completion(MonitorHMP *mon, const char *input)
+{
+ DIR *ffs;
+ struct dirent *d;
+ char path[1024];
+ char file[1024], file_prefix[1024];
+ int input_path_len;
+ const char *p;
+
+ p = strrchr(input, '/');
+ if (!p) {
+ input_path_len = 0;
+ pstrcpy(file_prefix, sizeof(file_prefix), input);
+ pstrcpy(path, sizeof(path), ".");
+ } else {
+ input_path_len = p - input + 1;
+ memcpy(path, input, input_path_len);
+ if (input_path_len > sizeof(path) - 1)
+ input_path_len = sizeof(path) - 1;
+ path[input_path_len] = '\0';
+ pstrcpy(file_prefix, sizeof(file_prefix), p + 1);
+ }
+
+ ffs = opendir(path);
+ if (!ffs)
+ return;
+ for(;;) {
+ struct stat sb;
+ d = readdir(ffs);
+ if (!d)
+ break;
+
+ if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) {
+ continue;
+ }
+
+ if (strstart(d->d_name, file_prefix, NULL)) {
+ memcpy(file, input, input_path_len);
+ if (input_path_len < sizeof(file))
+ pstrcpy(file + input_path_len, sizeof(file) - input_path_len,
+ d->d_name);
+ /* stat the file to find out if it's a directory.
+ * In that case add a slash to speed up typing long paths
+ */
+ if (stat(file, &sb) == 0 && S_ISDIR(sb.st_mode)) {
+ pstrcat(file, sizeof(file), "/");
+ }
+ readline_add_completion(mon->rs, file);
+ }
+ }
+ closedir(ffs);
+}
+
+static const char *next_arg_type(const char *typestr)
+{
+ const char *p = strchr(typestr, ':');
+ return (p != NULL ? ++p : typestr);
+}
+
+static void monitor_find_completion_by_table(MonitorHMP *mon,
+ const mon_cmd_t *cmd_table,
+ char **args,
+ int nb_args)
+{
+ const char *cmdname;
+ int i;
+ const char *ptype, *old_ptype, *str, *name;
+ const mon_cmd_t *cmd;
+ BlockBackend *blk = NULL;
+
+ if (nb_args <= 1) {
+ /* command completion */
+ if (nb_args == 0)
+ cmdname = "";
+ else
+ cmdname = args[0];
+ readline_set_completion_index(mon->rs, strlen(cmdname));
+ for (cmd = cmd_table; cmd->name != NULL; cmd++) {
+ if (!runstate_check(RUN_STATE_PRECONFIG) ||
+ cmd_can_preconfig(cmd)) {
+ cmd_completion(mon, cmdname, cmd->name);
+ }
+ }
+ } else {
+ /* find the command */
+ for (cmd = cmd_table; cmd->name != NULL; cmd++) {
+ if (compare_cmd(args[0], cmd->name) &&
+ (!runstate_check(RUN_STATE_PRECONFIG) ||
+ cmd_can_preconfig(cmd))) {
+ break;
+ }
+ }
+ if (!cmd->name) {
+ return;
+ }
+
+ if (cmd->sub_table) {
+ /* do the job again */
+ monitor_find_completion_by_table(mon, cmd->sub_table,
+ &args[1], nb_args - 1);
+ return;
+ }
+ if (cmd->command_completion) {
+ cmd->command_completion(mon->rs, nb_args, args[nb_args - 1]);
+ return;
+ }
+
+ ptype = next_arg_type(cmd->args_type);
+ for(i = 0; i < nb_args - 2; i++) {
+ if (*ptype != '\0') {
+ ptype = next_arg_type(ptype);
+ while (*ptype == '?')
+ ptype = next_arg_type(ptype);
+ }
+ }
+ str = args[nb_args - 1];
+ old_ptype = NULL;
+ while (*ptype == '-' && old_ptype != ptype) {
+ old_ptype = ptype;
+ ptype = next_arg_type(ptype);
+ }
+ switch(*ptype) {
+ case 'F':
+ /* file completion */
+ readline_set_completion_index(mon->rs, strlen(str));
+ file_completion(mon, str);
+ break;
+ case 'B':
+ /* block device name completion */
+ readline_set_completion_index(mon->rs, strlen(str));
+ while ((blk = blk_next(blk)) != NULL) {
+ name = blk_name(blk);
+ if (str[0] == '\0' ||
+ !strncmp(name, str, strlen(str))) {
+ readline_add_completion(mon->rs, name);
+ }
+ }
+ break;
+ case 's':
+ case 'S':
+ if (!strcmp(cmd->name, "help|?")) {
+ monitor_find_completion_by_table(mon, cmd_table,
+ &args[1], nb_args - 1);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void monitor_find_completion(void *opaque,
+ const char *cmdline)
+{
+ MonitorHMP *mon = opaque;
+ char *args[MAX_ARGS];
+ int nb_args, len;
+
+ /* 1. parse the cmdline */
+ if (parse_cmdline(cmdline, &nb_args, args) < 0) {
+ return;
+ }
+
+ /* if the line ends with a space, it means we want to complete the
+ next arg */
+ len = strlen(cmdline);
+ if (len > 0 && qemu_isspace(cmdline[len - 1])) {
+ if (nb_args >= MAX_ARGS) {
+ goto cleanup;
+ }
+ args[nb_args++] = g_strdup("");
+ }
+
+ /* 2. auto complete according to args */
+ monitor_find_completion_by_table(mon, mon->cmd_table, args, nb_args);
+
+cleanup:
+ free_cmdline_args(args, nb_args);
+}
+
+static void monitor_read(void *opaque, const uint8_t *buf, int size)
+{
+ MonitorHMP *mon;
+ Monitor *old_mon = cur_mon;
+ int i;
+
+ cur_mon = opaque;
+ mon = container_of(cur_mon, MonitorHMP, common);
+
+ if (mon->rs) {
+ for (i = 0; i < size; i++) {
+ readline_handle_byte(mon->rs, buf[i]);
+ }
+ } else {
+ if (size == 0 || buf[size - 1] != 0) {
+ monitor_printf(cur_mon, "corrupted command\n");
+ } else {
+ handle_hmp_command(mon, (char *)buf);
+ }
+ }
+
+ cur_mon = old_mon;
+}
+
+static void monitor_event(void *opaque, int event)
+{
+ Monitor *mon = opaque;
+ MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
+
+ switch (event) {
+ case CHR_EVENT_MUX_IN:
+ qemu_mutex_lock(&mon->mon_lock);
+ mon->mux_out = 0;
+ qemu_mutex_unlock(&mon->mon_lock);
+ if (mon->reset_seen) {
+ readline_restart(hmp_mon->rs);
+ monitor_resume(mon);
+ monitor_flush(mon);
+ } else {
+ atomic_mb_set(&mon->suspend_cnt, 0);
+ }
+ break;
+
+ case CHR_EVENT_MUX_OUT:
+ if (mon->reset_seen) {
+ if (atomic_mb_read(&mon->suspend_cnt) == 0) {
+ monitor_printf(mon, "\n");
+ }
+ monitor_flush(mon);
+ monitor_suspend(mon);
+ } else {
+ atomic_inc(&mon->suspend_cnt);
+ }
+ qemu_mutex_lock(&mon->mon_lock);
+ mon->mux_out = 1;
+ qemu_mutex_unlock(&mon->mon_lock);
+ break;
+
+ case CHR_EVENT_OPENED:
+ monitor_printf(mon, "QEMU %s monitor - type 'help' for more "
+ "information\n", QEMU_VERSION);
+ if (!mon->mux_out) {
+ readline_restart(hmp_mon->rs);
+ readline_show_prompt(hmp_mon->rs);
+ }
+ mon->reset_seen = 1;
+ mon_refcount++;
+ break;
+
+ case CHR_EVENT_CLOSED:
+ mon_refcount--;
+ monitor_fdsets_cleanup();
+ break;
+ }
+}
+
+
+/* These functions just adapt the readline interface in a typesafe way. We
+ * could cast function pointers but that discards compiler checks.
+ */
+static void GCC_FMT_ATTR(2, 3) monitor_readline_printf(void *opaque,
+ const char *fmt, ...)
+{
+ MonitorHMP *mon = opaque;
+ va_list ap;
+ va_start(ap, fmt);
+ monitor_vprintf(&mon->common, fmt, ap);
+ va_end(ap);
+}
+
+static void monitor_readline_flush(void *opaque)
+{
+ MonitorHMP *mon = opaque;
+ monitor_flush(&mon->common);
+}
+
+void monitor_data_init_hmp(MonitorHMP *mon, int flags, bool skip_flush)
+{
+ monitor_data_init(&mon->common, flags, skip_flush, false);
+
+ /* Use *mon_cmds by default. */
+ mon->cmd_table = mon_cmds;
+}
+
+void monitor_init_hmp(Chardev *chr, int flags)
+{
+ MonitorHMP *mon = g_malloc0(sizeof(*mon));
+ bool use_readline = flags & MONITOR_USE_READLINE;
+
+ monitor_data_init_hmp(mon, flags, false);
+ qemu_chr_fe_init(&mon->common.chr, chr, &error_abort);
+
+ if (use_readline) {
+ mon->rs = readline_init(monitor_readline_printf,
+ monitor_readline_flush,
+ mon,
+ monitor_find_completion);
+ monitor_read_command(mon, 0);
+ }
+
+ qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, monitor_read,
+ monitor_event, NULL, &mon->common, NULL, true);
+ monitor_list_append(&mon->common);
+}
diff --git a/monitor/misc.c b/monitor/misc.c
index 6c67f0978c..408d11e1fe 100644
--- a/monitor/misc.c
+++ b/monitor/misc.c
@@ -24,7 +24,6 @@
#include "qemu/osdep.h"
#include "monitor_int.h"
-#include "qemu/units.h"
#include <dirent.h>
#include "cpu.h"
#include "hw/hw.h"
@@ -155,7 +154,6 @@ static QLIST_HEAD(, MonFdset) mon_fdsets;
int mon_refcount;
-static mon_cmd_t mon_cmds[];
static mon_cmd_t info_cmds[];
__thread Monitor *cur_mon;
@@ -540,8 +538,6 @@ static void monitor_qapi_event_init(void)
qapi_event_throttle_equal);
}
-static void handle_hmp_command(MonitorHMP *mon, const char *cmdline);
-
static void monitor_iothread_init(void);
void monitor_data_init(Monitor *mon, int flags, bool skip_flush,
@@ -558,14 +554,6 @@ void monitor_data_init(Monitor *mon, int flags, bool skip_flush,
mon->flags = flags;
}
-static void monitor_data_init_hmp(MonitorHMP *mon, int flags, bool skip_flush)
-{
- monitor_data_init(&mon->common, flags, skip_flush, false);
-
- /* Use *mon_cmds by default. */
- mon->cmd_table = mon_cmds;
-}
-
static void monitor_data_destroy(Monitor *mon)
{
g_free(mon->mon_cpu_path);
@@ -619,248 +607,6 @@ out:
return output;
}
-static int compare_cmd(const char *name, const char *list)
-{
- const char *p, *pstart;
- int len;
- len = strlen(name);
- p = list;
- for(;;) {
- pstart = p;
- p = qemu_strchrnul(p, '|');
- if ((p - pstart) == len && !memcmp(pstart, name, len))
- return 1;
- if (*p == '\0')
- break;
- p++;
- }
- return 0;
-}
-
-static int get_str(char *buf, int buf_size, const char **pp)
-{
- const char *p;
- char *q;
- int c;
-
- q = buf;
- p = *pp;
- while (qemu_isspace(*p)) {
- p++;
- }
- if (*p == '\0') {
- fail:
- *q = '\0';
- *pp = p;
- return -1;
- }
- if (*p == '\"') {
- p++;
- while (*p != '\0' && *p != '\"') {
- if (*p == '\\') {
- p++;
- c = *p++;
- switch (c) {
- case 'n':
- c = '\n';
- break;
- case 'r':
- c = '\r';
- break;
- case '\\':
- case '\'':
- case '\"':
- break;
- default:
- printf("unsupported escape code: '\\%c'\n", c);
- goto fail;
- }
- if ((q - buf) < buf_size - 1) {
- *q++ = c;
- }
- } else {
- if ((q - buf) < buf_size - 1) {
- *q++ = *p;
- }
- p++;
- }
- }
- if (*p != '\"') {
- printf("unterminated string\n");
- goto fail;
- }
- p++;
- } else {
- while (*p != '\0' && !qemu_isspace(*p)) {
- if ((q - buf) < buf_size - 1) {
- *q++ = *p;
- }
- p++;
- }
- }
- *q = '\0';
- *pp = p;
- return 0;
-}
-
-#define MAX_ARGS 16
-
-static void free_cmdline_args(char **args, int nb_args)
-{
- int i;
-
- assert(nb_args <= MAX_ARGS);
-
- for (i = 0; i < nb_args; i++) {
- g_free(args[i]);
- }
-
-}
-
-/*
- * Parse the command line to get valid args.
- * @cmdline: command line to be parsed.
- * @pnb_args: location to store the number of args, must NOT be NULL.
- * @args: location to store the args, which should be freed by caller, must
- * NOT be NULL.
- *
- * Returns 0 on success, negative on failure.
- *
- * NOTE: this parser is an approximate form of the real command parser. Number
- * of args have a limit of MAX_ARGS. If cmdline contains more, it will
- * return with failure.
- */
-static int parse_cmdline(const char *cmdline,
- int *pnb_args, char **args)
-{
- const char *p;
- int nb_args, ret;
- char buf[1024];
-
- p = cmdline;
- nb_args = 0;
- for (;;) {
- while (qemu_isspace(*p)) {
- p++;
- }
- if (*p == '\0') {
- break;
- }
- if (nb_args >= MAX_ARGS) {
- goto fail;
- }
- ret = get_str(buf, sizeof(buf), &p);
- if (ret < 0) {
- goto fail;
- }
- args[nb_args] = g_strdup(buf);
- nb_args++;
- }
- *pnb_args = nb_args;
- return 0;
-
- fail:
- free_cmdline_args(args, nb_args);
- return -1;
-}
-
-/*
- * Can command @cmd be executed in preconfig state?
- */
-static bool cmd_can_preconfig(const mon_cmd_t *cmd)
-{
- if (!cmd->flags) {
- return false;
- }
-
- return strchr(cmd->flags, 'p');
-}
-
-static void help_cmd_dump_one(Monitor *mon,
- const mon_cmd_t *cmd,
- char **prefix_args,
- int prefix_args_nb)
-{
- int i;
-
- if (runstate_check(RUN_STATE_PRECONFIG) && !cmd_can_preconfig(cmd)) {
- return;
- }
-
- for (i = 0; i < prefix_args_nb; i++) {
- monitor_printf(mon, "%s ", prefix_args[i]);
- }
- monitor_printf(mon, "%s %s -- %s\n", cmd->name, cmd->params, cmd->help);
-}
-
-/* @args[@arg_index] is the valid command need to find in @cmds */
-static void help_cmd_dump(Monitor *mon, const mon_cmd_t *cmds,
- char **args, int nb_args, int arg_index)
-{
- const mon_cmd_t *cmd;
- size_t i;
-
- /* No valid arg need to compare with, dump all in *cmds */
- if (arg_index >= nb_args) {
- for (cmd = cmds; cmd->name != NULL; cmd++) {
- help_cmd_dump_one(mon, cmd, args, arg_index);
- }
- return;
- }
-
- /* Find one entry to dump */
- for (cmd = cmds; cmd->name != NULL; cmd++) {
- if (compare_cmd(args[arg_index], cmd->name) &&
- ((!runstate_check(RUN_STATE_PRECONFIG) ||
- cmd_can_preconfig(cmd)))) {
- if (cmd->sub_table) {
- /* continue with next arg */
- help_cmd_dump(mon, cmd->sub_table,
- args, nb_args, arg_index + 1);
- } else {
- help_cmd_dump_one(mon, cmd, args, arg_index);
- }
- return;
- }
- }
-
- /* Command not found */
- monitor_printf(mon, "unknown command: '");
- for (i = 0; i <= arg_index; i++) {
- monitor_printf(mon, "%s%s", args[i], i == arg_index ? "'\n" : " ");
- }
-}
-
-static void help_cmd(Monitor *mon, const char *name)
-{
- MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
- char *args[MAX_ARGS];
- int nb_args = 0;
-
- /* 1. parse user input */
- if (name) {
- /* special case for log, directly dump and return */
- if (!strcmp(name, "log")) {
- const QEMULogItem *item;
- monitor_printf(mon, "Log items (comma separated):\n");
- monitor_printf(mon, "%-10s %s\n", "none", "remove all logs");
- for (item = qemu_log_items; item->mask != 0; item++) {
- monitor_printf(mon, "%-10s %s\n", item->name, item->help);
- }
- return;
- }
-
- if (parse_cmdline(name, &nb_args, args) < 0) {
- return;
- }
- }
-
- /* 2. dump the contents according to parsed args */
- help_cmd_dump(mon, hmp_mon->cmd_table, args, nb_args, 0);
-
- free_cmdline_args(args, nb_args);
-}
-
static void do_help_cmd(Monitor *mon, const QDict *qdict)
{
help_cmd(mon, qdict_get_try_str(qdict, "name"));
@@ -2510,30 +2256,16 @@ static mon_cmd_t info_cmds[] = {
};
/* mon_cmds and info_cmds would be sorted at runtime */
-static mon_cmd_t mon_cmds[] = {
+mon_cmd_t mon_cmds[] = {
#include "hmp-commands.h"
{ NULL, NULL, },
};
-/*******************************************************************/
-
-static const char *pch;
-static sigjmp_buf expr_env;
-
-
-static void GCC_FMT_ATTR(2, 3) QEMU_NORETURN
-expr_error(Monitor *mon, const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- monitor_vprintf(mon, fmt, ap);
- monitor_printf(mon, "\n");
- va_end(ap);
- siglongjmp(expr_env, 1);
-}
-
-/* return 0 if OK, -1 if not found */
-static int get_monitor_def(target_long *pval, const char *name)
+/*
+ * Set @pval to the value in the register identified by @name.
+ * return 0 if OK, -1 if not found
+ */
+int get_monitor_def(int64_t *pval, const char *name)
{
const MonitorDef *md = target_monitor_defs();
CPUState *cs = mon_get_cpu();
@@ -2576,829 +2308,6 @@ static int get_monitor_def(target_long *pval, const char *name)
return ret;
}
-static void next(void)
-{
- if (*pch != '\0') {
- pch++;
- while (qemu_isspace(*pch))
- pch++;
- }
-}
-
-static int64_t expr_sum(Monitor *mon);
-
-static int64_t expr_unary(Monitor *mon)
-{
- int64_t n;
- char *p;
- int ret;
-
- switch(*pch) {
- case '+':
- next();
- n = expr_unary(mon);
- break;
- case '-':
- next();
- n = -expr_unary(mon);
- break;
- case '~':
- next();
- n = ~expr_unary(mon);
- break;
- case '(':
- next();
- n = expr_sum(mon);
- if (*pch != ')') {
- expr_error(mon, "')' expected");
- }
- next();
- break;
- case '\'':
- pch++;
- if (*pch == '\0')
- expr_error(mon, "character constant expected");
- n = *pch;
- pch++;
- if (*pch != '\'')
- expr_error(mon, "missing terminating \' character");
- next();
- break;
- case '$':
- {
- char buf[128], *q;
- target_long reg=0;
-
- pch++;
- q = buf;
- while ((*pch >= 'a' && *pch <= 'z') ||
- (*pch >= 'A' && *pch <= 'Z') ||
- (*pch >= '0' && *pch <= '9') ||
- *pch == '_' || *pch == '.') {
- if ((q - buf) < sizeof(buf) - 1)
- *q++ = *pch;
- pch++;
- }
- while (qemu_isspace(*pch))
- pch++;
- *q = 0;
- ret = get_monitor_def(®, buf);
- if (ret < 0)
- expr_error(mon, "unknown register");
- n = reg;
- }
- break;
- case '\0':
- expr_error(mon, "unexpected end of expression");
- n = 0;
- break;
- default:
- errno = 0;
- n = strtoull(pch, &p, 0);
- if (errno == ERANGE) {
- expr_error(mon, "number too large");
- }
- if (pch == p) {
- expr_error(mon, "invalid char '%c' in expression", *p);
- }
- pch = p;
- while (qemu_isspace(*pch))
- pch++;
- break;
- }
- return n;
-}
-
-
-static int64_t expr_prod(Monitor *mon)
-{
- int64_t val, val2;
- int op;
-
- val = expr_unary(mon);
- for(;;) {
- op = *pch;
- if (op != '*' && op != '/' && op != '%')
- break;
- next();
- val2 = expr_unary(mon);
- switch(op) {
- default:
- case '*':
- val *= val2;
- break;
- case '/':
- case '%':
- if (val2 == 0)
- expr_error(mon, "division by zero");
- if (op == '/')
- val /= val2;
- else
- val %= val2;
- break;
- }
- }
- return val;
-}
-
-static int64_t expr_logic(Monitor *mon)
-{
- int64_t val, val2;
- int op;
-
- val = expr_prod(mon);
- for(;;) {
- op = *pch;
- if (op != '&' && op != '|' && op != '^')
- break;
- next();
- val2 = expr_prod(mon);
- switch(op) {
- default:
- case '&':
- val &= val2;
- break;
- case '|':
- val |= val2;
- break;
- case '^':
- val ^= val2;
- break;
- }
- }
- return val;
-}
-
-static int64_t expr_sum(Monitor *mon)
-{
- int64_t val, val2;
- int op;
-
- val = expr_logic(mon);
- for(;;) {
- op = *pch;
- if (op != '+' && op != '-')
- break;
- next();
- val2 = expr_logic(mon);
- if (op == '+')
- val += val2;
- else
- val -= val2;
- }
- return val;
-}
-
-static int get_expr(Monitor *mon, int64_t *pval, const char **pp)
-{
- pch = *pp;
- if (sigsetjmp(expr_env, 0)) {
- *pp = pch;
- return -1;
- }
- while (qemu_isspace(*pch))
- pch++;
- *pval = expr_sum(mon);
- *pp = pch;
- return 0;
-}
-
-static int get_double(Monitor *mon, double *pval, const char **pp)
-{
- const char *p = *pp;
- char *tailp;
- double d;
-
- d = strtod(p, &tailp);
- if (tailp == p) {
- monitor_printf(mon, "Number expected\n");
- return -1;
- }
- if (d != d || d - d != 0) {
- /* NaN or infinity */
- monitor_printf(mon, "Bad number\n");
- return -1;
- }
- *pval = d;
- *pp = tailp;
- return 0;
-}
-
-/*
- * Store the command-name in cmdname, and return a pointer to
- * the remaining of the command string.
- */
-static const char *get_command_name(const char *cmdline,
- char *cmdname, size_t nlen)
-{
- size_t len;
- const char *p, *pstart;
-
- p = cmdline;
- while (qemu_isspace(*p))
- p++;
- if (*p == '\0')
- return NULL;
- pstart = p;
- while (*p != '\0' && *p != '/' && !qemu_isspace(*p))
- p++;
- len = p - pstart;
- if (len > nlen - 1)
- len = nlen - 1;
- memcpy(cmdname, pstart, len);
- cmdname[len] = '\0';
- return p;
-}
-
-/**
- * Read key of 'type' into 'key' and return the current
- * 'type' pointer.
- */
-static char *key_get_info(const char *type, char **key)
-{
- size_t len;
- char *p, *str;
-
- if (*type == ',')
- type++;
-
- p = strchr(type, ':');
- if (!p) {
- *key = NULL;
- return NULL;
- }
- len = p - type;
-
- str = g_malloc(len + 1);
- memcpy(str, type, len);
- str[len] = '\0';
-
- *key = str;
- return ++p;
-}
-
-static int default_fmt_format = 'x';
-static int default_fmt_size = 4;
-
-static int is_valid_option(const char *c, const char *typestr)
-{
- char option[3];
-
- option[0] = '-';
- option[1] = *c;
- option[2] = '\0';
-
- typestr = strstr(typestr, option);
- return (typestr != NULL);
-}
-
-static const mon_cmd_t *search_dispatch_table(const mon_cmd_t *disp_table,
- const char *cmdname)
-{
- const mon_cmd_t *cmd;
-
- for (cmd = disp_table; cmd->name != NULL; cmd++) {
- if (compare_cmd(cmdname, cmd->name)) {
- return cmd;
- }
- }
-
- return NULL;
-}
-
-/*
- * Parse command name from @cmdp according to command table @table.
- * If blank, return NULL.
- * Else, if no valid command can be found, report to @mon, and return
- * NULL.
- * Else, change @cmdp to point right behind the name, and return its
- * command table entry.
- * Do not assume the return value points into @table! It doesn't when
- * the command is found in a sub-command table.
- */
-static const mon_cmd_t *monitor_parse_command(MonitorHMP *hmp_mon,
- const char *cmdp_start,
- const char **cmdp,
- mon_cmd_t *table)
-{
- Monitor *mon = &hmp_mon->common;
- const char *p;
- const mon_cmd_t *cmd;
- char cmdname[256];
-
- /* extract the command name */
- p = get_command_name(*cmdp, cmdname, sizeof(cmdname));
- if (!p)
- return NULL;
-
- cmd = search_dispatch_table(table, cmdname);
- if (!cmd) {
- monitor_printf(mon, "unknown command: '%.*s'\n",
- (int)(p - cmdp_start), cmdp_start);
- return NULL;
- }
- if (runstate_check(RUN_STATE_PRECONFIG) && !cmd_can_preconfig(cmd)) {
- monitor_printf(mon, "Command '%.*s' not available with -preconfig "
- "until after exit_preconfig.\n",
- (int)(p - cmdp_start), cmdp_start);
- return NULL;
- }
-
- /* filter out following useless space */
- while (qemu_isspace(*p)) {
- p++;
- }
-
- *cmdp = p;
- /* search sub command */
- if (cmd->sub_table != NULL && *p != '\0') {
- return monitor_parse_command(hmp_mon, cmdp_start, cmdp, cmd->sub_table);
- }
-
- return cmd;
-}
-
-/*
- * Parse arguments for @cmd.
- * If it can't be parsed, report to @mon, and return NULL.
- * Else, insert command arguments into a QDict, and return it.
- * Note: On success, caller has to free the QDict structure.
- */
-
-static QDict *monitor_parse_arguments(Monitor *mon,
- const char **endp,
- const mon_cmd_t *cmd)
-{
- const char *typestr;
- char *key;
- int c;
- const char *p = *endp;
- char buf[1024];
- QDict *qdict = qdict_new();
-
- /* parse the parameters */
- typestr = cmd->args_type;
- for(;;) {
- typestr = key_get_info(typestr, &key);
- if (!typestr)
- break;
- c = *typestr;
- typestr++;
- switch(c) {
- case 'F':
- case 'B':
- case 's':
- {
- int ret;
-
- while (qemu_isspace(*p))
- p++;
- if (*typestr == '?') {
- typestr++;
- if (*p == '\0') {
- /* no optional string: NULL argument */
- break;
- }
- }
- ret = get_str(buf, sizeof(buf), &p);
- if (ret < 0) {
- switch(c) {
- case 'F':
- monitor_printf(mon, "%s: filename expected\n",
- cmd->name);
- break;
- case 'B':
- monitor_printf(mon, "%s: block device name expected\n",
- cmd->name);
- break;
- default:
- monitor_printf(mon, "%s: string expected\n", cmd->name);
- break;
- }
- goto fail;
- }
- qdict_put_str(qdict, key, buf);
- }
- break;
- case 'O':
- {
- QemuOptsList *opts_list;
- QemuOpts *opts;
-
- opts_list = qemu_find_opts(key);
- if (!opts_list || opts_list->desc->name) {
- goto bad_type;
- }
- while (qemu_isspace(*p)) {
- p++;
- }
- if (!*p)
- break;
- if (get_str(buf, sizeof(buf), &p) < 0) {
- goto fail;
- }
- opts = qemu_opts_parse_noisily(opts_list, buf, true);
- if (!opts) {
- goto fail;
- }
- qemu_opts_to_qdict(opts, qdict);
- qemu_opts_del(opts);
- }
- break;
- case '/':
- {
- int count, format, size;
-
- while (qemu_isspace(*p))
- p++;
- if (*p == '/') {
- /* format found */
- p++;
- count = 1;
- if (qemu_isdigit(*p)) {
- count = 0;
- while (qemu_isdigit(*p)) {
- count = count * 10 + (*p - '0');
- p++;
- }
- }
- size = -1;
- format = -1;
- for(;;) {
- switch(*p) {
- case 'o':
- case 'd':
- case 'u':
- case 'x':
- case 'i':
- case 'c':
- format = *p++;
- break;
- case 'b':
- size = 1;
- p++;
- break;
- case 'h':
- size = 2;
- p++;
- break;
- case 'w':
- size = 4;
- p++;
- break;
- case 'g':
- case 'L':
- size = 8;
- p++;
- break;
- default:
- goto next;
- }
- }
- next:
- if (*p != '\0' && !qemu_isspace(*p)) {
- monitor_printf(mon, "invalid char in format: '%c'\n",
- *p);
- goto fail;
- }
- if (format < 0)
- format = default_fmt_format;
- if (format != 'i') {
- /* for 'i', not specifying a size gives -1 as size */
- if (size < 0)
- size = default_fmt_size;
- default_fmt_size = size;
- }
- default_fmt_format = format;
- } else {
- count = 1;
- format = default_fmt_format;
- if (format != 'i') {
- size = default_fmt_size;
- } else {
- size = -1;
- }
- }
- qdict_put_int(qdict, "count", count);
- qdict_put_int(qdict, "format", format);
- qdict_put_int(qdict, "size", size);
- }
- break;
- case 'i':
- case 'l':
- case 'M':
- {
- int64_t val;
-
- while (qemu_isspace(*p))
- p++;
- if (*typestr == '?' || *typestr == '.') {
- if (*typestr == '?') {
- if (*p == '\0') {
- typestr++;
- break;
- }
- } else {
- if (*p == '.') {
- p++;
- while (qemu_isspace(*p))
- p++;
- } else {
- typestr++;
- break;
- }
- }
- typestr++;
- }
- if (get_expr(mon, &val, &p))
- goto fail;
- /* Check if 'i' is greater than 32-bit */
- if ((c == 'i') && ((val >> 32) & 0xffffffff)) {
- monitor_printf(mon, "\'%s\' has failed: ", cmd->name);
- monitor_printf(mon, "integer is for 32-bit values\n");
- goto fail;
- } else if (c == 'M') {
- if (val < 0) {
- monitor_printf(mon, "enter a positive value\n");
- goto fail;
- }
- val *= MiB;
- }
- qdict_put_int(qdict, key, val);
- }
- break;
- case 'o':
- {
- int ret;
- uint64_t val;
- const char *end;
-
- while (qemu_isspace(*p)) {
- p++;
- }
- if (*typestr == '?') {
- typestr++;
- if (*p == '\0') {
- break;
- }
- }
- ret = qemu_strtosz_MiB(p, &end, &val);
- if (ret < 0 || val > INT64_MAX) {
- monitor_printf(mon, "invalid size\n");
- goto fail;
- }
- qdict_put_int(qdict, key, val);
- p = end;
- }
- break;
- case 'T':
- {
- double val;
-
- while (qemu_isspace(*p))
- p++;
- if (*typestr == '?') {
- typestr++;
- if (*p == '\0') {
- break;
- }
- }
- if (get_double(mon, &val, &p) < 0) {
- goto fail;
- }
- if (p[0] && p[1] == 's') {
- switch (*p) {
- case 'm':
- val /= 1e3; p += 2; break;
- case 'u':
- val /= 1e6; p += 2; break;
- case 'n':
- val /= 1e9; p += 2; break;
- }
- }
- if (*p && !qemu_isspace(*p)) {
- monitor_printf(mon, "Unknown unit suffix\n");
- goto fail;
- }
- qdict_put(qdict, key, qnum_from_double(val));
- }
- break;
- case 'b':
- {
- const char *beg;
- bool val;
-
- while (qemu_isspace(*p)) {
- p++;
- }
- beg = p;
- while (qemu_isgraph(*p)) {
- p++;
- }
- if (p - beg == 2 && !memcmp(beg, "on", p - beg)) {
- val = true;
- } else if (p - beg == 3 && !memcmp(beg, "off", p - beg)) {
- val = false;
- } else {
- monitor_printf(mon, "Expected 'on' or 'off'\n");
- goto fail;
- }
- qdict_put_bool(qdict, key, val);
- }
- break;
- case '-':
- {
- const char *tmp = p;
- int skip_key = 0;
- /* option */
-
- c = *typestr++;
- if (c == '\0')
- goto bad_type;
- while (qemu_isspace(*p))
- p++;
- if (*p == '-') {
- p++;
- if(c != *p) {
- if(!is_valid_option(p, typestr)) {
-
- monitor_printf(mon, "%s: unsupported option -%c\n",
- cmd->name, *p);
- goto fail;
- } else {
- skip_key = 1;
- }
- }
- if(skip_key) {
- p = tmp;
- } else {
- /* has option */
- p++;
- qdict_put_bool(qdict, key, true);
- }
- }
- }
- break;
- case 'S':
- {
- /* package all remaining string */
- int len;
-
- while (qemu_isspace(*p)) {
- p++;
- }
- if (*typestr == '?') {
- typestr++;
- if (*p == '\0') {
- /* no remaining string: NULL argument */
- break;
- }
- }
- len = strlen(p);
- if (len <= 0) {
- monitor_printf(mon, "%s: string expected\n",
- cmd->name);
- goto fail;
- }
- qdict_put_str(qdict, key, p);
- p += len;
- }
- break;
- default:
- bad_type:
- monitor_printf(mon, "%s: unknown type '%c'\n", cmd->name, c);
- goto fail;
- }
- g_free(key);
- key = NULL;
- }
- /* check that all arguments were parsed */
- while (qemu_isspace(*p))
- p++;
- if (*p != '\0') {
- monitor_printf(mon, "%s: extraneous characters at the end of line\n",
- cmd->name);
- goto fail;
- }
-
- return qdict;
-
-fail:
- qobject_unref(qdict);
- g_free(key);
- return NULL;
-}
-
-static void handle_hmp_command(MonitorHMP *mon, const char *cmdline)
-{
- QDict *qdict;
- const mon_cmd_t *cmd;
- const char *cmd_start = cmdline;
-
- trace_handle_hmp_command(mon, cmdline);
-
- cmd = monitor_parse_command(mon, cmdline, &cmdline, mon->cmd_table);
- if (!cmd) {
- return;
- }
-
- qdict = monitor_parse_arguments(&mon->common, &cmdline, cmd);
- if (!qdict) {
- while (cmdline > cmd_start && qemu_isspace(cmdline[-1])) {
- cmdline--;
- }
- monitor_printf(&mon->common, "Try \"help %.*s\" for more information\n",
- (int)(cmdline - cmd_start), cmd_start);
- return;
- }
-
- cmd->cmd(&mon->common, qdict);
- qobject_unref(qdict);
-}
-
-static void cmd_completion(MonitorHMP *mon, const char *name, const char *list)
-{
- const char *p, *pstart;
- char cmd[128];
- int len;
-
- p = list;
- for(;;) {
- pstart = p;
- p = qemu_strchrnul(p, '|');
- len = p - pstart;
- if (len > sizeof(cmd) - 2)
- len = sizeof(cmd) - 2;
- memcpy(cmd, pstart, len);
- cmd[len] = '\0';
- if (name[0] == '\0' || !strncmp(name, cmd, strlen(name))) {
- readline_add_completion(mon->rs, cmd);
- }
- if (*p == '\0')
- break;
- p++;
- }
-}
-
-static void file_completion(MonitorHMP *mon, const char *input)
-{
- DIR *ffs;
- struct dirent *d;
- char path[1024];
- char file[1024], file_prefix[1024];
- int input_path_len;
- const char *p;
-
- p = strrchr(input, '/');
- if (!p) {
- input_path_len = 0;
- pstrcpy(file_prefix, sizeof(file_prefix), input);
- pstrcpy(path, sizeof(path), ".");
- } else {
- input_path_len = p - input + 1;
- memcpy(path, input, input_path_len);
- if (input_path_len > sizeof(path) - 1)
- input_path_len = sizeof(path) - 1;
- path[input_path_len] = '\0';
- pstrcpy(file_prefix, sizeof(file_prefix), p + 1);
- }
-
- ffs = opendir(path);
- if (!ffs)
- return;
- for(;;) {
- struct stat sb;
- d = readdir(ffs);
- if (!d)
- break;
-
- if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) {
- continue;
- }
-
- if (strstart(d->d_name, file_prefix, NULL)) {
- memcpy(file, input, input_path_len);
- if (input_path_len < sizeof(file))
- pstrcpy(file + input_path_len, sizeof(file) - input_path_len,
- d->d_name);
- /* stat the file to find out if it's a directory.
- * In that case add a slash to speed up typing long paths
- */
- if (stat(file, &sb) == 0 && S_ISDIR(sb.st_mode)) {
- pstrcat(file, sizeof(file), "/");
- }
- readline_add_completion(mon->rs, file);
- }
- }
- closedir(ffs);
-}
-
-static const char *next_arg_type(const char *typestr)
-{
- const char *p = strchr(typestr, ':');
- return (p != NULL ? ++p : typestr);
-}
-
static void add_completion_option(ReadLineState *rs, const char *str,
const char *option)
{
@@ -3829,127 +2738,6 @@ void loadvm_completion(ReadLineState *rs, int nb_args, const char *str)
}
}
-static void monitor_find_completion_by_table(MonitorHMP *mon,
- const mon_cmd_t *cmd_table,
- char **args,
- int nb_args)
-{
- const char *cmdname;
- int i;
- const char *ptype, *old_ptype, *str, *name;
- const mon_cmd_t *cmd;
- BlockBackend *blk = NULL;
-
- if (nb_args <= 1) {
- /* command completion */
- if (nb_args == 0)
- cmdname = "";
- else
- cmdname = args[0];
- readline_set_completion_index(mon->rs, strlen(cmdname));
- for (cmd = cmd_table; cmd->name != NULL; cmd++) {
- if (!runstate_check(RUN_STATE_PRECONFIG) ||
- cmd_can_preconfig(cmd)) {
- cmd_completion(mon, cmdname, cmd->name);
- }
- }
- } else {
- /* find the command */
- for (cmd = cmd_table; cmd->name != NULL; cmd++) {
- if (compare_cmd(args[0], cmd->name) &&
- (!runstate_check(RUN_STATE_PRECONFIG) ||
- cmd_can_preconfig(cmd))) {
- break;
- }
- }
- if (!cmd->name) {
- return;
- }
-
- if (cmd->sub_table) {
- /* do the job again */
- monitor_find_completion_by_table(mon, cmd->sub_table,
- &args[1], nb_args - 1);
- return;
- }
- if (cmd->command_completion) {
- cmd->command_completion(mon->rs, nb_args, args[nb_args - 1]);
- return;
- }
-
- ptype = next_arg_type(cmd->args_type);
- for(i = 0; i < nb_args - 2; i++) {
- if (*ptype != '\0') {
- ptype = next_arg_type(ptype);
- while (*ptype == '?')
- ptype = next_arg_type(ptype);
- }
- }
- str = args[nb_args - 1];
- old_ptype = NULL;
- while (*ptype == '-' && old_ptype != ptype) {
- old_ptype = ptype;
- ptype = next_arg_type(ptype);
- }
- switch(*ptype) {
- case 'F':
- /* file completion */
- readline_set_completion_index(mon->rs, strlen(str));
- file_completion(mon, str);
- break;
- case 'B':
- /* block device name completion */
- readline_set_completion_index(mon->rs, strlen(str));
- while ((blk = blk_next(blk)) != NULL) {
- name = blk_name(blk);
- if (str[0] == '\0' ||
- !strncmp(name, str, strlen(str))) {
- readline_add_completion(mon->rs, name);
- }
- }
- break;
- case 's':
- case 'S':
- if (!strcmp(cmd->name, "help|?")) {
- monitor_find_completion_by_table(mon, cmd_table,
- &args[1], nb_args - 1);
- }
- break;
- default:
- break;
- }
- }
-}
-
-static void monitor_find_completion(void *opaque,
- const char *cmdline)
-{
- MonitorHMP *mon = opaque;
- char *args[MAX_ARGS];
- int nb_args, len;
-
- /* 1. parse the cmdline */
- if (parse_cmdline(cmdline, &nb_args, args) < 0) {
- return;
- }
-
- /* if the line ends with a space, it means we want to complete the
- next arg */
- len = strlen(cmdline);
- if (len > 0 && qemu_isspace(cmdline[len - 1])) {
- if (nb_args >= MAX_ARGS) {
- goto cleanup;
- }
- args[nb_args++] = g_strdup("");
- }
-
- /* 2. auto complete according to args */
- monitor_find_completion_by_table(mon, mon->cmd_table, args, nb_args);
-
-cleanup:
- free_cmdline_args(args, nb_args);
-}
-
int monitor_can_read(void *opaque)
{
Monitor *mon = opaque;
@@ -3957,28 +2745,6 @@ int monitor_can_read(void *opaque)
return !atomic_mb_read(&mon->suspend_cnt);
}
-static void monitor_read(void *opaque, const uint8_t *buf, int size)
-{
- MonitorHMP *mon;
- Monitor *old_mon = cur_mon;
- int i;
-
- cur_mon = opaque;
- mon = container_of(cur_mon, MonitorHMP, common);
-
- if (mon->rs) {
- for (i = 0; i < size; i++)
- readline_handle_byte(mon->rs, buf[i]);
- } else {
- if (size == 0 || buf[size - 1] != 0)
- monitor_printf(cur_mon, "corrupted command\n");
- else
- handle_hmp_command(mon, (char *)buf);
- }
-
- cur_mon = old_mon;
-}
-
static void monitor_command_cb(void *opaque, const char *cmdline,
void *readline_opaque)
{
@@ -4043,58 +2809,6 @@ void monitor_resume(Monitor *mon)
trace_monitor_suspend(mon, -1);
}
-static void monitor_event(void *opaque, int event)
-{
- Monitor *mon = opaque;
- MonitorHMP *hmp_mon = container_of(cur_mon, MonitorHMP, common);
-
- switch (event) {
- case CHR_EVENT_MUX_IN:
- qemu_mutex_lock(&mon->mon_lock);
- mon->mux_out = 0;
- qemu_mutex_unlock(&mon->mon_lock);
- if (mon->reset_seen) {
- readline_restart(hmp_mon->rs);
- monitor_resume(mon);
- monitor_flush(mon);
- } else {
- atomic_mb_set(&mon->suspend_cnt, 0);
- }
- break;
-
- case CHR_EVENT_MUX_OUT:
- if (mon->reset_seen) {
- if (atomic_mb_read(&mon->suspend_cnt) == 0) {
- monitor_printf(mon, "\n");
- }
- monitor_flush(mon);
- monitor_suspend(mon);
- } else {
- atomic_inc(&mon->suspend_cnt);
- }
- qemu_mutex_lock(&mon->mon_lock);
- mon->mux_out = 1;
- qemu_mutex_unlock(&mon->mon_lock);
- break;
-
- case CHR_EVENT_OPENED:
- monitor_printf(mon, "QEMU %s monitor - type 'help' for more "
- "information\n", QEMU_VERSION);
- if (!mon->mux_out) {
- readline_restart(hmp_mon->rs);
- readline_show_prompt(hmp_mon->rs);
- }
- mon->reset_seen = 1;
- mon_refcount++;
- break;
-
- case CHR_EVENT_CLOSED:
- mon_refcount--;
- monitor_fdsets_cleanup();
- break;
- }
-}
-
static int
compare_mon_cmd(const void *a, const void *b)
{
@@ -4137,25 +2851,6 @@ void monitor_init_globals(void)
NULL);
}
-/* These functions just adapt the readline interface in a typesafe way. We
- * could cast function pointers but that discards compiler checks.
- */
-static void GCC_FMT_ATTR(2, 3) monitor_readline_printf(void *opaque,
- const char *fmt, ...)
-{
- MonitorHMP *mon = opaque;
- va_list ap;
- va_start(ap, fmt);
- monitor_vprintf(&mon->common, fmt, ap);
- va_end(ap);
-}
-
-static void monitor_readline_flush(void *opaque)
-{
- MonitorHMP *mon = opaque;
- monitor_flush(&mon->common);
-}
-
/*
* Print to current monitor if we have one, else to stderr.
*/
@@ -4198,27 +2893,6 @@ void monitor_list_append(Monitor *mon)
}
}
-static void monitor_init_hmp(Chardev *chr, int flags)
-{
- MonitorHMP *mon = g_malloc0(sizeof(*mon));
- bool use_readline = flags & MONITOR_USE_READLINE;
-
- monitor_data_init_hmp(mon, flags, false);
- qemu_chr_fe_init(&mon->common.chr, chr, &error_abort);
-
- if (use_readline) {
- mon->rs = readline_init(monitor_readline_printf,
- monitor_readline_flush,
- mon,
- monitor_find_completion);
- monitor_read_command(mon, 0);
- }
-
- qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, monitor_read,
- monitor_event, NULL, &mon->common, NULL, true);
- monitor_list_append(&mon->common);
-}
-
void monitor_init(Chardev *chr, int flags)
{
if (flags & MONITOR_USE_CONTROL) {
diff --git a/monitor/Makefile.objs b/monitor/Makefile.objs
index d04d58b583..48c73eed51 100644
--- a/monitor/Makefile.objs
+++ b/monitor/Makefile.objs
@@ -1,2 +1,2 @@
obj-y += misc.o
-common-obj-y += qmp.o
+common-obj-y += qmp.o hmp.o
--
2.20.1
next prev parent reply other threads:[~2019-06-07 14:07 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-06-07 13:54 [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 01/10] monitor: Remove unused password prompting fields Kevin Wolf
2019-06-07 15:39 ` Dr. David Alan Gilbert
2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 02/10] monitor: Split monitor_init in HMP and QMP function Kevin Wolf
2019-06-07 15:46 ` Dr. David Alan Gilbert
2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 03/10] monitor: Make MonitorQMP a child class of Monitor Kevin Wolf
2019-06-07 16:17 ` Dr. David Alan Gilbert
2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 04/10] monitor: Create MonitorHMP with readline state Kevin Wolf
2019-06-07 16:32 ` Dr. David Alan Gilbert
2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 05/10] monitor: Move cmd_table to MonitorHMP Kevin Wolf
2019-06-07 16:35 ` Dr. David Alan Gilbert
2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 06/10] Move monitor.c to monitor/misc.c Kevin Wolf
2019-06-07 16:39 ` Dr. David Alan Gilbert
2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 07/10] monitor: Create monitor_int.h with common definitions Kevin Wolf
2019-06-07 16:52 ` Dr. David Alan Gilbert
2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 08/10] monitor: Split out monitor/qmp.c Kevin Wolf
2019-06-07 16:59 ` Dr. David Alan Gilbert
2019-06-07 13:54 ` Kevin Wolf [this message]
2019-06-07 17:21 ` [Qemu-devel] [RFC PATCH 09/10] monitor: Split out monitor/hmp.c Dr. David Alan Gilbert
2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 10/10] monitor: Split out monitor/core.c Kevin Wolf
2019-06-07 17:29 ` Dr. David Alan Gilbert
2019-06-11 9:22 ` Kevin Wolf
2019-06-11 9:25 ` Dr. David Alan Gilbert
2019-06-07 17:30 ` Dr. David Alan Gilbert
2019-06-07 14:03 ` [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc Daniel P. Berrangé
2019-06-07 14:25 ` Kevin Wolf
2019-06-07 14:31 ` Daniel P. Berrangé
2019-06-07 15:35 ` Dr. David Alan Gilbert
2019-06-07 18:11 ` [Qemu-devel] [Qemu-block] " Eric Blake
2019-06-07 16:48 ` [Qemu-devel] " no-reply
2019-06-07 20:42 ` no-reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190607135430.22149-10-kwolf@redhat.com \
--to=kwolf@redhat.com \
--cc=armbru@redhat.com \
--cc=dgilbert@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.