From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 2424E3858025 for ; Fri, 3 Dec 2021 16:30:13 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 2424E3858025 Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-47-FTdrhJL8PCGZTjWBkxumUw-1; Fri, 03 Dec 2021 11:30:11 -0500 X-MC-Unique: FTdrhJL8PCGZTjWBkxumUw-1 Received: by mail-wm1-f70.google.com with SMTP id a85-20020a1c7f58000000b0033ddc0eacc8so3664644wmd.9 for ; Fri, 03 Dec 2021 08:30:11 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=bo1v8+i6nofZ2FUgHhy/Qro+zqEflceMcFbbbek5lb0=; b=tNYsB5S3cAikcIQPZZz60pXbGHN4o18EChpSZI37ukAKbV3qDOglh4me9RvXHe2a4v X4QH+izXtGq6JP8Q96L551/bYyWwgoBWxZMv22pdeWJY0eKSVj93wHwcC40sQYIC52Jj VBuIKRTJzZqAEb5uhCLKIAacXXmmBKF34gVUmeC3TOmJwwv5dI8/0KUx0sdBD3FjWlqO kmO8DgYq+AbFAHsCtMQ6rEMMFzAPP7bjxgTlgBq0cT50336mJmPxnVVi4vktD56ntOgn q/mA3sqG2AyV5Y5hGy2mnahN58ZYbjeEi6PFVlMs7HHLT0+uv/68mBo+6D65fGDg1Bv9 A7iA== X-Gm-Message-State: AOAM532SJ5q2O2G7t0Cq0Qi6zvS1mfpF+8j1iWew+EOtd7x70rhxDSx2 OETT2xeAXOw7vkcj82Ly+5+9lCi1xNDe1TNsa5pKQyKFZzXq03c9iO0WkRKvtbWrWteqLfhJ/iP MVg3o0CgUwdViPH2jVj4afZWbNP7eDOTJBdSQwb10ZxaZAaOkeCbkY4mDxqaEhc5ga1OuqgPtAA == X-Received: by 2002:adf:e512:: with SMTP id j18mr22912352wrm.532.1638549009918; Fri, 03 Dec 2021 08:30:09 -0800 (PST) X-Google-Smtp-Source: ABdhPJwvT+L77kYnRnRapI/71qGewCIjbesgCbrb9abEOaG+tEnVdcYBq5EAgxOrw0Cau4gfB0A+KQ== X-Received: by 2002:adf:e512:: with SMTP id j18mr22912295wrm.532.1638549009370; Fri, 03 Dec 2021 08:30:09 -0800 (PST) Received: from localhost (host86-134-238-138.range86-134.btcentralplus.com. [86.134.238.138]) by smtp.gmail.com with ESMTPSA id s8sm3269810wra.9.2021.12.03.08.30.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 03 Dec 2021 08:30:09 -0800 (PST) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Jan Vrany Subject: [PATCHv2 4/5] gdb/mi: use separate classes for different types of MI command Date: Fri, 3 Dec 2021 16:29:59 +0000 Message-Id: <79f9acb59f96d9353b55f81a1f0c6bb1dcfc5b3c.1638548421.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="US-ASCII" X-Spam-Status: No, score=-10.6 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 03 Dec 2021 16:30:15 -0000 From: Jan Vrany 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. --- gdb/mi/mi-cmds.c | 140 +++++++++++++++++++++++++++++++++++++--------- gdb/mi/mi-cmds.h | 67 ++++++++++++++-------- gdb/mi/mi-main.c | 37 +----------- gdb/mi/mi-main.h | 12 ++++ gdb/mi/mi-parse.c | 18 +----- gdb/mi/mi-parse.h | 4 ++ 6 files changed, 179 insertions(+), 99 deletions(-) diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c index 4999c9f81b3..c3e5b4d3263 100644 --- a/gdb/mi/mi-cmds.c +++ b/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 #include @@ -33,6 +34,81 @@ typedef std::unique_ptr mi_cmd_up; static std::map 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.c_str (), m_args_p ? 1 : 0, + args); + } + +private: + + /* The name of the CLI command to execute. */ + std::string 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 +118,9 @@ static bool insert_mi_cmd_entry (mi_cmd_up command) { gdb_assert (command != nullptr); - gdb_assert (command->name != nullptr); + gdb_assert (!command->name ().empty ()); - 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 +129,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 +137,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); - - 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); } @@ -90,18 +152,42 @@ 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) +{ /* Nothing. */ } + +/* See mi-cmds.h. */ + +void +mi_cmd::invoke (struct mi_parse *parse) const +{ + gdb::optional> restore + = do_suppress_notification (); + this->do_invoke (parse); +} + +/* See mi-cmds.h. */ + +gdb::optional> +mi_cmd::do_suppress_notification () const +{ + if (m_suppress_notification != nullptr) + return scoped_restore_tmpl (m_suppress_notification, 1); + else + return {}; +} + +/* Initialize the available MI commands. */ static void build_table () diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h index e92737be8c8..b859ff21da7 100644 --- a/gdb/mi/mi-cmds.h +++ b/gdb/mi/mi-cmds.h @@ -22,6 +22,7 @@ #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 +138,57 @@ 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, 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 () { /* Nothing. */ } + + /* Return the name of this command. This is the command that the user + will actually type in, without any arguments. */ + const std::string &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> do_suppress_notification () const; + + /* The name of the command. */ + std::string 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; diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index 269c01d5176..710eef7e725 100644 --- a/gdb/mi/mi-main.c +++ b/gdb/mi/mi-main.c @@ -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> 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) diff --git a/gdb/mi/mi-main.h b/gdb/mi/mi-main.h index 7f986969450..064f1d587f2 100644 --- a/gdb/mi/mi-main.h +++ b/gdb/mi/mi-main.h @@ -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, diff --git a/gdb/mi/mi-parse.c b/gdb/mi/mi-parse.c index b5b01cf4db0..203024fb01c 100644 --- a/gdb/mi/mi-parse.c +++ b/gdb/mi/mi-parse.c @@ -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; diff --git a/gdb/mi/mi-parse.h b/gdb/mi/mi-parse.h index a60ce5b3a20..ceaac72e867 100644 --- a/gdb/mi/mi-parse.h +++ b/gdb/mi/mi-parse.h @@ -79,4 +79,8 @@ extern std::unique_ptr 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 */ -- 2.25.4