[patch] PR python/10807 API for macros.

Matt Rice
2011-08-16T06:36:29Z

[-- Attachment #1: Type: text/plain, Size: 1652 bytes --]

In the gdb.Macro class, I didn't used methods instead of attributes,
because the values are lazily computed/can return different objects if
called multiple times, thus attributes seemed weird, even though I
think the Macro methods are fairly attribute like. so if anyone has
any opinion here on attributes vs methods.

contains one unrelated change, to stpy_dealloc which seemed to leak.

its missing macro expansion, user defined macros, a sal/scoped version
of the macros() method
and whatever else anyone can think of, will save that for another time.

2011-08-15 Matt Rice <ratmice@gmail.com>

PR python/10807

* NEWS: Mention new macro api.
* Makefile.in: Add py-macro.c.
* python/py-macro.c: New file.
* python/py-objfile.c (objfpy_symtab): New function.
(objfile_getset): Add symtab attribute.
* python/py-symtab.c (add_macro_to_list, stpy_macros,
salpy_macro_named): New functions.
(stpy_dealloc): Free the PyObject.
(symtab_object_methods): Add macros method.
(sal_object_methods): Add macro_named method.
* python/py-symtab.h: New File:
(symtab_to_symtab_object): Make public.
* python/python.h: Add gdb_initialize_macros.
* python/python.c: Call gdb_initialize_macros.

2011-08-15 Matt Rice <ratmice@gmail.com>

* gdb.python/py-macro.c: New file.
* gdb.python/py-macro.exp: Ditto.

2011-08-15 Matt Rice <ratmice@gmail.com>

* gdb.texinfo (Macros In Python): New section.
(Symbols In Python): Add macro_named, and macros methods.
(Objfiles In Python): Add symtab attribute.

[-- Attachment #2: foo.diff --]
[-- Type: text/x-patch, Size: 32429 bytes --]

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index bd00644..71389a6 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -289,6 +289,7 @@ SUBDIR_PYTHON_OBS = \
py-inferior.o \
py-infthread.o \
py-lazy-string.o \
+ py-macro.o \
py-objfile.o \
py-param.o \
py-prettyprint.o \
@@ -319,6 +320,7 @@ SUBDIR_PYTHON_SRCS = \
python/py-inferior.c \
python/py-infthread.c \
python/py-lazy-string.c \
+ python/py-macro.c \
python/py-objfile.c \
python/py-param.c \
python/py-prettyprint.c \
@@ -2110,6 +2112,10 @@ py-lazy-string.o: $(srcdir)/python/py-lazy-string.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-lazy-string.c
$(POSTCOMPILE)

+py-macro.o: $(srcdir)/python/py-macro.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-macro.c
+ $(POSTCOMPILE)
+
py-objfile.o: $(srcdir)/python/py-objfile.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-objfile.c
$(POSTCOMPILE)
diff --git a/gdb/NEWS b/gdb/NEWS
index 089e6ce..a6c2d11 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -30,6 +30,13 @@

** Symbols now provide the "type" attribute, the type of the symbol.

+ ** Objfiles now provide a "symtab" attribute.
+
+ ** The Macro object is now available for representing preprocessor macros.
+ The following objects now have methods for macro lookup.
+ - Symtab_and_line now has a "macro_named" method
+ - Symtab now has a "macros" method.
+
* libthread-db-search-path now supports two special values: $sdir and $pdir.
$sdir specifies the default system locations of shared libraries.
$pdir specifies the directory where the libpthread used by the application
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index b477cf3..db74e67 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -20955,6 +20955,7 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
* Blocks In Python:: Accessing frame blocks from Python.
* Symbols In Python:: Python representation of symbols.
* Symbol Tables In Python:: Python representation of symbol tables.
+* Macros In Python:: Python representation of preprocessor macros.
* Lazy Strings In Python:: Python representation of lazy strings.
* Breakpoints In Python:: Manipulating breakpoints using Python.
@end menu
@@ -22945,6 +22946,10 @@ which is used to format the value. @xref{Pretty Printing API}, for more
information.
@end defivar

+@defivar Objfile symtab
+The objfile's symbol table represented as a @code{gdb.Symtab} object.
+@end defivar
+
A @code{gdb.Objfile} object has the following methods:

@defmethod Objfile is_valid
@@ -23415,6 +23420,11 @@ exist in @value{GDBN} any longer. All other
@code{gdb.Symtab_and_line} methods will throw an exception if it is
invalid at the time the method is called.
@end defmethod
+
+@defmethod Symtab_and_line macro_named @r{[}name@r{]}
+Returns a @code{gdb.Macro} object, for the macro
+with the given name.
+@end defmethod
@end table

A @code{gdb.Symtab} object has the following attributes:
@@ -23444,8 +23454,48 @@ if it is invalid at the time the method is called.
@defmethod Symtab fullname
Return the symbol table's source absolute file name.
@end defmethod
+
+@defmethod Symtab macros
+Return all of the macros contained in the symbol table.
+@end defmethod
@end table

+
+@node Macros In Python
+@subsubsection Python representation of preprocessor macros.
+
+@cindex macros in python
+@tindex gdb.macro
+
+Python code can query information about preprocessor macros using the
+@code{gdb.macro} class. For obtaining a @code{gdb.macro} object see
+@xref{Symbol Tables In Python}.
+
+@defmethod Macro name
+Returns the name of the macro.
+@end defmethod
+
+@defmethod Macro definition
+Returns a string with the definition of the macro.
+@end defmethod
+
+@defmethod Macro is_function_like
+Returns @code{true} If the macro is function like.
+@end defmethod
+
+@defmethod Macro argv
+Returns a list of the macros arguments if the macro is function like.
+If the macro is not function like, returns @code{None}
+@end defmethod
+
+@defmethod Macro include_trail
+Returns a list of tuples containing the filenames, and line numbers
+of header and source files that correspond to the include directives
+and file location that caused the macro to be defined.
+The list is sorted starting with the place of definition,
+and ending with the first include directive.
+@end defmethod
+
@node Breakpoints In Python
@subsubsection Manipulating breakpoints using Python

diff --git a/gdb/python/py-macro.c b/gdb/python/py-macro.c
new file mode 100644
index 0000000..4b2f385
--- /dev/null
+++ b/gdb/python/py-macro.c
@@ -0,0 +1,463 @@
+/* Python interface to macros.
+
+ Copyright (C) 2011 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 "python-internal.h"
+#include "macrotab.h"
+#include "macroexp.h"
+#include "macroscope.h"
+#include "charset.h"
+
+typedef struct
+{
+ PyObject_HEAD;
+ const char *name;
+ struct macro_source_file *src_file;
+ int src_line;
+} macro_object;
+
+static PyTypeObject macro_object_type;
+
+static PyObject *
+definition_to_py (struct macro_definition *macro)
+{
+ if (macro->replacement)
+ return PyString_FromString (macro->replacement);
+ else
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+is_function_like_to_py (struct macro_definition *macro)
+{
+ if (macro->kind == macro_function_like)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+static PyObject *
+argv_to_py (struct macro_definition *macro)
+{
+ PyObject *ret = NULL;
+
+ if (macro->kind == macro_function_like)
+ {
+ Py_ssize_t i;
+ PyObject *ret = PyList_New (macro->argc);
+
+ if (ret == NULL)
+ return NULL;
+
+ for (i = 0; i < macro->argc; i++)
+ {
+ PyObject *item = PyString_FromString (macro->argv[i]);
+
+ if (!item)
+ goto err_ret;
+
+ if (PyList_SetItem (ret, i, item) != 0)
+ goto err_ret;
+ }
+
+ return ret;
+ }
+
+ Py_RETURN_NONE;
+
+ err_ret:
+ Py_XDECREF (ret);
+ return NULL;
+}
+
+
+static PyObject *
+include_trail_to_py(struct macro_definition *macro,
+ const char *name,
+ struct macro_source_file *src_file,
+ int src_line)
+{
+ PyObject *tuple = PyTuple_New (2);
+ PyObject *result = PyList_New (0);
+ PyObject *tmp;
+ struct macro_source_file *file;
+ int line;
+
+ if (!tuple || !result)
+ goto err_exit;
+
+ file = macro_definition_location (src_file, src_line, name, &line);
+ if (!file)
+ goto err_exit;
+
+ tmp = PyString_FromString (file->filename);
+ if (!tmp)
+ goto err_exit;
+ PyTuple_SetItem (tuple, 0, tmp);
+
+ tmp = PyInt_FromLong (line);
+ if (!tmp)
+ goto err_exit;
+ if (PyTuple_SetItem (tuple, 1, tmp) != 0)
+ goto err_exit;
+ if (PyList_Append (result, tuple) != 0)
+ goto err_exit;
+ Py_DECREF (tuple);
+
+ while (file->included_by)
+ {
+ tuple = PyTuple_New (2);
+
+ if (!tuple)
+ goto err_exit;
+
+ tmp = PyString_FromString (file->included_by->filename);
+ if (!tmp)
+ goto err_exit;
+ if (PyTuple_SetItem (tuple, 0, tmp) != 0)
+ goto err_exit;
+
+ tmp = PyInt_FromLong (file->included_at_line);
+ if (!tmp)
+ goto err_exit;
+ if (PyTuple_SetItem (tuple, 1, tmp) != 0)
+ goto err_exit;
+
+ if (PyList_Append (result, tuple) != 0)
+ goto err_exit;
+ Py_DECREF (tuple);
+
+ file = file->included_by;
+ }
+
+ return result;
+
+ err_exit:
+ Py_XDECREF (tuple);
+ Py_DECREF (result);
+ return NULL;
+}
+
+/* Create a new macro (gdb.Macro) object that encapsulates the
+ macro_definition structure from GDB. */
+PyObject *
+macropy_object_create (struct macro_definition *macro,
+ const char *name,
+ struct macro_source_file *ms,
+ int line)
+{
+ macro_object *macro_obj;
+
+ macro_obj = PyObject_New (macro_object, &macro_object_type);
+ if (macro_obj)
+ {
+ /* Save enough to lookup the macro again in the methods.
+ Then do a lookup and lazily copy things into PyObjects.
+ Consecutive lookups should be OK, because of the splay tree.
+ We cannot save a macro definition due to inconsistent memory
+ management. We rely on the fact that the macro_source_file
+ is not released until exit.
+
+ It seems we may need to move to using a 'macro_scope'
+ if we want a python api for user-defined macros. */
+ macro_obj->src_file = ms;
+ macro_obj->src_line = line;
+ macro_obj->name = xstrdup (name);
+ }
+
+ return (PyObject *) macro_obj;
+}
+
+static void
+macropy_dealloc (PyObject *obj)
+{
+ macro_object *macro_obj = (macro_object *) obj;
+
+ xfree ((void *) macro_obj->name);
+ obj->ob_type->tp_free (obj);
+}
+
+static PyObject *
+macropy_name_method (PyObject *self, PyObject *args)
+{
+ macro_object *me = (macro_object *) self;
+
+ return PyString_Decode (me->name, strlen (me->name), host_charset (), NULL);
+}
+
+static PyObject *
+macropy_definition_method (PyObject *self, PyObject *args)
+{
+ macro_object *me = (macro_object *) self;
+ struct macro_definition *macro;
+
+ macro = macro_lookup_definition (me->src_file, me->src_line, me->name);
+ return definition_to_py (macro);
+}
+
+static PyObject *
+macropy_is_function_like_method (PyObject *self, PyObject *args)
+{
+ macro_object *me = (macro_object *) self;
+ struct macro_definition *macro;
+
+ macro = macro_lookup_definition (me->src_file, me->src_line, me->name);
+ return is_function_like_to_py (macro);
+}
+
+static PyObject *
+macropy_argv_method (PyObject *self, PyObject *args)
+{
+ macro_object *me = (macro_object *) self;
+ struct macro_definition *macro;
+
+ macro = macro_lookup_definition (me->src_file, me->src_line, me->name);
+ return argv_to_py (macro);
+}
+
+static PyObject *
+macropy_include_trail_method (PyObject *self, PyObject *args)
+{
+ macro_object *me = (macro_object *) self;
+ struct macro_definition *macro;
+
+ macro = macro_lookup_definition (me->src_file, me->src_line, me->name);
+ return include_trail_to_py (macro, me->name, me->src_file, me->src_line);
+}
+
+static int
+concat_chars (PyObject **result, const char *stuff)
+{
+ PyObject *tmp = PyString_FromString (stuff);
+
+ if (!tmp)
+ return -1;
+
+ PyString_ConcatAndDel (result, tmp);
+ if (*result == NULL)
+ return -1;
+
+ return 0;
+}
+
+static int
+concat_py_obj (PyObject **result, PyObject *stuff)
+{
+ PyObject *tmp = PyObject_Str (stuff);
+
+ if (!tmp)
+ return -1;
+
+ PyString_ConcatAndDel (result, tmp);
+ if (*result == NULL)
+ return -1;
+
+ return 0;
+}
+
+static PyObject *
+macropy_str (PyObject *self)
+{
+ PyObject *result = PyString_FromString ("<gdb.Macro ");
+ macro_object *me = (macro_object *) self;
+ struct macro_definition *macro;
+ PyObject *argv = macropy_argv_method (self, Py_None);
+ PyObject *definition = macropy_definition_method (self, Py_None);
+ PyObject *include_trail = macropy_include_trail_method (self, Py_None);
+ PyObject *is_function_like = macropy_is_function_like_method (self, Py_None);
+ PyObject *name = PyString_FromString (me->name);
+
+ if (!definition || !is_function_like || !argv
+ || !include_trail || !name || !result)
+ goto err_ret;
+
+ if (concat_py_obj (&result, name) != 0)
+ goto err_ret;
+
+ if (is_function_like == Py_True)
+ {
+ Py_ssize_t sz = PyList_Size (argv);
+ Py_ssize_t i;
+
+ if (concat_chars (&result, "(") != 0)
+ goto err_ret;
+
+ for (i = 0; i < sz; i++)
+ {
+ /* borrowed */
+ if (concat_py_obj (&result, PyList_GetItem (argv, i)) != 0)
+ goto err_ret;
+
+ if (i < sz - 1)
+ if (concat_chars (&result, ", ") != 0)
+ goto err_ret;
+ }
+
+ if (concat_chars (&result, ")") != 0)
+ goto err_ret;
+ }
+
+ if (definition != Py_None && PyString_Size (definition))
+ {
+ if (concat_chars (&result, "=") != 0)
+ goto err_ret;
+
+ if (concat_py_obj (&result, definition) != 0)
+ goto err_ret;
+ }
+
+ if (concat_chars (&result, " ") != 0)
+ goto err_ret;
+ if (concat_chars (&result, "include_trail=") != 0)
+ goto err_ret;
+ if (concat_py_obj (&result, include_trail) != 0)
+ goto err_ret;
+
+ if (concat_chars (&result, ">") != 0)
+ goto err_ret;
+
+ goto normal_ret;
+
+ err_ret:
+ Py_XDECREF (result);
+ result = NULL;
+ /* fall-through */
+ normal_ret:
+ Py_XDECREF (argv);
+ Py_XDECREF (definition);
+ Py_XDECREF (include_trail);
+ Py_XDECREF (is_function_like);
+ Py_XDECREF (name);
+ return result;
+}
+
+static int
+macropy_compare (PyObject *self, PyObject *o2)
+{
+ PyObject *my_str = macropy_str (self);
+ int result;
+
+ if (!my_str)
+ return -1;
+
+ if (PyObject_TypeCheck (o2, &macro_object_type))
+ {
+ PyObject *other_str = macropy_str (o2);
+
+ if (other_str)
+ result = PyObject_Compare (my_str, other_str);
+ else
+ result = -1;
+
+ Py_DECREF (my_str);
+ Py_XDECREF (other_str);
+ return result;
+ }
+
+ result = PyObject_Compare (my_str, o2);
+
+ Py_DECREF (my_str);
+ return result;
+}
+
+static long
+macropy_hash(PyObject *o)
+{
+ long result;
+ PyObject *my_str = macropy_str (o);
+
+ if (!my_str)
+ return -1;
+
+ result = PyObject_Hash (my_str);
+ Py_DECREF (my_str);
+ return result;
+}
+
+void
+gdbpy_initialize_macros (void)
+{
+ macro_object_type.tp_new = PyType_GenericNew;
+
+ if (PyType_Ready (&macro_object_type) < 0)
+ return;
+
+ Py_INCREF (&macro_object_type);
+ PyModule_AddObject (gdb_module, "Macro",
+ (PyObject *) &macro_object_type);
+}
+
+static PyGetSetDef macro_object_getset[] = {
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef macro_object_methods[] = {
+ { "argv", macropy_argv_method, METH_NOARGS,
+ "argv () -> List.\n\
+Return a list containing the names of the arguments for a function like \
+macro." },
+ { "definition", macropy_definition_method, METH_NOARGS,
+ "definition () -> String.\n\
+Return the macro's definition." },
+ { "include_trail", macropy_include_trail_method, METH_NOARGS,
+ "include_trail () -> List.\n\
+Return a list containing tuples with the filename and line number describing \
+how and where this macro came to be defined." },
+ { "is_function_like", macropy_is_function_like_method, METH_NOARGS,
+ "is_function_like () -> Bool.\n\
+Return True if the macro is function like, False otherwise." },
+ { "name", macropy_name_method, METH_NOARGS,
+ "name () -> String.\n\
+Return the macro's name." },
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject macro_object_type = {
+ PyObject_HEAD_INIT (NULL)
+ 0, /*ob_size*/
+ "gdb.Macro", /*tp_name*/
+ sizeof (macro_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ macropy_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ macropy_compare, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ macropy_hash, /*tp_hash */
+ 0, /*tp_call*/
+ macropy_str, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "GDB macro object", /*tp_doc */
+ 0, /*tp_traverse */
+ 0, /*tp_clear */
+ 0, /*tp_richcompare */
+ 0, /*tp_weaklistoffset */
+ 0, /*tp_iter */
+ 0, /*tp_iternext */
+ macro_object_methods, /*tp_methods */
+ 0, /*tp_members */
+ macro_object_getset, /*tp_getset */
+};
diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c
index f9821f5..2697218 100644
--- a/gdb/python/py-objfile.c
+++ b/gdb/python/py-objfile.c
@@ -22,6 +22,7 @@
#include "charset.h"
#include "objfiles.h"
#include "language.h"
+#include "py-symtab.h"

typedef struct
{
@@ -118,6 +119,17 @@ objfpy_set_printers (PyObject *o, PyObject *value, void *ignore)
return 0;
}

+static PyObject *
+objfpy_symtab (PyObject *self, void *ignore)
+{
+ objfile_object *obj = (objfile_object *) self;
+
+ if (! obj->objfile)
+ return Py_None;
+
+ return symtab_to_symtab_object (obj->objfile->symtabs);
+}
+
/* Implementation of gdb.Objfile.is_valid (self) -> Boolean.
Returns True if this object file still exists in GDB. */

@@ -210,6 +222,8 @@ static PyGetSetDef objfile_getset[] =
"The objfile's filename, or None.", NULL },
{ "pretty_printers", objfpy_get_printers, objfpy_set_printers,
"Pretty printers.", NULL },
+ { "symtab", objfpy_symtab, NULL,
+ "The objfile's symtab, or None.", NULL },
{ NULL }
};

diff --git a/gdb/python/py-symtab.c b/gdb/python/py-symtab.c
index 107cdec..033a21d 100644
--- a/gdb/python/py-symtab.c
+++ b/gdb/python/py-symtab.c
@@ -22,6 +22,7 @@
#include "symtab.h"
#include "source.h"
#include "python-internal.h"
+#include "py-macro.h"
#include "objfiles.h"

typedef struct stpy_symtab_object {
@@ -138,6 +139,66 @@ stpy_fullname (PyObject *self, PyObject *args)
Py_RETURN_NONE;
}

+struct macro_user_data {
+ PyObject *list;
+ int errors;
+};
+
+static void add_macro_to_list (const char *name,
+ const struct macro_definition *definition,
+ struct macro_source_file *source,
+ int line,
+ void *user_data)
+{
+ struct macro_user_data *mud = user_data;
+ PyObject *tmp;
+
+ if (! PyObject_TypeCheck (mud->list, &PyList_Type))
+ goto err_exit;
+
+ if (mud->errors != 0)
+ goto err_exit;
+
+ tmp = macropy_object_create (definition, name, source, line);
+ if (tmp)
+ {
+ if (PyList_Append (mud->list, tmp) != 0)
+ goto err_exit;
+ Py_DECREF (tmp);
+ return;
+ }
+
+ err_exit:
+ mud->errors = 1;
+ return;
+}
+
+static PyObject *
+stpy_macros (PyObject *self, PyObject *args)
+{
+ struct symtab *st = symtab_object_to_symtab (self);
+ struct macro_user_data mud;
+ PyObject *result;
+
+ STPY_REQUIRE_VALID (self, st);
+
+ result = PyList_New (0);
+ if (result == NULL)
+ return NULL;
+
+ mud.list = result;
+ mud.errors = 0;
+ macro_for_each (st->macro_table, add_macro_to_list, &mud);
+
+ if (mud.errors != 0)
+ {
+ Py_DECREF (result);
+ return NULL;
+ }
+
+ return result;
+}
+
/* Implementation of gdb.Symtab.is_valid (self) -> Boolean.
Returns True if this Symbol table still exists in GDB. */

@@ -191,6 +252,7 @@ stpy_dealloc (PyObject *obj)
if (symtab->next)
symtab->next->prev = symtab->prev;
symtab->symtab = NULL;
+ obj->ob_type->tp_free (obj);
}

@@ -242,6 +304,39 @@ salpy_is_valid (PyObject *self, PyObject *args)
Py_RETURN_TRUE;
}

+static PyObject *
+salpy_macro_named (PyObject *self, PyObject *args)
+{
+ struct symtab_and_line *sal;
+ struct macro_scope *ms;
+ struct macro_definition *mdef;
+ char *macro_name;
+ struct cleanup *cleanup_chain;
+ PyObject *result;
+
+ if (!PyArg_ParseTuple (args, "s", &macro_name))
+ return NULL;
+
+ SALPY_REQUIRE_VALID (self, sal);
+
+ ms = sal_macro_scope (*sal);
+ cleanup_chain = make_cleanup (free_current_contents, &ms);
+ if (ms == NULL)
+ goto none_exit;
+
+ mdef = macro_lookup_definition (ms->file, ms->line, macro_name);
+ if (mdef == NULL)
+ goto none_exit;
+
+ result = macropy_object_create (mdef, macro_name, ms->file, ms->line);
+ do_cleanups (cleanup_chain);
+ return result;
+
+ none_exit:
+ do_cleanups (cleanup_chain);
+ return Py_None;
+}
+
static void
salpy_dealloc (PyObject *self)
{
@@ -477,6 +572,9 @@ Return true if this symbol table is valid, false if not." },
{ "fullname", stpy_fullname, METH_NOARGS,
"fullname () -> String.\n\
Return the symtab's full source filename." },
+ { "macros", stpy_macros, METH_NOARGS,
+ "macros () -> List.\n\
+Return a list of macros in the symtab." },
{NULL} /* Sentinel */
};

@@ -526,6 +624,10 @@ static PyMethodDef sal_object_methods[] = {
{ "is_valid", salpy_is_valid, METH_NOARGS,
"is_valid () -> Boolean.\n\
Return true if this symbol table and line is valid, false if not." },
+ { "macro_named", salpy_macro_named, METH_VARARGS,
+ "macro_named (name) -> Macro.\n\
+Return the macro object for the given name, \
+or None if the macro cannot be found." },
{NULL} /* Sentinel */
};

diff --git a/gdb/python/py-symtab.h b/gdb/python/py-symtab.h
new file mode 100644
index 0000000..911a051
--- /dev/null
+++ b/gdb/python/py-symtab.h
@@ -0,0 +1,7 @@
+#ifndef GDB_PY_SYMTAB_H
+#define GDB_PY_SYMTAB_H
+
+PyObject *
+symtab_to_symtab_object (struct symtab *symtab);
+
+#endif
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 996b23b..532552a 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -211,6 +211,7 @@ void gdbpy_initialize_breakpoint_event (void);
void gdbpy_initialize_continue_event (void);
void gdbpy_initialize_exited_event (void);
void gdbpy_initialize_thread_event (void);
+void gdbpy_initialize_macros (void);

struct cleanup *make_cleanup_py_decref (PyObject *py);

diff --git a/gdb/python/python.c b/gdb/python/python.c
index 03edce9..092b354 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1198,6 +1198,7 @@ Enables or disables printing of Python stack traces."),
gdbpy_initialize_lazy_string ();
gdbpy_initialize_thread ();
gdbpy_initialize_inferior ();
+ gdbpy_initialize_macros ();
gdbpy_initialize_events ();

gdbpy_initialize_eventregistry ();
diff --git a/gdb/testsuite/gdb.python/py-macro.c b/gdb/testsuite/gdb.python/py-macro.c
new file mode 100644
index 0000000..8ac10e0
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-macro.c
@@ -0,0 +1,72 @@
+#ifdef DEF_MACROS
+
+ #ifdef ONE
+ #ifdef FOO
+ #undef FOO
+ #endif
+
+ #define FOO "hello"
+ #else
+ #undef FOO
+ #endif
+
+
+ #ifdef TWO
+ #ifdef FOO
+ #undef FOO
+ #endif
+ #define FOO " "
+ #endif
+
+ #ifdef THREE
+ #ifdef FOO
+ #undef FOO
+ #endif
+ #define FOO(a,b)
+ #endif
+
+ #ifdef FOUR
+ #ifdef FOO
+ #undef FOO
+ #endif
+ #define FOO(a) foo = a
+ #endif
+#else
+
+int main (int argc, const char **argv)
+{
+ char *foo;
+
+ #define DEF_MACROS
+ #define ONE
+ #include "py-macro.c"
+ foo = FOO;
+
+ #define TWO
+ #include "py-macro.c"
+ foo = FOO;
+
+ #define THREE
+ #include "py-macro.c"
+ foo = "world"FOO(0,1);
+
+ #undef THREE
+ #include "py-macro.c"
+ foo = FOO;
+
+ #undef TWO
+ #include "py-macro.c"
+ foo = FOO;
+
+ #undef ONE
+ #include "py-macro.c"
+ foo = (char *)0;
+
+ #define FOUR
+ #include "py-macro.c"
+ FOO ("the end.");
+
+ return 0;
+}
+#endif
+
diff --git a/gdb/testsuite/gdb.python/py-macro.exp b/gdb/testsuite/gdb.python/py-macro.exp
new file mode 100644
index 0000000..ccbabb6
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-macro.exp
@@ -0,0 +1,288 @@
+# Copyright (C) 2011 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 macros to Python.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+load_lib gdb-python.exp
+
+set testfile "py-macro"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+get_compiler_info ${binfile}
+if [test_compiler_info gcc*] {
+ lappend options additional_flags=-g3
+} else {
+ untested ${testfile}.exp
+ return -1
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} $options] } {
+ untested ${testfile}.exp
+ return -1
+}
+
+# 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 }
+
+gdb_py_test_multiple "setup macro test objects" \
+ "python" "" \
+ "def find_objfile():" "" \
+ " for objfile in gdb.objfiles():" "" \
+ " if objfile.filename == \"$binfile\":" "" \
+ " print objfile.filename" "" \
+ " return objfile" "" \
+ "def here_macro(name):" "" \
+ " return gdb.decode_line(\"*\$pc\")\[1\]\[0\].macro_named(name)" "" \
+ "macros = list()" "" \
+ "end" ""
+
+gdb_test "python objfile = find_objfile()" "$binfile" "found objfile"
+gdb_test "python objfile.symtab.macros()" \
+ "Symbol Table is invalid.*" "symtab is invalid"
+
+if ![runto_main] {
+ untested ${testfile}.exp
+ return -1
+}
+
+gdb_py_test_silent_cmd "python m = objfile.symtab.macros()" "get all macros" 1
+
+gdb_py_test_silent_cmd "python include_guard = here_macro(\"DEF_MACROS\")" \
+ "get guard macro #1" \
+ 1
+
+gdb_test "python print include_guard.name() == \"DEF_MACROS\"" \
+ "True" \
+ "guard name"
+
+gdb_test "python print include_guard.is_function_like() == False" \
+ "True" \
+ "guard isnt function like"
+
+gdb_test "python print include_guard.argv() == None" \
+ "True" \
+ "guard has no args"
+
+gdb_test "python print 'foo' + include_guard.definition() + 'bar'" \
+ "foobar" \
+ "guard definition is empty"
+
+gdb_test "python print include_guard.include_trail()\[0\]\[0\]" \
+ "$srcfile.*" \
+ "guard trail has srcfile"
+
+#<gdb.Macro include_trail=[('./gdb.python/py-macro.c', 8), ('./gdb.python/py-macro.c', 43)] FOO="hello">
+gdb_test "python print include_guard" \
+"<gdb\.Macro DEF_MACROS include_trail=\\\[\\\('$srcdir/$subdir/$srcfile', \[0-9\]+\\\).*\\\]>" \
+"guard string rep"
+
+gdb_py_test_silent_cmd "python macros.append(include_guard)" \
+ "add to macros list" \
+ 0
+
+gdb_py_test_silent_cmd "python foo = here_macro(\"FOO\")" \
+ "get FOO macro #1" \
+ 1
+
+gdb_test "python print foo.name()" \
+ "FOO" \
+ "FOO macro #1 name"
+
+gdb_test "python print foo.is_function_like()" \
+ "False" \
+ "FOO macro #1 isnt function like"
+
+gdb_test "python print foo.argv()" \
+ "None" \
+ "FOO macro #1 has no args"
+
+gdb_test "python print foo.definition()" \
+ "\"hello\"" \
+ "FOO macro #1 definition is \"hello\""
+
+gdb_test "python print include_guard.include_trail()\[0\]\[0\]" \
+ "$srcfile.*" \
+ "FOO macro #1 has srcfile"
+
+gdb_test "python print foo" \
+"<gdb\.Macro FOO=\"hello\" include_trail=\\\[\\\('$srcdir/$subdir/$srcfile', \[0-9\]+\\\).*\\\]>" \
+"FOO macro #1 string rep"
+
+gdb_py_test_silent_cmd "python macros.append(foo)" \
+ "add to macros list" \
+ 0
+
+gdb_test "next" "" ""
+gdb_py_test_silent_cmd "python foo = here_macro(\"FOO\")" \
+ "get FOO macro #2" \
+ 1
+
+gdb_test "python print foo.name()" \
+ "FOO" \
+ "FOO macro #2 name"
+
+gdb_test "python print foo.is_function_like()" \
+ "False" \
+ "FOO macro #2 isnt function like"
+
+gdb_test "python print foo.argv()" \
+ "None" \
+ "FOO macro #2 has no args"
+
+gdb_test "python print foo.definition()" \
+ "\" \"" \
+ "FOO macro #2 definition is \" \""
+
+gdb_test "python print foo.include_trail()\[0\]\[0\]" \
+ "$srcfile.*" \
+ "FOO macro #2 has srcfile"
+
+gdb_test "python print foo" \
+"<gdb\.Macro FOO=\" \" include_trail=\\\[\\\('$srcdir/$subdir/$srcfile', \[0-9\]+\\\).*\\\]>" \
+"FOO macro #2 string rep"
+
+gdb_py_test_silent_cmd "python macros.append(foo)" \
+ "add to macros list" \
+ 0
+
+gdb_test "next" "" ""
+gdb_py_test_silent_cmd "python foo = here_macro(\"FOO\")" \
+ "get FOO macro #3" \
+ 1
+gdb_test "python print foo.name()" \
+ "FOO" \
+ "FOO macro #3 name"
+
+gdb_test "python print foo.is_function_like()" \
+ "True" \
+ "FOO macro #3 is function like"
+
+gdb_test "python print foo.argv()" \
+ "\\\['a', 'b'\\\]" \
+ "FOO macro #3 has args"
+
+gdb_test "python print 'foo' + foo.definition() + 'bar'" \
+ "foobar" \
+ "FOO macro #3 definition is empty"
+
+gdb_test "python print include_guard.include_trail()\[0\]\[0\]" \
+ "$srcfile.*" \
+ "FOO macro #3 has srcfile"
+
+gdb_test "python print foo" \
+"<gdb\.Macro FOO\\\(a, b\\\) include_trail=\\\[\\\('$srcdir/$subdir/$srcfile', \[0-9\]+\\\).*\\\]>" \
+"FOO macro #3 string rep"
+
+gdb_py_test_silent_cmd "python macros.append(foo)" \
+ "add to macros list" \
+ 0
+gdb_test "next" "" ""
+gdb_test "next" "" ""
+gdb_test "next" "" ""
+gdb_py_test_silent_cmd "python foo = here_macro(\"FOO\")" \
+ "get FOO macro #4" \
+ 1
+gdb_test "python print foo" \
+ "None" \
+ "there is no Foo macro #4"
+
+gdb_test "next" "" ""
+gdb_py_test_silent_cmd "python foo = here_macro(\"FOO\")" \
+ "get FOO macro #5" \
+ 1
+
+gdb_test "python print foo.name()" \
+ "" \
+ "FOO macro #5 name"
+
+gdb_test "python print foo.is_function_like()" \
+ "True" \
+ "FOO macro #5 is function like"
+
+gdb_test "python print foo.argv()" \
+ "\\\['a'\\\]" \
+ "FOO macro #5 has args"
+
+gdb_test "python print foo.definition()" \
+ "foo = a" \
+ "FOO macro #5 definition ok"
+
+gdb_test "python print include_guard.include_trail()\[0\]\[0\]" \
+ "$srcfile.*" \
+ "FOO macro #5 has srcfile"
+
+gdb_test "python print foo" \
+"<gdb\.Macro FOO\\\(a\\\)=foo = a include_trail=\\\[\\\('$srcdir/$subdir/$srcfile', \[0-9\]+\\\).*\\\]>" \
+"FOO macro #5 string rep"
+gdb_py_test_silent_cmd "python macros.append(foo)" \
+ "add to macros list" \
+ 0
+
+# this could find some ref count bugs if they were to happen for a singleton.
+gdb_py_test_multiple "run macros a couple of times" \
+ "python" "" \
+ "c = 0" "" \
+ "while c > 3:" "" \
+ " c = c + 1" "" \
+ " for macro in objfile.symtab.macros():" "" \
+ " macro.name()" "" \
+ " macro.is_function_like()" "" \
+ " macro.argv()" "" \
+ " macro.include_path()" "" \
+ " macro.definition()" "" \
+ " str(macro)" "" \
+ " hash(macro)" "" \
+ "end" ""
+
+gdb_py_test_multiple "find selected macros in the big list of macros" \
+ "python" "" \
+ "set1 = set(objfile.symtab.macros())" "" \
+ "set2 = set(macros)" "" \
+ "intersect = (set1 & set2)" "" \
+ "set3 = set(filter(lambda(x): x.name() == \"FOO\", objfile.symtab.macros()))" "" \
+ "intersect2 = (set3 & set2)" "" \
+ "print \"set2\", map(lambda(x): x.name(), set2)" "" \
+ "print \"set3\", map(lambda(x): x.name(), set3)" "" \
+ "print \"intersect\", map(lambda(x): x.name(), intersect)" "" \
+ "print \"intersect2\", map(lambda(x): x.name(), intersect2)" "" \
+ "print \"set2 - intersect\", map(lambda(x): x.name(), set2 - intersect)" "" \
+ "print \"intersect - set2\", map(lambda(x): x.name(), intersect - set2)" "" \
+ "print \"set2 - intersect2\", map(lambda(x): x.name(), set2 - intersect2)" "" \
+ "print \"intersect2 - set2\", map(lambda(x): x.name(), intersect2 - set2)" "" \
+ "end" ""
+
+gdb_test "python print len(set2)" "5" "macro set length 5"
+gdb_test "python print len(set1) > len(set2)" "True" "all macros is longer."
+gdb_test "python print set1 >= set2" "True" "macro set2 is a subset"
+gdb_test "python print len(intersect - set2), len(set2 - intersect)" \
+ "0 0" \
+ "macro set intersection equality"
+gdb_test "python print len(intersect2 - set2)" \
+ "0" \
+ "macro set intersection equality 2"
+gdb_test "python print len(set2 - intersect2), (set2 - intersect2).pop()" \
+ "1 <gdb.Macro DEF_MACROS.*>" \
+ "macro set intersection 3"