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.
This commit is contained in:
parent
c8551de35c
commit
8a1ea21f7e
11 changed files with 846 additions and 131 deletions
|
@ -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)
|
||||
|
|
4
gdb/NEWS
4
gdb/NEWS
|
@ -71,6 +71,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
|
||||
|
|
|
@ -483,7 +483,7 @@ Script filename extension recognition is \"%s\".\n"),
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
|
@ -19741,6 +19741,7 @@ Python programming language}. This feature is available only if
|
|||
@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
|
||||
|
@ -19818,7 +19819,6 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
|
|||
@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 API:: Pretty-printing values.
|
||||
|
@ -19964,53 +19964,6 @@ message as its value, and the Python call stack backtrace at the
|
|||
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
|
||||
|
@ -21640,6 +21593,162 @@ resolve this to the lazy string's character type, use the type's
|
|||
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 look for @var{real-name} in all of the
|
||||
directories mentioned in the value of @code{debug-file-directory}.
|
||||
|
||||
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
|
||||
|
@ -29442,6 +29551,16 @@ Print a dump of all known object files. For each object file, this
|
|||
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
|
||||
|
|
459
gdb/python/py-auto-load.c
Normal file
459
gdb/python/py-auto-load.c
Normal file
|
@ -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);
|
||||
}
|
|
@ -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 (PyObject *obj);
|
|||
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 *python_language;
|
|||
|
||||
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);
|
||||
|
|
|
@ -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, PyObject *unused2)
|
|||
|
||||
|
||||
/* 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, const char *file)
|
|||
|
||||
/* 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 stack traces."),
|
|||
&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 Python code when an object is opened."),
|
|||
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 Python code when an object is opened."),
|
|||
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");
|
||||
|
|
52
gdb/testsuite/gdb.python/py-section-script.c
Normal file
52
gdb/testsuite/gdb.python/py-section-script.c
Normal file
|
@ -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 */
|
||||
}
|
65
gdb/testsuite/gdb.python/py-section-script.exp
Normal file
65
gdb/testsuite/gdb.python/py-section-script.exp
Normal file
|
@ -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}
|
63
gdb/testsuite/gdb.python/py-section-script.py
Normal file
63
gdb/testsuite/gdb.python/py-section-script.py
Normal file
|
@ -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)
|
Loading…
Reference in a new issue