From patchwork Wed Apr 25 15:41:33 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Tromey X-Patchwork-Id: 26962 Received: (qmail 2225 invoked by alias); 25 Apr 2018 15:41:44 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 2102 invoked by uid 89); 25 Apr 2018 15:41:44 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=breakpoints, 1356 X-HELO: gateway24.websitewelcome.com Received: from gateway24.websitewelcome.com (HELO gateway24.websitewelcome.com) (192.185.50.66) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 25 Apr 2018 15:41:39 +0000 Received: from cm16.websitewelcome.com (cm16.websitewelcome.com [100.42.49.19]) by gateway24.websitewelcome.com (Postfix) with ESMTP id 7CFB9360D60 for ; Wed, 25 Apr 2018 10:41:38 -0500 (CDT) Received: from box5379.bluehost.com ([162.241.216.53]) by cmsmtp with SMTP id BMY6fdPtFWCOCBMY6fXxDn; Wed, 25 Apr 2018 10:41:38 -0500 X-Authority-Reason: nr=8 Received: from 97-122-176-117.hlrn.qwest.net ([97.122.176.117]:55830 helo=bapiya.Home) by box5379.bluehost.com with esmtpsa (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.89_1) (envelope-from ) id 1fBMY6-001wTf-8g; Wed, 25 Apr 2018 10:41:38 -0500 From: Tom Tromey To: gdb-patches@sourceware.org Cc: Tom Tromey Subject: [RFA v2 8/8] Let gdb.execute handle multi-line commands Date: Wed, 25 Apr 2018 09:41:33 -0600 Message-Id: <20180425154133.3989-9-tom@tromey.com> In-Reply-To: <20180425154133.3989-1-tom@tromey.com> References: <20180425154133.3989-1-tom@tromey.com> X-BWhitelist: no X-Source-L: No X-Exim-ID: 1fBMY6-001wTf-8g X-Source-Sender: 97-122-176-117.hlrn.qwest.net (bapiya.Home) [97.122.176.117]:55830 X-Source-Auth: tom+tromey.com X-Email-Count: 11 X-Source-Cap: ZWx5bnJvYmk7ZWx5bnJvYmk7Ym94NTM3OS5ibHVlaG9zdC5jb20= X-Local-Domain: yes This changes the Python API so that gdb.execute can now handle multi-line commands, like "commands" or "define". gdb/ChangeLog 2018-04-25 Tom Tromey PR python/22730: * NEWS: Mention gdb.execute change. * gdbcmd.h (execute_control_command): Don't declare. * python/python.c (execute_gdb_command): Use read_command_lines_1, execute_control_commands, execute_control_commands_to_string. * cli/cli-script.h (execute_control_commands) (execute_control_commands_to_string): Declare. (execute_control_command): Add from_tty parameter. * cli/cli-script.c (execute_control_commands) (execute_control_commands_to_string): New functions. (execute_user_command): Use execute_control_commands. (execute_control_command_1): Add "from_tty" parameter. Update. (execute_control_command): Likewise. gdb/testsuite/ChangeLog 2018-04-25 Tom Tromey PR python/22730: * gdb.python/python.exp: Test multi-line execute. --- gdb/ChangeLog | 16 +++++++ gdb/NEWS | 2 + gdb/cli/cli-script.c | 93 ++++++++++++++++++++++++++----------- gdb/cli/cli-script.h | 15 +++++- gdb/gdbcmd.h | 2 - gdb/python/python.c | 19 +++++++- gdb/testsuite/ChangeLog | 5 ++ gdb/testsuite/gdb.python/python.exp | 3 ++ 8 files changed, 123 insertions(+), 32 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index 14d5fbb7c0..a72ee21cf8 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -29,6 +29,8 @@ set|show record btrace cpu ** The commands attached to a breakpoint can be set by assigning to the breakpoint's "commands" field. + ** gdb.execute can now execute multi-line gdb commands. + * New targets RiscV ELF riscv*-*-elf diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c index e336c58ad0..a62e4fe1c1 100644 --- a/gdb/cli/cli-script.c +++ b/gdb/cli/cli-script.c @@ -374,12 +374,69 @@ execute_cmd_post_hook (struct cmd_list_element *c) } } +/* See cli-script.h. */ + +void +execute_control_commands (struct command_line *cmdlines, int from_tty) +{ + /* Set the instream to 0, indicating execution of a + user-defined function. */ + scoped_restore restore_instream + = make_scoped_restore (¤t_ui->instream, nullptr); + scoped_restore save_async = make_scoped_restore (¤t_ui->async, 0); + scoped_restore save_nesting + = make_scoped_restore (&command_nest_depth, command_nest_depth + 1); + + while (cmdlines) + { + enum command_control_type ret = execute_control_command (cmdlines, + from_tty); + if (ret != simple_control && ret != break_control) + { + warning (_("Error executing canned sequence of commands.")); + break; + } + cmdlines = cmdlines->next; + } +} + +/* See cli-script.h. */ + +std::string +execute_control_commands_to_string (struct command_line *commands, + int from_tty) +{ + /* GDB_STDOUT should be better already restored during these + restoration callbacks. */ + set_batch_flag_and_restore_page_info save_page_info; + + string_file str_file; + + { + current_uiout->redirect (&str_file); + ui_out_redirect_pop redirect_popper (current_uiout); + + scoped_restore save_stdout + = make_scoped_restore (&gdb_stdout, &str_file); + scoped_restore save_stderr + = make_scoped_restore (&gdb_stderr, &str_file); + scoped_restore save_stdlog + = make_scoped_restore (&gdb_stdlog, &str_file); + scoped_restore save_stdtarg + = make_scoped_restore (&gdb_stdtarg, &str_file); + scoped_restore save_stdtargerr + = make_scoped_restore (&gdb_stdtargerr, &str_file); + + execute_control_commands (commands, from_tty); + } + + return std::move (str_file.string ()); +} + void execute_user_command (struct cmd_list_element *c, const char *args) { - struct ui *ui = current_ui; counted_command_line cmdlines_copy; - enum command_control_type ret; extern unsigned int max_user_call_depth; /* Ensure that the user commands can't be deleted while they are @@ -395,25 +452,7 @@ execute_user_command (struct cmd_list_element *c, const char *args) if (user_args_stack.size () > max_user_call_depth) error (_("Max user call depth exceeded -- command aborted.")); - /* Set the instream to 0, indicating execution of a - user-defined function. */ - scoped_restore restore_instream - = make_scoped_restore (&ui->instream, nullptr); - - scoped_restore save_async = make_scoped_restore (¤t_ui->async, 0); - - scoped_restore save_nesting - = make_scoped_restore (&command_nest_depth, command_nest_depth + 1); - while (cmdlines) - { - ret = execute_control_command (cmdlines); - if (ret != simple_control && ret != break_control) - { - warning (_("Error executing canned sequence of commands.")); - break; - } - cmdlines = cmdlines->next; - } + execute_control_commands (cmdlines, 0); } /* This function is called every time GDB prints a prompt. It ensures @@ -465,7 +504,7 @@ print_command_trace (const char *fmt, ...) /* Helper for execute_control_command. */ static enum command_control_type -execute_control_command_1 (struct command_line *cmd) +execute_control_command_1 (struct command_line *cmd, int from_tty) { struct command_line *current; struct value *val; @@ -483,7 +522,7 @@ execute_control_command_1 (struct command_line *cmd) { /* A simple command, execute it and return. */ std::string new_line = insert_user_defined_cmd_args (cmd->line); - execute_command (new_line.c_str (), 0); + execute_command (new_line.c_str (), from_tty); ret = cmd->control_type; break; } @@ -538,7 +577,7 @@ execute_control_command_1 (struct command_line *cmd) { scoped_restore save_nesting = make_scoped_restore (&command_nest_depth, command_nest_depth + 1); - ret = execute_control_command_1 (current); + ret = execute_control_command_1 (current, from_tty); /* If we got an error, or a "break" command, then stop looping. */ @@ -593,7 +632,7 @@ execute_control_command_1 (struct command_line *cmd) { scoped_restore save_nesting = make_scoped_restore (&command_nest_depth, command_nest_depth + 1); - ret = execute_control_command_1 (current); + ret = execute_control_command_1 (current, from_tty); /* If we got an error, get out. */ if (ret != simple_control) @@ -644,7 +683,7 @@ execute_control_command_1 (struct command_line *cmd) } enum command_control_type -execute_control_command (struct command_line *cmd) +execute_control_command (struct command_line *cmd, int from_tty) { /* Make sure we use the console uiout. It's possible that we are executing breakpoint commands while running the MI interpreter. */ @@ -652,7 +691,7 @@ execute_control_command (struct command_line *cmd) scoped_restore save_uiout = make_scoped_restore (¤t_uiout, interp_ui_out (console)); - return execute_control_command_1 (cmd); + return execute_control_command_1 (cmd, from_tty); } /* Like execute_control_command, but first set diff --git a/gdb/cli/cli-script.h b/gdb/cli/cli-script.h index 3bebd0ed9d..736ebb3a7b 100644 --- a/gdb/cli/cli-script.h +++ b/gdb/cli/cli-script.h @@ -122,10 +122,23 @@ extern void show_user_1 (struct cmd_list_element *c, const char *name, struct ui_file *stream); +/* Execute the commands in CMDLINES. */ + +extern void execute_control_commands (struct command_line *cmdlines, + int from_tty); + +/* Run execute_control_commands for COMMANDS. Capture its output into + the returned string, do not display it to the screen. BATCH_FLAG + will be temporarily set to true. */ + +extern std::string execute_control_commands_to_string + (struct command_line *commands, int from_tty); + /* Exported to gdb/breakpoint.c */ extern enum command_control_type - execute_control_command (struct command_line *cmd); + execute_control_command (struct command_line *cmd, + int from_tty = 0); extern enum command_control_type execute_control_command_untraced (struct command_line *cmd); diff --git a/gdb/gdbcmd.h b/gdb/gdbcmd.h index 342c8b2c0e..b675ae8618 100644 --- a/gdb/gdbcmd.h +++ b/gdb/gdbcmd.h @@ -135,8 +135,6 @@ extern struct cmd_list_element *save_cmdlist; extern void execute_command (const char *, int); extern std::string execute_command_to_string (const char *p, int from_tty); -enum command_control_type execute_control_command (struct command_line *); - extern void print_command_line (struct command_line *, unsigned int, struct ui_file *); extern void print_command_lines (struct ui_out *, diff --git a/gdb/python/python.c b/gdb/python/python.c index 45b6516fc2..befd3bb5aa 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -581,6 +581,20 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw) { struct interp *interp; + std::string arg_copy = arg; + bool first = true; + char *save_ptr = nullptr; + auto reader + = [&] () + { + const char *result = strtok_r (first ? &arg_copy[0] : nullptr, + "\n", &save_ptr); + first = false; + return result; + }; + + counted_command_line lines = read_command_lines_1 (reader, 1, nullptr); + scoped_restore save_async = make_scoped_restore (¤t_ui->async, 0); scoped_restore save_uiout = make_scoped_restore (¤t_uiout); @@ -592,9 +606,10 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw) scoped_restore preventer = prevent_dont_repeat (); if (to_string) - to_string_res = execute_command_to_string (arg, from_tty); + to_string_res = execute_control_commands_to_string (lines.get (), + from_tty); else - execute_command (arg, from_tty); + execute_control_commands (lines.get (), from_tty); } CATCH (except, RETURN_MASK_ALL) { diff --git a/gdb/testsuite/gdb.python/python.exp b/gdb/testsuite/gdb.python/python.exp index cee195f315..f6bf93add0 100644 --- a/gdb/testsuite/gdb.python/python.exp +++ b/gdb/testsuite/gdb.python/python.exp @@ -119,6 +119,9 @@ gdb_test_no_output \ "python x = gdb.execute('printf \"%d\", 23', to_string = True)" gdb_test "python print (x)" "23" +gdb_test "python gdb.execute('echo 2\\necho 3\\\\n\\n')" "23" \ + "multi-line execute" + # Test post_event. gdb_py_test_multiple "post event insertion" \ "python" "" \