* [patch][python] Add symbol, symbol table and frame block support to GDB API @ 2010-02-01 13:42 Phil Muldoon 2010-02-01 20:54 ` Eli Zaretskii 2010-02-04 23:25 ` Tom Tromey 0 siblings, 2 replies; 23+ messages in thread From: Phil Muldoon @ 2010-02-01 13:42 UTC (permalink / raw) To: gdb-patches ml This patch adds symbol, symbol table and block support to the Python GDB API. It also reconstitutes several functions missing from py-frame, and adds the glue back into python.c to make these code segments work together. This is for the most part a merge of the code that has existed in the archer repository for sometime. OK? Regards -- ChangeLog 2010-02-01 Phil Muldoon <pmuldoon@redhat.com> Tom Tromey <tromey@redhat.com> Thiago Jung Bauermann <bauerman@br.ibm.com> * 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. doc/Changelog 2010-02-01 Phil Muldoon <pmuldoon@redhat.com> * 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. testsuite/ChangeLog 2010-02-01 Phil Muldoon <pmuldoon@redhat.com> * 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. -- diff --git a/gdb/Makefile.in b/gdb/Makefile.in index ff8b86e..453f88c 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/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index fc11609..268a011 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -19538,7 +19538,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:: Symbol table representation in Python. * Lazy Strings In Python:: Python representation of lazy strings. @end menu @@ -20698,7 +20701,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 @@ -20761,6 +20764,15 @@ function to a string. Returns the frame's resume address. @end defmethod +@defmethod Frame block +Returns the frame's code block. (@pxref{Blocks In Python}). +@end defmethod + +@defmethod Frame function +Returns the symbol for the function corresponding to this frame. +(@pxref{Symbols In Python}). +@end defmethod + @defmethod Frame older Return the frame that called this frame. @end defmethod @@ -20769,10 +20781,310 @@ 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. +(@pxref{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 user's selected frame. +@end defmethod +@end table + +@node Blocks In Python +@subsubsection Accessing frame blocks from Python. + +@cindex blocks in python +@tindex gdb.Block + +All of the name-scope contours of a program are represented as 'block' +objects in @value{GDBN}. Similarly, in Python these objects are +represented as @code{gdb.Block} objects. Each @code{gdb.Block} object +has to be sourced, and parented from a @code{gdb.Frame} object. The +validity of a @code{gdb.Block} follows the same rules as that of a +@code{gdb.Frame} (@pxref{Frames In Python} for more information). + +The structure of a @code{gdb.Block} follows the same rules as the +underlying @value{GDBN} block. This can be summarized as: each block +represents one name scope; each lexical context has its own block. + +The following block-related functions are available in the @code{gdb} +module: + +@findex gdb.block_for_pc pc +@defun block_for_pc pc +Return the @code{gdb.Block} containing the given @code{pc} value. If the +block cannot be found for the @code{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 +This attribute holds the start address of the block. This attribute is not +writable. +@end defivar + +@defivar Block end +This attribute holds the end address of the block. This attribute +is not writable. +@end defivar + +@defivar Block function +This attribute holds the name of the block represented as a +@code{gdb.Symbol}. If the block is not named, then this attribute +returns @code{None}. This attribute is not writable. +@end defivar + +@defivar Block superblock +This attribute holds the superblock containing this block represented as a +@code{gdb.Block}. If a superblock 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 the name of every variable, function and type +as a symbol (@pxref{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 name [block] [domain] +@defun lookup_symbol name [block] [domain] +This function looks up 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 to look-up. It must be a +string. The optional @var{block} argument restricts the look-up 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 look-up 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 +name or 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 +Returns @code{True} if the symbol is an argument of a function. +@end defivar + +@defivar Symbol is_constant +Returns @code{True} if the symbol is a constant. +@end defivar + +@defivar Symbol is_function +Returns @code{True} if the symbol is a function or a method. +@end defivar + +@defivar Symbol is_variable +Returns @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. +@findex SYMBOL_LOC_REF_ARG +@findex gdb.SYMBOL_LOC_REF_ARG +@item SYMBOL_LOC_REF_ARG +Value address is an offset in arglist. +@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}. Access to the @code{gdb.Symtab_and_line} object for +each frame is returned from the @code{find_sal} method in +@code{gdb.Frame} object (@pxref{Frames In Python}). + +For more information on @value{GDBN}'s symbol table management +@xref{Symbols, ,Examining the Symbol Table}. + +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 information 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 full source filename. +@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..5fc4760 --- /dev/null +++ b/gdb/python/py-block.c @@ -0,0 +1,265 @@ +/* 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" + +typedef struct { + PyObject_HEAD + struct block *block; +} block_object; + +typedef struct { + PyObject_HEAD + struct dictionary *dict; + struct dict_iterator iter; + int initialized_p; +} block_syms_iterator_object; + +static PyTypeObject block_syms_iterator_object_type; + +static PyObject * +blpy_iter (PyObject *self) +{ + block_syms_iterator_object *block_iter_obj; + + block_iter_obj = PyObject_New (block_syms_iterator_object, + &block_syms_iterator_object_type); + if (block_iter_obj == NULL) + { + PyErr_SetString (PyExc_MemoryError, + "Could not allocate iterator object."); + return NULL; + } + + block_iter_obj->dict = BLOCK_DICT (((block_object *) self)->block); + block_iter_obj->initialized_p = 0; + + return (PyObject *) block_iter_obj; +} + +static PyObject * +blpy_get_start (PyObject *self, void *closure) +{ + block_object *self_block = (block_object *) self; + + return PyLong_FromUnsignedLongLong (BLOCK_START (self_block->block)); +} + +static PyObject * +blpy_get_end (PyObject *self, void *closure) +{ + block_object *self_block = (block_object *) self; + + return PyLong_FromUnsignedLongLong (BLOCK_END (self_block->block)); +} + +static PyObject * +blpy_get_function (PyObject *self, void *closure) +{ + block_object *self_block = (block_object *) self; + struct symbol *sym; + + sym = BLOCK_FUNCTION (self_block->block); + if (sym) + return symbol_to_symbol_object (sym); + + Py_RETURN_NONE; +} + +static PyObject * +blpy_get_superblock (PyObject *self, void *closure) +{ + block_object *self_block = (block_object *) self; + struct block *block; + + block = BLOCK_SUPERBLOCK (self_block->block); + if (block) + return block_to_block_object (block); + + Py_RETURN_NONE; +} + +PyObject * +block_to_block_object (struct block *block) +{ + block_object *block_obj; + + block_obj = PyObject_New (block_object, &block_object_type); + if (block_obj == NULL) + { + PyErr_SetString (PyExc_MemoryError, "Could not allocate block object."); + return NULL; + } + + block_obj->block = block; + + return (PyObject *) block_obj; +} + +struct block * +block_object_to_block (PyObject *obj) +{ + if (! PyObject_TypeCheck (obj, &block_object_type)) + return NULL; + return ((block_object *) obj)->block; +} + +static PyObject * +blpy_block_syms_iter (PyObject *self) +{ + return self; +} + +static PyObject * +blpy_block_syms_iternext (PyObject *self) +{ + block_syms_iterator_object *iter_obj = (block_syms_iterator_object *) self; + struct symbol *sym; + + 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)); + + return (sym == NULL)? NULL : symbol_to_symbol_object (sym); +} + +/* 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; + PyObject *sym_obj; + + if (!PyArg_ParseTuple (args, "K", &pc)) + return NULL; + + block = block_for_pc (pc); + if (block) + return block_to_block_object (block); + + Py_RETURN_NONE; +} + +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; + + 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*/ + 0, /*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*/ + 0, /*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..f48a3ad 100644 --- a/gdb/python/py-frame.c +++ b/gdb/python/py-frame.c @@ -202,6 +202,55 @@ 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; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + block = block_for_pc (get_frame_address_in_block (frame)); + } + GDB_PY_HANDLE_EXCEPTION (except); + + if (block) + return block_to_block_object (block); + + 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 +345,29 @@ 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; + 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 +384,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 +439,25 @@ 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 +577,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..2a33b63 --- /dev/null +++ b/gdb/python/py-symbol.c @@ -0,0 +1,314 @@ +/* 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" + +typedef struct { + PyObject_HEAD + struct symbol *symbol; +} symbol_object; + + +static PyObject * +sympy_str (PyObject *self) +{ + int ret; + char *s; + PyObject *result; + + ret = asprintf (&s, "symbol for %s", + SYMBOL_PRINT_NAME (((symbol_object *) self)->symbol)); + if (ret < 0) + Py_RETURN_NONE; + + result = PyString_FromString (s); + xfree (s); + + return result; +} + +static PyObject * +sympy_get_symtab (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + + return symtab_to_symtab_object (SYMBOL_SYMTAB (self_sym->symbol)); +} + +static PyObject * +sympy_get_name (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + + return PyString_FromString (SYMBOL_NATURAL_NAME (self_sym->symbol)); +} + +static PyObject * +sympy_get_linkage_name (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + + return PyString_FromString (SYMBOL_LINKAGE_NAME (self_sym->symbol)); +} + +static PyObject * +sympy_get_print_name (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + + return PyString_FromString (SYMBOL_PRINT_NAME (self_sym->symbol)); +} + +static PyObject * +sympy_get_addr_class (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + + return PyInt_FromLong (SYMBOL_CLASS (self_sym->symbol)); +} + +static PyObject * +sympy_is_argument (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + + return PyBool_FromLong (SYMBOL_IS_ARGUMENT (self_sym->symbol)); +} + +static PyObject * +sympy_is_constant (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + enum address_class class = SYMBOL_CLASS (self_sym->symbol); + + return PyBool_FromLong (class == LOC_CONST || class == LOC_CONST_BYTES); +} + +static PyObject * +sympy_is_function (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + enum address_class class = SYMBOL_CLASS (self_sym->symbol); + + return PyBool_FromLong (class == LOC_BLOCK); +} + +static PyObject * +sympy_is_variable (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + enum address_class class = SYMBOL_CLASS (self_sym->symbol); + + return PyBool_FromLong (!SYMBOL_IS_ARGUMENT (self_sym->symbol) + && (class == LOC_LOCAL || class == LOC_REGISTER || class == LOC_STATIC + || class == LOC_COMPUTED || class == LOC_OPTIMIZED_OUT)); +} + +PyObject * +symbol_to_symbol_object (struct symbol *sym) +{ + symbol_object *sym_obj; + + sym_obj = PyObject_New (symbol_object, &symbol_object_type); + if (sym_obj == NULL) + { + PyErr_SetString (PyExc_MemoryError, "Could not allocate symbol object."); + return NULL; + } + + sym_obj->symbol = sym; + + return (PyObject *) sym_obj; +} + +struct symbol * +symbol_object_to_symbol (PyObject *obj) +{ + if (! PyObject_TypeCheck (obj, &symbol_object_type)) + return NULL; + return ((symbol_object *) obj)->symbol; +} + +/* 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) + { + PyErr_SetString (PyExc_MemoryError, "Could not allocate tuple object."); + 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; +} + +void +gdbpy_initialize_symbols (void) +{ + if (PyType_Ready (&symbol_object_type) < 0) + return; + + 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*/ + 0, /*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..866c71a --- /dev/null +++ b/gdb/python/py-symtab.c @@ -0,0 +1,322 @@ +/* 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" + +typedef struct { + PyObject_HEAD + struct symtab *symtab; +} symtab_object; + +static PyTypeObject symtab_object_type; + +typedef struct { + PyObject_HEAD + symtab_object *symtab; + struct symtab_and_line *sal; +} sal_object; + +static PyTypeObject sal_object_type; + + +static PyObject * +stpy_str (PyObject *self) +{ + int ret; + char *s; + PyObject *result; + + ret = asprintf (&s, "symbol table for %s", + ((symtab_object *) self)->symtab->filename); + if (ret < 0) + Py_RETURN_NONE; + + result = PyString_FromString (s); + xfree (s); + + return result; +} + +static PyObject * +stpy_get_filename (PyObject *self, void *closure) +{ + symtab_object *self_symtab = (symtab_object *) self; + PyObject *str_obj; + + /* FIXME: Can symtab->filename really be NULL? */ + if (self_symtab->symtab->filename) + str_obj = PyString_Decode (self_symtab->symtab->filename, + strlen (self_symtab->symtab->filename), + host_charset (), NULL); + else + { + str_obj = Py_None; + Py_INCREF (Py_None); + } + + return str_obj; +} + +static PyObject * +stpy_get_objfile (PyObject *self, void *closure) +{ + symtab_object *self_symtab = (symtab_object *) self; + PyObject *result = objfile_to_objfile_object (self_symtab->symtab->objfile); + Py_INCREF (result); + return result; +} + +static PyObject * +stpy_fullname (PyObject *self, PyObject *args) +{ + char *fullname; + + fullname = symtab_to_fullname (((symtab_object *) self)->symtab); + if (fullname) + return PyString_Decode (fullname, strlen (fullname), host_charset (), NULL); + + Py_RETURN_NONE; +} + +static PyObject * +salpy_str (PyObject *self) +{ + int ret; + char *s, *filename; + sal_object *sal_obj; + PyObject *result; + + sal_obj = (sal_object *) self; + filename = (sal_obj->symtab == (symtab_object *) Py_None)? "<unknown>" : + sal_obj->symtab->symtab->filename; + ret = asprintf (&s, "symbol and line for %s, line %d", filename, + sal_obj->sal->line); + if (ret < 0) + Py_RETURN_NONE; + + result = PyString_FromString (s); + xfree (s); + + return result; +} + +static PyObject * +salpy_get_pc (PyObject *self, void *closure) +{ + return PyLong_FromUnsignedLongLong (((sal_object *) self)->sal->pc); +} + +static PyObject * +salpy_get_line (PyObject *self, void *closure) +{ + return PyLong_FromUnsignedLongLong (((sal_object *) self)->sal->line); +} + +static PyObject * +salpy_get_symtab (PyObject *self, void *closure) +{ + sal_object *self_sal = (sal_object *) self; + + Py_INCREF (self_sal->symtab); + + return (PyObject *) self_sal->symtab; +} + +static void +salpy_dealloc (PyObject *self) +{ + sal_object *self_sal = (sal_object *) self; + + Py_DECREF (self_sal->symtab); + xfree (self_sal->sal); + self_sal->ob_type->tp_free (self); +} + +PyObject * +symtab_and_line_to_sal_object (struct symtab_and_line sal) +{ + sal_object *sal_obj; + symtab_object *symtab_obj; + + sal_obj = PyObject_New (sal_object, &sal_object_type); + if (sal_obj == NULL) + { + PyErr_SetString (PyExc_MemoryError, + "Could not allocate Symtab_and_line object."); + return NULL; + } + + if (sal.symtab) + { + symtab_obj = (symtab_object *) symtab_to_symtab_object (sal.symtab); + if (symtab_obj == NULL) + { + Py_DECREF (sal_obj); + return NULL; + } + + symtab_obj->symtab = sal.symtab; + } + else + { + symtab_obj = (symtab_object *) Py_None; + Py_INCREF (Py_None); + } + + sal_obj->sal = (struct symtab_and_line *) + xmalloc (sizeof (struct symtab_and_line)); + *(sal_obj->sal) = sal; + sal_obj->symtab = symtab_obj; + + return (PyObject *) sal_obj; +} + +PyObject * +symtab_to_symtab_object (struct symtab *symtab) +{ + symtab_object *symtab_obj; + + symtab_obj = PyObject_New (symtab_object, &symtab_object_type); + if (symtab_obj == NULL) + { + PyErr_SetString (PyExc_MemoryError, + "Could not allocate Symtab object."); + + return NULL; + } + + symtab_obj->symtab = symtab; + + return (PyObject *) symtab_obj; +} + +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; + + 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, + "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*/ + 0, /*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 9196f08..8edba30 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -61,32 +61,49 @@ 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); 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); 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" ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-01 13:42 [patch][python] Add symbol, symbol table and frame block support to GDB API Phil Muldoon @ 2010-02-01 20:54 ` Eli Zaretskii 2010-02-02 10:24 ` Phil Muldoon 2010-02-04 23:25 ` Tom Tromey 1 sibling, 1 reply; 23+ messages in thread From: Eli Zaretskii @ 2010-02-01 20:54 UTC (permalink / raw) To: Phil Muldoon; +Cc: gdb-patches > Date: Mon, 01 Feb 2010 13:42:13 +0000 > From: Phil Muldoon <pmuldoon@redhat.com> > > This patch adds symbol, symbol table and block support to the Python GDB API. It also reconstitutes several functions missing from py-frame, and adds the glue back into python.c to make these code segments work together. This is for the most part a merge of the code that has existed in the archer repository for sometime. > > OK? Thanks. I have a few comments regarding the doco part. > +* 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:: Symbol table representation in Python. > * Lazy Strings In Python:: Python representation of lazy strings. I would prefer a consistent phrasing here: "Python representation of FOO". > +@defmethod Frame block > +Returns the frame's code block. (@pxref{Blocks In Python}). Please use "@xref{Blocks In Python}." here (without the parens). @pxref is for references in the middle or end of a sentence. Stand-alone cross-references should use @xref. You have a few more of these. > +@defmethod Frame select > +Set this frame to be the user's selected frame. I got confused by "user's selected frame" in this description. If you meant the "selected frame" in the sense we use that in the node "Stack", then I suggest to drop the "user's" part and add a cross-reference to the node "Stack" where this term is explained. > +All of the name-scope contours of a program are represented as 'block' What are "contours"? Is this a widespread enough terminology to be understood without defining it first? If not, I suggest to define it. Also, we don't use single quotes in Texinfo, as in 'block'. If you meant to make it stand out, I suggest @dfn{block objects} instead. If you meant to quote it, please use double quotes, as in ``block''. > + Each @code{gdb.Block} object > +has to be sourced, and parented from a @code{gdb.Frame} object. I don't understand what it means ``sourced and parented from''. > + This can be summarized as: each block > +represents one name scope; each lexical context has its own block. Are you sure people without solid background in compilers will understand this? > +@findex gdb.block_for_pc pc findex entries should not include arguments, just the name of the function. > +@defun block_for_pc pc > +Return the @code{gdb.Block} containing the given @code{pc} value. If the ^^^^^^^^^ Arguments should have a @var markup, not @code. > +@defivar Block superblock > +This attribute holds the superblock containing this block represented as a Isn't it better to say This attribute holds the block containing this block ? After all, the value of the superblock attribute is just another block, right? > +@value{GDBN} represents the name of every variable, function and type > +as a symbol (@pxref{Symbols, ,Examining the Symbol Table}). I think, from the GDB user POV, a name of a variable, function, and type is just a string, not a symbol. > +@findex gdb.lookup_symbol name [block] [domain] Arguments in @findex again. > +@defivar Symbol print_name > +The name of the symbol in a form suitable for output. This is either > +name or linkage_name, depending on whether the user asked @value{GDBN} Please give "name" and "linkage_name" the @code markup here, since they are names of attributes. > +@defivar Symbol is_argument > +Returns @code{True} if the symbol is an argument of a function. "Returns"? maybe you meant "holds"? This is an attribute, not a method, right? > +@item SYMBOL_VAR_DOMAIN > +This domain contains variables, function names, typedef names and enum > +type values. Isn't this description too C-centric? What about other languages? > +@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). Same here. > +@item SYMBOL_LOC_REF_ARG > +Value address is an offset in arglist. I couldn't understand what this means. > + Access to the @code{gdb.Symtab_and_line} object for > +each frame is returned from the @code{find_sal} method in > +@code{gdb.Frame} object (@pxref{Frames In Python}). Something is wrong in this sentence ("Access to ... object ... is returned from ..." -- how can access be returned from somewhere?). > +For more information on @value{GDBN}'s symbol table management > +@xref{Symbols, ,Examining the Symbol Table}. ^^^^^ You want "see @ref" here, since "@xref" produces a capitalized "See", which will look wrong in the middle of a sentence. > + > +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 information for this object. What is the ``current line information''? Do you mean line number? If not, what kind of object is it? > +@defivar Symtab objfile > +The symbol table's backing object file. @xref{Objfiles In Python}. ^^ Two spaces, please. > +@defmethod Symtab fullname > +Return the symbol table's full source filename. "Full" as in "absolute file name" or something else? Do we need a NEWS entry for this? ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-01 20:54 ` Eli Zaretskii @ 2010-02-02 10:24 ` Phil Muldoon 2010-02-02 20:14 ` Eli Zaretskii 0 siblings, 1 reply; 23+ messages in thread From: Phil Muldoon @ 2010-02-02 10:24 UTC (permalink / raw) To: Eli Zaretskii; +Cc: gdb-patches ml > >> +* 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:: Symbol table representation in Python. >> * Lazy Strings In Python:: Python representation of lazy strings. > I would prefer a consistent phrasing here: "Python representation of FOO". OK. >> +@defmethod Frame block >> +Returns the frame's code block. (@pxref{Blocks In Python}). > > Please use "@xref{Blocks In Python}." here (without the parens). > @pxref is for references in the middle or end of a sentence. > Stand-alone cross-references should use @xref. OK. >> +@defmethod Frame select >> +Set this frame to be the user's selected frame. > > I got confused by "user's selected frame" in this description. If you > meant the "selected frame" in the sense we use that in the node > "Stack", then I suggest to drop the "user's" part and add a > cross-reference to the node "Stack" where this term is explained. OK, will drop user in this context. >> +All of the name-scope contours of a program are represented as 'block' > > What are "contours"? Is this a widespread enough terminology to be > understood without defining it first? If not, I suggest to define it. I really agonized over the whole block description, as there is no (as far as I know) analogue to the GDB CLI for blocks. It's revealing an API that GDB uses to manipulate blocks in a frame. I could use some help making this more palatable enough to the consumer of the API, over trying to teach the user compiler/runtime semantics (which is not the purpose of the GDB manual). What do you think? > Also, we don't use single quotes in Texinfo, as in 'block'. If you > meant to make it stand out, I suggest @dfn{block objects} instead. If > you meant to quote it, please use double quotes, as in ``block''. I'll use the dfn comment in this case, thanks. >> + Each @code{gdb.Block} object >> +has to be sourced, and parented from a @code{gdb.Frame} object. > > I don't understand what it means ``sourced and parented from''. I'll delete this as this is obvious (a block has to belong to a frame). The sourced and parented from is confusing and redundant. Thanks. >> + This can be summarized as: each block >> +represents one name scope; each lexical context has its own block. > > Are you sure people without solid background in compilers will > understand this? See above on the block general comment. ;) > >> +@findex gdb.block_for_pc pc > > findex entries should not include arguments, just the name of the > function. OK. > >> +@defun block_for_pc pc >> +Return the @code{gdb.Block} containing the given @code{pc} value. If the > ^^^^^^^^^ > Arguments should have a @var markup, not @code. OK. > >> +@defivar Block superblock >> +This attribute holds the superblock containing this block represented as a > > Isn't it better to say > > This attribute holds the block containing this block > > ? After all, the value of the superblock attribute is just another > block, right? OK. > >> +@value{GDBN} represents the name of every variable, function and type >> +as a symbol (@pxref{Symbols, ,Examining the Symbol Table}). > > I think, from the GDB user POV, a name of a variable, function, and > type is just a string, not a symbol. But in the context of the Python API, they are represented as symbols? How should I word this? >> +@findex gdb.lookup_symbol name [block] [domain] > > Arguments in @findex again. OK, and for all others too! > >> +@defivar Symbol print_name >> +The name of the symbol in a form suitable for output. This is either >> +name or linkage_name, depending on whether the user asked @value{GDBN} > > Please give "name" and "linkage_name" the @code markup here, since > they are names of attributes. OK. >> +@defivar Symbol is_argument >> +Returns @code{True} if the symbol is an argument of a function. > > "Returns"? maybe you meant "holds"? This is an attribute, not a > method, right? OK, for all other examples of definitions too. > >> +@item SYMBOL_VAR_DOMAIN >> +This domain contains variables, function names, typedef names and enum >> +type values. > > Isn't this description too C-centric? What about other languages? This is straight from the comments that represent this enum. I think from a GDB point of view, this is correct. I'd have to ask other language hackers if this holds true? Joel, what about ADA? >> +@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). > > Same here. See above comment >> +@item SYMBOL_LOC_REF_ARG >> +Value address is an offset in arglist. > > I couldn't understand what this means. Yeah, this is a concept expressed in the comments of the code. I'm not sure how to word it any differently. > >> + Access to the @code{gdb.Symtab_and_line} object for >> +each frame is returned from the @code{find_sal} method in >> +@code{gdb.Frame} object (@pxref{Frames In Python}). > > Something is wrong in this sentence ("Access to ... object ... is > returned from ..." -- how can access be returned from somewhere?). I'll reword it. >> +For more information on @value{GDBN}'s symbol table management >> +@xref{Symbols, ,Examining the Symbol Table}. > ^^^^^ > You want "see @ref" here, since "@xref" produces a capitalized "See", > which will look wrong in the middle of a sentence. OK. >> + >> +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 information for this object. > > What is the ``current line information''? Do you mean line number? > If not, what kind of object is it? Just line number in this context will be ok. Thanks! >> +@defivar Symtab objfile >> +The symbol table's backing object file. @xref{Objfiles In Python}. > ^^ > Two spaces, please. OK. >> +@defmethod Symtab fullname >> +Return the symbol table's full source filename. > > "Full" as in "absolute file name" or something else? > > Do we need a NEWS entry for this? Not sure. From my point of view I am merging code from Archer to FSF GDB. I'll happily write one up if you think we need one? What do you think? Cheers, Phil ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-02 10:24 ` Phil Muldoon @ 2010-02-02 20:14 ` Eli Zaretskii 2010-02-03 20:55 ` Phil Muldoon 0 siblings, 1 reply; 23+ messages in thread From: Eli Zaretskii @ 2010-02-02 20:14 UTC (permalink / raw) To: Phil Muldoon; +Cc: gdb-patches > Date: Tue, 02 Feb 2010 10:24:24 +0000 > From: Phil Muldoon <pmuldoon@redhat.com> > CC: gdb-patches ml <gdb-patches@sourceware.org> > > >> +All of the name-scope contours of a program are represented as 'block' > > > > What are "contours"? Is this a widespread enough terminology to be > > understood without defining it first? If not, I suggest to define it. > > > I really agonized over the whole block description, as there is no (as > far as I know) analogue to the GDB CLI for blocks. It's revealing an > API that GDB uses to manipulate blocks in a frame. I could use some > help making this more palatable enough to the consumer of the API, > over trying to teach the user compiler/runtime semantics (which is not > the purpose of the GDB manual). What do you think? How about if you tell what you want in the most technical way you think about these issues, disregarding the fact that it's for GDB users, and I will then rephrase it to be palatable to mere mortals? > >> +@value{GDBN} represents the name of every variable, function and type > >> +as a symbol (@pxref{Symbols, ,Examining the Symbol Table}). > > > > I think, from the GDB user POV, a name of a variable, function, and > > type is just a string, not a symbol. > > But in the context of the Python API, they are represented as symbols? How should I word this? How about @value{GDBN} represents every variable, function and type as a an entry in a symbol table. > >> +@item SYMBOL_LOC_REF_ARG > >> +Value address is an offset in arglist. > > > > I couldn't understand what this means. > > > Yeah, this is a concept expressed in the comments of the code. Where? I don't see it in the patch you submitted. > > Do we need a NEWS entry for this? > > Not sure. From my point of view I am merging code from Archer to FSF > GDB. I'll happily write one up if you think we need one? What do you > think? Something like The GDB Python API now has access to symbols, symbol tables, and frame's code blocks. Thanks. ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-02 20:14 ` Eli Zaretskii @ 2010-02-03 20:55 ` Phil Muldoon 2010-02-05 10:53 ` Phil Muldoon 2010-02-05 11:05 ` Eli Zaretskii 0 siblings, 2 replies; 23+ messages in thread From: Phil Muldoon @ 2010-02-03 20:55 UTC (permalink / raw) To: Eli Zaretskii; +Cc: gdb-patches [-- Attachment #1: Type: text/plain, Size: 2035 bytes --] On 02/02/2010 08:14 PM, Eli Zaretskii wrote: >>>> +All of the name-scope contours of a program are represented as 'block' >>> >>> What are "contours"? Is this a widespread enough terminology to be >>> understood without defining it first? If not, I suggest to define it. >> >> >> I really agonized over the whole block description, as there is no (as >> far as I know) analogue to the GDB CLI for blocks. It's revealing an >> API that GDB uses to manipulate blocks in a frame. I could use some >> help making this more palatable enough to the consumer of the API, >> over trying to teach the user compiler/runtime semantics (which is not >> the purpose of the GDB manual). What do you think? > > How about if you tell what you want in the most technical way you > think about these issues, disregarding the fact that it's for GDB > users, and I will then rephrase it to be palatable to mere mortals? I've attached an updated patch. What do you think? >>>> +@item SYMBOL_LOC_REF_ARG >>>> +Value address is an offset in arglist. >>> >>> I couldn't understand what this means. >> >> >> Yeah, this is a concept expressed in the comments of the code. > > Where? I don't see it in the patch you submitted. > I was referring to the comments in the GDB code that this Python API was exposing: http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/symtab.h?rev=1.146&content-type=text/x-cvsweb-markup&cvsroot=src&only_with_tag=MAIN under the LOC_REF_ARG entry in the address_class enum. Though I'm not sure that under the current Python API the the user can access arglist, but we still have to add it so the symbol address location type can be tested (and in this case, discarded). >>> Do we need a NEWS entry for this? >> >> Not sure. From my point of view I am merging code from Archer to FSF >> GDB. I'll happily write one up if you think we need one? What do you >> think? > > Something like > > The GDB Python API now has access to symbols, symbol tables, and > frame's code blocks. Added, thanks Cheers, Phil [-- Attachment #2: gdb_merge_doc.patch --] [-- Type: text/plain, Size: 11902 bytes --] 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. + * Bug fixes Process record now works correctly with hardware watchpoints. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 2145f2b..1830356 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -19538,7 +19538,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 @@ -20698,7 +20701,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 @@ -20761,6 +20764,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 @@ -20769,10 +20781,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 in a hierarchical +order, and are represented individually within 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 +This attribute holds the start address of the block. This attribute is not +writable. +@end defivar + +@defivar Block end +This attribute holds the end address of the block. This attribute +is not writable. +@end defivar + +@defivar Block function +This attribute holds the name of the block represented as a +@code{gdb.Symbol}. If the block is not named, then this attribute +returns @code{None}. This attribute is not writable. +@end defivar + +@defivar Block superblock +This attribute holds 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 looks up 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 to look-up. It must be a +string. The optional @var{block} argument restricts the look-up 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 look-up 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 +Is @code{True} if the symbol is an argument of a function. +@end defivar + +@defivar Symbol is_constant +Is @code{True} if the symbol is a constant. +@end defivar + +@defivar Symbol is_function +Is @code{True} if the symbol is a function or a method. +@end defivar + +@defivar Symbol is_variable +Is @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. +@findex SYMBOL_LOC_REF_ARG +@findex gdb.SYMBOL_LOC_REF_ARG +@item SYMBOL_LOC_REF_ARG +Value address is an offset in arglist. +@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 ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-03 20:55 ` Phil Muldoon @ 2010-02-05 10:53 ` Phil Muldoon 2010-02-05 18:06 ` Eli Zaretskii 2010-02-05 11:05 ` Eli Zaretskii 1 sibling, 1 reply; 23+ messages in thread From: Phil Muldoon @ 2010-02-05 10:53 UTC (permalink / raw) To: Eli Zaretskii; +Cc: gdb-patches On 02/03/2010 08:55 PM, Phil Muldoon wrote: > On 02/02/2010 08:14 PM, Eli Zaretskii wrote: > > I've attached an updated patch. What do you think? > I thought I'd nip in with another quick patch in-between this review. I fixed a few nits. Apologies for this, but this patch should be considered the latest. Cheers, Phil -- diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 2145f2b..dcd2e96 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -19538,7 +19538,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 @@ -20698,7 +20701,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 @@ -20761,6 +20764,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 @@ -20769,10 +20781,305 @@ 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 returns @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 +Is @code{True} if the symbol is an argument of a function. +@end defivar + +@defivar Symbol is_constant +Is @code{True} if the symbol is a constant. +@end defivar + +@defivar Symbol is_function +Is @code{True} if the symbol is a function or a method. +@end defivar + +@defivar Symbol is_variable +Is @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. +@findex SYMBOL_LOC_REF_ARG +@findex gdb.SYMBOL_LOC_REF_ARG +@item SYMBOL_LOC_REF_ARG +Value address is an offset in arglist. +@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 ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-05 10:53 ` Phil Muldoon @ 2010-02-05 18:06 ` Eli Zaretskii 0 siblings, 0 replies; 23+ messages in thread From: Eli Zaretskii @ 2010-02-05 18:06 UTC (permalink / raw) To: Phil Muldoon; +Cc: gdb-patches > Date: Fri, 05 Feb 2010 10:52:59 +0000 > From: Phil Muldoon <pmuldoon@redhat.com> > CC: gdb-patches@sourceware.org > > On 02/03/2010 08:55 PM, Phil Muldoon wrote: > > On 02/02/2010 08:14 PM, Eli Zaretskii wrote: > > > > I've attached an updated patch. What do you think? > > > > > I thought I'd nip in with another quick patch in-between this review. > I fixed a few nits. Apologies for this, but this patch should be > considered the latest. Same comments as before. And maybe one more (sorry I didn't catch that before): > +@defivar Block function > +The name of the block represented as a @code{gdb.Symbol}. If the > +block is not named, then this attribute returns @code{None}. This ^^^^^^^ "holds", not "returns". ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-03 20:55 ` Phil Muldoon 2010-02-05 10:53 ` Phil Muldoon @ 2010-02-05 11:05 ` Eli Zaretskii 1 sibling, 0 replies; 23+ messages in thread From: Eli Zaretskii @ 2010-02-05 11:05 UTC (permalink / raw) To: Phil Muldoon; +Cc: gdb-patches > Date: Wed, 03 Feb 2010 20:55:34 +0000 > From: Phil Muldoon <pmuldoon@redhat.com> > CC: gdb-patches@sourceware.org > > This is a multi-part message in MIME format. > --------------050506000002080100010500 > Content-Type: text/plain; charset=ISO-8859-1 > Content-Transfer-Encoding: 7bit > > On 02/02/2010 08:14 PM, Eli Zaretskii wrote: > > >>>> +All of the name-scope contours of a program are represented as 'block' > >>> > >>> What are "contours"? Is this a widespread enough terminology to be > >>> understood without defining it first? If not, I suggest to define it. > >> > >> > >> I really agonized over the whole block description, as there is no (as > >> far as I know) analogue to the GDB CLI for blocks. It's revealing an > >> API that GDB uses to manipulate blocks in a frame. I could use some > >> help making this more palatable enough to the consumer of the API, > >> over trying to teach the user compiler/runtime semantics (which is not > >> the purpose of the GDB manual). What do you think? > > > > How about if you tell what you want in the most technical way you > > think about these issues, disregarding the fact that it's for GDB > > users, and I will then rephrase it to be palatable to mere mortals? > > > I've attached an updated patch. What do you think? It's good, thanks. I have only a couple of comments: > +@defivar Symbol is_argument > +Is @code{True} if the symbol is an argument of a function. I'd prefer to drop the "Is" part altogether, here and elsewhere. > +@findex SYMBOL_LOC_ARG > +@findex gdb.SYMBOL_LOC_ARG > +@item SYMBOL_LOC_ARG > +Value is an argument. The comment in the source says: /* It's an argument; the value is at SYMBOL_VALUE offset in arglist. */ Should we expand the above description by adding some text from the comment? > +@findex SYMBOL_LOC_REF_ARG > +@findex gdb.SYMBOL_LOC_REF_ARG > +@item SYMBOL_LOC_REF_ARG > +Value address is an offset in arglist. The comment in the code seems to be a continuation of the previous comment (shown above). Again, perhaps we should say more. Can you or someone else explain what these constants mean, i.e. say a bit more than the comment says? ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-01 13:42 [patch][python] Add symbol, symbol table and frame block support to GDB API Phil Muldoon 2010-02-01 20:54 ` Eli Zaretskii @ 2010-02-04 23:25 ` Tom Tromey 2010-02-15 15:15 ` Phil Muldoon 1 sibling, 1 reply; 23+ messages in thread From: Tom Tromey @ 2010-02-04 23:25 UTC (permalink / raw) To: Phil Muldoon; +Cc: gdb-patches ml >>>>> "Phil" == Phil Muldoon <pmuldoon@redhat.com> writes: Phil> This patch adds symbol, symbol table and block support to the Phil> Python GDB API. It also reconstitutes several functions missing Phil> from py-frame, and adds the glue back into python.c to make these Phil> code segments work together. This is for the most part a merge of Phil> the code that has existed in the archer repository for sometime. Phil> OK? Thanks for doing this. The code bits look mostly ok to me. There are a few formatting nits, of course ;-), but also a more substantial issue. Phil> +typedef struct { Phil> + PyObject_HEAD Phil> + struct block *block; Phil> +} block_object; When an objfile is destroyed, so are blocks coming from that objfile. However, this module doesn't take that into account. That means it can lead to crashes. One possible fix would be to have a notion of an "invalid" Block object, where the block field is ==NULL. Then each method of Block would check validity right away, throwing an error if it is invalid. Then, arrange to clear these fields when an objfile is destroyed. See py-type.c for an example of how the latter is done -- Types can't be invalidated this way but they are instead copied to the heap when the objfile disappears. This same problem affects symtabs and I suppose sals and block iterators as well, by extension. Phil> +static PyObject * Phil> +blpy_get_superblock (PyObject *self, void *closure) Phil> +{ [...] Phil> +PyObject * Phil> +block_to_block_object (struct block *block) Phil> +{ I'm sorry to foist this off on you, but I think exported functions like block_to_block_object should have header comments. Functions like blpy_get_superblock, which are just methods, don't need comments (IMO). Phil> +static PyObject * Phil> +blpy_block_syms_iter (PyObject *self) Phil> +{ Phil> + return self; Does this need a Py_INCREF? Phil> + return (sym == NULL)? NULL : symbol_to_symbol_object (sym); Space before the "?" Phil> + ret = asprintf (&s, "symbol for %s", Phil> + SYMBOL_PRINT_NAME (((symbol_object *) self)->symbol)); Use xstrprintf instead. Phil> + return PyBool_FromLong (!SYMBOL_IS_ARGUMENT (self_sym->symbol) Phil> + && (class == LOC_LOCAL || class == LOC_REGISTER || class == LOC_STATIC Phil> + || class == LOC_COMPUTED || class == LOC_OPTIMIZED_OUT)); The indentation looks weird here. Phil> +PyObject *gdbpy_lookup_symbol (PyObject *self, PyObject *args, PyObject *kw) Newline before gdbpy_lookup_symbol. Phil> + ret_tuple = PyTuple_New (2); Phil> + if (!ret_tuple) Phil> + { Phil> + PyErr_SetString (PyExc_MemoryError, "Could not allocate tuple object."); Phil> + return NULL; Phil> + } If ret_tuple==NULL, you don't need to call PyErr_SetString, just return NULL; PyTuple_New will have set the error. Phil> + ret = asprintf (&s, "symbol table for %s", Phil> + ((symtab_object *) self)->symtab->filename); xstrprintf Phil> +static PyObject * Phil> +stpy_get_filename (PyObject *self, void *closure) Phil> +{ Phil> + symtab_object *self_symtab = (symtab_object *) self; Phil> + PyObject *str_obj; Phil> + Phil> + /* FIXME: Can symtab->filename really be NULL? */ Phil> + if (self_symtab->symtab->filename) Could you take a quick look through other parts of gdb and see if anything else does this check? I'd prefer we eliminate this FIXME before it goes in. Phil> + filename = (sal_obj->symtab == (symtab_object *) Py_None)? "<unknown>" : Phil> + sal_obj->symtab->symtab->filename; Formatting looks weird. Phil> + ret = asprintf (&s, "symbol and line for %s, line %d", filename, Phil> + sal_obj->sal->line); xstrprintf Phil> + sal_obj->sal = (struct symtab_and_line *) Phil> + xmalloc (sizeof (struct symtab_and_line)); Phil> + *(sal_obj->sal) = sal; This assignment looks weird; just use xmemdup instead. Tom ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-04 23:25 ` Tom Tromey @ 2010-02-15 15:15 ` Phil Muldoon 2010-02-15 18:45 ` Eli Zaretskii 2010-02-18 2:50 ` Tom Tromey 0 siblings, 2 replies; 23+ messages in thread From: Phil Muldoon @ 2010-02-15 15:15 UTC (permalink / raw) To: tromey, Eli Zaretskii; +Cc: gdb-patches ml On 02/04/2010 11:24 PM, Tom Tromey wrote: >>>>>> "Phil" == Phil Muldoon <pmuldoon@redhat.com> writes: > The code bits look mostly ok to me. There are a few formatting nits, of > course ;-), but also a more substantial issue. > > Phil> +typedef struct { > Phil> + PyObject_HEAD > Phil> + struct block *block; > Phil> +} block_object; > > When an objfile is destroyed, so are blocks coming from that objfile. > However, this module doesn't take that into account. That means it can > lead to crashes. Tom, I've added life-cycle support for symbols, symbol tables, symbol tables and line, and blocks. This was a little more involved than I first thought. I've also added the other changes you requested Eli, I've made that last changes you requested, too. What do you think? 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 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. + * 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..6f15e3b --- /dev/null +++ b/gdb/python/py-block.c @@ -0,0 +1,441 @@ +/* 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 "exceptions.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. This must be called inside a TRY_CATCH, or + another context in which a gdb exception is allowed. */ +#define BLPY_REQUIRE_VALID(block_obj, block) \ + do { \ + block = block_object_to_block (block_obj); \ + if (block == NULL) \ + error (_("Block is invalid.")); \ + } while (0) + +/* Require a valid block. This macro is called during block iterator + creation, and at each next call. This must be called inside a + TRY_CATCH, or another context in which a gdb exception is + allowed. */ +#define BLPY_ITER_REQUIRE_VALID(block_obj) \ + do { \ + if (block_obj->block == NULL) \ + error (_("Source block for iterator is invalid.")); \ + } 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; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + BLPY_REQUIRE_VALID (self, block); + } + GDB_PY_HANDLE_EXCEPTION (except); + + 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; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + BLPY_REQUIRE_VALID (self, block); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return PyLong_FromUnsignedLongLong (BLOCK_START (block)); +} + +static PyObject * +blpy_get_end (PyObject *self, void *closure) +{ + struct block *block = NULL; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + BLPY_REQUIRE_VALID (self, block); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return PyLong_FromUnsignedLongLong (BLOCK_END (block)); +} + +static PyObject * +blpy_get_function (PyObject *self, void *closure) +{ + struct symbol *sym; + struct block *block = NULL; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + BLPY_REQUIRE_VALID (self, block); + } + GDB_PY_HANDLE_EXCEPTION (except); + + 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; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + BLPY_REQUIRE_VALID (self, block); + } + GDB_PY_HANDLE_EXCEPTION (except); + + 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; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + BLPY_ITER_REQUIRE_VALID (iter_obj->source); + } + GDB_PY_HANDLE_EXCEPTION (except); + + 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; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + BLPY_ITER_REQUIRE_VALID (iter_obj->source); + } + GDB_PY_HANDLE_EXCEPTION (except); + + 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)); + + return (sym == NULL) ? NULL : 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..bb892bd 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,63 @@ 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 +355,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 +395,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 +450,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 +589,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..28d3d5d --- /dev/null +++ b/gdb/python/py-symbol.c @@ -0,0 +1,467 @@ +/* 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. This must be called inside a TRY_CATCH, or + another context in which a gdb exception is allowed. */ +#define SYMPY_REQUIRE_VALID(symbol_obj, symbol) \ + do { \ + symbol = symbol_object_to_symbol (symbol_obj); \ + if (symbol == NULL) \ + error (_("Symbol is invalid.")); \ + } 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; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + SYMPY_REQUIRE_VALID (self, symbol); + } + GDB_PY_HANDLE_EXCEPTION (except); + + 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; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + SYMPY_REQUIRE_VALID (self, symbol); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return symtab_to_symtab_object (SYMBOL_SYMTAB (symbol)); +} + +static PyObject * +sympy_get_name (PyObject *self, void *closure) +{ + struct symbol *symbol = NULL; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + SYMPY_REQUIRE_VALID (self, symbol); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return PyString_FromString (SYMBOL_NATURAL_NAME (symbol)); +} + +static PyObject * +sympy_get_linkage_name (PyObject *self, void *closure) +{ + struct symbol *symbol = NULL; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + SYMPY_REQUIRE_VALID (self, symbol); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return PyString_FromString (SYMBOL_LINKAGE_NAME (symbol)); +} + +static PyObject * +sympy_get_print_name (PyObject *self, void *closure) +{ + struct symbol *symbol = NULL; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + SYMPY_REQUIRE_VALID (self, symbol); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return PyString_FromString (SYMBOL_PRINT_NAME (symbol)); +} + +static PyObject * +sympy_get_addr_class (PyObject *self, void *closure) +{ + struct symbol *symbol = NULL; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + SYMPY_REQUIRE_VALID (self, symbol); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return PyInt_FromLong (SYMBOL_CLASS (symbol)); +} + +static PyObject * +sympy_is_argument (PyObject *self, void *closure) +{ + struct symbol *symbol = NULL; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + SYMPY_REQUIRE_VALID (self, symbol); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return PyBool_FromLong (SYMBOL_IS_ARGUMENT (symbol)); +} + +static PyObject * +sympy_is_constant (PyObject *self, void *closure) +{ + struct symbol *symbol = NULL; + volatile struct gdb_exception except; + enum address_class class; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + SYMPY_REQUIRE_VALID (self, symbol); + } + GDB_PY_HANDLE_EXCEPTION (except); + + 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; + volatile struct gdb_exception except; + enum address_class class; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + SYMPY_REQUIRE_VALID (self, symbol); + } + GDB_PY_HANDLE_EXCEPTION (except); + + class = SYMBOL_CLASS (symbol); + + return PyBool_FromLong (class == LOC_BLOCK); +} + +static PyObject * +sympy_is_variable (PyObject *self, void *closure) +{ + struct symbol *symbol = NULL; + volatile struct gdb_exception except; + enum address_class class; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + SYMPY_REQUIRE_VALID (self, symbol); + } + GDB_PY_HANDLE_EXCEPTION (except); + + 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) + { + obj->next = objfile_data (symbol->symtab->objfile, sympy_objfile_data_key); + if (obj->next) + obj->next->prev = obj; + set_objfile_data (symbol->symtab->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 (sym_obj->symbol->symtab) + { + set_objfile_data (sym_obj->symbol->symtab->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..c1592b5 --- /dev/null +++ b/gdb/python/py-symtab.c @@ -0,0 +1,550 @@ +/* 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 "exceptions.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. This must be called inside a + TRY_CATCH, or another context in which a gdb exception is + allowed. */ +#define STPY_REQUIRE_VALID(symtab_obj, symtab) \ + do { \ + symtab = symtab_object_to_symtab (symtab_obj); \ + if (symtab == NULL) \ + error (_("Symbol table is invalid.")); \ + } 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. This must be called + inside a TRY_CATCH, or another context in which a gdb exception is + allowed. */ +#define SALPY_REQUIRE_VALID(sal_obj, sal) \ + do { \ + sal = sal_object_to_symtab_and_line (sal_obj); \ + if (sal == NULL) \ + error (_("Symbol Table and Line is invalid.")); \ + } while (0) + +static PyObject * +stpy_str (PyObject *self) +{ + char *s; + PyObject *result; + struct symtab *symtab = NULL; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + STPY_REQUIRE_VALID (self, symtab); + } + GDB_PY_HANDLE_EXCEPTION (except); + + 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; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + STPY_REQUIRE_VALID (self, symtab); + } + GDB_PY_HANDLE_EXCEPTION (except); + + 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; + volatile struct gdb_exception except; + PyObject *result; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + STPY_REQUIRE_VALID (self, symtab); + } + + result = objfile_to_objfile_object (symtab->objfile); + Py_INCREF (result); + return result; +} + +static PyObject * +stpy_fullname (PyObject *self, PyObject *args) +{ + char *fullname; + struct symtab *symtab = NULL; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + STPY_REQUIRE_VALID (self, symtab); + } + GDB_PY_HANDLE_EXCEPTION (except); + + 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; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + SALPY_REQUIRE_VALID (self, sal); + } + GDB_PY_HANDLE_EXCEPTION (except); + + 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; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + SALPY_REQUIRE_VALID (self, sal); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return PyLong_FromUnsignedLongLong (sal->pc); +} + +static PyObject * +salpy_get_line (PyObject *self, void *closure) +{ + struct symtab_and_line *sal = NULL; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + SALPY_REQUIRE_VALID (self, sal); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return PyLong_FromUnsignedLongLong (sal->line); +} + +static PyObject * +salpy_get_symtab (PyObject *self, void *closure) +{ + struct symtab_and_line *sal; + volatile struct gdb_exception except; + sal_object *self_sal = (sal_object *) self; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + SALPY_REQUIRE_VALID (self, sal); + } + GDB_PY_HANDLE_EXCEPTION (except); + + 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. */ +static void +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 (symtab_obj == NULL) + { + Py_DECREF (sal_obj); + return; + } + } + 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; +} + +/* 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; + + sal_obj = PyObject_New (sal_object, &sal_object_type); + + if (sal_obj) + set_sal (sal_obj, sal); + + 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, + "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 9196f08..eaf84fc 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" ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-15 15:15 ` Phil Muldoon @ 2010-02-15 18:45 ` Eli Zaretskii 2010-02-15 23:39 ` Phil Muldoon 2010-02-18 2:50 ` Tom Tromey 1 sibling, 1 reply; 23+ messages in thread From: Eli Zaretskii @ 2010-02-15 18:45 UTC (permalink / raw) To: Phil Muldoon; +Cc: tromey, gdb-patches > Date: Mon, 15 Feb 2010 15:15:18 +0000 > From: Phil Muldoon <pmuldoon@redhat.com> > CC: gdb-patches ml <gdb-patches@sourceware.org> > > Eli, > > I've made that last changes you requested, too. > > What do you think? I like it. But I want more ;-) > +@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 Sometimes "Returns", sometimes "Return". I think the latter is better, and we also use it more. In any case, we should use one or the other consistently. > +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. Please add a comma after the right brace that closes the argument of @ref (two counts above). Otherwise, makeinfo will bitch at you. Thanks. ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-15 18:45 ` Eli Zaretskii @ 2010-02-15 23:39 ` Phil Muldoon 2010-02-16 4:12 ` Eli Zaretskii 0 siblings, 1 reply; 23+ messages in thread From: Phil Muldoon @ 2010-02-15 23:39 UTC (permalink / raw) To: Eli Zaretskii; +Cc: tromey, gdb-patches On 02/15/2010 06:43 PM, Eli Zaretskii wrote: >> What do you think? > > I like it. But I want more ;-) > >> +@defmethod Frame find_sal >> +Return the frame's symtab and line object. >> +@xref{Symbol Tables In Python}. >> +@end defmethod > > Sometimes "Returns", sometimes "Return". I think the latter is > better, and we also use it more. In any case, we should use one or > the other consistently. Ok fixed in the patch and in a few other places the patch touches. >> +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. Ok. I'm not sure if your previous Ok carries forward here. I've attached an updated copy of the doc patch just to be sure. Cheers, Phil -- diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 0e3e093..81a71af 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 @@ -20733,7 +20736,7 @@ Return the selected frame object. (@pxref{Selection,,Selecting a Frame}). @end defun @defun frame_stop_reason_string reason -Return a string explaining the reason why @value{GDBN} stopped unwinding +Returns a string explaining the reason why @value{GDBN} stopped unwinding frames, as expressed by the given @var{reason} code (an integer, see the @code{unwind_stop_reason} method further down in this section). @end defun @@ -20760,7 +20763,7 @@ or @code{gdb.SENTINEL_FRAME}. @end defmethod @defmethod Frame unwind_stop_reason -Return an integer representing the reason why it's not possible to find +Returns an integer representing the reason why it's not possible to find more frames toward the outermost frame. Use @code{gdb.frame_stop_reason_string} to convert the value returned by this function to a string. @@ -20770,18 +20773,325 @@ 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. +Returns the frame that called this frame. @end defmethod @defmethod Frame newer -Return the frame called by this frame. +Returns the frame called by this frame. +@end defmethod + +@defmethod Frame find_sal +Returns 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 +Returns 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 +Returns 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 +Returns the symbol table's source absolute file name. +@end defmethod @end table @node Lazy Strings In Python ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-15 23:39 ` Phil Muldoon @ 2010-02-16 4:12 ` Eli Zaretskii 0 siblings, 0 replies; 23+ messages in thread From: Eli Zaretskii @ 2010-02-16 4:12 UTC (permalink / raw) To: Phil Muldoon; +Cc: tromey, gdb-patches > Date: Mon, 15 Feb 2010 23:39:18 +0000 > From: Phil Muldoon <pmuldoon@redhat.com> > CC: tromey@redhat.com, gdb-patches@sourceware.org > > On 02/15/2010 06:43 PM, Eli Zaretskii wrote: > > >> What do you think? > > > > I like it. But I want more ;-) > > > >> +@defmethod Frame find_sal > >> +Return the frame's symtab and line object. > >> +@xref{Symbol Tables In Python}. > >> +@end defmethod > > > > Sometimes "Returns", sometimes "Return". I think the latter is > > better, and we also use it more. In any case, we should use one or > > the other consistently. > > > Ok fixed in the patch and in a few other places the patch touches. Actually, I meant the other way around: to say "Return". That's because you also say "Set", not "Sets", etc. > I'm not sure if your previous Ok carries forward here. It is OK to commit once the above single issue is resolved. Thanks. ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-15 15:15 ` Phil Muldoon 2010-02-15 18:45 ` Eli Zaretskii @ 2010-02-18 2:50 ` Tom Tromey 2010-02-19 14:15 ` Phil Muldoon 1 sibling, 1 reply; 23+ messages in thread From: Tom Tromey @ 2010-02-18 2:50 UTC (permalink / raw) To: Phil Muldoon; +Cc: Eli Zaretskii, gdb-patches ml Phil> I've added life-cycle support for symbols, symbol tables, symbol tables Phil> and line, and blocks. This was a little more involved than I first Phil> thought. I've also added the other changes you requested Thanks for doing this. 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. 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'. 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. Phil> +/* Require a valid symbol. All access to symbol_object->symbol 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 SYMPY_REQUIRE_VALID(symbol_obj, symbol) \ Phil> + do { \ Phil> + symbol = symbol_object_to_symbol (symbol_obj); \ Phil> + if (symbol == NULL) \ Phil> + error (_("Symbol is invalid.")); \ Phil> + } while (0) The comment that applied to BLPY_REQUIRE_VALID applies here. 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. 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. 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. Phil> +/* Require a valid symbol table. All access to symtab_object->symtab Phil> + should be gated by this call. This must be called inside a Phil> + TRY_CATCH, or another context in which a gdb exception is Phil> + allowed. */ Phil> +#define STPY_REQUIRE_VALID(symtab_obj, symtab) \ Phil> + do { \ Phil> + symtab = symtab_object_to_symtab (symtab_obj); \ Phil> + if (symtab == NULL) \ Phil> + error (_("Symbol table is invalid.")); \ Phil> + } while (0) As above. Also SALPY_REQUIRE_VALID. Phil> + s = xstrprintf ("symbol table for %s", Phil> + symtab->filename); Also as above. 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. Phil> + s = xstrprintf ("symbol and line for %s, line %d", filename, Phil> + sal->line); As above. Phil> +static void Phil> +set_sal (sal_object *sal_obj, struct symtab_and_line sal) Phil> +{ Phil> + Spurious blank line. 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> + sizeof(struct symtab_and_line)); Space before paren. 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. 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. 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. thanks, Tom ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-18 2:50 ` Tom Tromey @ 2010-02-19 14:15 ` Phil Muldoon 2010-02-19 14:28 ` Eli Zaretskii ` (2 more replies) 0 siblings, 3 replies; 23+ messages in thread From: Phil Muldoon @ 2010-02-19 14:15 UTC (permalink / raw) To: Tom Tromey; +Cc: Eli Zaretskii, gdb-patches ml 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" ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-19 14:15 ` Phil Muldoon @ 2010-02-19 14:28 ` Eli Zaretskii 2010-02-19 15:13 ` Phil Muldoon 2010-02-23 23:05 ` Tom Tromey 2010-02-23 23:09 ` Tom Tromey 2 siblings, 1 reply; 23+ messages in thread From: Eli Zaretskii @ 2010-02-19 14:28 UTC (permalink / raw) To: Phil Muldoon; +Cc: tromey, gdb-patches > Date: Fri, 19 Feb 2010 14:14:57 +0000 > From: Phil Muldoon <pmuldoon@redhat.com> > Cc: Eli Zaretskii <eliz@gnu.org>, gdb-patches ml <gdb-patches@sourceware.org> > > +* Python scripting > + > +The GDB Python API now has access to symbols, symbol tables, and > +frame's code blocks. > + This is okay, thanks. > +@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 Please use "Return" rather than "Returns". > +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. And still no comma after @ref{...}. ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-19 14:28 ` Eli Zaretskii @ 2010-02-19 15:13 ` Phil Muldoon 0 siblings, 0 replies; 23+ messages in thread From: Phil Muldoon @ 2010-02-19 15:13 UTC (permalink / raw) To: Eli Zaretskii; +Cc: tromey, gdb-patches On Fri, Feb 19, 2010 at 04:26:36PM +0200, Eli Zaretskii wrote: > > Date: Fri, 19 Feb 2010 14:14:57 +0000 > > From: Phil Muldoon <pmuldoon@redhat.com> > > Cc: Eli Zaretskii <eliz@gnu.org>, gdb-patches ml <gdb-patches@sourceware.org> > > > > +* Python scripting > > + > > +The GDB Python API now has access to symbols, symbol tables, and > > +frame's code blocks. > > + > > This is okay, thanks. > > Please use "Return" rather than "Returns". > > > +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. > > And still no comma after @ref{...}. Apologies for this. I keep the doc and code trees separate, and a slightly older documentation cut was in the code review. Locally I have these changes. Thanks for spotting it, though! Cheers, Phil ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-19 14:15 ` Phil Muldoon 2010-02-19 14:28 ` Eli Zaretskii @ 2010-02-23 23:05 ` Tom Tromey 2010-02-24 16:58 ` Phil Muldoon 2010-02-23 23:09 ` Tom Tromey 2 siblings, 1 reply; 23+ messages in thread From: Tom Tromey @ 2010-02-23 23:05 UTC (permalink / raw) To: Phil Muldoon; +Cc: Eli Zaretskii, gdb-patches ml >>>>> "Phil" == Phil Muldoon <pmuldoon@redhat.com> writes: Tom> I think this could use a NEWS entry. I suggest waiting until my earlier Tom> patch is approved, then adding items to that block... assuming your Tom> patch goes in before 7.1. Otherwise, add a new Python block in the Tom> post-7.1 changes. Phil> I included one in the patch I sent. Here is the hunk: Thanks, I must have missed it. Sorry about that. Phil> This hunk puts it in the 7.1 release section. I'll move it when we Phil> figure out what release it will be in (as of today, looks like 7.2). Yeah, 7.2 now. Phil> I ended up just reusing the FRAPY_REQUIRE_VALID code that is in Phil> py-frame.c. That code is bogus too, but I didn't want to burden you with this, at least not for this patch ;). Phil> +static PyObject * Phil> +sympy_str (PyObject *self) [...] Phil> + s = xstrprintf ("symbol for %s", Phil> + SYMBOL_PRINT_NAME (symbol)); Tom> Why not just have this be SYMBOL_PRINT_NAME? Tom> I forgot the difference between the various python to-string methods. Tom> Maybe this one is supposed to be more verbose? Let me know. Phil> One of the tricky things I've found in merging work is I'm often not Phil> the original author of that work. Totally understood. This is all my fault or Thiago's :) Phil> And my understanding of Python's "print object" Phil> -> string is more for human consumption that for comparison or Phil> assingment. That being said, I've no strong feelings on it. I did not Phil> change it in this patch. If you want it changed, I'll happily do it. Yes, I think we should change it so that "print foo" or "str(foo)" yields the "most natural" name. In this case it is just the print name. Phil> + s = xstrprintf ("symbol table for %s", Phil> + symtab->filename); Tom> Also as above. Phil> I'm not sure what this means, is it referring to the sympy_str Phil> comment? Yeah, sorry, do like sympy_str. In this case I think it should just return the filename. Phil> + s = xstrprintf ("symbol and line for %s, line %d", filename, Phil> + sal->line); Tom> Phil> Ditto, sympy_str comment. I am not sure what is nicest to return here; it is probably fine to leave it as-is for the time being. thanks, Tom ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-23 23:05 ` Tom Tromey @ 2010-02-24 16:58 ` Phil Muldoon 2010-02-24 17:22 ` Tom Tromey 2010-02-24 18:43 ` Eli Zaretskii 0 siblings, 2 replies; 23+ messages in thread From: Phil Muldoon @ 2010-02-24 16:58 UTC (permalink / raw) To: Tom Tromey; +Cc: Eli Zaretskii, gdb-patches ml On Tue, Feb 23, 2010 at 04:05:40PM -0700, Tom Tromey wrote: > Phil> This hunk puts it in the 7.1 release section. I'll move it when we > Phil> figure out what release it will be in (as of today, looks like 7.2). > > Yeah, 7.2 now. Fixed, I put it in "Since 7.1" as there is not a 7.2 section yet. > Phil> And my understanding of Python's "print object" > Phil> -> string is more for human consumption that for comparison or > Phil> assingment. That being said, I've no strong feelings on it. I did not > Phil> change it in this patch. If you want it changed, I'll happily do it. > > Yes, I think we should change it so that "print foo" or "str(foo)" > yields the "most natural" name. Fixed here and other places regarding _str returns. > Phil> Ditto, sympy_str comment. > > I am not sure what is nicest to return here; it is probably fine to > leave it as-is for the time being. I left it alone for now. Also fixed the _("") on the error message for block. I took the oppurtunity to use "skip_python_tests" function in this patch, too What do you think? 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..babd18a 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/gdb.texinfo b/gdb/doc/gdb.texinfo index d886787..2eea484 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 0000000..3523664 --- /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..94211db 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..5b282a2 --- /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 <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) +{ + 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 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..f91f322 --- /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 <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) +{ + 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) + ? "<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..c1ea250 --- /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 <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} + +# 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" "<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" "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" "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..6eaa943 --- /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 <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} + +# 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 0000000..5c60ad3 --- /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 <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} + +# 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" "<gdb.Objfile object at ${hex}>" "Test symtab.objfile" +gdb_test "python print symtab.fullname()" "testsuite/gdb.python/py-symbol.c.*" "Test symtab.fullname" ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-24 16:58 ` Phil Muldoon @ 2010-02-24 17:22 ` Tom Tromey 2010-02-24 21:49 ` Phil Muldoon 2010-02-24 18:43 ` Eli Zaretskii 1 sibling, 1 reply; 23+ messages in thread From: Tom Tromey @ 2010-02-24 17:22 UTC (permalink / raw) To: Phil Muldoon; +Cc: Eli Zaretskii, gdb-patches ml >>>>> "Phil" == Phil Muldoon <pmuldoon@redhat.com> writes: Tom> Yes, I think we should change it so that "print foo" or "str(foo)" Tom> yields the "most natural" name. Phil> Fixed here and other places regarding _str returns. One last fix... Phil> +static PyObject * Phil> +sympy_str (PyObject *self) Phil> +{ This function is the same as sympy_get_print_name. So, remove the latter and just make both methods point to the same implementation. (IMO it is fine to have an explicit method doing the same thing as str). Ok with this change. Thanks. Tom ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-24 17:22 ` Tom Tromey @ 2010-02-24 21:49 ` Phil Muldoon 0 siblings, 0 replies; 23+ messages in thread From: Phil Muldoon @ 2010-02-24 21:49 UTC (permalink / raw) To: Tom Tromey; +Cc: Eli Zaretskii, gdb-patches ml >> What do you think? > One last fix... > > Ok with this change. Thanks. > > Tom > I'm happy with the parts for NEWS and the manual. Thanks. > Eli http://sourceware.org/ml/gdb-cvs/2010-02/msg00196.html So committed. Thanks for all your help in assisting this merge. Cheers, Phil ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-24 16:58 ` Phil Muldoon 2010-02-24 17:22 ` Tom Tromey @ 2010-02-24 18:43 ` Eli Zaretskii 1 sibling, 0 replies; 23+ messages in thread From: Eli Zaretskii @ 2010-02-24 18:43 UTC (permalink / raw) To: Phil Muldoon; +Cc: tromey, gdb-patches > Date: Wed, 24 Feb 2010 16:57:09 +0000 > From: Phil Muldoon <pmuldoon@redhat.com> > Cc: Eli Zaretskii <eliz@gnu.org>, gdb-patches ml <gdb-patches@sourceware.org> > > What do you think? I'm happy with the parts for NEWS and the manual. Thanks. ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [patch][python] Add symbol, symbol table and frame block support to GDB API 2010-02-19 14:15 ` Phil Muldoon 2010-02-19 14:28 ` Eli Zaretskii 2010-02-23 23:05 ` Tom Tromey @ 2010-02-23 23:09 ` Tom Tromey 2 siblings, 0 replies; 23+ messages in thread From: Tom Tromey @ 2010-02-23 23:09 UTC (permalink / raw) To: Phil Muldoon; +Cc: Eli Zaretskii, gdb-patches ml >>>>> "Phil" == Phil Muldoon <pmuldoon@redhat.com> writes: One last thing I noticed... Phil> +/* Require a valid block. All access to block_object->block should be Phil> + gated by this call. */ Phil> +#define BLPY_REQUIRE_VALID(block_obj, block) \ Phil> + do { \ Phil> + block = block_object_to_block (block_obj); \ Phil> + if (block == NULL) \ Phil> + { \ Phil> + PyErr_SetString (PyExc_RuntimeError, \ Phil> + "Block is invalid."); \ Phil> + return NULL; \ Phil> + } \ Phil> + } while (0) The error message here is missing _(). The others all seem to be ok. Tom ^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2010-02-24 21:49 UTC | newest] Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2010-02-01 13:42 [patch][python] Add symbol, symbol table and frame block support to GDB API Phil Muldoon 2010-02-01 20:54 ` Eli Zaretskii 2010-02-02 10:24 ` Phil Muldoon 2010-02-02 20:14 ` Eli Zaretskii 2010-02-03 20:55 ` Phil Muldoon 2010-02-05 10:53 ` Phil Muldoon 2010-02-05 18:06 ` Eli Zaretskii 2010-02-05 11:05 ` Eli Zaretskii 2010-02-04 23:25 ` Tom Tromey 2010-02-15 15:15 ` Phil Muldoon 2010-02-15 18:45 ` Eli Zaretskii 2010-02-15 23:39 ` Phil Muldoon 2010-02-16 4:12 ` Eli Zaretskii 2010-02-18 2:50 ` Tom Tromey 2010-02-19 14:15 ` Phil Muldoon 2010-02-19 14:28 ` Eli Zaretskii 2010-02-19 15:13 ` Phil Muldoon 2010-02-23 23:05 ` Tom Tromey 2010-02-24 16:58 ` Phil Muldoon 2010-02-24 17:22 ` Tom Tromey 2010-02-24 21:49 ` Phil Muldoon 2010-02-24 18:43 ` Eli Zaretskii 2010-02-23 23:09 ` Tom Tromey
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox