From f3e9a8177c41893858fce2bdf339dbe90b3a4ef5 Mon Sep 17 00:00:00 2001 From: Phil Muldoon Date: Wed, 24 Feb 2010 21:18:28 +0000 Subject: [PATCH] 2010-02-24 Phil Muldoon Tom Tromey Thiago Jung Bauermann * python/python.c (_initialize_python): Call gdbpy_initialize_symtabs, gdbpy_initialize_symbols and gdbpy_initialize_blocks. * python/python-internal.h: Declare struct symbol, block and symtab_and_line. Declare block_object_type and symbol_object_type (gdbpy_lookup_symbol gdbpy_block_for_pc) (symtab_and_line_to_sal_object, symtab_to_symtab_object) (symbol_to_symbol_object, block_to_block_object) (gdbpy_initialize_symtabs,gdbpy_initialize_symbols) (gdbpy_initialize_blocks ): Declare. * python/py-frame.c (frapy_block, frapy_function, frapy_find_sal) (frapy_select): Add methods. (frapy_read_var): Add symbol branch. * Makefile.in (SUBDIR_PYTHON_OBS): Add py-symbol, py-symtab, py-block. (SUBDIR_PYTHON_SRCS): Likewise. (py-symbol.o): New rule. (py-symtab.o): Likewise. (py-block.o): Likewise. * python/py-symbol.c: New file. * python/py-symtab.c: Likewise. * python/py-block.c: Likewise. 2010-02-24 Phil Muldoon * Makefile.in: Add py-block and py-symbol. * gdb.python/py-symbol.exp: New File. * gdb.python/py-symtab.exp: New File. * gdb.python/py-block.exp: New File. * gdb.python/py-symbol.c: New File. * gdb.python/py-block.c: New File. 2010-02-24 Phil Muldoon * gdb.texinfo (Frames In Python): Add block, find_sal, function and select method descriptions. (Python API): Add Blocks In Python, Symbols in Python and Symbol Tables in Python to menu. (Blocks In Python): New node. (Symbols In Python): New node. (Symbol Tables in Python): New node. --- gdb/ChangeLog | 28 ++ gdb/Makefile.in | 18 + gdb/NEWS | 5 + gdb/doc/ChangeLog | 10 + gdb/doc/gdb.texinfo | 314 ++++++++++++++- gdb/python/py-block.c | 418 ++++++++++++++++++++ gdb/python/py-frame.c | 119 +++++- gdb/python/py-symbol.c | 419 ++++++++++++++++++++ gdb/python/py-symtab.c | 523 +++++++++++++++++++++++++ gdb/python/python-internal.h | 19 + gdb/python/python.c | 12 +- gdb/testsuite/ChangeLog | 9 + gdb/testsuite/gdb.python/Makefile.in | 3 +- gdb/testsuite/gdb.python/py-block.c | 41 ++ gdb/testsuite/gdb.python/py-block.exp | 79 ++++ gdb/testsuite/gdb.python/py-symbol.c | 62 +++ gdb/testsuite/gdb.python/py-symbol.exp | 132 +++++++ gdb/testsuite/gdb.python/py-symtab.exp | 73 ++++ 18 files changed, 2279 insertions(+), 5 deletions(-) create mode 100644 gdb/python/py-block.c create mode 100644 gdb/python/py-symbol.c create mode 100644 gdb/python/py-symtab.c create mode 100644 gdb/testsuite/gdb.python/py-block.c create mode 100644 gdb/testsuite/gdb.python/py-block.exp create mode 100644 gdb/testsuite/gdb.python/py-symbol.c create mode 100644 gdb/testsuite/gdb.python/py-symbol.exp create mode 100644 gdb/testsuite/gdb.python/py-symtab.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 962a3c954bf..9cc9051041f 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,31 @@ +2010-02-24 Phil Muldoon + Tom Tromey + Thiago Jung Bauermann + + * python/python.c (_initialize_python): Call + gdbpy_initialize_symtabs, gdbpy_initialize_symbols and + gdbpy_initialize_blocks. + * python/python-internal.h: Declare struct symbol, block and + symtab_and_line. Declare block_object_type and + symbol_object_type + (gdbpy_lookup_symbol gdbpy_block_for_pc) + (symtab_and_line_to_sal_object, symtab_to_symtab_object) + (symbol_to_symbol_object, block_to_block_object) + (gdbpy_initialize_symtabs,gdbpy_initialize_symbols) + (gdbpy_initialize_blocks ): Declare. + * python/py-frame.c (frapy_block, frapy_function, frapy_find_sal) + (frapy_select): Add methods. + (frapy_read_var): Add symbol branch. + * Makefile.in (SUBDIR_PYTHON_OBS): Add py-symbol, py-symtab, + py-block. + (SUBDIR_PYTHON_SRCS): Likewise. + (py-symbol.o): New rule. + (py-symtab.o): Likewise. + (py-block.o): Likewise. + * python/py-symbol.c: New file. + * python/py-symtab.c: Likewise. + * python/py-block.c: Likewise. + 2010-02-24 Pedro Alves PR gdb/11321 diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 8e68bb1765b..84cefb409a5 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 @@ -1971,6 +1977,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) @@ -1995,6 +2005,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 9592d39e3a2..babd18abf4d 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -3,6 +3,11 @@ *** Changes since GDB 7.1 +* Python scripting + +The GDB Python API now has access to symbols, symbol tables, and +frame's code blocks. + *** Changes in GDB 7.1 * C++ Improvements diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 0755e59e5c8..1c2053e5c1c 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,13 @@ +2010-02-24 Phil Muldoon + + * gdb.texinfo (Frames In Python): Add block, find_sal, function + and select method descriptions. + (Python API): Add Blocks In Python, Symbols in Python and Symbol + Tables in Python to menu. + (Blocks In Python): New node. + (Symbols In Python): New node. + (Symbol Tables in Python): New node. + 2010-02-24 Vladimir Prus Multiexec MI diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index d886787ab5c..2eea484b366 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 +Return the frame's code block. @xref{Blocks In Python}. +@end defmethod + +@defmethod Frame function +Return 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 00000000000..3523664ebfa --- /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 . */ + +#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); +} + + + +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 334bad9c973..94211db9f1f 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 00000000000..e4c5fef6690 --- /dev/null +++ b/gdb/python/py-symbol.c @@ -0,0 +1,419 @@ +/* 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 . */ + +#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) +{ + PyObject *result; + struct symbol *symbol = NULL; + + SYMPY_REQUIRE_VALID (self, symbol); + + result = PyString_FromString (SYMBOL_PRINT_NAME (symbol)); + + 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 sympy_str (self); +} + +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); +} + + + +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 00000000000..f91f32201dd --- /dev/null +++ b/gdb/python/py-symtab.c @@ -0,0 +1,523 @@ +/* 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 . */ + +#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) +{ + PyObject *result; + struct symtab *symtab = NULL; + + STPY_REQUIRE_VALID (self, symtab); + + result = PyString_FromString (symtab->filename); + + 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) + ? "" : 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); +} + + + +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 1bfa700b8e5..c48c354adc2 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 29386c92053..3d38de60265 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/ChangeLog b/gdb/testsuite/ChangeLog index c81edff9c73..bfacf61a5d5 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2010-02-24 Phil Muldoon + + * Makefile.in: Add py-block and py-symbol. + * gdb.python/py-symbol.exp: New File. + * gdb.python/py-symtab.exp: New File. + * gdb.python/py-block.exp: New File. + * gdb.python/py-symbol.c: New File. + * gdb.python/py-block.c: New File. + 2010-02-24 Phil Muldoon PR python/11314 diff --git a/gdb/testsuite/gdb.python/Makefile.in b/gdb/testsuite/gdb.python/Makefile.in index 3e81bd3683d..06f8c9c76aa 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 00000000000..a748044e7ef --- /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 . +*/ + + + +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 00000000000..c1ea2507e17 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-block.exp @@ -0,0 +1,79 @@ +# 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 . + +# 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} + +# Skip all tests if Python scripting is not enabled. +if { [skip_python_tests] } { continue } + +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" "" "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" "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" "" "Check block not None" +gdb_test "python print block.function" "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 00000000000..0c8bb6037ac --- /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 . +*/ + +#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 00000000000..6eaa943a203 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-symbol.exp @@ -0,0 +1,132 @@ +# 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 . + +# 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} + +# Skip all tests if Python scripting is not enabled. +if { [skip_python_tests] } { continue } + +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" "gdb.python/py-symbol.c.*" "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 00000000000..5c60ad3735f --- /dev/null +++ b/gdb/testsuite/gdb.python/py-symtab.exp @@ -0,0 +1,73 @@ +# 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 . + +# 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} + +# Skip all tests if Python scripting is not enabled. +if { [skip_python_tests] } { continue } + +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" "" "Test symtab.objfile" +gdb_test "python print symtab.fullname()" "testsuite/gdb.python/py-symbol.c.*" "Test symtab.fullname" -- 2.30.2