qemu-block
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-block] [PATCH v2 10/11] monitor: Split out monitor/hmp.c


From: Kevin Wolf
Subject: [Qemu-block] [PATCH v2 10/11] monitor: Split out monitor/hmp.c
Date: Tue, 11 Jun 2019 15:40:42 +0200

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 <address@hidden>
Reviewed-by: Dr. David Alan Gilbert <address@hidden>
---
 include/monitor/monitor.h |    1 +
 monitor/monitor_int.h     |   31 +
 monitor/hmp.c             | 1387 +++++++++++++++++++++++++++++++++++++
 monitor/misc.c            | 1338 +----------------------------------
 monitor/Makefile.objs     |    2 +-
 monitor/trace-events      |    4 +-
 6 files changed, 1429 insertions(+), 1334 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 4aabee54e1..88eaed9c5c 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"
@@ -154,6 +155,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;
@@ -162,6 +186,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);
@@ -173,4 +199,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..bb5a59b8c8
--- /dev/null
+++ b/monitor/hmp.c
@@ -0,0 +1,1387 @@
+/*
+ * 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.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(&reg, 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 7e6f09106c..4f1168b7c3 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"));
@@ -2512,30 +2258,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();
@@ -2578,829 +2310,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(&reg, 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)
 {
@@ -3831,127 +2740,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;
@@ -3959,28 +2747,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)
 {
@@ -4045,58 +2811,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)
 {
@@ -4139,25 +2853,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.
  */
@@ -4200,27 +2895,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 1037c09ff8..bea8838acc 100644
--- a/monitor/Makefile.objs
+++ b/monitor/Makefile.objs
@@ -1,3 +1,3 @@
 obj-y += misc.o
-common-obj-y += qmp.o
+common-obj-y += qmp.o hmp.o
 common-obj-y += qmp-cmds.o hmp-cmds.o
diff --git a/monitor/trace-events b/monitor/trace-events
index a06dde3fd3..2285d26121 100644
--- a/monitor/trace-events
+++ b/monitor/trace-events
@@ -1,10 +1,12 @@
 # See docs/devel/tracing.txt for syntax documentation.
 
+# hmp.c
+handle_hmp_command(void *mon, const char *cmdline) "mon %p cmdline: %s"
+
 # misc.c
 monitor_protocol_event_handler(uint32_t event, void *qdict) "event=%d data=%p"
 monitor_protocol_event_emit(uint32_t event, void *data) "event=%d data=%p"
 monitor_protocol_event_queue(uint32_t event, void *qdict, uint64_t rate) 
"event=%d data=%p rate=%" PRId64
-handle_hmp_command(void *mon, const char *cmdline) "mon %p cmdline: %s"
 monitor_suspend(void *ptr, int cnt) "mon %p: %d"
 
 # qmp.c
-- 
2.20.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]