Re: [patch][python] Add symbol, symbol table and frame block support to GDB API

Phil Muldoon
2010-02-19T14:15:45Z

On Wed, Feb 17, 2010 at 07:49:56PM -0700, Tom Tromey wrote:
> I think this could use a NEWS entry. I suggest waiting until my earlier
> patch is approved, then adding items to that block... assuming your
> patch goes in before 7.1. Otherwise, add a new Python block in the
> post-7.1 changes.

I included one in the patch I sent. Here is the hunk:

diff --git a/gdb/NEWS b/gdb/NEWS
index 867b51f..a7bdec8 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -203,6 +203,11 @@ QTDisconnected
qTfP, qTsP
Get data about the tracepoints currently in use.

+* Python scripting
+
+The GDB Python API now has access to symbols, symbol tables, and
+frame's code blocks.
+

This hunk puts it in the 7.1 release section. I'll move it when we
figure out what release it will be in (as of today, looks like 7.2).

> Phil> +/* Require a valid block. All access to block_object->block should be
> Phil> + gated by this call. This must be called inside a TRY_CATCH, or
> Phil> + another context in which a gdb exception is allowed. */
> Phil> +#define BLPY_REQUIRE_VALID(block_obj, block) \
> Phil> + do { \
> Phil> + block = block_object_to_block (block_obj); \
> Phil> + if (block == NULL) \
> Phil> + error (_("Block is invalid.")); \
> Phil> + } while (0)
>
> All the uses of this macro appear in a TRY_CATCH, which is then followed
> by GDB_PY_HANDLE_EXCEPTION. That is quite roundabout; it would be
> better to bypass the middle man and just set the Python exception
> directly and `return NULL'.

I ended up just reusing the FRAPY_REQUIRE_VALID code that is in
py-frame.c. But (as you point out) it is roundabout. I can't think why I
did not spot this in the first place. ;) Anyway, changed as suggested
in all iterations in the attached patch.

> Phil> +static PyObject *
> Phil> +blpy_block_syms_iternext (PyObject *self)
> [...]
> Phil> + return (sym == NULL) ? NULL : symbol_to_symbol_object (sym);
>
> If you return NULL you must set the Python exception.
> I think in this case you want to raise StopIteration.

OK.

> Phil> +static PyObject *
> Phil> +sympy_str (PyObject *self)
> Phil> +{
> Phil> + char *s;
> Phil> + PyObject *result;
> Phil> + struct symbol *symbol = NULL;
> Phil> + volatile struct gdb_exception except;
> Phil> +
> Phil> + TRY_CATCH (except, RETURN_MASK_ALL)
> Phil> + {
> Phil> + SYMPY_REQUIRE_VALID (self, symbol);
> Phil> + }
> Phil> + GDB_PY_HANDLE_EXCEPTION (except);
> Phil> +
> Phil> + s = xstrprintf ("symbol for %s",
> Phil> + SYMBOL_PRINT_NAME (symbol));
>
> Why not just have this be SYMBOL_PRINT_NAME?
>
> I forgot the difference between the various python to-string methods.
> Maybe this one is supposed to be more verbose? Let me know.

One of the tricky things I've found in merging work is I'm often not
the original author of that work. In this case, I just deferred to
the case as written. And my understanding of Python's "print object"
-> string is more for human consumption that for comparison or
assingment. That being said, I've no strong feelings on it. I did not
change it in this patch. If you want it changed, I'll happily do it.

> Phil> + obj->next = objfile_data (symbol->symtab->objfile, sympy_objfile_data_key);
>
> Use the SYMBOL_SYMTAB macro here, and anywhere you have to refer to the
> symbol's symtab.

OK, and in all cases.

> Phil> + set_objfile_data (sym_obj->symbol->symtab->objfile, sympy_objfile_data_key, sym_obj->next);
>
> This wraps, I think a couple of other lines nearby do too.
> Line break after a comma somewhere.

OK, and in all other cases.

> Phil> + s = xstrprintf ("symbol table for %s",
> Phil> + symtab->filename);
>
> Also as above.

I'm not sure what this means, is it referring to the sympy_str
comment? If so, the reasoning is the same. If not, can you elaborate
further?

> Phil> + result = objfile_to_objfile_object (symtab->objfile);
> Phil> + Py_INCREF (result);
> Phil> + return result;
>
> objfile_to_objfile_object can return NULL, which would make
> that incref crash.

In this case, I just changed to Py_XINCREF. This is NULL safe, and if
objfile_to_objfile returns a NULL there should be an exception set.

> Phil> + s = xstrprintf ("symbol and line for %s, line %d", filename,
> Phil> + sal->line);
>

Ditto, sympy_str comment.

>
> Phil> + if (symtab_obj == NULL)
> Phil> + {
> Phil> + Py_DECREF (sal_obj);
> Phil> + return;
> Phil> + }
>
> This does not make sense to me.
> This destroys the sal_obj but the caller then proceeds to return it.

>
> Phil> +PyObject *
> Phil> +symtab_and_line_to_sal_object (struct symtab_and_line sal)
> Phil> +
> Phil> +{
> Phil> + sal_object *sal_obj;
> Phil> + symtab_object *symtab_obj;
> Phil> +
> Phil> + sal_obj = PyObject_New (sal_object, &sal_object_type);
> Phil> +
> Phil> + if (sal_obj)
> Phil> + set_sal (sal_obj, sal);
> Phil> +
> Phil> + return (PyObject *) sal_obj;
>
> Here's the bad return. If set_sal destroy sal_obj, gdb will crash.

Thanks for spotting this. I'm not sure what was going on there. :(
I've rewritten the code. If:

symtab_obj = (symtab_object *) symtab_to_symtab_object (sal.symtab);

returns NULL (the only failure case in the above function, I return
NULL. I believe the Python exception should already be set from the
previous call, so I preserve that. Then further on, in set_sal I check
for success. If not, I return NULL again and the original Python
exception should propogate.

> Phil> +static PyMethodDef symtab_object_methods[] = {
> Phil> + { "fullname", stpy_fullname, METH_NOARGS,
> Phil> + "Return the symtab's full source filename." },
>
> For methods we're trying to put the type info into the help.
> I forgot to check the other new methods in this patch, but please do
> this. See the existing python.c for examples.

OK.

> Phil> "lookup_type (name [, block]) -> type\n\
> Phil> Return a Type corresponding to the given name." },
>
> It is funny that this "[, block]" help is still there.
> I must have forgot to remove this when I stripped the block stuff from a
> patch I upstreamed.
>
> Anyway, I was going to mention this ... could you put the block code
> back into lookup_type? It is fine by me if you'd rather do this as a
> second patch.
>
> There may be some other block-related addition on the branch that should
> go in now. I forget.

I've done all the ones in py-frame. I just missed the one in
py-type. I'll send any fixes (including the one above) in a seperate patch.

Anyway patch follows:

Cheers,

Phil

--

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 98f42b9..d0764fd 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -267,23 +267,29 @@ SUBDIR_TUI_CFLAGS= \
#
SUBDIR_PYTHON_OBS = \
python.o \
+ py-block.o \
py-cmd.o \
py-frame.o \
py-function.o \
py-lazy-string.o \
py-objfile.o \
py-prettyprint.o \
+ py-symbol.o \
+ py-symtab.o \
py-type.o \
py-utils.o \
py-value.o
SUBDIR_PYTHON_SRCS = \
python/python.c \
+ python/py-block.c \
python/py-cmd.c \
python/py-frame.c \
python/py-function.c \
python/py-lazy-string.c \
python/py-objfile.c \
python/py-prettyprint.c \
+ python/py-symbol.c \
+ python/py-symtab.c \
python/py-type.c \
python/py-utils.c \
python/py-value.c
@@ -1970,6 +1976,10 @@ python.o: $(srcdir)/python/python.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python.c
$(POSTCOMPILE)

+py-block.o: $(srcdir)/python/py-block.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-block.c
+ $(POSTCOMPILE)
+
py-cmd.o: $(srcdir)/python/py-cmd.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-cmd.c
$(POSTCOMPILE)
@@ -1994,6 +2004,14 @@ py-prettyprint.o: $(srcdir)/python/py-prettyprint.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-prettyprint.c
$(POSTCOMPILE)

+py-symbol.o: $(srcdir)/python/py-symbol.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-symbol.c
+ $(POSTCOMPILE)
+
+py-symtab.o: $(srcdir)/python/py-symtab.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-symtab.c
+ $(POSTCOMPILE)
+
py-type.o: $(srcdir)/python/py-type.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-type.c
$(POSTCOMPILE)
diff --git a/gdb/NEWS b/gdb/NEWS
index 9592d39..f807b11 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -240,6 +240,11 @@ QTDisconnected
qTfP, qTsP
Get data about the tracepoints currently in use.

+* Python scripting
+
+The GDB Python API now has access to symbols, symbol tables, and
+frame's code blocks.
+
* Bug fixes

Process record now works correctly with hardware watchpoints.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 0e3e093..fdb7ddb 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -19547,7 +19547,10 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
* Commands In Python:: Implementing new commands in Python.
* Functions In Python:: Writing new convenience functions.
* Objfiles In Python:: Object files.
-* Frames In Python:: Acessing inferior stack frames from Python.
+* Frames In Python:: Accessing inferior stack frames from Python.
+* Blocks In Python:: Accessing frame blocks from Python.
+* Symbols In Python:: Python representation of symbols.
+* Symbol Tables In Python:: Python representation of symbol tables.
* Lazy Strings In Python:: Python representation of lazy strings.
@end menu

@@ -20707,7 +20710,7 @@ information.
@end defivar

@node Frames In Python
-@subsubsection Acessing inferior stack frames from Python.
+@subsubsection Accessing inferior stack frames from Python.

@cindex frames in python
When the debugged program stops, @value{GDBN} is able to analyze its call
@@ -20770,6 +20773,15 @@ function to a string.
Returns the frame's resume address.
@end defmethod

+@defmethod Frame block
+Returns the frame's code block. @xref{Blocks In Python}.
+@end defmethod
+
+@defmethod Frame function
+Returns the symbol for the function corresponding to this frame.
+@xref{Symbols In Python}.
+@end defmethod
+
@defmethod Frame older
Return the frame that called this frame.
@end defmethod
@@ -20778,10 +20790,308 @@ Return the frame that called this frame.
Return the frame called by this frame.
@end defmethod

+@defmethod Frame find_sal
+Return the frame's symtab and line object.
+@xref{Symbol Tables In Python}.
+@end defmethod
+
@defmethod Frame read_var variable
Return the value of the given variable in this frame. @var{variable} must
be a string.
@end defmethod
+
+@defmethod Frame select
+Set this frame to be the selected frame. @xref{Stack, ,Examining the
+Stack}.
+@end defmethod
+@end table
+
+@node Blocks In Python
+@subsubsection Accessing frame blocks from Python.
+
+@cindex blocks in python
+@tindex gdb.Block
+
+Within each frame, @value{GDBN} maintains information on each block
+stored in that frame. These blocks are organized hierarchically, and
+are represented individually in Python as a @code{gdb.Block}.
+Please see @ref{Frames In Python} for a more in-depth discussion on
+frames. Furthermore, see @ref{Stack, ,Examining the Stack} for more
+detailed technical information on @value{GDBN}'s book-keeping of the
+stack.
+
+The following block-related functions are available in the @code{gdb}
+module:
+
+@findex gdb.block_for_pc
+@defun block_for_pc pc
+Return the @code{gdb.Block} containing the given @var{pc} value. If the
+block cannot be found for the @var{pc} value specified, the function
+will return @code{None}.
+@end defun
+
+A @code{gdb.Block} object has the following attributes:
+
+@table @code
+@defivar Block start
+The start address of the block. This attribute is not writable.
+@end defivar
+
+@defivar Block end
+The end address of the block. This attribute is not writable.
+@end defivar
+
+@defivar Block function
+The name of the block represented as a @code{gdb.Symbol}. If the
+block is not named, then this attribute holds @code{None}. This
+attribute is not writable.
+@end defivar
+
+@defivar Block superblock
+The block containing this block. If this parent block does not exist,
+this attribute holds @code{None}. This attribute is not writable.
+@end defivar
+@end table
+
+@node Symbols In Python
+@subsubsection Python representation of Symbols.
+
+@cindex symbols in python
+@tindex gdb.Symbol
+
+@value{GDBN} represents every variable, function and type as an
+entry in a symbol table. @xref{Symbols, ,Examining the Symbol Table}.
+Similarly, Python represents these symbols in @value{GDBN} with the
+@code{gdb.Symbol} object.
+
+The following symbol-related functions are available in the @code{gdb}
+module:
+
+@findex gdb.lookup_symbol
+@defun lookup_symbol name [block] [domain]
+This function searches for a symbol by name. The search scope can be
+restricted to the parameters defined in the optional domain and block
+arguments.
+
+@var{name} is the name of the symbol. It must be a string. The
+optional @var{block} argument restricts the search to symbols visible
+in that @var{block}. The @var{block} argument must be a
+@code{gdb.Block} object. The optional @var{domain} argument restricts
+the search to the domain type. The @var{domain} argument must be a
+domain constant defined in the @code{gdb} module and described later
+in this chapter.
+@end defun
+
+A @code{gdb.Symbol} object has the following attributes:
+
+@table @code
+@defivar Symbol symtab
+The symbol table in which the symbol appears. This attribute is
+represented as a @code{gdb.Symtab} object. @xref{Symbol Tables In
+Python}. This attribute is not writable.
+@end defivar
+
+@defivar Symbol name
+The name of the symbol as a string. This attribute is not writable.
+@end defivar
+
+@defivar Symbol linkage_name
+The name of the symbol, as used by the linker (i.e., may be mangled).
+This attribute is not writable.
+@end defivar
+
+@defivar Symbol print_name
+The name of the symbol in a form suitable for output. This is either
+@code{name} or @code{linkage_name}, depending on whether the user
+asked @value{GDBN} to display demangled or mangled names.
+@end defivar
+
+@defivar Symbol addr_class
+The address class of the symbol. This classifies how to find the value
+of a symbol. Each address class is a constant defined in the
+@code{gdb} module and described later in this chapter.
+@end defivar
+
+@defivar Symbol is_argument
+@code{True} if the symbol is an argument of a function.
+@end defivar
+
+@defivar Symbol is_constant
+@code{True} if the symbol is a constant.
+@end defivar
+
+@defivar Symbol is_function
+@code{True} if the symbol is a function or a method.
+@end defivar
+
+@defivar Symbol is_variable
+@code{True} if the symbol is a variable.
+@end defivar
+@end table
+
+The available domain categories in @code{gdb.Symbol} are represented
+as constants in the @code{gdb} module:
+
+@table @code
+@findex SYMBOL_UNDEF_DOMAIN
+@findex gdb.SYMBOL_UNDEF_DOMAIN
+@item SYMBOL_UNDEF_DOMAIN
+This is used when a domain has not been discovered or none of the
+following domains apply. This usually indicates an error either
+in the symbol information or in @value{GDBN}'s handling of symbols.
+@findex SYMBOL_VAR_DOMAIN
+@findex gdb.SYMBOL_VAR_DOMAIN
+@item SYMBOL_VAR_DOMAIN
+This domain contains variables, function names, typedef names and enum
+type values.
+@findex SYMBOL_STRUCT_DOMAIN
+@findex gdb.SYMBOL_STRUCT_DOMAIN
+@item SYMBOL_STRUCT_DOMAIN
+This domain holds struct, union and enum type names.
+@findex SYMBOL_LABEL_DOMAIN
+@findex gdb.SYMBOL_LABEL_DOMAIN
+@item SYMBOL_LABEL_DOMAIN
+This domain contains names of labels (for gotos).
+@findex SYMBOL_VARIABLES_DOMAIN
+@findex gdb.SYMBOL_VARIABLES_DOMAIN
+@item SYMBOL_VARIABLES_DOMAIN
+This domain holds a subset of the @code{SYMBOLS_VAR_DOMAIN}; it
+contains everything minus functions and types.
+@findex SYMBOL_FUNCTIONS_DOMAIN
+@findex gdb.SYMBOL_FUNCTIONS_DOMAIN
+@item SYMBOL_FUNCTION_DOMAIN
+This domain contains all functions.
+@findex SYMBOL_TYPES_DOMAIN
+@findex gdb.SYMBOL_TYPES_DOMAIN
+@item SYMBOL_TYPES_DOMAIN
+This domain contains all types.
+@end table
+
+The available address class categories in @code{gdb.Symbol} are represented
+as constants in the @code{gdb} module:
+
+@table @code
+@findex SYMBOL_LOC_UNDEF
+@findex gdb.SYMBOL_LOC_UNDEF
+@item SYMBOL_LOC_UNDEF
+If this is returned by address class, it indicates an error either in
+the symbol information or in @value{GDBN}'s handling of symbols.
+@findex SYMBOL_LOC_CONST
+@findex gdb.SYMBOL_LOC_CONST
+@item SYMBOL_LOC_CONST
+Value is constant int.
+@findex SYMBOL_LOC_STATIC
+@findex gdb.SYMBOL_LOC_STATIC
+@item SYMBOL_LOC_STATIC
+Value is at a fixed address.
+@findex SYMBOL_LOC_REGISTER
+@findex gdb.SYMBOL_LOC_REGISTER
+@item SYMBOL_LOC_REGISTER
+Value is in a register.
+@findex SYMBOL_LOC_ARG
+@findex gdb.SYMBOL_LOC_ARG
+@item SYMBOL_LOC_ARG
+Value is an argument. This value is at the offset stored within the
+symbol inside the frame's argument list.
+@findex SYMBOL_LOC_REF_ARG
+@findex gdb.SYMBOL_LOC_REF_ARG
+@item SYMBOL_LOC_REF_ARG
+Value address is stored in the frame's argument list. Just like
+@code{LOC_ARG} except that the value's address is stored at the
+offset, not the value itself.
+@findex SYMBOL_LOC_REGPARM_ADDR
+@findex gdb.SYMBOL_LOC_REGPARM_ADDR
+@item SYMBOL_LOC_REGPARM_ADDR
+Value is a specified register. Just like @code{LOC_REGISTER} except
+the register holds the address of the argument instead of the argument
+itself.
+@findex SYMBOL_LOC_LOCAL
+@findex gdb.SYMBOL_LOC_LOCAL
+@item SYMBOL_LOC_LOCAL
+Value is a local variable.
+@findex SYMBOL_LOC_TYPEDEF
+@findex gdb.SYMBOL_LOC_TYPEDEF
+@item SYMBOL_LOC_TYPEDEF
+Value not used. Symbols in the domain @code{SYMBOL_STRUCT_DOMAIN} all
+have this class.
+@findex SYMBOL_LOC_BLOCK
+@findex gdb.SYMBOL_LOC_BLOCK
+@item SYMBOL_LOC_BLOCK
+Value is a block.
+@findex SYMBOL_LOC_CONST_BYTES
+@findex gdb.SYMBOL_LOC_CONST_BYTES
+@item SYMBOL_LOC_CONST_BYTES
+Value is a byte-sequence.
+@findex SYMBOL_LOC_UNRESOLVED
+@findex gdb.SYMBOL_LOC_UNRESOLVED
+@item SYMBOL_LOC_UNRESOLVED
+Value is at a fixed address, but the address of the variable has to be
+determined from the minimal symbol table whenever the variable is
+referenced.
+@findex SYMBOL_LOC_OPTIMIZED_OUT
+@findex gdb.SYMBOL_LOC_OPTIMIZED_OUT
+@item SYMBOL_LOC_OPTIMIZED_OUT
+The value does not actually exist in the program.
+@findex SYMBOL_LOC_COMPUTED
+@findex gdb.SYMBOL_LOC_COMPUTED
+@item SYMBOL_LOC_COMPUTED
+The value's address is a computed location.
+@end table
+
+@node Symbol Tables In Python
+@subsubsection Symbol table representation in Python.
+
+@cindex symbol tables in python
+@tindex gdb.Symtab
+@tindex gdb.Symtab_and_line
+
+Access to symbol table data maintained by @value{GDBN} on the inferior
+is exposed to Python via two objects: @code{gdb.Symtab_and_line} and
+@code{gdb.Symtab}. Symbol table and line data for a frame is returned
+from the @code{find_sal} method in @code{gdb.Frame} object.
+@xref{Frames In Python}.
+
+For more information on @value{GDBN}'s symbol table management, see
+@ref{Symbols, ,Examining the Symbol Table} for more information.
+
+A @code{gdb.Symtab_and_line} object has the following attributes:
+
+@table @code
+@defivar Symtab_and_line symtab
+The symbol table object (@code{gdb.Symtab}) for this frame.
+This attribute is not writable.
+@end defivar
+
+@defivar Symtab_and_line pc
+Indicates the current program counter address. This attribute is not
+writable.
+@end defivar
+
+@defivar Symtab_and_line line
+Indicates the current line number for this object. This
+attribute is not writable.
+@end defivar
+@end table
+
+A @code{gdb.Symtab} object has the following attributes:
+
+@table @code
+@defivar Symtab filename
+The symbol table's source filename. This attribute is not writable.
+@end defivar
+
+@defivar Symtab objfile
+The symbol table's backing object file. @xref{Objfiles In Python}.
+This attribute is not writable.
+@end defivar
+@end table
+
+The following methods are provided:
+
+@table @code
+@defmethod Symtab fullname
+Return the symbol table's source absolute file name.
+@end defmethod
@end table

@node Lazy Strings In Python
diff --git a/gdb/python/py-block.c b/gdb/python/py-block.c
new file mode 100644
index 0000000..30db04e
--- /dev/null
+++ b/gdb/python/py-block.c
@@ -0,0 +1,418 @@
+/* Python interface to blocks.
+
+ Copyright (C) 2008, 2009, 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 "block.h"
+#include "dictionary.h"
+#include "symtab.h"
+#include "python-internal.h"
+#include "objfiles.h"
+#include "symtab.h"
+
+typedef struct blpy_block_object {
+ PyObject_HEAD
+ /* The GDB block structure that represents a frame's code block. */
+ struct block *block;
+ /* The backing object file. There is no direct relationship in GDB
+ between a block and an object file. When a block is created also
+ store a pointer to the object file for later use. */
+ struct objfile *objfile;
+ /* Keep track of all blocks with a doubly-linked list. Needed for
+ block invalidation if the source object file has been freed. */
+ struct blpy_block_object *prev;
+ struct blpy_block_object *next;
+} block_object;
+
+typedef struct {
+ PyObject_HEAD
+ /* The block dictionary of symbols. */
+ struct dictionary *dict;
+ /* The iterator for that dictionary. */
+ struct dict_iterator iter;
+ /* Has the iterator been initialized flag. */
+ int initialized_p;
+ /* Pointer back to the original source block object. Needed to
+ check if the block is still valid, and has not been invalidated
+ when an object file has been freed. */
+ struct blpy_block_object *source;
+} block_syms_iterator_object;
+
+/* Require a valid block. All access to block_object->block should be
+ gated by this call. */
+#define BLPY_REQUIRE_VALID(block_obj, block) \
+ do { \
+ block = block_object_to_block (block_obj); \
+ if (block == NULL) \
+ { \
+ PyErr_SetString (PyExc_RuntimeError, \
+ "Block is invalid."); \
+ return NULL; \
+ } \
+ } while (0)
+
+/* Require a valid block. This macro is called during block iterator
+ creation, and at each next call. */
+#define BLPY_ITER_REQUIRE_VALID(block_obj) \
+ do { \
+ if (block_obj->block == NULL) \
+ { \
+ PyErr_SetString (PyExc_RuntimeError, \
+ _("Source block for iterator is invalid.")); \
+ return NULL; \
+ } \
+ } while (0)
+
+static PyTypeObject block_syms_iterator_object_type;
+static const struct objfile_data *blpy_objfile_data_key;
+
+static PyObject *
+blpy_iter (PyObject *self)
+{
+ block_syms_iterator_object *block_iter_obj;
+ struct block *block = NULL;
+
+ BLPY_REQUIRE_VALID (self, block);
+
+ block_iter_obj = PyObject_New (block_syms_iterator_object,
+ &block_syms_iterator_object_type);
+ if (block_iter_obj == NULL)
+ return NULL;
+
+ block_iter_obj->dict = BLOCK_DICT (block);
+ block_iter_obj->initialized_p = 0;
+ Py_INCREF (self);
+ block_iter_obj->source = (block_object *) self;
+
+ return (PyObject *) block_iter_obj;
+}
+
+static PyObject *
+blpy_get_start (PyObject *self, void *closure)
+{
+ struct block *block = NULL;
+
+ BLPY_REQUIRE_VALID (self, block);
+
+ return PyLong_FromUnsignedLongLong (BLOCK_START (block));
+}
+
+static PyObject *
+blpy_get_end (PyObject *self, void *closure)
+{
+ struct block *block = NULL;
+
+ BLPY_REQUIRE_VALID (self, block);
+
+ return PyLong_FromUnsignedLongLong (BLOCK_END (block));
+}
+
+static PyObject *
+blpy_get_function (PyObject *self, void *closure)
+{
+ struct symbol *sym;
+ struct block *block = NULL;
+
+ BLPY_REQUIRE_VALID (self, block);
+
+ sym = BLOCK_FUNCTION (block);
+ if (sym)
+ return symbol_to_symbol_object (sym);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+blpy_get_superblock (PyObject *self, void *closure)
+{
+ struct block *block = NULL;
+ struct block *super_block = NULL;
+ block_object *self_obj = (block_object *) self;
+
+ BLPY_REQUIRE_VALID (self, block);
+
+ super_block = BLOCK_SUPERBLOCK (block);
+ if (super_block)
+ return block_to_block_object (super_block, self_obj->objfile);
+
+ Py_RETURN_NONE;
+}
+
+static void
+blpy_dealloc (PyObject *obj)
+{
+ block_object *block = (block_object *) obj;
+
+ if (block->prev)
+ block->prev->next = block->next;
+ else if (block->objfile)
+ {
+ set_objfile_data (block->objfile, blpy_objfile_data_key,
+ block->next);
+ }
+ if (block->next)
+ block->next->prev = block->prev;
+ block->block = NULL;
+}
+
+/* Given a block, and a block_object that has previously been
+ allocated and initialized, populate the block_object with the
+ struct block data. Also, register the block_object life-cycle
+ with the life-cycle of the the object file associated with this
+ block, if needed. */
+static void
+set_block (block_object *obj, struct block *block,
+ struct objfile *objfile)
+{
+ obj->block = block;
+ obj->prev = NULL;
+ if (objfile)
+ {
+ obj->objfile = objfile;
+ obj->next = objfile_data (objfile, blpy_objfile_data_key);
+ if (obj->next)
+ obj->next->prev = obj;
+ set_objfile_data (objfile, blpy_objfile_data_key, obj);
+ }
+ else
+ obj->next = NULL;
+}
+
+/* Create a new block object (gdb.Block) that encapsulates the struct
+ block object from GDB. */
+PyObject *
+block_to_block_object (struct block *block, struct objfile *objfile)
+{
+ block_object *block_obj;
+
+ block_obj = PyObject_New (block_object, &block_object_type);
+ if (block_obj)
+ set_block (block_obj, block, objfile);
+
+ return (PyObject *) block_obj;
+}
+
+/* Return struct block reference that is wrapped by this object. */
+struct block *
+block_object_to_block (PyObject *obj)
+{
+ if (! PyObject_TypeCheck (obj, &block_object_type))
+ return NULL;
+ return ((block_object *) obj)->block;
+}
+
+/* Return a reference to the block iterator. */
+static PyObject *
+blpy_block_syms_iter (PyObject *self)
+{
+ block_syms_iterator_object *iter_obj = (block_syms_iterator_object *) self;
+
+ BLPY_ITER_REQUIRE_VALID (iter_obj->source);
+
+ Py_INCREF (self);
+ return self;
+}
+
+/* Return the next symbol in the iteration through the block's
+ dictionary. */
+static PyObject *
+blpy_block_syms_iternext (PyObject *self)
+{
+ block_syms_iterator_object *iter_obj = (block_syms_iterator_object *) self;
+ struct symbol *sym;
+
+ BLPY_ITER_REQUIRE_VALID (iter_obj->source);
+
+ if (!iter_obj->initialized_p)
+ {
+ sym = dict_iterator_first (iter_obj->dict, &(iter_obj->iter));
+ iter_obj->initialized_p = 1;
+ }
+ else
+ sym = dict_iterator_next (&(iter_obj->iter));
+
+ if (sym == NULL)
+ {
+ PyErr_SetString (PyExc_StopIteration, "Symbol is null.");
+ return NULL;
+ }
+
+ return symbol_to_symbol_object (sym);
+}
+
+static void
+blpy_block_syms_dealloc (PyObject *obj)
+{
+ block_syms_iterator_object *iter_obj = (block_syms_iterator_object *) obj;
+ Py_XDECREF (iter_obj->source);
+}
+
+/* Return the innermost lexical block containing the specified pc value,
+ or 0 if there is none. */
+PyObject *
+gdbpy_block_for_pc (PyObject *self, PyObject *args)
+{
+ unsigned PY_LONG_LONG pc;
+ struct block *block;
+ struct obj_section *section;
+ struct symtab *symtab;
+ PyObject *sym_obj;
+
+ if (!PyArg_ParseTuple (args, "K", &pc))
+ return NULL;
+
+ section = find_pc_mapped_section (pc);
+ symtab = find_pc_sect_symtab (pc, section);
+ if (!symtab || symtab->objfile == NULL)
+ {
+ PyErr_SetString (PyExc_RuntimeError,
+ "Cannot locate object file for block.");
+ return NULL;
+ }
+
+ block = block_for_pc (pc);
+ if (block)
+ return block_to_block_object (block, symtab->objfile);
+
+ Py_RETURN_NONE;
+}
+
+/* This function is called when an objfile is about to be freed.
+ Invalidate the block as further actions on the block would result
+ in bad data. All access to obj->symbol should be gated by
+ BLPY_REQUIRE_VALID which will raise an exception on invalid
+ blocks. */
+static void
+del_objfile_blocks (struct objfile *objfile, void *datum)
+{
+ block_object *obj = datum;
+ while (obj)
+ {
+ block_object *next = obj->next;
+
+ obj->block = NULL;
+ obj->objfile = NULL;
+ obj->next = NULL;
+ obj->prev = NULL;
+
+ obj = next;
+ }
+}
+
+void
+gdbpy_initialize_blocks (void)
+{
+ block_object_type.tp_new = PyType_GenericNew;
+ if (PyType_Ready (&block_object_type) < 0)
+ return;
+
+ block_syms_iterator_object_type.tp_new = PyType_GenericNew;
+ if (PyType_Ready (&block_syms_iterator_object_type) < 0)
+ return;
+
+ /* Register an objfile "free" callback so we can properly
+ invalidate blocks when an object file is about to be
+ deleted. */
+ blpy_objfile_data_key
+ = register_objfile_data_with_cleanup (NULL, del_objfile_blocks);
+
+ Py_INCREF (&block_object_type);
+ PyModule_AddObject (gdb_module, "Block", (PyObject *) &block_object_type);
+
+ Py_INCREF (&block_syms_iterator_object_type);
+ PyModule_AddObject (gdb_module, "BlockIterator",
+ (PyObject *) &block_syms_iterator_object_type);
+}
+
+\f
+
+static PyGetSetDef block_object_getset[] = {
+ { "start", blpy_get_start, NULL, "Start address of the block.", NULL },
+ { "end", blpy_get_end, NULL, "End address of the block.", NULL },
+ { "function", blpy_get_function, NULL,
+ "Symbol that names the block, or None.", NULL },
+ { "superblock", blpy_get_superblock, NULL,
+ "Block containing the block, or None.", NULL },
+ { NULL } /* Sentinel */
+};
+
+PyTypeObject block_object_type = {
+ PyObject_HEAD_INIT (NULL)
+ 0, /*ob_size*/
+ "gdb.Block", /*tp_name*/
+ sizeof (block_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ blpy_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/
+ "GDB block object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ blpy_iter, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ block_object_getset /* tp_getset */
+};
+
+static PyTypeObject block_syms_iterator_object_type = {
+ PyObject_HEAD_INIT (NULL)
+ 0, /*ob_size*/
+ "gdb.BlockIterator", /*tp_name*/
+ sizeof (block_syms_iterator_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ blpy_block_syms_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/
+ "GDB block syms iterator object", /*tp_doc */
+ 0, /*tp_traverse */
+ 0, /*tp_clear */
+ 0, /*tp_richcompare */
+ 0, /*tp_weaklistoffset */
+ blpy_block_syms_iter, /*tp_iter */
+ blpy_block_syms_iternext, /*tp_iternext */
+ 0 /*tp_methods */
+};
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index 334bad9..0c81c57 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -26,6 +26,8 @@
#include "stack.h"
#include "value.h"
#include "python-internal.h"
+#include "symfile.h"
+#include "objfiles.h"

typedef struct {
PyObject_HEAD
@@ -202,6 +204,64 @@ frapy_pc (PyObject *self, PyObject *args)
return PyLong_FromUnsignedLongLong (pc);
}

+/* Implementation of gdb.Frame.block (self) -> gdb.Block.
+ Returns the frame's code block. */
+
+static PyObject *
+frapy_block (PyObject *self, PyObject *args)
+{
+ struct frame_info *frame;
+ struct block *block = NULL;
+ volatile struct gdb_exception except;
+ struct symtab_and_line sal;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ FRAPY_REQUIRE_VALID ((frame_object *) self, frame);
+
+ find_frame_sal (frame, &sal);
+ block = block_for_pc (get_frame_address_in_block (frame));
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ if (!sal.symtab || !sal.symtab->objfile)
+ {
+ PyErr_SetString (PyExc_RuntimeError,
+ "Cannot locate object file for block.");
+ return NULL;
+ }
+
+ if (block)
+ return block_to_block_object (block, sal.symtab->objfile);
+
+ Py_RETURN_NONE;
+}
+
+
+/* Implementation of gdb.Frame.function (self) -> gdb.Symbol.
+ Returns the symbol for the function corresponding to this frame. */
+
+static PyObject *
+frapy_function (PyObject *self, PyObject *args)
+{
+ struct symbol *sym = NULL;
+ struct frame_info *frame;
+ volatile struct gdb_exception except;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ FRAPY_REQUIRE_VALID ((frame_object *) self, frame);
+
+ sym = find_pc_function (get_frame_address_in_block (frame));
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ if (sym)
+ return symbol_to_symbol_object (sym);
+
+ Py_RETURN_NONE;
+}
+
/* Convert a frame_info struct to a Python Frame object.
Sets a Python exception and returns NULL on error. */

@@ -296,6 +356,30 @@ frapy_newer (PyObject *self, PyObject *args)
return next_obj;
}

+/* Implementation of gdb.Frame.find_sal (self) -> gdb.Symtab_and_line.
+ Returns the frame's symtab and line. */
+
+static PyObject *
+frapy_find_sal (PyObject *self, PyObject *args)
+{
+ struct frame_info *frame;
+ struct symtab_and_line sal;
+ struct objfile *objfile = NULL;
+ volatile struct gdb_exception except;
+ PyObject *sal_obj = NULL; /* Initialize to appease gcc warning. */
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ FRAPY_REQUIRE_VALID ((frame_object *) self, frame);
+
+ find_frame_sal (frame, &sal);
+ sal_obj = symtab_and_line_to_sal_object (sal);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ return sal_obj;
+}
+
/* Implementation of gdb.Frame.read_var_value (self, variable) -> gdb.Value.
Returns the value of the given variable in this frame. The argument must be
a string. Returns None if GDB can't find the specified variable. */
@@ -312,7 +396,9 @@ frapy_read_var (PyObject *self, PyObject *args)
if (!PyArg_ParseTuple (args, "O", &sym_obj))
return NULL;

- if (gdbpy_is_string (sym_obj))
+ if (PyObject_TypeCheck (sym_obj, &symbol_object_type))
+ var = symbol_object_to_symbol (sym_obj);
+ else if (gdbpy_is_string (sym_obj))
{
char *var_name;
struct block *block = NULL;
@@ -365,6 +451,26 @@ frapy_read_var (PyObject *self, PyObject *args)
Py_RETURN_NONE;
}

+/* Select this frame. */
+
+static PyObject *
+frapy_select (PyObject *self, PyObject *args)
+{
+ struct frame_info *fi;
+ frame_object *frame = (frame_object *) self;
+ volatile struct gdb_exception except;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ FRAPY_REQUIRE_VALID (frame, fi);
+
+ select_frame (fi);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ Py_RETURN_NONE;
+}
+
/* Implementation of gdb.selected_frame () -> gdb.Frame.
Returns the selected frame object. */

@@ -484,15 +590,26 @@ Return the reason why it's not possible to find frames older than this." },
{ "pc", frapy_pc, METH_NOARGS,
"pc () -> Long.\n\
Return the frame's resume address." },
+ { "block", frapy_block, METH_NOARGS,
+ "block () -> gdb.Block.\n\
+Return the frame's code block." },
+ { "function", frapy_function, METH_NOARGS,
+ "function () -> gdb.Symbol.\n\
+Returns the symbol for the function corresponding to this frame." },
{ "older", frapy_older, METH_NOARGS,
"older () -> gdb.Frame.\n\
Return the frame that called this frame." },
{ "newer", frapy_newer, METH_NOARGS,
"newer () -> gdb.Frame.\n\
Return the frame called by this frame." },
+ { "find_sal", frapy_find_sal, METH_NOARGS,
+ "find_sal () -> gdb.Symtab_and_line.\n\
+Return the frame's symtab and line." },
{ "read_var", frapy_read_var, METH_VARARGS,
"read_var (variable) -> gdb.Value.\n\
Return the value of the variable in this frame." },
+ { "select", frapy_select, METH_NOARGS,
+ "Select this frame as the user's current frame." },
{NULL} /* Sentinel */
};

diff --git a/gdb/python/py-symbol.c b/gdb/python/py-symbol.c
new file mode 100644
index 0000000..d2ae43d
--- /dev/null
+++ b/gdb/python/py-symbol.c
@@ -0,0 +1,424 @@
+/* Python interface to symbols.
+
+ Copyright (C) 2008, 2009, 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 "block.h"
+#include "exceptions.h"
+#include "frame.h"
+#include "symtab.h"
+#include "python-internal.h"
+#include "objfiles.h"
+
+typedef struct sympy_symbol_object {
+ PyObject_HEAD
+ /* The GDB symbol structure this object is wrapping. */
+ struct symbol *symbol;
+ /* A symbol object is associated with an objfile, so keep track with
+ doubly-linked list, rooted in the objfile. This lets us
+ invalidate the underlying struct symbol when the objfile is
+ deleted. */
+ struct sympy_symbol_object *prev;
+ struct sympy_symbol_object *next;
+} symbol_object;
+
+/* Require a valid symbol. All access to symbol_object->symbol should be
+ gated by this call. */
+#define SYMPY_REQUIRE_VALID(symbol_obj, symbol) \
+ do { \
+ symbol = symbol_object_to_symbol (symbol_obj); \
+ if (symbol == NULL) \
+ { \
+ PyErr_SetString (PyExc_RuntimeError, \
+ _("Symbol is invalid.")); \
+ return NULL; \
+ } \
+ } while (0)
+
+static const struct objfile_data *sympy_objfile_data_key;
+
+static PyObject *
+sympy_str (PyObject *self)
+{
+ char *s;
+ PyObject *result;
+ struct symbol *symbol = NULL;
+
+ SYMPY_REQUIRE_VALID (self, symbol);
+
+ s = xstrprintf ("symbol for %s",
+ SYMBOL_PRINT_NAME (symbol));
+
+ result = PyString_FromString (s);
+ xfree (s);
+
+ return result;
+}
+
+static PyObject *
+sympy_get_symtab (PyObject *self, void *closure)
+{
+ struct symbol *symbol = NULL;
+
+ SYMPY_REQUIRE_VALID (self, symbol);
+
+ return symtab_to_symtab_object (SYMBOL_SYMTAB (symbol));
+}
+
+static PyObject *
+sympy_get_name (PyObject *self, void *closure)
+{
+ struct symbol *symbol = NULL;
+
+ SYMPY_REQUIRE_VALID (self, symbol);
+
+ return PyString_FromString (SYMBOL_NATURAL_NAME (symbol));
+}
+
+static PyObject *
+sympy_get_linkage_name (PyObject *self, void *closure)
+{
+ struct symbol *symbol = NULL;
+
+ SYMPY_REQUIRE_VALID (self, symbol);
+
+ return PyString_FromString (SYMBOL_LINKAGE_NAME (symbol));
+}
+
+static PyObject *
+sympy_get_print_name (PyObject *self, void *closure)
+{
+ struct symbol *symbol = NULL;
+
+ SYMPY_REQUIRE_VALID (self, symbol);
+
+ return PyString_FromString (SYMBOL_PRINT_NAME (symbol));
+}
+
+static PyObject *
+sympy_get_addr_class (PyObject *self, void *closure)
+{
+ struct symbol *symbol = NULL;
+
+ SYMPY_REQUIRE_VALID (self, symbol);
+
+ return PyInt_FromLong (SYMBOL_CLASS (symbol));
+}
+
+static PyObject *
+sympy_is_argument (PyObject *self, void *closure)
+{
+ struct symbol *symbol = NULL;
+
+ SYMPY_REQUIRE_VALID (self, symbol);
+
+ return PyBool_FromLong (SYMBOL_IS_ARGUMENT (symbol));
+}
+
+static PyObject *
+sympy_is_constant (PyObject *self, void *closure)
+{
+ struct symbol *symbol = NULL;
+ enum address_class class;
+
+ SYMPY_REQUIRE_VALID (self, symbol);
+
+ class = SYMBOL_CLASS (symbol);
+
+ return PyBool_FromLong (class == LOC_CONST || class == LOC_CONST_BYTES);
+}
+
+static PyObject *
+sympy_is_function (PyObject *self, void *closure)
+{
+ struct symbol *symbol = NULL;
+ enum address_class class;
+
+ SYMPY_REQUIRE_VALID (self, symbol);
+
+ class = SYMBOL_CLASS (symbol);
+
+ return PyBool_FromLong (class == LOC_BLOCK);
+}
+
+static PyObject *
+sympy_is_variable (PyObject *self, void *closure)
+{
+ struct symbol *symbol = NULL;
+ enum address_class class;
+
+ SYMPY_REQUIRE_VALID (self, symbol);
+
+ class = SYMBOL_CLASS (symbol);
+
+ return PyBool_FromLong (!SYMBOL_IS_ARGUMENT (symbol)
+ && (class == LOC_LOCAL || class == LOC_REGISTER
+ || class == LOC_STATIC || class == LOC_COMPUTED
+ || class == LOC_OPTIMIZED_OUT));
+}
+
+/* Given a symbol, and a symbol_object that has previously been
+ allocated and initialized, populate the symbol_object with the
+ struct symbol data. Also, register the symbol_object life-cycle
+ with the life-cycle of the the object file associated with this
+ symbol, if needed. */
+static void
+set_symbol (symbol_object *obj, struct symbol *symbol)
+{
+ obj->symbol = symbol;
+ obj->prev = NULL;
+ if (SYMBOL_SYMTAB (symbol))
+ {
+ obj->next = objfile_data (SYMBOL_SYMTAB (symbol)->objfile,
+ sympy_objfile_data_key);
+
+ if (obj->next)
+ obj->next->prev = obj;
+ set_objfile_data (SYMBOL_SYMTAB (symbol)->objfile,
+ sympy_objfile_data_key, obj);
+ }
+ else
+ obj->next = NULL;
+}
+
+/* Create a new symbol object (gdb.Symbol) that encapsulates the struct
+ symbol object from GDB. */
+PyObject *
+symbol_to_symbol_object (struct symbol *sym)
+{
+ symbol_object *sym_obj;
+
+ sym_obj = PyObject_New (symbol_object, &symbol_object_type);
+ if (sym_obj)
+ set_symbol (sym_obj, sym);
+
+ return (PyObject *) sym_obj;
+}
+
+/* Return the symbol that is wrapped by this symbol object. */
+struct symbol *
+symbol_object_to_symbol (PyObject *obj)
+{
+ if (! PyObject_TypeCheck (obj, &symbol_object_type))
+ return NULL;
+ return ((symbol_object *) obj)->symbol;
+}
+
+static void
+sympy_dealloc (PyObject *obj)
+{
+ symbol_object *sym_obj = (symbol_object *) obj;
+
+ if (sym_obj->prev)
+ sym_obj->prev->next = sym_obj->next;
+ else if (SYMBOL_SYMTAB (sym_obj->symbol))
+ {
+ set_objfile_data (SYMBOL_SYMTAB (sym_obj->symbol)->objfile,
+ sympy_objfile_data_key, sym_obj->next);
+ }
+ if (sym_obj->next)
+ sym_obj->next->prev = sym_obj->prev;
+ sym_obj->symbol = NULL;
+}
+
+/* Implementation of
+ gdb.lookup_symbol (name [, block] [, domain]) -> (symbol, is_field_of_this)
+ A tuple with 2 elements is always returned. The first is the symbol
+ object or None, the second is a boolean with the value of
+ is_a_field_of_this (see comment in lookup_symbol_in_language). */
+PyObject *
+gdbpy_lookup_symbol (PyObject *self, PyObject *args, PyObject *kw)
+{
+ int domain = VAR_DOMAIN, is_a_field_of_this = 0;
+ const char *name;
+ static char *keywords[] = { "name", "block", "domain", NULL };
+ struct symbol *symbol;
+ PyObject *block_obj = NULL, *ret_tuple, *sym_obj, *bool_obj;
+ struct block *block = NULL;
+
+ if (! PyArg_ParseTupleAndKeywords (args, kw, "s|O!i", keywords, &name,
+ &block_object_type, &block_obj, &domain))
+ return NULL;
+
+ if (block_obj)
+ block = block_object_to_block (block_obj);
+ else
+ {
+ struct frame_info *selected_frame;
+ volatile struct gdb_exception except;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ selected_frame = get_selected_frame (_("No frame selected."));
+ block = block_for_pc (get_frame_address_in_block (selected_frame));
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+ }
+
+ symbol = lookup_symbol (name, block, domain, &is_a_field_of_this);
+
+ ret_tuple = PyTuple_New (2);
+ if (!ret_tuple)
+ return NULL;
+
+ if (symbol)
+ {
+ sym_obj = symbol_to_symbol_object (symbol);
+ if (!sym_obj)
+ {
+ Py_DECREF (ret_tuple);
+ return NULL;
+ }
+ }
+ else
+ {
+ sym_obj = Py_None;
+ Py_INCREF (Py_None);
+ }
+ PyTuple_SET_ITEM (ret_tuple, 0, sym_obj);
+
+ bool_obj = is_a_field_of_this? Py_True : Py_False;
+ Py_INCREF (bool_obj);
+ PyTuple_SET_ITEM (ret_tuple, 1, bool_obj);
+
+ return ret_tuple;
+}
+
+/* This function is called when an objfile is about to be freed.
+ Invalidate the symbol as further actions on the symbol would result
+ in bad data. All access to obj->symbol should be gated by
+ SYMPY_REQUIRE_VALID which will raise an exception on invalid
+ symbols. */
+static void
+del_objfile_symbols (struct objfile *objfile, void *datum)
+{
+ symbol_object *obj = datum;
+ while (obj)
+ {
+ symbol_object *next = obj->next;
+
+ obj->symbol = NULL;
+ obj->next = NULL;
+ obj->prev = NULL;
+
+ obj = next;
+ }
+}
+
+void
+gdbpy_initialize_symbols (void)
+{
+ if (PyType_Ready (&symbol_object_type) < 0)
+ return;
+
+ /* Register an objfile "free" callback so we can properly
+ invalidate symbol when an object file that is about to be
+ deleted. */
+ sympy_objfile_data_key
+ = register_objfile_data_with_cleanup (NULL, del_objfile_symbols);
+
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_UNDEF", LOC_UNDEF);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_CONST", LOC_CONST);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_STATIC", LOC_STATIC);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_REGISTER", LOC_REGISTER);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_ARG", LOC_ARG);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_REF_ARG", LOC_REF_ARG);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_LOCAL", LOC_LOCAL);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_TYPEDEF", LOC_TYPEDEF);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_LABEL", LOC_LABEL);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_BLOCK", LOC_BLOCK);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_CONST_BYTES",
+ LOC_CONST_BYTES);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_UNRESOLVED", LOC_UNRESOLVED);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_OPTIMIZED_OUT",
+ LOC_OPTIMIZED_OUT);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_COMPUTED", LOC_COMPUTED);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_REGPARM_ADDR",
+ LOC_REGPARM_ADDR);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_UNDEF_DOMAIN", UNDEF_DOMAIN);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_VAR_DOMAIN", VAR_DOMAIN);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_STRUCT_DOMAIN", STRUCT_DOMAIN);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LABEL_DOMAIN", LABEL_DOMAIN);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_VARIABLES_DOMAIN",
+ VARIABLES_DOMAIN);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_FUNCTIONS_DOMAIN",
+ FUNCTIONS_DOMAIN);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_TYPES_DOMAIN", TYPES_DOMAIN);
+
+ Py_INCREF (&symbol_object_type);
+ PyModule_AddObject (gdb_module, "Symbol", (PyObject *) &symbol_object_type);
+}
+
+\f
+
+static PyGetSetDef symbol_object_getset[] = {
+ { "symtab", sympy_get_symtab, NULL,
+ "Symbol table in which the symbol appears.", NULL },
+ { "name", sympy_get_name, NULL,
+ "Name of the symbol, as it appears in the source code.", NULL },
+ { "linkage_name", sympy_get_linkage_name, NULL,
+ "Name of the symbol, as used by the linker (i.e., may be mangled).", NULL },
+ { "print_name", sympy_get_print_name, NULL,
+ "Name of the symbol in a form suitable for output.\n\
+This is either name or linkage_name, depending on whether the user asked GDB\n\
+to display demangled or mangled names.", NULL },
+ { "addr_class", sympy_get_addr_class, NULL, "Address class of the symbol." },
+ { "is_argument", sympy_is_argument, NULL,
+ "True if the symbol is an argument of a function." },
+ { "is_constant", sympy_is_constant, NULL,
+ "True if the symbol is a constant." },
+ { "is_function", sympy_is_function, NULL,
+ "True if the symbol is a function or method." },
+ { "is_variable", sympy_is_variable, NULL,
+ "True if the symbol is a variable." },
+ { NULL } /* Sentinel */
+};
+
+PyTypeObject symbol_object_type = {
+ PyObject_HEAD_INIT (NULL)
+ 0, /*ob_size*/
+ "gdb.Symbol", /*tp_name*/
+ sizeof (symbol_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ sympy_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ sympy_str, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "GDB symbol object", /*tp_doc */
+ 0, /*tp_traverse */
+ 0, /*tp_clear */
+ 0, /*tp_richcompare */
+ 0, /*tp_weaklistoffset */
+ 0, /*tp_iter */
+ 0, /*tp_iternext */
+ 0, /*tp_methods */
+ 0, /*tp_members */
+ symbol_object_getset /*tp_getset */
+};
diff --git a/gdb/python/py-symtab.c b/gdb/python/py-symtab.c
new file mode 100644
index 0000000..fc39e0b
--- /dev/null
+++ b/gdb/python/py-symtab.c
@@ -0,0 +1,528 @@
+/* Python interface to symbol tables.
+
+ Copyright (C) 2008, 2009, 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 "charset.h"
+#include "symtab.h"
+#include "source.h"
+#include "python-internal.h"
+#include "objfiles.h"
+
+typedef struct stpy_symtab_object {
+ PyObject_HEAD
+ /* The GDB Symbol table structure. */
+ struct symtab *symtab;
+ /* A symtab object is associated with an objfile, so keep track with
+ a doubly-linked list, rooted in the objfile. This allows
+ invalidation of the underlying struct symtab when the objfile is
+ deleted. */
+ struct stpy_symtab_object *prev;
+ struct stpy_symtab_object *next;
+} symtab_object;
+
+static PyTypeObject symtab_object_type;
+static const struct objfile_data *stpy_objfile_data_key;
+
+/* Require a valid symbol table. All access to symtab_object->symtab
+ should be gated by this call. */
+#define STPY_REQUIRE_VALID(symtab_obj, symtab) \
+ do { \
+ symtab = symtab_object_to_symtab (symtab_obj); \
+ if (symtab == NULL) \
+ { \
+ PyErr_SetString (PyExc_RuntimeError, \
+ _("Symbol Table is invalid.")); \
+ return NULL; \
+ } \
+ } while (0)
+
+typedef struct salpy_sal_object {
+ PyObject_HEAD
+ /* The GDB Symbol table structure. */
+ symtab_object *symtab;
+ /* The GDB Symbol table and line structure. */
+ struct symtab_and_line *sal;
+ /* A Symtab and line object is associated with an objfile, so keep
+ track with a doubly-linked list, rooted in the objfile. This
+ allows invalidation of the underlying struct symtab_and_line
+ when the objfile is deleted. */
+ struct salpy_sal_object *prev;
+ struct salpy_sal_object *next;
+} sal_object;
+
+static PyTypeObject sal_object_type;
+static const struct objfile_data *salpy_objfile_data_key;
+
+/* Require a valid symbol table and line object. All access to
+ sal_object->sal should be gated by this call. */
+#define SALPY_REQUIRE_VALID(sal_obj, sal) \
+ do { \
+ sal = sal_object_to_symtab_and_line (sal_obj); \
+ if (sal == NULL) \
+ { \
+ PyErr_SetString (PyExc_RuntimeError, \
+ _("Symbol Table and Line is invalid.")); \
+ return NULL; \
+ } \
+ } while (0)
+
+static PyObject *
+stpy_str (PyObject *self)
+{
+ char *s;
+ PyObject *result;
+ struct symtab *symtab = NULL;
+
+ STPY_REQUIRE_VALID (self, symtab);
+
+ s = xstrprintf ("symbol table for %s",
+ symtab->filename);
+
+ result = PyString_FromString (s);
+ xfree (s);
+
+ return result;
+}
+
+static PyObject *
+stpy_get_filename (PyObject *self, void *closure)
+{
+ PyObject *str_obj;
+ struct symtab *symtab = NULL;
+
+ STPY_REQUIRE_VALID (self, symtab);
+
+ str_obj = PyString_Decode (symtab->filename,
+ strlen (symtab->filename),
+ host_charset (), NULL);
+ return str_obj;
+}
+
+static PyObject *
+stpy_get_objfile (PyObject *self, void *closure)
+{
+ struct symtab *symtab = NULL;
+ PyObject *result;
+
+ STPY_REQUIRE_VALID (self, symtab);
+
+ result = objfile_to_objfile_object (symtab->objfile);
+ Py_XINCREF (result);
+ return result;
+}
+
+static PyObject *
+stpy_fullname (PyObject *self, PyObject *args)
+{
+ char *fullname;
+ struct symtab *symtab = NULL;
+
+ STPY_REQUIRE_VALID (self, symtab);
+
+ fullname = symtab_to_fullname (symtab);
+ if (fullname)
+ return PyString_Decode (fullname, strlen (fullname),
+ host_charset (), NULL);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+salpy_str (PyObject *self)
+{
+ char *s, *filename;
+ sal_object *sal_obj;
+ PyObject *result;
+ struct symtab_and_line *sal = NULL;
+
+ SALPY_REQUIRE_VALID (self, sal);
+
+ sal_obj = (sal_object *) self;
+ filename = (sal_obj->symtab == (symtab_object *) Py_None)
+ ? "<unknown>" : sal_obj->symtab->symtab->filename;
+
+ s = xstrprintf ("symbol and line for %s, line %d", filename,
+ sal->line);
+
+ result = PyString_FromString (s);
+ xfree (s);
+
+ return result;
+}
+
+static void
+stpy_dealloc (PyObject *obj)
+{
+ symtab_object *symtab = (symtab_object *) obj;
+
+ if (symtab->prev)
+ symtab->prev->next = symtab->next;
+ else if (symtab->symtab)
+ {
+ set_objfile_data (symtab->symtab->objfile,
+ stpy_objfile_data_key, symtab->next);
+ }
+ if (symtab->next)
+ symtab->next->prev = symtab->prev;
+ symtab->symtab = NULL;
+}
+
+
+static PyObject *
+salpy_get_pc (PyObject *self, void *closure)
+{
+ struct symtab_and_line *sal = NULL;
+
+ SALPY_REQUIRE_VALID (self, sal);
+
+ return PyLong_FromUnsignedLongLong (sal->pc);
+}
+
+static PyObject *
+salpy_get_line (PyObject *self, void *closure)
+{
+ struct symtab_and_line *sal = NULL;
+
+ SALPY_REQUIRE_VALID (self, sal);
+
+ return PyLong_FromUnsignedLongLong (sal->line);
+}
+
+static PyObject *
+salpy_get_symtab (PyObject *self, void *closure)
+{
+ struct symtab_and_line *sal;
+ sal_object *self_sal = (sal_object *) self;
+
+ SALPY_REQUIRE_VALID (self, sal);
+
+ Py_INCREF (self_sal->symtab);
+
+ return (PyObject *) self_sal->symtab;
+}
+
+static void
+salpy_dealloc (PyObject *self)
+{
+ sal_object *self_sal = (sal_object *) self;
+
+ if (self_sal->prev)
+ self_sal->prev->next = self_sal->next;
+ else if (self_sal->symtab != (symtab_object * ) Py_None)
+ set_objfile_data (self_sal->symtab->symtab->objfile,
+ salpy_objfile_data_key, self_sal->next);
+
+ if (self_sal->next)
+ self_sal->next->prev = self_sal->prev;
+
+ Py_DECREF (self_sal->symtab);
+ xfree (self_sal->sal);
+ self_sal->ob_type->tp_free (self);
+}
+
+/* Given a sal, and a sal_object that has previously been
+ allocated and initialized, populate the sal_object with the
+ struct sal data. Also, register the sal_object life-cycle with the
+ life-cycle of the the object file associated with this sal, if
+ needed. If a failure occurs during the sal population, this
+ function will return NULL. */
+static int
+set_sal (sal_object *sal_obj, struct symtab_and_line sal)
+{
+ symtab_object *symtab_obj;
+
+ if (sal.symtab)
+ {
+ symtab_obj = (symtab_object *) symtab_to_symtab_object (sal.symtab);
+ /* If a symtab existed in the sal, but it cannot be duplicated,
+ we exit. */
+ if (symtab_obj == NULL)
+ return 0;
+ }
+ else
+ {
+ symtab_obj = (symtab_object *) Py_None;
+ Py_INCREF (Py_None);
+ }
+
+ sal_obj->sal = xmemdup (&sal, sizeof (struct symtab_and_line),
+ sizeof (struct symtab_and_line));
+ sal_obj->symtab = symtab_obj;
+ sal_obj->prev = NULL;
+
+ /* If the SAL does not have a symtab, we do not add it to the
+ objfile cleanup observer linked list. */
+ if (sal_obj->symtab != (symtab_object *)Py_None)
+ {
+ sal_obj->next = objfile_data (sal_obj->symtab->symtab->objfile,
+ salpy_objfile_data_key);
+ if (sal_obj->next)
+ sal_obj->next->prev = sal_obj;
+
+ set_objfile_data (sal_obj->symtab->symtab->objfile,
+ salpy_objfile_data_key, sal_obj);
+ }
+ else
+ sal_obj->next = NULL;
+
+ return 1;
+}
+
+/* Given a symtab, and a symtab_object that has previously been
+ allocated and initialized, populate the symtab_object with the
+ struct symtab data. Also, register the symtab_object life-cycle
+ with the life-cycle of the the object file associated with this
+ symtab, if needed. */
+static void
+set_symtab (symtab_object *obj, struct symtab *symtab)
+{
+ obj->symtab = symtab;
+ obj->prev = NULL;
+ if (symtab)
+ {
+ obj->next = objfile_data (symtab->objfile, stpy_objfile_data_key);
+ if (obj->next)
+ obj->next->prev = obj;
+ set_objfile_data (symtab->objfile, stpy_objfile_data_key, obj);
+ }
+ else
+ obj->next = NULL;
+}
+
+/* Create a new symbol table (gdb.Symtab) object that encapsulates the
+ symtab structure from GDB. */
+PyObject *
+symtab_to_symtab_object (struct symtab *symtab)
+{
+ symtab_object *symtab_obj;
+
+ symtab_obj = PyObject_New (symtab_object, &symtab_object_type);
+ if (symtab_obj)
+ set_symtab (symtab_obj, symtab);
+
+ return (PyObject *) symtab_obj;
+}
+
+/* Create a new symtab and line (gdb.Symtab_and_line) object
+ that encapsulates the symtab_and_line structure from GDB. */
+PyObject *
+symtab_and_line_to_sal_object (struct symtab_and_line sal)
+
+{
+ sal_object *sal_obj;
+ symtab_object *symtab_obj;
+ int success = 0;
+ sal_obj = PyObject_New (sal_object, &sal_object_type);
+
+ if (sal_obj)
+ {
+ success = set_sal (sal_obj, sal);
+ if (!success)
+ {
+ Py_DECREF (sal_obj);
+ return NULL;
+ }
+ }
+
+ return (PyObject *) sal_obj;
+}
+
+/* Return struct symtab_and_line reference that is wrapped by this
+ object. */
+struct symtab_and_line *
+sal_object_to_symtab_and_line (PyObject *obj)
+{
+ if (! PyObject_TypeCheck (obj, &sal_object_type))
+ return NULL;
+ return ((sal_object *) obj)->sal;
+}
+
+/* Return struct symtab reference that is wrapped by this object. */
+struct symtab *
+symtab_object_to_symtab (PyObject *obj)
+{
+ if (! PyObject_TypeCheck (obj, &symtab_object_type))
+ return NULL;
+ return ((symtab_object *) obj)->symtab;
+}
+
+/* This function is called when an objfile is about to be freed.
+ Invalidate the symbol table as further actions on the symbol table
+ would result in bad data. All access to obj->symtab should be
+ gated by STPY_REQUIRE_VALID which will raise an exception on
+ invalid symbol tables. */
+static void
+del_objfile_symtab (struct objfile *objfile, void *datum)
+{
+ symtab_object *obj = datum;
+ while (obj)
+ {
+ symtab_object *next = obj->next;
+
+ obj->symtab = NULL;
+ obj->next = NULL;
+ obj->prev = NULL;
+ obj = next;
+ }
+}
+
+/* This function is called when an objfile is about to be freed.
+ Invalidate the sal object as further actions on the sal
+ would result in bad data. All access to obj->sal should be
+ gated by SALPY_REQUIRE_VALID which will raise an exception on
+ invalid symbol table and line objects. */
+static void
+del_objfile_sal (struct objfile *objfile, void *datum)
+{
+ sal_object *obj = datum;
+ while (obj)
+ {
+ sal_object *next = obj->next;
+
+ obj->symtab = NULL;
+ obj->next = NULL;
+ obj->prev = NULL;
+ xfree (obj->sal);
+ obj->sal = NULL;
+
+ obj = next;
+ }
+}
+
+void
+gdbpy_initialize_symtabs (void)
+{
+ symtab_object_type.tp_new = PyType_GenericNew;
+ if (PyType_Ready (&symtab_object_type) < 0)
+ return;
+
+ sal_object_type.tp_new = PyType_GenericNew;
+ if (PyType_Ready (&sal_object_type) < 0)
+ return;
+
+ /* Register an objfile "free" callback so we can properly
+ invalidate symbol tables, and symbol table and line data
+ structures when an object file that is about to be
+ deleted. */
+ stpy_objfile_data_key
+ = register_objfile_data_with_cleanup (NULL, del_objfile_symtab);
+ salpy_objfile_data_key
+ = register_objfile_data_with_cleanup (NULL, del_objfile_sal);
+
+ Py_INCREF (&symtab_object_type);
+ PyModule_AddObject (gdb_module, "Symtab",
+ (PyObject *) &symtab_object_type);
+
+ Py_INCREF (&sal_object_type);
+ PyModule_AddObject (gdb_module, "Symtab_and_line",
+ (PyObject *) &sal_object_type);
+}
+
+\f
+
+static PyGetSetDef symtab_object_getset[] = {
+ { "filename", stpy_get_filename, NULL,
+ "The symbol table's source filename.", NULL },
+ { "objfile", stpy_get_objfile, NULL, "The symtab's objfile.",
+ NULL },
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef symtab_object_methods[] = {
+ { "fullname", stpy_fullname, METH_NOARGS,
+ "fullname () -> String.\n\
+Return the symtab's full source filename." },
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject symtab_object_type = {
+ PyObject_HEAD_INIT (NULL)
+ 0, /*ob_size*/
+ "gdb.Symtab", /*tp_name*/
+ sizeof (symtab_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ stpy_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ stpy_str, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "GDB symtab object", /*tp_doc */
+ 0, /*tp_traverse */
+ 0, /*tp_clear */
+ 0, /*tp_richcompare */
+ 0, /*tp_weaklistoffset */
+ 0, /*tp_iter */
+ 0, /*tp_iternext */
+ symtab_object_methods, /*tp_methods */
+ 0, /*tp_members */
+ symtab_object_getset /*tp_getset */
+};
+
+static PyGetSetDef sal_object_getset[] = {
+ { "symtab", salpy_get_symtab, NULL, "Symtab object.", NULL },
+ { "pc", salpy_get_pc, NULL, "Return the symtab_and_line's pc.", NULL },
+ { "line", salpy_get_line, NULL,
+ "Return the symtab_and_line's line.", NULL },
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject sal_object_type = {
+ PyObject_HEAD_INIT (NULL)
+ 0, /*ob_size*/
+ "gdb.Symtab_and_line", /*tp_name*/
+ sizeof (sal_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ salpy_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ salpy_str, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "GDB symtab_and_line object", /*tp_doc */
+ 0, /*tp_traverse */
+ 0, /*tp_clear */
+ 0, /*tp_richcompare */
+ 0, /*tp_weaklistoffset */
+ 0, /*tp_iter */
+ 0, /*tp_iternext */
+ 0, /*tp_methods */
+ 0, /*tp_members */
+ sal_object_getset /*tp_getset */
+};
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 1bfa700..c48c354 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -61,32 +61,51 @@ typedef int Py_ssize_t;
#define PyEval_ReleaseLock() 0
#endif

+struct block;
+struct symbol;
+struct symtab_and_line;
struct value;
struct language_defn;

extern PyObject *gdb_module;
extern PyTypeObject value_object_type;
+extern PyTypeObject block_object_type;
+extern PyTypeObject symbol_object_type;

PyObject *gdbpy_history (PyObject *self, PyObject *args);
PyObject *gdbpy_frame_stop_reason_string (PyObject *, PyObject *);
+PyObject *gdbpy_lookup_symbol (PyObject *self, PyObject *args, PyObject *kw);
PyObject *gdbpy_selected_frame (PyObject *self, PyObject *args);
+PyObject *gdbpy_block_for_pc (PyObject *self, PyObject *args);
PyObject *gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw);
PyObject *gdbpy_create_lazy_string_object (CORE_ADDR address, long length,
const char *encoding, struct type *type);

+PyObject *symtab_and_line_to_sal_object (struct symtab_and_line sal);
+PyObject *symtab_to_symtab_object (struct symtab *symtab);
+PyObject *symbol_to_symbol_object (struct symbol *sym);
+PyObject *block_to_block_object (struct block *block, struct objfile *objfile);
PyObject *value_to_value_object (struct value *v);
PyObject *type_to_type_object (struct type *);
PyObject *objfile_to_objfile_object (struct objfile *);

PyObject *objfpy_get_printers (PyObject *, void *);

+struct block *block_object_to_block (PyObject *obj);
+struct symbol *symbol_object_to_symbol (PyObject *obj);
struct value *value_object_to_value (PyObject *self);
struct value *convert_value_from_python (PyObject *obj);
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_values (void);
void gdbpy_initialize_frames (void);
+void gdbpy_initialize_symtabs (void);
void gdbpy_initialize_commands (void);
+void gdbpy_initialize_symbols (void);
+void gdbpy_initialize_symtabs (void);
+void gdbpy_initialize_blocks (void);
void gdbpy_initialize_types (void);
void gdbpy_initialize_functions (void);
void gdbpy_initialize_objfile (void);
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 29386c9..3d38de6 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -644,6 +644,9 @@ Enables or disables auto-loading of Python code when an object is opened."),
gdbpy_initialize_values ();
gdbpy_initialize_frames ();
gdbpy_initialize_commands ();
+ gdbpy_initialize_symbols ();
+ gdbpy_initialize_symtabs ();
+ gdbpy_initialize_blocks ();
gdbpy_initialize_functions ();
gdbpy_initialize_types ();
gdbpy_initialize_objfile ();
@@ -724,7 +727,14 @@ Return a string explaining unwind stop reason." },
METH_VARARGS | METH_KEYWORDS,
"lookup_type (name [, block]) -> type\n\
Return a Type corresponding to the given name." },
-
+ { "lookup_symbol", (PyCFunction) gdbpy_lookup_symbol,
+ METH_VARARGS | METH_KEYWORDS,
+ "lookup_symbol (name [, block] [, domain]) -> (symbol, is_field_of_this)\n\
+Return a tuple with the symbol corresponding to the given name (or None) and\n\
+a boolean indicating if name is a field of the current implied argument\n\
+`this' (when the current language is object-oriented)." },
+ { "block_for_pc", gdbpy_block_for_pc, METH_VARARGS,
+ "Return the block containing the given pc value, or None." },
{ "parse_and_eval", gdbpy_parse_and_eval, METH_VARARGS,
"parse_and_eval (String) -> Value.\n\
Parse String as an expression, evaluate it, and return the result as a Value."
diff --git a/gdb/testsuite/gdb.python/Makefile.in b/gdb/testsuite/gdb.python/Makefile.in
index 3e81bd3..06f8c9c 100644
--- a/gdb/testsuite/gdb.python/Makefile.in
+++ b/gdb/testsuite/gdb.python/Makefile.in
@@ -1,7 +1,8 @@
VPATH = @srcdir@
srcdir = @srcdir@

-EXECUTABLES = py-type py-value py-prettyprint py-template
+EXECUTABLES = py-type py-value py-prettyprint py-template py-block \
+ py-symbol

all info install-info dvi install uninstall installcheck check:
@echo "Nothing to be done for $@..."
diff --git a/gdb/testsuite/gdb.python/py-block.c b/gdb/testsuite/gdb.python/py-block.c
new file mode 100644
index 0000000..a748044
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-block.c
@@ -0,0 +1,41 @@
+/* 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/>.
+*/
+
+
+
+int block_func (void)
+{
+ int i = 0;
+ {
+ double i = 1.0;
+ double f = 2.0;
+ {
+ const char *i = "stuff";
+ const char *f = "foo";
+ const char *b = "bar";
+ return 0; /* Block break here. */
+ }
+ }
+}
+
+
+int main (int argc, char *argv[])
+{
+ block_func ();
+ return 0; /* Break at end. */
+}
diff --git a/gdb/testsuite/gdb.python/py-block.exp b/gdb/testsuite/gdb.python/py-block.exp
new file mode 100644
index 0000000..31345e3
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-block.exp
@@ -0,0 +1,84 @@
+# 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 the mechanism
+# exposing values to Python.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+set testfile "py-block"
+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
+}
+
+# Run a command in GDB, and report a failure if a Python exception is thrown.
+# If report_pass is true, report a pass if no exception is thrown.
+proc gdb_py_test_silent_cmd {cmd name report_pass} {
+ global gdb_prompt
+
+ gdb_test_multiple $cmd $name {
+ -re "Traceback.*$gdb_prompt $" { fail $name }
+ -re "$gdb_prompt $" { if $report_pass { pass $name } }
+ }
+}
+
+# Start with a fresh gdb.
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+gdb_test_multiple "python print 'hello, world!'" "verify python support" {
+ -re "not supported.*$gdb_prompt $" {
+ unsupported "python support is disabled"
+ return -1
+ }
+ -re "$gdb_prompt $" {}
+}
+
+if ![runto_main] then {
+ fail "Can't run to main"
+ return 0
+}
+
+global hex decimal
+gdb_breakpoint [gdb_get_line_number "Block break here."]
+gdb_continue_to_breakpoint "Block break here."
+
+# Test initial innermost block.
+gdb_py_test_silent_cmd "python frame = gdb.selected_frame()" "Get Frame" 0
+gdb_py_test_silent_cmd "python block = frame.block()" "Get block" 0
+gdb_test "python print block" "<gdb.Block object at $hex>" "Check block not None"
+gdb_test "python print block.function" "None" "First anonymous block"
+gdb_test "python print block.start" "${decimal}" "Check start not None"
+gdb_test "python print block.end" "${decimal}" "Check end not None"
+
+# Move up superblock(s) until we reach function block_func.
+gdb_test "python block = block.superblock" "" "Get superblock"
+gdb_test "python print block.function" "None" "Second anonymous block"
+gdb_test "python block = block.superblock" "" "Get superblock"
+gdb_test "python print block.function" "symbol for block_func"
+
+# Switch frames, then test for main block.
+gdb_test "up" ""
+gdb_py_test_silent_cmd "python frame = gdb.selected_frame()" "Get Frame" 0
+gdb_py_test_silent_cmd "python block = frame.block()" "Get block" 0
+gdb_test "python print block" "<gdb.Block object at $hex>" "Check block not None"
+gdb_test "python print block.function" "symbol for main" "main block"
diff --git a/gdb/testsuite/gdb.python/py-symbol.c b/gdb/testsuite/gdb.python/py-symbol.c
new file mode 100644
index 0000000..0c8bb60
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-symbol.c
@@ -0,0 +1,62 @@
+/* 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/>.
+*/
+
+#ifdef __cplusplus
+class SimpleClass
+{
+ private:
+ int i;
+
+ public:
+ void seti (int arg)
+ {
+ i = arg;
+ }
+
+ int valueofi (void)
+ {
+ return i; /* Break in class. */
+ }
+};
+#endif
+
+int func (int arg)
+{
+ int i = 2;
+ i = i * arg;
+ return arg; /* Block break here. */
+}
+
+int main (int argc, char *argv[])
+{
+#ifdef __cplusplus
+ SimpleClass sclass;
+#endif
+ int a = 0;
+ int result;
+ enum tag {one, two, three};
+ enum tag t = one;
+
+ result = func (42);
+
+#ifdef __cplusplus
+ sclass.seti (42);
+ sclass.valueofi ();
+#endif
+ return 0; /* Break at end. */
+}
diff --git a/gdb/testsuite/gdb.python/py-symbol.exp b/gdb/testsuite/gdb.python/py-symbol.exp
new file mode 100644
index 0000000..23b7844
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-symbol.exp
@@ -0,0 +1,137 @@
+# 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 the mechanism
+# exposing values to Python.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+set testfile "py-symbol"
+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
+}
+
+# Run a command in GDB, and report a failure if a Python exception is thrown.
+# If report_pass is true, report a pass if no exception is thrown.
+proc gdb_py_test_silent_cmd {cmd name report_pass} {
+ global gdb_prompt
+
+ gdb_test_multiple $cmd $name {
+ -re "Traceback.*$gdb_prompt $" { fail $name }
+ -re "$gdb_prompt $" { if $report_pass { pass $name } }
+ }
+}
+
+# Start with a fresh gdb.
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+gdb_test_multiple "python print 'hello, world!'" "verify python support" {
+ -re "not supported.*$gdb_prompt $" {
+ unsupported "python support is disabled"
+ return -1
+ }
+ -re "$gdb_prompt $" {}
+}
+
+if ![runto_main] then {
+ fail "Can't run to main"
+ return 0
+}
+
+global hex decimal
+
+gdb_breakpoint [gdb_get_line_number "Block break here."]
+gdb_continue_to_breakpoint "Block break here."
+gdb_py_test_silent_cmd "python frame = gdb.selected_frame()" "Get Frame" 0
+gdb_py_test_silent_cmd "python block = frame.block()" "Get block" 0
+
+# Test is_argument attribute.
+gdb_py_test_silent_cmd "python arg = gdb.lookup_symbol(\"arg\")" "Get variable a" 0
+gdb_test "python print arg\[0\].is_variable" "False" "Test arg.is_variable"
+gdb_test "python print arg\[0\].is_constant" "False" "Test arg.is_constant"
+gdb_test "python print arg\[0\].is_argument" "True" "Test arg.is_argument"
+gdb_test "python print arg\[0\].is_function" "False" "Test arg.is_function"
+
+# Test is_function attribute.
+gdb_py_test_silent_cmd "python func = frame.block().function" "Get block" 0
+gdb_test "python print func.is_variable" "False" "Test func.is_variable"
+gdb_test "python print func.is_constant" "False" "Test func.is_constant"
+gdb_test "python print func.is_argument" "False" "Test func.is_argument"
+gdb_test "python print func.is_function" "True" "Test func.is_function"
+gdb_test "python print func.name" "func" "Test func.name"
+gdb_test "python print func.print_name" "func" "Test func.print_name"
+gdb_test "python print func.linkage_name" "func" "Test func.linkage_name"
+gdb_test "python print func.addr_class == gdb.SYMBOL_LOC_BLOCK" "True" "Test func.addr_class"
+
+gdb_breakpoint [gdb_get_line_number "Break at end."]
+gdb_continue_to_breakpoint "Break at end."
+gdb_py_test_silent_cmd "python frame = gdb.selected_frame()" "Get Frame" 0
+
+# Test is_variable attribute.
+gdb_py_test_silent_cmd "python a = gdb.lookup_symbol(\'a\')" "Get variable a" 0
+gdb_test "python print a\[0\].is_variable" "True" "Test a.is_variable"
+gdb_test "python print a\[0\].is_constant" "False" "Test a.is_constant"
+gdb_test "python print a\[0\].is_argument" "False" "Test a.is_argument"
+gdb_test "python print a\[0\].is_function" "False" "Test a.is_function"
+gdb_test "python print a\[0\].addr_class == gdb.SYMBOL_LOC_COMPUTED" "True" "Test a.addr_class"
+
+# Test is_constant attribute
+gdb_py_test_silent_cmd "python t = gdb.lookup_symbol(\"one\")" "Get variable a" 0
+gdb_test "python print t\[0\].is_variable" "False" "Test t.is_variable"
+gdb_test "python print t\[0\].is_constant" "True" "Test t.is_constant"
+gdb_test "python print t\[0\].is_argument" "False" "Test t.is_argument"
+gdb_test "python print t\[0\].is_function" "False" "Test t.is_function"
+gdb_test "python print t\[0\].addr_class == gdb.SYMBOL_LOC_CONST" "True" "Test t.addr_class"
+gdb_test "python print t\[0\].symtab" "symbol table for.*" "Get symtab"
+
+# C++ tests
+# Recompile binary.
+ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "debug c++"] != "" } {
+ untested "Couldn't compile ${srcfile} in c++ mode"
+ return -1
+ }
+
+# Start with a fresh gdb.
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if ![runto_main] then {
+ fail "Can't run to main"
+ return 0
+}
+
+gdb_breakpoint [gdb_get_line_number "Break in class."]
+gdb_continue_to_breakpoint "Break in class."
+
+gdb_py_test_silent_cmd "python cplusframe = gdb.selected_frame()" "Get Frame" 0
+gdb_py_test_silent_cmd "python cplusfunc = cplusframe.block().function" "Get block" 0
+gdb_test "python print cplusfunc.is_variable" "False" "Test func.is_variable"
+gdb_test "python print cplusfunc.is_constant" "False" "Test func.is_constant"
+gdb_test "python print cplusfunc.is_argument" "False" "Test func.is_argument"
+gdb_test "python print cplusfunc.is_function" "True" "Test func.is_function"
+gdb_test "python print cplusfunc.name" "SimpleClass::valueofi().*" "Test func.name"
+gdb_test "python print cplusfunc.print_name" "SimpleClass::valueofi().*" "Test func.print_name"
+gdb_test "python print cplusfunc.linkage_name" "_ZN11SimpleClass8valueofiEv" "Test func.linkage_name"
+gdb_test "python print cplusfunc.addr_class == gdb.SYMBOL_LOC_BLOCK" "True" "Test func.addr_class"
diff --git a/gdb/testsuite/gdb.python/py-symtab.exp b/gdb/testsuite/gdb.python/py-symtab.exp
new file mode 100644
index 0000000..a43207b
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-symtab.exp
@@ -0,0 +1,78 @@
+# 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 the mechanism
+# exposing values to Python.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+set testfile "py-symbol"
+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
+}
+
+# Run a command in GDB, and report a failure if a Python exception is thrown.
+# If report_pass is true, report a pass if no exception is thrown.
+proc gdb_py_test_silent_cmd {cmd name report_pass} {
+ global gdb_prompt
+
+ gdb_test_multiple $cmd $name {
+ -re "Traceback.*$gdb_prompt $" { fail $name }
+ -re "$gdb_prompt $" { if $report_pass { pass $name } }
+ }
+}
+
+# Start with a fresh gdb.
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+gdb_test_multiple "python print 'hello, world!'" "verify python support" {
+ -re "not supported.*$gdb_prompt $" {
+ unsupported "python support is disabled"
+ return -1
+ }
+ -re "$gdb_prompt $" {}
+}
+
+if ![runto_main] then {
+ fail "Can't run to main"
+ return 0
+}
+
+global hex decimal
+
+# Setup and get the symbol table.
+gdb_breakpoint [gdb_get_line_number "Block break here."]
+gdb_continue_to_breakpoint "Block break here."
+gdb_py_test_silent_cmd "python frame = gdb.selected_frame()" "Get Frame" 0
+gdb_py_test_silent_cmd "python sal = frame.find_sal()" "Get block" 0
+gdb_py_test_silent_cmd "python symtab = sal.symtab" "Get block" 0
+
+# Test sal.
+gdb_test "python print sal.symtab" "gdb/testsuite/gdb.python/py-symbol.c.*" "Test symtab"
+gdb_test "python print sal.pc" "${decimal}" "Test sal.pc"
+gdb_test "python print sal.line" "42" "Test sal.line"
+
+# Test symbol table.
+gdb_test "python print symtab.filename" "testsuite/gdb.python/py-symbol.c.*" "Test symtab.filename"
+gdb_test "python print symtab.objfile" "<gdb.Objfile object at ${hex}>" "Test symtab.objfile"
+gdb_test "python print symtab.fullname()" "testsuite/gdb.python/py-symbol.c.*" "Test symtab.fullname"