#include "top.h"
#include "mi-cmds.h"
#include "mi-main.h"
+#include "mi-parse.h"
#include <map>
#include <string>
static std::map<std::string, mi_cmd_up> mi_cmd_table;
+/* MI command with a pure MI implementation. */
+
+struct mi_command_mi : public mi_cmd
+{
+ /* Constructor. For NAME and SUPPRESS_NOTIFICATION see mi_cmd
+ constructor, FUNC is the function called from do_invoke, which
+ implements this MI command. */
+ mi_command_mi (const char *name, mi_cmd_argv_ftype func,
+ int *suppress_notification)
+ : mi_cmd (name, suppress_notification),
+ m_argv_function (func)
+ {
+ gdb_assert (func != nullptr);
+ }
+
+protected:
+
+ /* Called when this MI command has been invoked, calls m_argv_function
+ with arguments contained within PARSE. */
+ void do_invoke (struct mi_parse *parse) const override
+ {
+ mi_parse_argv (parse->args, parse);
+
+ if (parse->argv == nullptr)
+ error (_("Problem parsing arguments: %s %s"), parse->command,
+ parse->args);
+
+ this->m_argv_function (parse->command, parse->argv, parse->argc);
+ }
+
+private:
+
+ /* The function that implements this MI command. */
+ mi_cmd_argv_ftype *m_argv_function;
+};
+
+/* MI command implemented on top of a CLI command. */
+
+struct mi_command_cli : public mi_cmd
+{
+ /* Constructor. For NAME and SUPPRESS_NOTIFICATION see mi_cmd
+ constructor, CLI_NAME is the name of a CLI command that should be
+ invoked to implement this MI command. If ARGS_P is true then any
+ arguments from entered by the user as part of the MI command line are
+ forwarded to CLI_NAME as its argument string, otherwise, if ARGS_P is
+ false, nullptr is send to CLI_NAME as its argument string. */
+ mi_command_cli (const char *name, const char *cli_name, bool args_p,
+ int *suppress_notification)
+ : mi_cmd (name, suppress_notification),
+ m_cli_name (cli_name),
+ m_args_p (args_p)
+ { /* Nothing. */ }
+
+protected:
+
+ /* Called when this MI command has been invoked, calls the m_cli_name
+ CLI function. In m_args_p is true then the argument string from
+ within PARSE is passed through to the CLI function, otherwise nullptr
+ is passed through to the CLI function as its argument string. */
+ void do_invoke (struct mi_parse *parse) const override
+ {
+ const char *args = m_args_p ? parse->args : nullptr;
+ mi_execute_cli_command (m_cli_name, m_args_p, args);
+ }
+
+private:
+
+ /* The name of the CLI command to execute. */
+ const char *m_cli_name;
+
+ /* Should we be passing an argument string to the m_cli_name function? */
+ bool m_args_p;
+};
+
/* Insert COMMAND into the global mi_cmd_table. Return false if
COMMAND->name already exists in mi_cmd_table, in which case COMMAND will
not have been added to mi_cmd_table. Otherwise, return true, and
insert_mi_cmd_entry (mi_cmd_up command)
{
gdb_assert (command != nullptr);
- gdb_assert (command->name != nullptr);
- std::string name (command->name);
+ const std::string &name = command->name ();
if (mi_cmd_table.find (name) != mi_cmd_table.end ())
return false;
return true;
}
-/* Create an mi_cmd structure with name NAME. */
-
-static mi_cmd_up
-create_mi_cmd (const char *name)
-{
- mi_cmd_up cmd (new mi_cmd ());
- cmd->name = name;
- return cmd;
-}
-
/* Create and register a new MI command with an MI specific implementation.
NAME must name an MI command that does not already exist, otherwise an
assertion will trigger. */
add_mi_cmd_mi (const char *name, mi_cmd_argv_ftype function,
int *suppress_notification = nullptr)
{
- mi_cmd_up cmd_up = create_mi_cmd (name);
-
- cmd_up->cli.cmd = nullptr;
- cmd_up->cli.args_p = 0;
- cmd_up->argv_func = function;
- cmd_up->suppress_notification = suppress_notification;
+ mi_cmd_up command (new mi_command_mi (name, function,
+ suppress_notification));
- bool success = insert_mi_cmd_entry (std::move (cmd_up));
+ bool success = insert_mi_cmd_entry (std::move (command));
gdb_assert (success);
}
add_mi_cmd_cli (const char *name, const char *cli_name, int args_p,
int *suppress_notification = nullptr)
{
- mi_cmd_up cmd_up = create_mi_cmd (name);
-
- cmd_up->cli.cmd = cli_name;
- cmd_up->cli.args_p = args_p;
- cmd_up->argv_func = nullptr;
- cmd_up->suppress_notification = suppress_notification;
+ mi_cmd_up command (new mi_command_cli (name, cli_name, args_p != 0,
+ suppress_notification));
- bool success = insert_mi_cmd_entry (std::move (cmd_up));
+ bool success = insert_mi_cmd_entry (std::move (command));
gdb_assert (success);
}
-/* Initialize MI_CMD_TABLE, the global map of MI commands. */
+/* See mi-cmds.h. */
+
+mi_cmd::mi_cmd (const char *name, int *suppress_notification)
+ : m_name (name),
+ m_suppress_notification (suppress_notification)
+{
+ gdb_assert (m_name != nullptr && m_name[0] != '\0');
+}
+
+/* See mi-cmds.h. */
+
+void
+mi_cmd::invoke (struct mi_parse *parse) const
+{
+ gdb::optional<scoped_restore_tmpl<int>> restore
+ = do_suppress_notification ();
+ this->do_invoke (parse);
+}
+
+/* See mi-cmds.h. */
+
+gdb::optional<scoped_restore_tmpl<int>>
+mi_cmd::do_suppress_notification () const
+{
+ if (m_suppress_notification != nullptr)
+ return scoped_restore_tmpl<int> (m_suppress_notification, 1);
+ else
+ return {};
+}
+
+/* Initialize the available MI commands. */
static void
build_table ()
#ifndef MI_MI_CMDS_H
#define MI_MI_CMDS_H
+#include "gdbsupport/gdb_optional.h"
+
enum print_values {
PRINT_NO_VALUES,
PRINT_ALL_VALUES,
extern mi_cmd_argv_ftype mi_cmd_var_set_update_range;
extern mi_cmd_argv_ftype mi_cmd_complete;
-/* Description of a single command. */
-
-struct mi_cli
-{
- /* Corresponding CLI command. If ARGS_P is non-zero, the MI
- command's argument list is appended to the CLI command. */
- const char *cmd;
- int args_p;
-};
+/* The abstract base class for all MI command types. */
struct mi_cmd
{
- /* Official name of the command. */
- const char *name;
- /* The corresponding CLI command that can be used to implement this
- MI command (if cli.lhs is non NULL). */
- struct mi_cli cli;
- /* If non-null, the function implementing the MI command. */
- mi_cmd_argv_ftype *argv_func;
- /* If non-null, the pointer to a field in
- 'struct mi_suppress_notification', which will be set to true by MI
- command processor (mi-main.c:mi_cmd_execute) when this command is
- being executed. It will be set back to false when command has been
- executed. */
- int *suppress_notification;
+ /* Constructor. NAME is the name of this MI command, excluding any
+ leading dash, that is the initial string the user will enter to run
+ this command. The SUPPRESS_NOTIFICATION pointer is a flag which will
+ be set to 1 when this command is invoked, and reset to its previous
+ value once the command invocation has completed. */
+ mi_cmd (const char *name, int *suppress_notification);
+
+ /* Destructor. */
+ virtual ~mi_cmd () = default;
+
+ /* Return the name of this command. This is the command that the user
+ will actually type in, without any arguments, and without the leading
+ dash. */
+ const char *name () const
+ { return m_name; }
+
+ /* Execute the MI command. Can throw an exception if something goes
+ wrong. */
+ void invoke (struct mi_parse *parse) const;
+
+protected:
+
+ /* The core of command invocation, this needs to be overridden in each
+ base class. PARSE is the parsed command line from the user. */
+ virtual void do_invoke (struct mi_parse *parse) const = 0;
+
+private:
+
+ /* If this command was created with a suppress notifications pointer,
+ then this function will set the suppress flag and return a
+ gdb::optional with its value set to an object that will restore the
+ previous value of the suppress notifications flag.
+
+ If this command was created without a suppress notifications points,
+ then this function returns an empty gdb::optional. */
+ gdb::optional<scoped_restore_tmpl<int>> do_suppress_notification () const;
+
+ /* The name of the command. */
+ const char *m_name;
+
+ /* Pointer to integer to set during command's invocation. */
+ int *m_suppress_notification;
};
/* Lookup a command in the MI command table, returns nullptr if COMMAND is
not found. */
-extern struct mi_cmd *mi_cmd_lookup (const char *command);
+extern mi_cmd *mi_cmd_lookup (const char *command);
/* Debug flag */
extern int mi_debug_p;
static void mi_cmd_execute (struct mi_parse *parse);
-static void mi_execute_cli_command (const char *cmd, bool args_p,
- const char *args);
static void mi_execute_async_cli_command (const char *cli_command,
char **argv, int argc);
static bool register_changed_p (int regnum, readonly_detached_regcache *,
{
ptid_t previous_ptid = inferior_ptid;
- gdb::optional<scoped_restore_tmpl<int>> restore_suppress;
-
- if (command->cmd != NULL && command->cmd->suppress_notification != NULL)
- restore_suppress.emplace (command->cmd->suppress_notification, 1);
-
command->token = token;
if (do_timings)
current_context = parse;
- if (parse->cmd->argv_func != NULL)
- {
- parse->cmd->argv_func (parse->command, parse->argv, parse->argc);
- }
- else if (parse->cmd->cli.cmd != 0)
- {
- /* FIXME: DELETE THIS. */
- /* The operation is still implemented by a cli command. */
- /* Must be a synchronous one. */
- bool args_p = parse->cmd->cli.args_p != 0;
- const char *args = args_p ? parse->args : nullptr;
- mi_execute_cli_command (parse->cmd->cli.cmd, args_p, args);
- }
- else
- {
- /* FIXME: DELETE THIS. */
- string_file stb;
-
- stb.puts ("Undefined mi command: ");
- stb.putstr (parse->command, '"');
- stb.puts (" (missing implementation)");
-
- error_stream (stb);
- }
+ gdb_assert (parse->cmd != nullptr);
+ parse->cmd->invoke (parse);
}
-/* FIXME: This is just a hack so we can get some extra commands going.
- We don't want to channel things through the CLI, but call libgdb directly.
- Use only for synchronous commands. */
+/* See mi-main.h. */
void
mi_execute_cli_command (const char *cmd, bool args_p, const char *args)
};
extern struct mi_suppress_notification mi_suppress_notification;
+/* This is a hack so we can get some extra commands going, but has existed
+ within GDB for many years now. Ideally we don't want to channel things
+ through the CLI, but implement all commands as pure MI commands with
+ their own implementation.
+
+ Execute the CLI command CMD, if ARGS_P is true then ARGS should be a
+ non-nullptr string containing arguments to add after CMD. If ARGS_P is
+ false then ARGS must be nullptr. */
+
+extern void mi_execute_cli_command (const char *cmd, bool args_p,
+ const char *args);
+
/* Implementation of -fix-multi-location-breakpoint-output. */
extern void mi_cmd_fix_multi_location_breakpoint_output (const char *command,
return c;
}
-static void
+void
mi_parse_argv (const char *args, struct mi_parse *parse)
{
const char *chp = args;
chp = skip_spaces (chp);
}
- /* For new argv commands, attempt to return the parsed argument
- list. */
- if (parse->cmd->argv_func != NULL)
- {
- mi_parse_argv (chp, parse.get ());
- if (parse->argv == NULL)
- error (_("Problem parsing arguments: %s %s"), parse->command, chp);
- }
-
- /* FIXME: DELETE THIS */
- /* For CLI commands, also return the remainder of the
- command line as a single string. */
- if (parse->cmd->cli.cmd != NULL)
- parse->args = xstrdup (chp);
+ /* Save the rest of the arguments for the command. */
+ parse->args = xstrdup (chp);
/* Fully parsed, flag as an MI command. */
parse->op = MI_COMMAND;
enum print_values mi_parse_print_values (const char *name);
+/* Split ARGS into argc/argv and store the result in PARSE. */
+
+extern void mi_parse_argv (const char *args, struct mi_parse *parse);
+
#endif /* MI_MI_PARSE_H */