[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-block] [RFC PATCH 09/10] monitor: Split out monitor/hmp.c
From: |
Dr. David Alan Gilbert |
Subject: |
Re: [Qemu-block] [RFC PATCH 09/10] monitor: Split out monitor/hmp.c |
Date: |
Fri, 7 Jun 2019 18:21:35 +0100 |
User-agent: |
Mutt/1.11.4 (2019-03-13) |
* Kevin Wolf (address@hidden) wrote:
> 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>
(The target_long change was well hidden!)
Reviewed-by: Dr. David Alan Gilbert <address@hidden>
> ---
> 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
>
--
Dr. David Alan Gilbert / address@hidden / Manchester, UK
Re: [Qemu-block] [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc, no-reply, 2019/06/07
Re: [Qemu-block] [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc, no-reply, 2019/06/07