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

Doug Evans dje@google.com
Wed Apr 21 19:23:00 GMT 2010


I've applied the requested doc changes, except that Auto-loading is
still moved up one level, moved from node Python API to node Python.

I'm going to defer fixing DOS path support to a separate patch.  This
is a bug in the existing code (all this patch does is move said code
from one file to another), and I don't want to overload this patch.

If there are no objections I will check this in tomorrow.

2010-04-21  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.
-------------- next part --------------
2010-04-21  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: 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	21 Apr 2010 19:07:16 -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: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.373
diff -u -p -r1.373 NEWS
--- NEWS	19 Apr 2010 00:48:43 -0000	1.373
+++ NEWS	21 Apr 2010 19:07:17 -0000
@@ -67,6 +67,10 @@ is now deprecated.
 
 ** Pretty-printers are now also looked up in the current program space.
 
+** GDB now looks for names of Python scripts to auto-load in a
+   special section named `.debug_gdb_scripts', in addition to looking
+   for a OBJFILE-gdb.py script when OBJFILE is read by the debugger.
+
 * 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: 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	21 Apr 2010 19:07:17 -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	21 Apr 2010 19:07:17 -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.708
diff -u -p -r1.708 gdb.texinfo
--- doc/gdb.texinfo	19 Apr 2010 00:48:44 -0000	1.708
+++ doc/gdb.texinfo	21 Apr 2010 19:07:18 -0000
@@ -19685,6 +19685,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
@@ -19762,7 +19763,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.
@@ -19908,53 +19908,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
@@ -21611,6 +21564,163 @@ 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 Python support scripts in several ways:
+@file{@var{objfile}-gdb.py} and @code{.debug_gdb_scripts} section.
+
+@menu
+* objfile-gdb.py file::         The @file{@var{objfile}-gdb.py} file
+* .debug_gdb_scripts section::  The @code{.debug_gdb_scripts} section
+* Which flavor to choose?::
+@end menu
+
+The auto-loading feature is useful for supplying application-specific
+debugging commands and scripts.
+
+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
+
+When reading an auto-loaded file, @value{GDBN} sets the
+@dfn{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.
+
+@node objfile-gdb.py file
+@subsubsection The @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 @file{-gdb.py} file should be careful to avoid errors if it
+is evaluated more than once.
+
+@node .debug_gdb_scripts section
+@subsubsection The @code{.debug_gdb_scripts} section
+@cindex @code{.debug_gdb_scripts} section
+
+For systems using file formats like ELF and COFF,
+when @value{GDBN} loads a new object file
+it will look for a special section named @samp{.debug_gdb_scripts}.
+If this section exists, its contents is a list of names of scripts to load.
+
+@value{GDBN} will look for each specified script file first in the
+current directory and then along the source search path
+(@pxref{Source Path, ,Specifying Source Directories}),
+except that @file{$cdir} is not searched, since the compilation
+directory is not relevant to scripts.
+
+Entries can be placed in section @code{.debug_gdb_scripts} with,
+for example, this GCC macro:
+
+@example
+/* Note: The "MS" section flags are to remote duplicates.  */
+#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
+
+@noindent
+Then one can reference the macro in a header or source file like this:
+
+@example
+DEFINE_GDB_SCRIPT ("my-app-scripts.py")
+@end example
+
+The script name may include directories if desired.
+
+If the macro is put in a header, any application or library
+using this header will get a reference to the specified script.
+
+@node Which flavor to choose?
+@subsubsection Which flavor to choose?
+
+Given the multiple ways of auto-loading Python 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 @code{.debug_gdb_scripts} section are searched for
+in the source search path.
+For publicly installed libraries, e.g., @file{libstdc++}, there typically
+isn't a source directory in which to find the script.
+
+@item
+Doesn't require source code additions.
+@end itemize
+
+Benefits of the @code{.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
+@code{.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
@@ -29413,6 +29523,16 @@ 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 @code{.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.
+@xref{.debug_gdb_scripts section}.
+
 @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	21 Apr 2010 19:07:18 -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);
+    }
+}
+

+/* 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--;
+}
+

+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	21 Apr 2010 19:07:18 -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	21 Apr 2010 19:07:18 -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
 

 
 /* 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,16 +626,7 @@ 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 +643,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 +660,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	21 Apr 2010 19:07:18 -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	21 Apr 2010 19:07:18 -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	21 Apr 2010 19:07:18 -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)


More information about the Gdb-patches mailing list