[RFA] [1/2] auto-loading scripts from .debug_gdb_scripts section

Doug Evans
2010-04-16T07:06:07Z

Hi.

This patch adds support for auto-loading scripts mentioned in
section .debug_gdb_scripts.
It is useful in some places where the auto-loading of ${objfile}-gdb.py isn't.

E.g.,
- static linking: collecting together scripts from various input libraries
can be problematic
- classes that are fully inlined: there may not be an associated objfile
to attach the -gdb.py script to
- scripts needn't be copied out of the source tree:
apps can be built out of large collections of internal
libraries, and the build infrastructure necessary to install the
-gdb.py scripts in a place where GDB can find them is
cumbersome. It may be easier to specify the scripts in the
.debug_gdb_scripts section as relative paths, and add a path to the
top of the source tree to the source search path.

The intended usage is to have a macro like DEFINE_GDB_SCRIPT and then
reference the macro in a header or source file.

#define DEFINE_GDB_SCRIPT(script_name) \
asm("\
.pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\n\
.byte 1\n\
.asciz \"" script_name "\"\n\
.popsection \n\
");

And then in, say, mylib.h,

DEFINE_GDB_SCRIPT ("mylib.py")

File names are recorded in the section instead of python code
so that the user doesn't have to relink when the script changes.
Plus there can be a plethora of different scripts for unrelated
classes and it's easier to manage/identify them this way.

NOTES:
- It may be useful to be able to add another search directory
for scripts outside of the source search path,
but it can be added if/when needed.
- It'd be useful to reload scripts when its timestamp changes,
but auto-loading won't retrigger until the objfile is reloaded anyway.
-gdb.py scripts suffer from this too.
- A useful extension is to be able to specify a $cdir-like directory to
entries in .debug_gdb_scripts.
- needs a gcc extension
All of these can be done later.

I moved the Auto-loading section of the docs out of the Python API section
because I like it better that way, and because it solves a technical
problem: there's no @subsubsubsection. :-)
This could be done differently of course.

Comments?

2010-04-15 Doug Evans <dje@google.com>

Add support for auto-loading scripts from .debug_gdb_scripts section.
* NEWS: Add entry for .debug_gdb_scripts.
* Makefile.in SUBDIR_PYTHON_OBS): Add py-auto-load.o.
(SUBDIR_PYTHON_SRCS): Add py-auto-load.c.
(py-auto-load.o): New rule.
* cli/cli-cmds.c (find_and_open_script): Make externally visible.
* cli/cli-cmds.h (find_and_open_script): Update prototype.
* python/py-auto-load.c: New file.
* python/python-internal.h: #include <stdio.h>.
(set_python_list, show_python_list): Declare.
(gdbpy_initialize_auto_load): Declare.
(source_python_script_for_objfile): Declare.
* python/python.c: Remove #include of observer.h.
(gdbpy_auto_load): Moved to py-auto-load.c.
(GDBPY_AUTO_FILENAME): Ditto.
(gdbpy_new_objfile): Delete.
(source_python_script_for_objfile): New function.
(set_python_list, show_python_list): Make externally visible.
(_initialize_python): Move "auto-load" command to py-auto-load.c
and observer_attach_new_objfile to py-auto-load.c.

doc/
* gdb.texinfo (Python): Move Auto-loading section here ...
(Python API): from here.
(Auto-loading): Add docs for .debug_gdb_scripts auto-loaded scripts.
(Maintenance Commands): Add docs for "maint print section-scripts".

testsuite/
* gdb.python/py-section-script.c: New file.
* gdb.python/py-section-script.exp: New file.
* gdb.python/py-section-script.py: New file.

Index: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.371
diff -u -p -r1.371 NEWS
--- NEWS 15 Apr 2010 19:54:12 -0000 1.371
+++ NEWS 16 Apr 2010 05:58:03 -0000
@@ -42,6 +42,8 @@

** Pretty-printers are now also looked up in the current program space.

+** GDB now looks for scripts to auto-load in the .debug_gdb_scripts section.
+
* Tracepoint actions were unified with breakpoint commands. In particular,
there are no longer differences in "info break" output for breakpoints and
tracepoints and the "commands" command can be used for both tracepoints and
Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.1118
diff -u -p -r1.1118 Makefile.in
--- Makefile.in 15 Apr 2010 19:54:12 -0000 1.1118
+++ Makefile.in 16 Apr 2010 05:54:34 -0000
@@ -267,6 +267,7 @@ SUBDIR_TUI_CFLAGS= \
#
SUBDIR_PYTHON_OBS = \
python.o \
+ py-auto-load.o \
py-block.o \
py-breakpoint.o \
py-cmd.o \
@@ -283,6 +284,7 @@ SUBDIR_PYTHON_OBS = \
py-value.o
SUBDIR_PYTHON_SRCS = \
python/python.c \
+ python/py-auto-load.c \
python/py-block.c \
python/py-breakpoint.c \
python/py-cmd.c \
@@ -1986,6 +1988,10 @@ python.o: $(srcdir)/python/python.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python.c
$(POSTCOMPILE)

+py-auto-load.o: $(srcdir)/python/py-auto-load.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-auto-load.c
+ $(POSTCOMPILE)
+
py-block.o: $(srcdir)/python/py-block.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-block.c
$(POSTCOMPILE)
Index: cli/cli-cmds.c
===================================================================
RCS file: /cvs/src/src/gdb/cli/cli-cmds.c,v
retrieving revision 1.101
diff -u -p -r1.101 cli-cmds.c
--- cli/cli-cmds.c 15 Apr 2010 17:45:52 -0000 1.101
+++ cli/cli-cmds.c 16 Apr 2010 05:54:35 -0000
@@ -483,7 +483,7 @@ Script filename extension recognition is
NOTE: This calls openp which uses xfullpath to compute the full path
instead of gdb_realpath. Symbolic links are not resolved. */

-static int
+int
find_and_open_script (const char *script_file, int search_path,
FILE **streamp, char **full_pathp)
{
Index: cli/cli-cmds.h
===================================================================
RCS file: /cvs/src/src/gdb/cli/cli-cmds.h,v
retrieving revision 1.14
diff -u -p -r1.14 cli-cmds.h
--- cli/cli-cmds.h 1 Jan 2010 07:31:46 -0000 1.14
+++ cli/cli-cmds.h 16 Apr 2010 05:54:35 -0000
@@ -123,6 +123,11 @@ extern void quit_command (char *, int);

extern void source_script (char *, int);

+/* Exported to objfiles.c. */
+
+extern int find_and_open_script (const char *file, int search_path,
+ FILE **streamp, char **full_path);
+
/* Used everywhere whenever at least one parameter is required and
none is specified. */

Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.706
diff -u -p -r1.706 gdb.texinfo
--- doc/gdb.texinfo 15 Apr 2010 19:54:13 -0000 1.706
+++ doc/gdb.texinfo 16 Apr 2010 05:54:35 -0000
@@ -19639,6 +19639,7 @@ Python programming language}. This feat
@menu
* Python Commands:: Accessing Python from @value{GDBN}.
* Python API:: Accessing @value{GDBN} from Python.
+* Auto-loading:: Automatically loading Python code.
@end menu

@node Python Commands
@@ -19716,7 +19717,6 @@ situation, a Python @code{KeyboardInterr
@menu
* Basic Python:: Basic Python Functions.
* Exception Handling::
-* Auto-loading:: Automatically loading Python code.
* Values From Inferior::
* Types In Python:: Python representation of types.
* Pretty Printing:: Pretty-printing values.
@@ -19862,53 +19862,6 @@ message as its value, and the Python cal
Python statement closest to where the @value{GDBN} error occured as the
traceback.

-@node Auto-loading
-@subsubsection Auto-loading
-@cindex auto-loading, Python
-
-When a new object file is read (for example, due to the @code{file}
-command, or because the inferior has loaded a shared library),
-@value{GDBN} will look for a file named @file{@var{objfile}-gdb.py},
-where @var{objfile} is the object file's real name, formed by ensuring
-that the file name is absolute, following all symlinks, and resolving
-@code{.} and @code{..} components. If this file exists and is
-readable, @value{GDBN} will evaluate it as a Python script.
-
-If this file does not exist, and if the parameter
-@code{debug-file-directory} is set (@pxref{Separate Debug Files}),
-then @value{GDBN} will use for its each separated directory component
-@code{component} the file named @file{@code{component}/@var{real-name}}, where
-@var{real-name} is the object file's real name, as described above.
-
-Finally, if this file does not exist, then @value{GDBN} will look for
-a file named @file{@var{data-directory}/python/auto-load/@var{real-name}}, where
-@var{data-directory} is @value{GDBN}'s data directory (available via
-@code{show data-directory}, @pxref{Data Files}), and @var{real-name}
-is the object file's real name, as described above.
-
-When reading an auto-loaded file, @value{GDBN} sets the ``current
-objfile''. This is available via the @code{gdb.current_objfile}
-function (@pxref{Objfiles In Python}). This can be useful for
-registering objfile-specific pretty-printers.
-
-The auto-loading feature is useful for supplying application-specific
-debugging commands and scripts. You can enable or disable this
-feature, and view its current state.
-
-@table @code
-@kindex maint set python auto-load
-@item maint set python auto-load [yes|no]
-Enable or disable the Python auto-loading feature.
-
-@kindex maint show python auto-load
-@item maint show python auto-load
-Show whether Python auto-loading is enabled or disabled.
-@end table
-
-@value{GDBN} does not track which files it has already auto-loaded.
-So, your @samp{-gdb.py} file should take care to ensure that it may be
-evaluated multiple times without error.
-
@node Values From Inferior
@subsubsection Values From Inferior
@cindex values from inferior, with Python
@@ -21565,6 +21518,172 @@ resolve this to the lazy string's charac
writable.
@end defivar

+@node Auto-loading
+@subsection Auto-loading
+@cindex auto-loading, Python
+
+When a new object file is read (for example, due to the @code{file}
+command, or because the inferior has loaded a shared library),
+@value{GDBN} will look for support scripts in up to two ways:
+@file{@var{objfile}-gdb.py} and @file{.debug_gdb_scripts} section.
+
+@menu
+* @file{@var{objfile}-gdb.py} file::
+* @file{.debug_gdb_scripts} section::
+* Which flavor to choose?::
+@end menu
+
+The auto-loading feature is useful for supplying application-specific
+debugging commands and scripts.
+
+When reading an auto-loaded file, @value{GDBN} sets the ``current
+objfile''. This is available via the @code{gdb.current_objfile}
+function (@pxref{Objfiles In Python}). This can be useful for
+registering objfile-specific pretty-printers.
+
+Auto-loading can be enabled or disabled.
+
+@table @code
+@kindex maint set python auto-load
+@item maint set python auto-load [yes|no]
+Enable or disable the Python auto-loading feature.
+
+@kindex maint show python auto-load
+@item maint show python auto-load
+Show whether Python auto-loading is enabled or disabled.
+@end table
+
+@node @file{@var{objfile}-gdb.py} file
+@subsubsection @file{@var{objfile}-gdb.py} file
+@cindex @file{@var{objfile}-gdb.py}
+
+When a new object file is read, @value{GDBN} looks for
+a file named @file{@var{objfile}-gdb.py},
+where @var{objfile} is the object file's real name, formed by ensuring
+that the file name is absolute, following all symlinks, and resolving
+@code{.} and @code{..} components. If this file exists and is
+readable, @value{GDBN} will evaluate it as a Python script.
+
+If this file does not exist, and if the parameter
+@code{debug-file-directory} is set (@pxref{Separate Debug Files}),
+then @value{GDBN} will use for its each separated directory component
+@code{component} the file named @file{@code{component}/@var{real-name}}, where
+@var{real-name} is the object file's real name, as described above.
+
+Finally, if this file does not exist, then @value{GDBN} will look for
+a file named @file{@var{data-directory}/python/auto-load/@var{real-name}}, where
+@var{data-directory} is @value{GDBN}'s data directory (available via
+@code{show data-directory}, @pxref{Data Files}), and @var{real-name}
+is the object file's real name, as described above.
+
+@value{GDBN} does not track which files it has already auto-loaded this way.
+@value{GDBN} will load the associated script every time the corresponding
+@var{objfile} is opened.
+So, your @samp{-gdb.py} file should take care to ensure that it may be
+evaluated multiple times without error.
+
+@node @file{.debug_gdb_scripts} section
+@subsubsection @file{.debug_gdb_scripts} section
+@cindex .debug_gdb_scripts section
+
+For systems using the ELF file format, and other formats supporting
+multiple sections, when @value{GDBN} loads an @var{objfile}
+it will look for scripts in the @file{.debug_gdb_scripts} section
+when an objfile is loaded.
+This section contains a list of names of scripts to load.
+File names are recorded instead of the file's contents so that
+the user doesn't have to relink if a script changes,
+and so that the plethora of random scripts are better managed,
+
+The scripts are searched for first in the current directory, and then
+in the source search path
+(@pxref{Source Path, ,Specifying Source Directories}),
+with the exception that @file{$cdir} is not searched, the compilation
+directory is not relevant to scripts.
+
+Entries can be placed in section @file{.debug_gdb_scripts} with,
+for example, this GCC macro:
+
+@example
+#define DEFINE_GDB_SCRIPT(script_name) \
+ asm("\
+.pushsection \".debug_gdb_scripts\", \"MS\",@@progbits,1\n\
+.byte 1\n\
+.asciz \"" script_name "\"\n\
+.popsection \n\
+");
+@end example
+
+Then one can reference the macro in a header or source file like this:
+
+@example
+DEFINE_GDB_SCRIPT ("my-app-scripts.py")
+@end example
+
+If the macro is put in a header, any application or library
+using this header will get a reference to the specified script.
+The above macro uses the @code{"MS"} GAS section flags to
+remove duplicate entries.
+
+Unlike loading of @file{@var{objfile}-gdb.py} scripts,
+@value{GDBN} keeps track of scripts loaded this way.
+If the reference to the script is coming from a header file,
+the script can be referenced by multiple shared libraries.
+As an optimization to prevent loading the script 100's or even 1000's
+of times, @value{GDBN} will only auto-load a script once in each
+program space.
+However, you should still write your scripts to ensure
+that it may be evaluated multiple times without error.
+
+@node Which flavor to choose?
+@subsubsection Which flavor to choose?
+
+Given the two ways of auto-loading scripts, it might not always be clear
+which one to choose. This section provides some guidance.
+
+Benefits of the @file{-gdb.py} way:
+
+@itemize @bullet
+@item
+Can be used with file formats that don't support multiple sections.
+
+@item
+Ease of finding scripts for public libraries.
+
+Scripts specified in the @file{.debug_gdb_scripts} section are searched for
+in the source search path.
+For publicly installed libraries, e.g. libstdc++, there typically isn't a
+source directory in which to find the script.
+@end itemize
+
+Benefits of the @file{.debug_gdb_scripts} way:
+
+@itemize @bullet
+@item
+Works with static linking.
+
+Scripts for libraries done the @file{-gdb.py} way require an objfile to
+trigger their loading. When an application is statically linked the only
+objfile available is the executable, and it is cumbersome to attach all the
+scripts from all the input libraries to the executable's @file{-gdb.py} script.
+
+@item
+Works with classes that are entirely inlined.
+
+Some classes can be entirely inlined, and thus there may not be an associated
+shared library to attach a @file{-gdb.py} script to.
+
+@item
+Scripts needn't be copied out of the source tree.
+
+In some circumstances, apps can be built out of large collections of internal
+libraries, and the build infrastructure necessary to install the
+@file{-gdb.py} scripts in a place where @value{GDBN} can find them is
+cumbersome. It may be easier to specify the scripts in the
+@file{.debug_gdb_scripts} section as relative paths, and add a path to the
+top of the source tree to the source search path.
+@end itemize
+
@node Interpreters
@chapter Command Interpreters
@cindex command interpreters
@@ -29367,6 +29486,15 @@ Print a dump of all known object files.
command prints its name, address in memory, and all of its psymtabs
and symtabs.

+@kindex maint print section-scripts
+@cindex info for known .debug_gdb_scripts-loaded scripts
+@item maint print section-scripts [@var{regexp}]
+Print a dump of scripts specified in the @file{.debug_gdb_section} section.
+If @var{regexp} is specified, only print scripts loaded by object files
+matching @var{regexp}.
+For each script, this command prints its name as specified in the objfile,
+and the full path if known.
+
@kindex maint print statistics
@cindex bcache statistics
@item maint print statistics
Index: python/py-auto-load.c
===================================================================
RCS file: python/py-auto-load.c
diff -N python/py-auto-load.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ python/py-auto-load.c 16 Apr 2010 05:54:35 -0000
@@ -0,0 +1,459 @@
+/* GDB routines for supporting auto-loaded scripts.
+
+ Copyright (C) 2010 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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 <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "gdb_string.h"
+#include "gdb_regex.h"
+#include "top.h"
+#include "exceptions.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "observer.h"
+#include "progspace.h"
+#include "objfiles.h"
+#include "python.h"
+#include "python-internal.h"
+#include "cli/cli-cmds.h"
+
+/* NOTE: It's trivial to also support auto-loading normal gdb scripts.
+ There has yet to be a need so it's not implemented. */
+
+/* The suffix of per-objfile scripts to auto-load.
+ E.g. When the program loads libfoo.so, look for libfoo-gdb.py. */
+#define GDBPY_AUTO_FILE_NAME "-gdb.py"
+
+/* The section to look for scripts (in file formats that support sections).
+ Each entry in this section is a byte of value 1, and then the nul-terminated
+ name of the script. The script name may include a directory.
+ The leading byte is to allow upward compatible extensions. */
+#define GDBPY_AUTO_SECTION_NAME ".debug_gdb_scripts"
+
+/* For scripts specified in .debug_gdb_scripts, multiple objfiles may load
+ the same script. There's no point in loading the script multiple times,
+ and there can be a lot of objfiles and scripts, so we keep track of scripts
+ loaded this way. */
+
+struct auto_load_pspace_info
+{
+ /* For each program space we keep track of loaded scripts. */
+ struct htab *loaded_scripts;
+};
+
+/* Objects of this type are stored in the loaded script hash table. */
+
+struct loaded_script_entry
+{
+ /* Name as provided by the objfile. */
+ const char *name;
+ /* Full path name or NULL if script wasn't found (or was otherwise
+ inaccessible). */
+ const char *full_path;
+};
+
+/* This is true if we should auto-load python code when an objfile is opened,
+ false otherwise. */
+static int gdbpy_auto_load = 1;
+
+/* Per-program-space data key. */
+static const struct program_space_data *auto_load_pspace_data;
+
+static void
+auto_load_pspace_data_cleanup (struct program_space *pspace, void *arg)
+{
+ struct auto_load_pspace_info *info;
+
+ info = program_space_data (pspace, auto_load_pspace_data);
+ if (info != NULL)
+ {
+ if (info->loaded_scripts)
+ htab_delete (info->loaded_scripts);
+ xfree (info);
+ }
+}
+
+/* Get the current autoload data. If none is found yet, add it now. This
+ function always returns a valid object. */
+
+static struct auto_load_pspace_info *
+get_auto_load_pspace_data (struct program_space *pspace)
+{
+ struct auto_load_pspace_info *info;
+
+ info = program_space_data (pspace, auto_load_pspace_data);
+ if (info == NULL)
+ {
+ info = XZALLOC (struct auto_load_pspace_info);
+ set_program_space_data (pspace, auto_load_pspace_data, info);
+ }
+
+ return info;
+}
+
+/* Hash function for the loaded script hash. */
+
+static hashval_t
+hash_loaded_script_entry (const void *data)
+{
+ const struct loaded_script_entry *e = data;
+ return htab_hash_string (e->name);
+}
+
+/* Equality function for the loaded script hash. */
+
+static int
+eq_loaded_script_entry (const void *a, const void *b)
+{
+ const struct loaded_script_entry *ea = a;
+ const struct loaded_script_entry *eb = b;
+ return strcmp (ea->name, eb->name) == 0;
+}
+
+/* Create the hash table used for loaded scripts.
+ Each entry is hashed by the full path name. */
+
+static void
+create_loaded_scripts_hash (struct auto_load_pspace_info *pspace_info)
+{
+ /* Choose 31 as the starting size of the hash table, somewhat arbitrarily.
+ Space for each entry is obtained with one malloc so we can free them
+ easily. */
+
+ pspace_info->loaded_scripts = htab_create (31,
+ hash_loaded_script_entry,
+ eq_loaded_script_entry,
+ xfree);
+}
+
+/* Load scripts specified in OBJFILE.
+ START,END delimit a buffer containing a list of nul-terminated
+ file names.
+ SOURCE_NAME is used in error messages.
+
+ Scripts are found per normal "source -s" command processing.
+ First the script is looked for in $cwd. If not found there the
+ source search path is used.
+
+ The section contains a list of path names of files containing
+ python code to load. Each path is null-terminated. */
+
+static void
+source_section_scripts (struct objfile *objfile, const char *source_name,
+ const char *start, const char *end)
+{
+ const char *p;
+ struct auto_load_pspace_info *pspace_info;
+ struct loaded_script_entry **slot, entry;
+
+ pspace_info = get_auto_load_pspace_data (current_program_space);
+ if (pspace_info->loaded_scripts == NULL)
+ create_loaded_scripts_hash (pspace_info);
+
+ for (p = start; p < end; ++p)
+ {
+ const char *file;
+ FILE *stream;
+ char *full_path;
+ int opened, in_hash_table;
+
+ if (*p != 1)
+ {
+ warning (_("Invalid entry in %s section"), GDBPY_AUTO_SECTION_NAME);
+ /* We could try various heuristics to find the next valid entry,
+ but it's safer to just punt. */
+ break;
+ }
+ file = ++p;
+
+ while (p < end && *p != '\0')
+ ++p;
+ if (p == end)
+ {
+ char *buf = alloca (p - file + 1);
+ memcpy (buf, file, p - file);
+ buf[p - file] = '\0';
+ warning (_("Non-null-terminated path in %s: %s"),
+ source_name, buf);
+ /* Don't load it. */
+ break;
+ }
+ if (p == file)
+ {
+ warning (_("Empty path in %s"), source_name);
+ continue;
+ }
+
+ opened = find_and_open_script (file, 1 /*search_path*/,
+ &stream, &full_path);
+
+ /* If the file is not found, we still record the file in the hash table,
+ we only want to print an error message once.
+ IWBN if complaints.c were more general-purpose. */
+
+ entry.name = file;
+ if (opened)
+ entry.full_path = full_path;
+ else
+ entry.full_path = NULL;
+ slot = ((struct loaded_script_entry **)
+ htab_find_slot (pspace_info->loaded_scripts,
+ &entry, INSERT));
+ in_hash_table = *slot != NULL;
+
+ /* If this file is not in the hash table, add it. */
+ if (! in_hash_table)
+ {
+ char *p;
+ *slot = xmalloc (sizeof (**slot)
+ + strlen (file) + 1
+ + (opened ? (strlen (full_path) + 1) : 0));
+ p = ((char*) *slot) + sizeof (**slot);
+ strcpy (p, file);
+ (*slot)->name = p;
+ if (opened)
+ {
+ p += strlen (p) + 1;
+ strcpy (p, full_path);
+ (*slot)->full_path = p;
+ }
+ else
+ (*slot)->full_path = NULL;
+ }
+
+ if (opened)
+ free (full_path);
+
+ if (! opened)
+ {
+ /* We don't throw an error, the program is still debuggable.
+ Check in_hash_table to only print the warning once. */
+ if (! in_hash_table)
+ warning (_("%s (referenced in %s): %s\n"),
+ file, GDBPY_AUTO_SECTION_NAME, safe_strerror (errno));
+ continue;
+ }
+
+ /* If this file is not currently loaded, load it. */
+ if (! in_hash_table)
+ source_python_script_for_objfile (objfile, stream, file);
+ }
+}
+
+/* Load scripts specified in section SECTION_NAME of OBJFILE. */
+
+static void
+auto_load_section_scripts (struct objfile *objfile, const char *section_name)
+{
+ bfd *abfd = objfile->obfd;
+ asection *scripts_sect;
+ bfd_size_type size;
+ char *p;
+ struct cleanup *cleanups;
+
+ scripts_sect = bfd_get_section_by_name (abfd, section_name);
+ if (scripts_sect == NULL)
+ return;
+
+ size = bfd_get_section_size (scripts_sect);
+ p = xmalloc (size);
+
+ cleanups = make_cleanup (xfree, p);
+
+ if (bfd_get_section_contents (abfd, scripts_sect, p, (file_ptr) 0, size))
+ source_section_scripts (objfile, section_name, p, p + size);
+ else
+ warning (_("Couldn't read %s section of %s"),
+ section_name, bfd_get_filename (abfd));
+
+ do_cleanups (cleanups);
+}
+
+/* Clear the table of loaded section scripts. */
+
+static void
+clear_section_scripts (void)
+{
+ struct program_space *pspace = current_program_space;
+ struct auto_load_pspace_info *info;
+
+ info = program_space_data (pspace, auto_load_pspace_data);
+ if (info != NULL && info->loaded_scripts != NULL)
+ {
+ htab_delete (info->loaded_scripts);
+ info->loaded_scripts = NULL;
+ }
+}
+
+/* Look for the auto-load script associated with OBJFILE and load it. */
+
+static void
+auto_load_objfile_script (struct objfile *objfile, const char *suffix)
+{
+ char *realname;
+ char *filename, *debugfile;
+ int len;
+ FILE *input;
+ struct cleanup *cleanups;
+
+ realname = gdb_realpath (objfile->name);
+ len = strlen (realname);
+ filename = xmalloc (len + strlen (suffix) + 1);
+ memcpy (filename, realname, len);
+ strcpy (filename + len, suffix);
+
+ cleanups = make_cleanup (xfree, filename);
+ make_cleanup (xfree, realname);
+
+ input = fopen (filename, "r");
+ debugfile = filename;
+
+ if (!input && debug_file_directory)
+ {
+ /* Also try the same file in the separate debug info directory. */
+ debugfile = xmalloc (strlen (filename)
+ + strlen (debug_file_directory) + 1);
+ strcpy (debugfile, debug_file_directory);
+ /* FILENAME is absolute, so we don't need a "/" here. */
+ strcat (debugfile, filename);
+
+ make_cleanup (xfree, debugfile);
+ input = fopen (debugfile, "r");
+ }
+
+ if (!input && gdb_datadir)
+ {
+ /* Also try the same file in a subdirectory of gdb's data
+ directory. */
+ debugfile = xmalloc (strlen (gdb_datadir) + strlen (filename)
+ + strlen ("/auto-load") + 1);
+ strcpy (debugfile, gdb_datadir);
+ strcat (debugfile, "/auto-load");
+ /* FILENAME is absolute, so we don't need a "/" here. */
+ strcat (debugfile, filename);
+
+ make_cleanup (xfree, debugfile);
+ input = fopen (debugfile, "r");
+ }
+
+ if (input)
+ {
+ source_python_script_for_objfile (objfile, input, debugfile);
+ fclose (input);
+ }
+
+ do_cleanups (cleanups);
+}
+
+/* This is a new_objfile observer callback to auto-load scripts.
+
+ Two flavors of auto-loaded scripts are supported.
+ 1) based on the path to the objfile
+ 2) from .debug_gdb_scripts section */
+
+static void
+auto_load_new_objfile (struct objfile *objfile)
+{
+ if (!objfile)
+ {
+ /* OBJFILE is NULL when loading a new "main" symbol-file. */
+ clear_section_scripts ();
+ return;
+ }
+ if (!objfile->name)
+ return;
+
+ if (gdbpy_auto_load)
+ {
+ auto_load_objfile_script (objfile, GDBPY_AUTO_FILE_NAME);
+ auto_load_section_scripts (objfile, GDBPY_AUTO_SECTION_NAME);
+ }
+}
+\f
+/* Traversal function for htab_traverse.
+ Print the entry if specified in the regex. */
+
+static int
+maybe_print_section_script (void **slot, void *info)
+{
+ struct loaded_script_entry *entry = *slot;
+
+ if (re_exec (entry->name))
+ {
+ printf_filtered (_("Script name: %s\n"), entry->name);
+ printf_filtered (_(" Full name: %s\n"),
+ entry->full_path ? entry->full_path : _("unknown"));
+ }
+
+ return 1;
+}
+
+/* "maint print section-scripts" command. */
+
+static void
+maintenance_print_section_scripts (char *pattern, int from_tty)
+{
+ struct auto_load_pspace_info *pspace_info;
+
+ dont_repeat ();
+
+ if (pattern && *pattern)
+ {
+ char *re_err = re_comp (pattern);
+
+ if (re_err)
+ error (_("Invalid regexp: %s"), re_err);
+
+ printf_filtered (_("Objfile scripts matching %s:\n"), pattern);
+ }
+ else
+ {
+ re_comp ("");
+ printf_filtered (_("Objfile scripts:\n"));
+ }
+
+ pspace_info = get_auto_load_pspace_data (current_program_space);
+ if (pspace_info == NULL || pspace_info->loaded_scripts == NULL)
+ return;
+
+ immediate_quit++;
+ htab_traverse_noresize (pspace_info->loaded_scripts,
+ maybe_print_section_script, NULL);
+ immediate_quit--;
+}
+\f
+void
+gdbpy_initialize_auto_load (void)
+{
+ auto_load_pspace_data
+ = register_program_space_data_with_cleanup (auto_load_pspace_data_cleanup);
+
+ observer_attach_new_objfile (auto_load_new_objfile);
+
+ add_setshow_boolean_cmd ("auto-load", class_maintenance,
+ &gdbpy_auto_load, _("\
+Enable or disable auto-loading of Python code when an object is opened."), _("\
+Show whether Python code will be auto-loaded when an object is opened."), _("\
+Enables or disables auto-loading of Python code when an object is opened."),
+ NULL, NULL,
+ &set_python_list,
+ &show_python_list);
+
+ add_cmd ("section-scripts", class_maintenance, maintenance_print_section_scripts,
+ _("Print dump of auto-loaded section scripts matching REGEXP."),
+ &maintenanceprintlist);
+}
Index: python/python-internal.h
===================================================================
RCS file: /cvs/src/src/gdb/python/python-internal.h,v
retrieving revision 1.24
diff -u -p -r1.24 python-internal.h
--- python/python-internal.h 15 Apr 2010 19:54:13 -0000 1.24
+++ python/python-internal.h 16 Apr 2010 05:54:35 -0000
@@ -20,6 +20,8 @@
#ifndef GDB_PYTHON_INTERNAL_H
#define GDB_PYTHON_INTERNAL_H

+#include <stdio.h>
+
/* Python 2.4 doesn't include stdint.h soon enough to get {u,}intptr_t
needed by pyport.h. */
#include <stdint.h>
@@ -75,6 +77,9 @@ extern PyTypeObject value_object_type;
extern PyTypeObject block_object_type;
extern PyTypeObject symbol_object_type;

+extern struct cmd_list_element *set_python_list;
+extern struct cmd_list_element *show_python_list;
+
PyObject *gdbpy_history (PyObject *self, PyObject *args);
PyObject *gdbpy_breakpoints (PyObject *, PyObject *);
PyObject *gdbpy_frame_stop_reason_string (PyObject *, PyObject *);
@@ -107,6 +112,7 @@ struct type *type_object_to_type (PyObje
struct symtab *symtab_object_to_symtab (PyObject *obj);
struct symtab_and_line *sal_object_to_symtab_and_line (PyObject *obj);

+void gdbpy_initialize_auto_load (void);
void gdbpy_initialize_values (void);
void gdbpy_initialize_frames (void);
void gdbpy_initialize_symtabs (void);
@@ -154,6 +160,9 @@ extern const struct language_defn *pytho

void gdbpy_print_stack (void);

+void source_python_script_for_objfile (struct objfile *objfile,
+ FILE *stream, const char *file);
+
PyObject *python_string_to_unicode (PyObject *obj);
char *unicode_to_target_string (PyObject *unicode_str);
char *python_string_to_target_string (PyObject *obj);
Index: python/python.c
===================================================================
RCS file: /cvs/src/src/gdb/python/python.c,v
retrieving revision 1.32
diff -u -p -r1.32 python.c
--- python/python.c 15 Apr 2010 19:54:13 -0000 1.32
+++ python/python.c 16 Apr 2010 05:54:35 -0000
@@ -25,7 +25,6 @@
#include "gdbcmd.h"
#include "progspace.h"
#include "objfiles.h"
-#include "observer.h"
#include "value.h"
#include "language.h"
#include "exceptions.h"
@@ -36,10 +35,6 @@
false otherwise. */
static int gdbpy_should_print_stack = 1;

-/* This is true if we should auto-load python code when an objfile is
- opened, false otherwise. */
-static int gdbpy_auto_load = 1;
-
#ifdef HAVE_PYTHON

#include "python.h"
@@ -460,85 +455,33 @@ gdbpy_progspaces (PyObject *unused1, PyO
\f

/* The "current" objfile. This is set when gdb detects that a new
- objfile has been loaded. It is only set for the duration of a call
- to gdbpy_new_objfile; it is NULL at other times. */
+ objfile has been loaded. It is only set for the duration of a call to
+ source_python_script_for_objfile; it is NULL at other times. */
static struct objfile *gdbpy_current_objfile;

-/* The file name we attempt to read. */
-#define GDBPY_AUTO_FILENAME "-gdb.py"
+/* Set the current objfile to OBJFILE and then read STREAM,FILE as
+ Python code. */

-/* This is a new_objfile observer callback which loads python code
- based on the path to the objfile. */
-static void
-gdbpy_new_objfile (struct objfile *objfile)
+void
+source_python_script_for_objfile (struct objfile *objfile,
+ FILE *stream, const char *file)
{
- char *realname;
- char *filename, *debugfile;
- int len;
- FILE *input;
struct cleanup *cleanups;

- if (!gdbpy_auto_load || !objfile || !objfile->name)
- return;
-
cleanups = ensure_python_env (get_objfile_arch (objfile), current_language);
-
gdbpy_current_objfile = objfile;

- realname = gdb_realpath (objfile->name);
- len = strlen (realname);
- filename = xmalloc (len + sizeof (GDBPY_AUTO_FILENAME));
- memcpy (filename, realname, len);
- strcpy (filename + len, GDBPY_AUTO_FILENAME);
-
- input = fopen (filename, "r");
- debugfile = filename;
-
- make_cleanup (xfree, filename);
- make_cleanup (xfree, realname);
-
- if (!input && debug_file_directory)
- {
- /* Also try the same file in the separate debug info directory. */
- debugfile = xmalloc (strlen (filename)
- + strlen (debug_file_directory) + 1);
- strcpy (debugfile, debug_file_directory);
- /* FILENAME is absolute, so we don't need a "/" here. */
- strcat (debugfile, filename);
-
- make_cleanup (xfree, debugfile);
- input = fopen (debugfile, "r");
- }
-
- if (!input && gdb_datadir)
- {
- /* Also try the same file in a subdirectory of gdb's data
- directory. */
- debugfile = xmalloc (strlen (gdb_datadir) + strlen (filename)
- + strlen ("/auto-load") + 1);
- strcpy (debugfile, gdb_datadir);
- strcat (debugfile, "/auto-load");
- /* FILENAME is absolute, so we don't need a "/" here. */
- strcat (debugfile, filename);
-
- make_cleanup (xfree, debugfile);
- input = fopen (debugfile, "r");
- }
-
- if (input)
- {
- /* We don't want to throw an exception here -- but the user
- would like to know that something went wrong. */
- if (PyRun_SimpleFile (input, debugfile))
- gdbpy_print_stack ();
- fclose (input);
- }
+ /* We don't want to throw an exception here -- but the user
+ would like to know that something went wrong. */
+ if (PyRun_SimpleFile (stream, file))
+ gdbpy_print_stack ();

do_cleanups (cleanups);
gdbpy_current_objfile = NULL;
}

/* Return the current Objfile, or None if there isn't one. */
+
static PyObject *
gdbpy_get_current_objfile (PyObject *unused1, PyObject *unused2)
{
@@ -617,8 +560,8 @@ source_python_script (FILE *stream, cons

/* Lists for 'maint set python' commands. */

-static struct cmd_list_element *set_python_list;
-static struct cmd_list_element *show_python_list;
+struct cmd_list_element *set_python_list;
+struct cmd_list_element *show_python_list;

/* Function for use by 'maint set python' prefix command. */

@@ -683,15 +626,6 @@ Enables or disables printing of Python s
&set_python_list,
&show_python_list);

- add_setshow_boolean_cmd ("auto-load", class_maintenance,
- &gdbpy_auto_load, _("\
-Enable or disable auto-loading of Python code when an object is opened."), _("\
-Show whether Python code will be auto-loaded when an object is opened."), _("\
-Enables or disables auto-loading of Python code when an object is opened."),
- NULL, NULL,
- &set_python_list,
- &show_python_list);
-
#ifdef HAVE_PYTHON
Py_Initialize ();
PyEval_InitThreads ();
@@ -703,6 +637,7 @@ Enables or disables auto-loading of Pyth
PyModule_AddStringConstant (gdb_module, "HOST_CONFIG", (char*) host_name);
PyModule_AddStringConstant (gdb_module, "TARGET_CONFIG", (char*) target_name);

+ gdbpy_initialize_auto_load ();
gdbpy_initialize_values ();
gdbpy_initialize_frames ();
gdbpy_initialize_commands ();
@@ -719,8 +654,6 @@ Enables or disables auto-loading of Pyth
PyRun_SimpleString ("import gdb");
PyRun_SimpleString ("gdb.pretty_printers = []");

- observer_attach_new_objfile (gdbpy_new_objfile);
-
gdbpy_to_string_cst = PyString_FromString ("to_string");
gdbpy_children_cst = PyString_FromString ("children");
gdbpy_display_hint_cst = PyString_FromString ("display_hint");
Index: testsuite/gdb.python/py-section-script.c
===================================================================
RCS file: testsuite/gdb.python/py-section-script.c
diff -N testsuite/gdb.python/py-section-script.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.python/py-section-script.c 16 Apr 2010 05:54:35 -0000
@@ -0,0 +1,52 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 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 <http://www.gnu.org/licenses/>. */
+
+/* Put the path to the pretty-printer script in .debug_gdb_scripts so
+ gdb will automagically loaded it. */
+
+#define DEFINE_GDB_SCRIPT(script_name) \
+ asm("\
+.pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\n\
+.byte 1\n\
+.asciz \"" script_name "\"\n\
+.popsection \n\
+");
+
+DEFINE_GDB_SCRIPT ("py-section-script.py")
+
+struct ss
+{
+ int a;
+ int b;
+};
+
+void
+init_ss (struct ss *s, int a, int b)
+{
+ s->a = a;
+ s->b = b;
+}
+
+int
+main ()
+{
+ struct ss ss;
+
+ init_ss (&ss, 1, 2);
+
+ return 0; /* break to inspect struct and union */
+}
Index: testsuite/gdb.python/py-section-script.exp
===================================================================
RCS file: testsuite/gdb.python/py-section-script.exp
diff -N testsuite/gdb.python/py-section-script.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.python/py-section-script.exp 16 Apr 2010 05:54:35 -0000
@@ -0,0 +1,65 @@
+# Copyright (C) 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 <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite. It tests automagic loading of
+# scripts specified in the .debug_gdb_scripts section.
+
+# This test can only be run on targets which support ELF and use gas.
+# For now pick a sampling of likely targets.
+if {![istarget *-*-linux*]
+ && ![istarget *-*-gnu*]
+ && ![istarget *-*-elf*]
+ && ![istarget *-*-openbsd*]
+ && ![istarget arm-*-eabi*]
+ && ![istarget powerpc-*-eabi*]} {
+ verbose "Skipping py-section-script.exp because of lack of support."
+ return
+}
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+set testfile "py-section-script"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested "Couldn't compile ${srcfile}"
+ return -1
+}
+
+# Make this available to gdb before the program starts, it is
+# automagically loaded by gdb.
+set remote_python_file [remote_download host ${srcdir}/${subdir}/${testfile}.py]
+
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if ![runto_main] {
+ perror "couldn't run to main"
+ return
+}
+
+gdb_test "b [gdb_get_line_number {break to inspect} ${testfile}.c ]" \
+ ".*Breakpoint.*"
+gdb_test "continue" ".*Breakpoint.*"
+
+gdb_test "print ss" " = a=<1> b=<2>"
+
+remote_file host delete ${remote_python_file}
Index: testsuite/gdb.python/py-section-script.py
===================================================================
RCS file: testsuite/gdb.python/py-section-script.py
diff -N testsuite/gdb.python/py-section-script.py
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.python/py-section-script.py 16 Apr 2010 05:54:35 -0000
@@ -0,0 +1,63 @@
+# Copyright (C) 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 <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite.
+
+import re
+
+class pp_ss:
+ def __init__(self, val):
+ self.val = val
+
+ def to_string(self):
+ return "a=<" + str(self.val["a"]) + "> b=<" + str(self.val["b"]) + ">"
+
+def lookup_function (val):
+ "Look-up and return a pretty-printer that can print val."
+
+ # Get the type.
+ type = val.type
+
+ # If it points to a reference, get the reference.
+ if type.code == gdb.TYPE_CODE_REF:
+ type = type.target ()
+
+ # Get the unqualified type, stripped of typedefs.
+ type = type.unqualified ().strip_typedefs ()
+
+ # Get the type name.
+ typename = type.tag
+
+ if typename == None:
+ return None
+
+ # Iterate over local dictionary of types to determine
+ # if a printer is registered for that type. Return an
+ # instantiation of the printer if found.
+ for function in pretty_printers_dict:
+ if function.match (typename):
+ return pretty_printers_dict[function] (val)
+
+ # Cannot find a pretty printer. Return None.
+
+ return None
+
+def register_pretty_printers ():
+ pretty_printers_dict[re.compile ('^ss$')] = pp_ss
+
+pretty_printers_dict = {}
+
+register_pretty_printers ()
+gdb.current_progspace().pretty_printers.append (lookup_function)