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 . */ + +#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, ¯o_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 ("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, ¯o_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 (¯o_object_type) < 0) + return; + + Py_INCREF (¯o_object_type); + PyModule_AddObject (gdb_module, "Macro", + (PyObject *) ¯o_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", ¯o_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 . + +# 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_test "python print include_guard" \ +"" \ +"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" \ +"" \ +"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" \ +"" \ +"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" \ +"" \ +"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" \ +"" \ +"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 " \ + "macro set intersection 3"