commit 6a67114416d55f906d0b5aa05e11c3cfaa5b7adf Author: Joel Brobecker Date: Mon Jan 18 09:54:28 2010 +0400 Allow "source" to load python scripts. gdb/ChangeLog: Tom Tromey Thiago Jung Bauermann * exceptions.h (enum errors): Add UNSUPPORTED_ERROR. * python/python.c (source_python_script): New function. * python/python.h (source_python_script): Add declaration. * cli/cli-cmds.c: #include exceptions.h and python/python.h. (script_ext_off, script_ext_soft, script_ext_strict) (script_ext_enums, script_ext_mode): New static constants. (show_script_ext_mode, find_and_open_script): New functions. (source_script): Enhance to handle Python scripts. (init_cli_cmds): Add set/show script-extension commands. gdb/doc/ChangeLog: Tom Tromey * gdb.texinfo (File Options): Document -x on .py files. (Command Files): Document handling of Python scripts. gdb/testsuite/ChangeLog: Tom Tromey Thiago Jung Bauermann * gdb.python/source2.py: New file. * gdb.python/source1: New file. * gdb.python/python.exp: Test "source" command. diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c index 4833898..7400967 100644 --- a/gdb/cli/cli-cmds.c +++ b/gdb/cli/cli-cmds.c @@ -19,6 +19,7 @@ along with this program. If not, see . */ #include "defs.h" +#include "exceptions.h" #include "arch-utils.h" #include "readline/readline.h" #include "readline/tilde.h" @@ -47,6 +48,8 @@ extern void disconnect_or_stop_tracing (int from_tty); #include "cli/cli-setshow.h" #include "cli/cli-cmds.h" +#include "python/python.h" + #ifdef TUI #include "tui/tui.h" /* For tui_active et.al. */ #endif @@ -187,6 +190,21 @@ struct cmd_list_element *showchecklist; int source_verbose = 0; int trace_commands = 0; +/* 'script-extension' option support. */ + +static const char script_ext_off[] = "off"; +static const char script_ext_soft[] = "soft"; +static const char script_ext_strict[] = "strict"; + +static const char *script_ext_enums[] = { + script_ext_off, + script_ext_soft, + script_ext_strict, + NULL +}; + +static const char *script_ext_mode = script_ext_soft; + /* Utility used everywhere when at least one argument is needed and none is supplied. */ @@ -441,18 +459,25 @@ cd_command (char *dir, int from_tty) pwd_command ((char *) 0, 1); } -void -source_script (char *file, int from_tty) +/* Show the current value of the 'script-extension' option. */ + +static void +show_script_ext_mode (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) { - FILE *stream; - struct cleanup *old_cleanups; + fprintf_filtered (file, _("\ +Script filename extension recognition is \"%s\".\n"), + value); +} + +static int +find_and_open_script (int from_tty, char **filep, FILE **streamp, + struct cleanup **cleanupp) +{ + char *file = *filep; char *full_pathname = NULL; int fd; - - if (file == NULL || *file == 0) - { - error (_("source command requires file name of file to source.")); - } + struct cleanup *old_cleanups; file = tilde_expand (file); old_cleanups = make_cleanup (xfree, file); @@ -476,12 +501,58 @@ source_script (char *file, int from_tty) else { do_cleanups (old_cleanups); - return; + return 0; } } - stream = fdopen (fd, FOPEN_RT); - script_from_file (stream, file); + *streamp = fdopen (fd, FOPEN_RT); + *filep = file; + *cleanupp = old_cleanups; + + return 1; +} + +void +source_script (char *file, int from_tty) +{ + FILE *stream; + struct cleanup *old_cleanups; + + if (file == NULL || *file == 0) + { + error (_("source command requires file name of file to source.")); + } + + if (!find_and_open_script (from_tty, &file, &stream, &old_cleanups)) + return; + + if (script_ext_mode != script_ext_off + && strlen (file) > 3 && !strcmp (&file[strlen (file) - 3], ".py")) + { + volatile struct gdb_exception e; + + TRY_CATCH (e, RETURN_MASK_ERROR) + { + source_python_script (stream, file); + } + if (e.reason < 0) + { + /* Should we fallback to ye olde GDB script mode? */ + if (script_ext_mode == script_ext_soft + && e.reason == RETURN_ERROR && e.error == UNSUPPORTED_ERROR) + { + if (!find_and_open_script (from_tty, &file, &stream, &old_cleanups)) + return; + + script_from_file (stream, file); + } + else + /* Nope, just punt. */ + throw_exception (e); + } + } + else + script_from_file (stream, file); do_cleanups (old_cleanups); } @@ -1314,6 +1385,19 @@ when GDB is started."), gdbinit); source_help_text, &cmdlist); set_cmd_completer (c, filename_completer); + add_setshow_enum_cmd ("script-extension", class_support, + script_ext_enums, &script_ext_mode, _("\ +Set mode for script filename extension recognition."), _("\ +Show mode for script filename extension recognition."), _("\ +off == no filename extension recognition (all sourced files are GDB scripts)\n\ +soft == evaluate script according to filename extension, fallback to GDB script" + "\n\ +strict == evaluate script according to filename extension, error if not supported" + ), + NULL, + show_script_ext_mode, + &setlist, &showlist); + add_com ("quit", class_support, quit_command, _("Exit gdb.")); c = add_com ("help", class_support, help_command, _("Print list of commands.")); diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 7cf1bb4..d37712b 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -963,8 +963,11 @@ Connect to process ID @var{number}, as with the @code{attach} command. @itemx -x @var{file} @cindex @code{--command} @cindex @code{-x} -Execute @value{GDBN} commands from file @var{file}. @xref{Command -Files,, Command files}. +Execute commands from file @var{file}. If @var{file} ends in +@samp{.py}, then the file is evaluated as Python code. If Python +support is not enabled in this @value{GDBN}, then the file is assumed to +contain @value{GDBN} commands, regardless of its extension. +@xref{Command Files,, Command files}. @item -eval-command @var{command} @itemx -ex @var{command} @@ -19159,6 +19162,11 @@ If @code{-v}, for verbose mode, is given then @value{GDBN} displays each command as it is executed. The option must be given before @var{filename}, and is interpreted as part of the filename anywhere else. +If @var{filename} ends in @samp{.py}, then @value{GDBN} evaluates the +contents of the file as Python code. If Python support is not compiled +in to @value{GDBN}, then the file is assumed to contain @value{GDBN} +commands, regardless of its extension. + Commands that would ask for confirmation if used interactively proceed without asking when used in a command file. Many @value{GDBN} commands that normally print messages to say what they are doing omit the messages diff --git a/gdb/exceptions.h b/gdb/exceptions.h index 84a9f01..6b3cbeb 100644 --- a/gdb/exceptions.h +++ b/gdb/exceptions.h @@ -75,6 +75,9 @@ enum errors { /* Error accessing memory. */ MEMORY_ERROR, + /* Feature is not supported in this copy of GDB. */ + UNSUPPORTED_ERROR, + /* Add more errors here. */ NR_ERRORS }; diff --git a/gdb/python/python.c b/gdb/python/python.c index 827372c..1f1ae72 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -343,6 +343,22 @@ gdbpy_parse_and_eval (PyObject *self, PyObject *args) return value_to_value_object (result); } +/* Read a file as Python code. STREAM is the input file; FILE is the + name of the file. */ + +void +source_python_script (FILE *stream, char *file) +{ + PyGILState_STATE state; + + state = PyGILState_Ensure (); + + PyRun_SimpleFile (stream, file); + + fclose (stream); + PyGILState_Release (state); +} + /* Printing. */ @@ -525,6 +541,14 @@ eval_python_from_control_command (struct command_line *cmd) error (_("Python scripting is not supported in this copy of GDB.")); } +void +source_python_script (FILE *stream, char *file) +{ + fclose (stream); + throw_error (UNSUPPORTED_ERROR, + _("Python scripting is not supported in this copy of GDB.")); +} + #endif /* HAVE_PYTHON */ diff --git a/gdb/python/python.h b/gdb/python/python.h index f35827b..5d93f67 100644 --- a/gdb/python/python.h +++ b/gdb/python/python.h @@ -24,6 +24,8 @@ void eval_python_from_control_command (struct command_line *); +void source_python_script (FILE *stream, char *file); + int apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr, int embedded_offset, CORE_ADDR address, struct ui_file *stream, int recurse, diff --git a/gdb/testsuite/gdb.python/python.exp b/gdb/testsuite/gdb.python/python.exp index 951c295..b345ad2 100644 --- a/gdb/testsuite/gdb.python/python.exp +++ b/gdb/testsuite/gdb.python/python.exp @@ -29,6 +29,10 @@ gdb_reinitialize_dir $srcdir/$subdir gdb_test_multiple "python print 23" "verify python support" { -re "not supported.*$gdb_prompt $" { unsupported "python support is disabled" + + # If Python is not supported, verify that sourcing a python script + # causes an error. + gdb_test "source $srcdir/$subdir/source2.py" "Error in sourced command file:.*" return -1 } -re "$gdb_prompt $" {} @@ -72,5 +76,7 @@ gdb_py_test_multiple "indented multi-line python command" \ "foo ()" "" \ "end" "hello, world!" +gdb_test "source $srcdir/$subdir/source2.py" "yes" + gdb_test "python print gdb.current_objfile()" "None" gdb_test "python print gdb.objfiles()" "\\\[\\\]" diff --git a/gdb/testsuite/gdb.python/source1 b/gdb/testsuite/gdb.python/source1 new file mode 100644 index 0000000..f9c19bd --- /dev/null +++ b/gdb/testsuite/gdb.python/source1 @@ -0,0 +1,19 @@ +# This testcase is part of GDB, the GNU debugger. + +# Copyright 2008, 2009, 2010 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This is sourced as python; pick an expression that is not valid for gdb. +print 'y%ss' % 'e' diff --git a/gdb/testsuite/gdb.python/source2.py b/gdb/testsuite/gdb.python/source2.py new file mode 100644 index 0000000..4e9a9e3 --- /dev/null +++ b/gdb/testsuite/gdb.python/source2.py @@ -0,0 +1,18 @@ +# This testcase is part of GDB, the GNU debugger. + +# Copyright 2008, 2009, 2010 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +print 'y%ss' % 'e'