Let gdb.execute handle multi-line commands

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.
This commit is contained in:
Tom Tromey 2018-04-18 20:10:43 -06:00
parent a913fffbde
commit 56bcdbea2b
8 changed files with 123 additions and 32 deletions

View File

@ -1,3 +1,19 @@
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> 2018-05-04 Tom Tromey <tom@tromey.com>
PR python/22731: PR python/22731:

View File

@ -34,6 +34,8 @@ set|show record btrace cpu
** The commands attached to a breakpoint can be set by assigning to ** The commands attached to a breakpoint can be set by assigning to
the breakpoint's "commands" field. the breakpoint's "commands" field.
** gdb.execute can now execute multi-line gdb commands.
* New targets * New targets
RiscV ELF riscv*-*-elf RiscV ELF riscv*-*-elf

View 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 void
execute_user_command (struct cmd_list_element *c, const char *args) execute_user_command (struct cmd_list_element *c, const char *args)
{ {
struct ui *ui = current_ui;
counted_command_line cmdlines_copy; counted_command_line cmdlines_copy;
enum command_control_type ret;
extern unsigned int max_user_call_depth; extern unsigned int max_user_call_depth;
/* Ensure that the user commands can't be deleted while they are /* 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) if (user_args_stack.size () > max_user_call_depth)
error (_("Max user call depth exceeded -- command aborted.")); error (_("Max user call depth exceeded -- command aborted."));
/* Set the instream to 0, indicating execution of a execute_control_commands (cmdlines, 0);
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;
}
} }
/* This function is called every time GDB prints a prompt. It ensures /* 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. */ /* Helper for execute_control_command. */
static enum command_control_type 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 command_line *current;
struct value *val; struct value *val;
@ -483,7 +522,7 @@ execute_control_command_1 (struct command_line *cmd)
{ {
/* A simple command, execute it and return. */ /* A simple command, execute it and return. */
std::string new_line = insert_user_defined_cmd_args (cmd->line); 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; ret = cmd->control_type;
break; break;
} }
@ -538,7 +577,7 @@ execute_control_command_1 (struct command_line *cmd)
{ {
scoped_restore save_nesting scoped_restore save_nesting
= make_scoped_restore (&command_nest_depth, command_nest_depth + 1); = 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 /* If we got an error, or a "break" command, then stop
looping. */ looping. */
@ -593,7 +632,7 @@ execute_control_command_1 (struct command_line *cmd)
{ {
scoped_restore save_nesting scoped_restore save_nesting
= make_scoped_restore (&command_nest_depth, command_nest_depth + 1); = 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 we got an error, get out. */
if (ret != simple_control) if (ret != simple_control)
@ -644,7 +683,7 @@ execute_control_command_1 (struct command_line *cmd)
} }
enum command_control_type 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 /* Make sure we use the console uiout. It's possible that we are executing
breakpoint commands while running the MI interpreter. */ breakpoint commands while running the MI interpreter. */
@ -652,7 +691,7 @@ execute_control_command (struct command_line *cmd)
scoped_restore save_uiout scoped_restore save_uiout
= make_scoped_restore (&current_uiout, interp_ui_out (console)); = 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 /* Like execute_control_command, but first set

View File

@ -122,10 +122,23 @@ extern void show_user_1 (struct cmd_list_element *c,
const char *name, const char *name,
struct ui_file *stream); 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 */ /* Exported to gdb/breakpoint.c */
extern enum command_control_type 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 extern enum command_control_type
execute_control_command_untraced (struct command_line *cmd); execute_control_command_untraced (struct command_line *cmd);

View File

@ -135,8 +135,6 @@ extern struct cmd_list_element *save_cmdlist;
extern void execute_command (const char *, int); extern void execute_command (const char *, int);
extern std::string execute_command_to_string (const char *p, int from_tty); 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, extern void print_command_line (struct command_line *, unsigned int,
struct ui_file *); struct ui_file *);
extern void print_command_lines (struct ui_out *, extern void print_command_lines (struct ui_out *,

View File

@ -588,6 +588,20 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
{ {
struct interp *interp; 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_async = make_scoped_restore (&current_ui->async, 0);
scoped_restore save_uiout = make_scoped_restore (&current_uiout); 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 (); scoped_restore preventer = prevent_dont_repeat ();
if (to_string) 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 else
execute_command (arg, from_tty); execute_control_commands (lines.get (), from_tty);
} }
CATCH (except, RETURN_MASK_ALL) CATCH (except, RETURN_MASK_ALL)
{ {

View File

@ -1,3 +1,8 @@
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> 2018-05-04 Tom Tromey <tom@tromey.com>
PR python/22731: PR python/22731:

View File

@ -119,6 +119,9 @@ gdb_test_no_output \
"python x = gdb.execute('printf \"%d\", 23', to_string = True)" "python x = gdb.execute('printf \"%d\", 23', to_string = True)"
gdb_test "python print (x)" "23" gdb_test "python print (x)" "23"
gdb_test "python gdb.execute('echo 2\\necho 3\\\\n\\n')" "23" \
"multi-line execute"
# Test post_event. # Test post_event.
gdb_py_test_multiple "post event insertion" \ gdb_py_test_multiple "post event insertion" \
"python" "" \ "python" "" \