binutils-gdb/gdb/python/py-symtab.c
Pedro Alves 0d1f4ceb39 -Wwrite-strings: Wrap PyGetSetDef for construction with string literals
Unfortunately, PyGetSetDef's 'name' and 'doc' members are 'char *'
instead of 'const char *', meaning that in order to list-initialize
PyGetSetDef arrays using string literals requires writing explicit
'char *' casts.  For example:

    static PyGetSetDef value_object_getset[] = {
   -  { "address", valpy_get_address, NULL, "The address of the value.",
   +  { (char *) "address", valpy_get_address, NULL,
   +    (char *) "The address of the value.",
	NULL },
   -  { "is_optimized_out", valpy_get_is_optimized_out, NULL,
   -    "Boolean telling whether the value is optimized "
   +  { (char *) "is_optimized_out", valpy_get_is_optimized_out, NULL,
   +    (char *) "Boolean telling whether the value is optimized "
	"out (i.e., not available).",
	NULL },
   -  { "type", valpy_get_type, NULL, "Type of the value.", NULL },
   -  { "dynamic_type", valpy_get_dynamic_type, NULL,
   -    "Dynamic type of the value.", NULL },
   -  { "is_lazy", valpy_get_is_lazy, NULL,
   -    "Boolean telling whether the value is lazy (not fetched yet\n\
   +  { (char *) "type", valpy_get_type, NULL,
   +    (char *) "Type of the value.", NULL },
   +  { (char *) "dynamic_type", valpy_get_dynamic_type, NULL,
   +    (char *) "Dynamic type of the value.", NULL },
   +  { (char *) "is_lazy", valpy_get_is_lazy, NULL,
   +    (char *) "Boolean telling whether the value is lazy (not fetched yet\n\
    from the inferior).  A lazy value is fetched when needed, or when\n\
    the \"fetch_lazy()\" method is called.", NULL },
      {NULL}  /* Sentinel */

We have ~20 such arrays, and I first wrote a patch that fixed all of
them like that...  It's not pretty...

One way to make these a bit less ugly would be add a new macro that
hides the casts, like:

  #define GDBPY_GSDEF(NAME, GET, SET, DOC, CLOSURE) \
     { (char *) NAME, GET, SET, (char *) DOC, CLOSURE }

and then use it like:

    static PyGetSetDef value_object_getset[] = {
       GDBPY_GSDEF ("address", valpy_get_address, NULL,
       		    "The address of the value.", NULL),
       GDBPY_GSDEF ("is_optimized_out", valpy_get_is_optimized_out, NULL,
       		    "Boolean telling whether the value is optimized ", NULL),
      {NULL}  /* Sentinel */
    };

But since we have C++11, which gives us constexpr and list
initialization, I thought of a way that requires no changes where the
arrays are initialized:

We add a new type that extends PyGetSetDef (called gdb_PyGetSetDef),
and add constexpr constructors that accept const 'name' and 'doc', and
then list/aggregate initialization simply "calls" these matching
constructors instead.

I put "calls" in quotes, because given "constexpr", it's all done at
compile time, and there's no overhead either in binary size or at run
time.  In fact, we get identical binaries, before/after this change.

Unlike the fixes that fix some old Python API to match the API of more
recent Python, this switches to using explicit "gdb_PyGetSetDef"
everywhere, just to be clear that we are using our own version of it.

gdb/ChangeLog:
2017-04-05  Pedro Alves  <palves@redhat.com>

	* python/python-internal.h (gdb_PyGetSetDef): New type.
	* python/py-block.c (block_object_getset)
	(breakpoint_object_getset): Now a gdb_PyGetSetDef array.
	* python/py-event.c (event_object_getset)
	(finish_breakpoint_object_getset): Likewise.
	* python/py-inferior.c (inferior_object_getset): Likewise.
	* python/py-infthread.c (thread_object_getset): Likewise.
	* python/py-lazy-string.c (lazy_string_object_getset): Likewise.
	* python/py-linetable.c (linetable_entry_object_getset): Likewise.
	* python/py-objfile.c (objfile_getset): Likewise.
	* python/py-progspace.c (pspace_getset): Likewise.
	* python/py-record-btrace.c (btpy_insn_getset, btpy_call_getset):
	Likewise.
	* python/py-record.c (recpy_record_getset): Likewise.
	* python/py-symbol.c (symbol_object_getset): Likewise.
	* python/py-symtab.c (symtab_object_getset, sal_object_getset):
	Likewise.
	* python/py-type.c (type_object_getset, field_object_getset):
	Likewise.
	* python/py-value.c (value_object_getset): Likewise.
2017-04-05 19:21:36 +01:00

658 lines
18 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Python interface to symbol tables.
Copyright (C) 2008-2017 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"
#include "block.h"
#include "py-ref.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;
extern PyTypeObject symtab_object_type
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("symtab_object");
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;
extern PyTypeObject sal_object_type
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("sal_object");
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_to_filename_for_display (symtab));
return result;
}
static PyObject *
stpy_get_filename (PyObject *self, void *closure)
{
PyObject *str_obj;
struct symtab *symtab = NULL;
const char *filename;
STPY_REQUIRE_VALID (self, symtab);
filename = symtab_to_filename_for_display (symtab);
str_obj = host_string_to_python_string (filename);
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 (symtab));
Py_XINCREF (result);
return result;
}
/* Getter function for symtab.producer. */
static PyObject *
stpy_get_producer (PyObject *self, void *closure)
{
struct symtab *symtab = NULL;
struct compunit_symtab *cust;
STPY_REQUIRE_VALID (self, symtab);
cust = SYMTAB_COMPUNIT (symtab);
if (COMPUNIT_PRODUCER (cust) != NULL)
{
const char *producer = COMPUNIT_PRODUCER (cust);
return host_string_to_python_string (producer);
}
Py_RETURN_NONE;
}
static PyObject *
stpy_fullname (PyObject *self, PyObject *args)
{
const char *fullname;
struct symtab *symtab = NULL;
STPY_REQUIRE_VALID (self, symtab);
fullname = symtab_to_fullname (symtab);
return host_string_to_python_string (fullname);
}
/* Implementation of gdb.Symtab.is_valid (self) -> Boolean.
Returns True if this Symbol table still exists in GDB. */
static PyObject *
stpy_is_valid (PyObject *self, PyObject *args)
{
struct symtab *symtab = NULL;
symtab = symtab_object_to_symtab (self);
if (symtab == NULL)
Py_RETURN_FALSE;
Py_RETURN_TRUE;
}
/* Return the GLOBAL_BLOCK of the underlying symtab. */
static PyObject *
stpy_global_block (PyObject *self, PyObject *args)
{
struct symtab *symtab = NULL;
struct block *block = NULL;
const struct blockvector *blockvector;
STPY_REQUIRE_VALID (self, symtab);
blockvector = SYMTAB_BLOCKVECTOR (symtab);
block = BLOCKVECTOR_BLOCK (blockvector, GLOBAL_BLOCK);
return block_to_block_object (block, SYMTAB_OBJFILE (symtab));
}
/* Return the STATIC_BLOCK of the underlying symtab. */
static PyObject *
stpy_static_block (PyObject *self, PyObject *args)
{
struct symtab *symtab = NULL;
struct block *block = NULL;
const struct blockvector *blockvector;
STPY_REQUIRE_VALID (self, symtab);
blockvector = SYMTAB_BLOCKVECTOR (symtab);
block = BLOCKVECTOR_BLOCK (blockvector, STATIC_BLOCK);
return block_to_block_object (block, SYMTAB_OBJFILE (symtab));
}
/* Implementation of gdb.Symtab.linetable (self) -> gdb.LineTable.
Returns a gdb.LineTable object corresponding to this symbol
table. */
static PyObject *
stpy_get_linetable (PyObject *self, PyObject *args)
{
struct symtab *symtab = NULL;
STPY_REQUIRE_VALID (self, symtab);
return symtab_to_linetable_object (self);
}
static PyObject *
salpy_str (PyObject *self)
{
char *s;
const char *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>" : symtab_to_filename_for_display (sal_obj->symtab->symtab);
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_OBJFILE (symtab->symtab),
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 gdb_py_long_from_ulongest (sal->pc);
}
/* Implementation of the get method for the 'last' attribute of
gdb.Symtab_and_line. */
static PyObject *
salpy_get_last (PyObject *self, void *closure)
{
struct symtab_and_line *sal = NULL;
SALPY_REQUIRE_VALID (self, sal);
if (sal->end > 0)
return gdb_py_long_from_ulongest (sal->end - 1);
else
Py_RETURN_NONE;
}
static PyObject *
salpy_get_line (PyObject *self, void *closure)
{
struct symtab_and_line *sal = NULL;
SALPY_REQUIRE_VALID (self, sal);
return PyInt_FromLong (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;
}
/* Implementation of gdb.Symtab_and_line.is_valid (self) -> Boolean.
Returns True if this Symbol table and line object still exists GDB. */
static PyObject *
salpy_is_valid (PyObject *self, PyObject *args)
{
struct symtab_and_line *sal;
sal = sal_object_to_symtab_and_line (self);
if (sal == NULL)
Py_RETURN_FALSE;
Py_RETURN_TRUE;
}
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 (SYMTAB_OBJFILE (self_sal->symtab->symtab),
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);
Py_TYPE (self)->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
object file associated with this sal, if needed. If a failure
occurs during the sal population, this function will return -1. */
static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
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 -1;
}
else
{
symtab_obj = (symtab_object *) Py_None;
Py_INCREF (Py_None);
}
sal_obj->sal = ((struct symtab_and_line *)
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
= ((struct salpy_sal_object *)
objfile_data (SYMTAB_OBJFILE (sal_obj->symtab->symtab),
salpy_objfile_data_key));
if (sal_obj->next)
sal_obj->next->prev = sal_obj;
set_objfile_data (SYMTAB_OBJFILE (sal_obj->symtab->symtab),
salpy_objfile_data_key, sal_obj);
}
else
sal_obj->next = NULL;
return 0;
}
/* 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 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
= ((struct stpy_symtab_object *)
objfile_data (SYMTAB_OBJFILE (symtab), stpy_objfile_data_key));
if (obj->next)
obj->next->prev = obj;
set_objfile_data (SYMTAB_OBJFILE (symtab), 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)
{
gdbpy_ref<sal_object> sal_obj (PyObject_New (sal_object, &sal_object_type));
if (sal_obj != NULL)
{
if (set_sal (sal_obj.get (), sal) < 0)
return NULL;
}
return (PyObject *) sal_obj.release ();
}
/* 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 = (symtab_object *) 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 = (sal_object *) datum;
while (obj)
{
sal_object *next = obj->next;
Py_DECREF (obj->symtab);
obj->symtab = (symtab_object *) Py_None;
Py_INCREF (Py_None);
obj->next = NULL;
obj->prev = NULL;
xfree (obj->sal);
obj->sal = NULL;
obj = next;
}
}
int
gdbpy_initialize_symtabs (void)
{
symtab_object_type.tp_new = PyType_GenericNew;
if (PyType_Ready (&symtab_object_type) < 0)
return -1;
sal_object_type.tp_new = PyType_GenericNew;
if (PyType_Ready (&sal_object_type) < 0)
return -1;
/* 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);
if (gdb_pymodule_addobject (gdb_module, "Symtab",
(PyObject *) &symtab_object_type) < 0)
return -1;
return gdb_pymodule_addobject (gdb_module, "Symtab_and_line",
(PyObject *) &sal_object_type);
}
static gdb_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 },
{ "producer", stpy_get_producer, NULL,
"The name/version of the program that compiled this symtab.", NULL },
{NULL} /* Sentinel */
};
static PyMethodDef symtab_object_methods[] = {
{ "is_valid", stpy_is_valid, METH_NOARGS,
"is_valid () -> Boolean.\n\
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." },
{ "global_block", stpy_global_block, METH_NOARGS,
"global_block () -> gdb.Block.\n\
Return the global block of the symbol table." },
{ "static_block", stpy_static_block, METH_NOARGS,
"static_block () -> gdb.Block.\n\
Return the static block of the symbol table." },
{ "linetable", stpy_get_linetable, METH_NOARGS,
"linetable () -> gdb.LineTable.\n\
Return the LineTable associated with this symbol table" },
{NULL} /* Sentinel */
};
PyTypeObject symtab_object_type = {
PyVarObject_HEAD_INIT (NULL, 0)
"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 gdb_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 },
{ "last", salpy_get_last, NULL,
"Return the symtab_and_line's last address.", NULL },
{ "line", salpy_get_line, NULL,
"Return the symtab_and_line's line.", NULL },
{NULL} /* Sentinel */
};
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." },
{NULL} /* Sentinel */
};
PyTypeObject sal_object_type = {
PyVarObject_HEAD_INIT (NULL, 0)
"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 */
sal_object_methods, /*tp_methods */
0, /*tp_members */
sal_object_getset /*tp_getset */
};