| /* Python interface to symbol tables. |
| |
| Copyright (C) 2008-2021 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" |
| |
| struct 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. */ |
| symtab_object *prev; |
| symtab_object *next; |
| }; |
| |
| 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) |
| |
| struct sal_object { |
| PyObject_HEAD |
| /* The GDB Symbol table structure. */ |
| PyObject *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. */ |
| sal_object *prev; |
| sal_object *next; |
| }; |
| |
| 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).release (); |
| return str_obj; |
| } |
| |
| static PyObject * |
| stpy_get_objfile (PyObject *self, void *closure) |
| { |
| struct symtab *symtab = NULL; |
| |
| STPY_REQUIRE_VALID (self, symtab); |
| |
| return objfile_to_objfile_object (SYMTAB_OBJFILE (symtab)).release (); |
| } |
| |
| /* 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).release (); |
| } |
| |
| 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).release (); |
| } |
| |
| /* 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; |
| const 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; |
| const 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) |
| { |
| const char *filename; |
| sal_object *sal_obj; |
| struct symtab_and_line *sal = NULL; |
| |
| SALPY_REQUIRE_VALID (self, sal); |
| |
| sal_obj = (sal_object *) self; |
| if (sal_obj->symtab == Py_None) |
| filename = "<unknown>"; |
| else |
| { |
| symtab *symtab = symtab_object_to_symtab (sal_obj->symtab); |
| filename = symtab_to_filename_for_display (symtab); |
| } |
| |
| return PyString_FromFormat ("symbol and line for %s, line %d", filename, |
| sal->line); |
| } |
| |
| 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; |
| Py_TYPE (obj)->tp_free (obj); |
| } |
| |
| |
| static PyObject * |
| salpy_get_pc (PyObject *self, void *closure) |
| { |
| struct symtab_and_line *sal = NULL; |
| |
| SALPY_REQUIRE_VALID (self, sal); |
| |
| return gdb_py_object_from_ulongest (sal->pc).release (); |
| } |
| |
| /* 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_object_from_ulongest (sal->end - 1).release (); |
| 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 gdb_py_object_from_longest (sal->line).release (); |
| } |
| |
| 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 != Py_None) |
| set_objfile_data |
| (SYMTAB_OBJFILE (symtab_object_to_symtab (self_sal->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) |
| { |
| PyObject *symtab_obj; |
| |
| if (sal.symtab) |
| { |
| symtab_obj = 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 = 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 != Py_None) |
| { |
| symtab *symtab = symtab_object_to_symtab (sal_obj->symtab); |
| |
| sal_obj->next |
| = ((sal_object *) objfile_data (SYMTAB_OBJFILE (symtab), |
| salpy_objfile_data_key)); |
| if (sal_obj->next) |
| sal_obj->next->prev = sal_obj; |
| |
| set_objfile_data (SYMTAB_OBJFILE (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 |
| = ((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; |
| |
| gdbpy_ref<> tmp (obj->symtab); |
| obj->symtab = Py_None; |
| Py_INCREF (Py_None); |
| |
| obj->next = NULL; |
| obj->prev = NULL; |
| xfree (obj->sal); |
| obj->sal = NULL; |
| |
| obj = next; |
| } |
| } |
| |
| void _initialize_py_symtab (); |
| void |
| _initialize_py_symtab () |
| { |
| /* 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); |
| } |
| |
| 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; |
| |
| 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 */ |
| }; |