Let gdb.execute handle multi-line commands
authorTom Tromey <tom@tromey.com>
Thu, 19 Apr 2018 02:10:43 +0000 (20:10 -0600)
committerTom Tromey <tom@tromey.com>
Fri, 4 May 2018 21:58:09 +0000 (15:58 -0600)
This changes the Python API so that gdb.execute can now handle
multi-line commands, like "commands" or "define".

ChangeLog
2018-05-04  Tom Tromey  <tom@tromey.com>

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.

testsuite/ChangeLog
2018-05-04  Tom Tromey  <tom@tromey.com>

PR python/22730:
* gdb.python/python.exp: Test multi-line execute.

gdb/ChangeLog
gdb/NEWS
gdb/cli/cli-script.c
gdb/cli/cli-script.h
gdb/gdbcmd.h
gdb/python/python.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.python/python.exp

index 0559c0b..f91a976 100644 (file)
@@ -1,5 +1,21 @@
 2018-05-04  Tom Tromey  <tom@tromey.com>
 
+       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.
+
+2018-05-04  Tom Tromey  <tom@tromey.com>
+
        PR python/22731:
        * NEWS: Mention that breakpoint commands are writable.
        * python/py-breakpoint.c (bppy_set_commands): New function.
index da7147b..cef5580 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -34,6 +34,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
index e336c58..a62e4fe 100644 (file)
@@ -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 (&current_ui->instream, nullptr);
+  scoped_restore save_async = make_scoped_restore (&current_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 (&current_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 (&current_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
index 3bebd0e..736ebb3 100644 (file)
@@ -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);
index 342c8b2..b675ae8 100644 (file)
@@ -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 *,
index b486be7..db37331 100644 (file)
@@ -588,6 +588,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 (&current_ui->async, 0);
 
       scoped_restore save_uiout = make_scoped_restore (&current_uiout);
@@ -599,9 +613,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)
     {
index 24d9d34..761fb73 100644 (file)
@@ -1,5 +1,10 @@
 2018-05-04  Tom Tromey  <tom@tromey.com>
 
+       PR python/22730:
+       * gdb.python/python.exp: Test multi-line execute.
+
+2018-05-04  Tom Tromey  <tom@tromey.com>
+
        PR python/22731:
        * gdb.python/py-breakpoint.exp: Test setting breakpoint commands.
 
index cee195f..f6bf93a 100644 (file)
@@ -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" "" \