mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-27 22:48:57 +08:00
gdb/mi: use separate classes for different types of MI command
This commit changes the infrastructure in mi-cmds.{c,h} to add new sub-classes for the different types of MI command. Instances of these sub-classes are then created and added into mi_cmd_table. The existing mi_cmd class becomes the abstract base class, this has an invoke method and takes care of the suppress notifications handling, before calling a do_invoke virtual method which is implemented by all of the sub-classes. There's currently two different sub-classes, one of pure MI commands, and a second for MI commands that delegate to CLI commands. There should be no user visible changes after this commit.
This commit is contained in:

committed by
Andrew Burgess

parent
3be0fed62e
commit
1f6c8c3317
140
gdb/mi/mi-cmds.c
140
gdb/mi/mi-cmds.c
@ -22,6 +22,7 @@
|
||||
#include "top.h"
|
||||
#include "mi-cmds.h"
|
||||
#include "mi-main.h"
|
||||
#include "mi-parse.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
@ -33,6 +34,80 @@ using mi_cmd_up = std::unique_ptr<struct mi_cmd>;
|
||||
|
||||
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
|
||||
@ -42,9 +117,8 @@ static bool
|
||||
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;
|
||||
@ -53,16 +127,6 @@ insert_mi_cmd_entry (mi_cmd_up command)
|
||||
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. */
|
||||
@ -71,14 +135,10 @@ static void
|
||||
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);
|
||||
mi_cmd_up command (new mi_command_mi (name, function,
|
||||
suppress_notification));
|
||||
|
||||
cmd_up->cli.cmd = nullptr;
|
||||
cmd_up->cli.args_p = 0;
|
||||
cmd_up->argv_func = function;
|
||||
cmd_up->suppress_notification = suppress_notification;
|
||||
|
||||
bool success = insert_mi_cmd_entry (std::move (cmd_up));
|
||||
bool success = insert_mi_cmd_entry (std::move (command));
|
||||
gdb_assert (success);
|
||||
}
|
||||
|
||||
@ -90,18 +150,44 @@ static void
|
||||
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);
|
||||
mi_cmd_up command (new mi_command_cli (name, cli_name, args_p != 0,
|
||||
suppress_notification));
|
||||
|
||||
cmd_up->cli.cmd = cli_name;
|
||||
cmd_up->cli.args_p = args_p;
|
||||
cmd_up->argv_func = nullptr;
|
||||
cmd_up->suppress_notification = 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 ()
|
||||
|
@ -22,6 +22,8 @@
|
||||
#ifndef MI_MI_CMDS_H
|
||||
#define MI_MI_CMDS_H
|
||||
|
||||
#include "gdbsupport/gdb_optional.h"
|
||||
|
||||
enum print_values {
|
||||
PRINT_NO_VALUES,
|
||||
PRINT_ALL_VALUES,
|
||||
@ -137,37 +139,58 @@ extern mi_cmd_argv_ftype mi_cmd_enable_frame_filters;
|
||||
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;
|
||||
|
@ -90,8 +90,6 @@ int mi_proceeded;
|
||||
|
||||
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 *,
|
||||
@ -1936,11 +1934,6 @@ mi_execute_command (const char *cmd, int from_tty)
|
||||
{
|
||||
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)
|
||||
@ -2079,35 +2072,11 @@ mi_cmd_execute (struct mi_parse *parse)
|
||||
|
||||
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)
|
||||
|
@ -54,6 +54,18 @@ struct mi_suppress_notification
|
||||
};
|
||||
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,
|
||||
|
@ -106,7 +106,7 @@ mi_parse_escape (const char **string_ptr)
|
||||
return c;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
mi_parse_argv (const char *args, struct mi_parse *parse)
|
||||
{
|
||||
const char *chp = args;
|
||||
@ -363,20 +363,8 @@ mi_parse (const char *cmd, char **token)
|
||||
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;
|
||||
|
@ -79,4 +79,8 @@ extern std::unique_ptr<struct mi_parse> mi_parse (const char *cmd,
|
||||
|
||||
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 */
|
||||
|
Reference in New Issue
Block a user