123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562 |
- /* Python interface to blocks.
- Copyright (C) 2008-2022 Free Software Foundation, Inc.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #include "defs.h"
- #include "block.h"
- #include "dictionary.h"
- #include "symtab.h"
- #include "python-internal.h"
- #include "objfiles.h"
- struct block_object {
- PyObject_HEAD
- /* The GDB block structure that represents a frame's code block. */
- const struct block *block;
- /* The backing object file. There is no direct relationship in GDB
- between a block and an object file. When a block is created also
- store a pointer to the object file for later use. */
- struct objfile *objfile;
- /* Keep track of all blocks with a doubly-linked list. Needed for
- block invalidation if the source object file has been freed. */
- block_object *prev;
- block_object *next;
- };
- struct block_syms_iterator_object {
- PyObject_HEAD
- /* The block. */
- const struct block *block;
- /* The iterator for that block. */
- struct block_iterator iter;
- /* Has the iterator been initialized flag. */
- int initialized_p;
- /* Pointer back to the original source block object. Needed to
- check if the block is still valid, and has not been invalidated
- when an object file has been freed. */
- block_object *source;
- };
- /* Require a valid block. All access to block_object->block should be
- gated by this call. */
- #define BLPY_REQUIRE_VALID(block_obj, block) \
- do { \
- block = block_object_to_block (block_obj); \
- if (block == NULL) \
- { \
- PyErr_SetString (PyExc_RuntimeError, \
- _("Block is invalid.")); \
- return NULL; \
- } \
- } while (0)
- /* Require a valid block. This macro is called during block iterator
- creation, and at each next call. */
- #define BLPY_ITER_REQUIRE_VALID(block_obj) \
- do { \
- if (block_obj->block == NULL) \
- { \
- PyErr_SetString (PyExc_RuntimeError, \
- _("Source block for iterator is invalid.")); \
- return NULL; \
- } \
- } while (0)
- extern PyTypeObject block_syms_iterator_object_type
- CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("block_syms_iterator_object");
- static const struct objfile_data *blpy_objfile_data_key;
- static PyObject *
- blpy_iter (PyObject *self)
- {
- block_syms_iterator_object *block_iter_obj;
- const struct block *block = NULL;
- BLPY_REQUIRE_VALID (self, block);
- block_iter_obj = PyObject_New (block_syms_iterator_object,
- &block_syms_iterator_object_type);
- if (block_iter_obj == NULL)
- return NULL;
- block_iter_obj->block = block;
- block_iter_obj->initialized_p = 0;
- Py_INCREF (self);
- block_iter_obj->source = (block_object *) self;
- return (PyObject *) block_iter_obj;
- }
- static PyObject *
- blpy_get_start (PyObject *self, void *closure)
- {
- const struct block *block = NULL;
- BLPY_REQUIRE_VALID (self, block);
- return gdb_py_object_from_ulongest (BLOCK_START (block)).release ();
- }
- static PyObject *
- blpy_get_end (PyObject *self, void *closure)
- {
- const struct block *block = NULL;
- BLPY_REQUIRE_VALID (self, block);
- return gdb_py_object_from_ulongest (BLOCK_END (block)).release ();
- }
- static PyObject *
- blpy_get_function (PyObject *self, void *closure)
- {
- struct symbol *sym;
- const struct block *block;
- BLPY_REQUIRE_VALID (self, block);
- sym = BLOCK_FUNCTION (block);
- if (sym)
- return symbol_to_symbol_object (sym);
- Py_RETURN_NONE;
- }
- static PyObject *
- blpy_get_superblock (PyObject *self, void *closure)
- {
- const struct block *block;
- const struct block *super_block;
- block_object *self_obj = (block_object *) self;
- BLPY_REQUIRE_VALID (self, block);
- super_block = BLOCK_SUPERBLOCK (block);
- if (super_block)
- return block_to_block_object (super_block, self_obj->objfile);
- Py_RETURN_NONE;
- }
- /* Return the global block associated to this block. */
- static PyObject *
- blpy_get_global_block (PyObject *self, void *closure)
- {
- const struct block *block;
- const struct block *global_block;
- block_object *self_obj = (block_object *) self;
- BLPY_REQUIRE_VALID (self, block);
- global_block = block_global_block (block);
- return block_to_block_object (global_block,
- self_obj->objfile);
- }
- /* Return the static block associated to this block. Return None
- if we cannot get the static block (this is the global block). */
- static PyObject *
- blpy_get_static_block (PyObject *self, void *closure)
- {
- const struct block *block;
- const struct block *static_block;
- block_object *self_obj = (block_object *) self;
- BLPY_REQUIRE_VALID (self, block);
- if (BLOCK_SUPERBLOCK (block) == NULL)
- Py_RETURN_NONE;
- static_block = block_static_block (block);
- return block_to_block_object (static_block, self_obj->objfile);
- }
- /* Implementation of gdb.Block.is_global (self) -> Boolean.
- Returns True if this block object is a global block. */
- static PyObject *
- blpy_is_global (PyObject *self, void *closure)
- {
- const struct block *block;
- BLPY_REQUIRE_VALID (self, block);
- if (BLOCK_SUPERBLOCK (block))
- Py_RETURN_FALSE;
- Py_RETURN_TRUE;
- }
- /* Implementation of gdb.Block.is_static (self) -> Boolean.
- Returns True if this block object is a static block. */
- static PyObject *
- blpy_is_static (PyObject *self, void *closure)
- {
- const struct block *block;
- BLPY_REQUIRE_VALID (self, block);
- if (BLOCK_SUPERBLOCK (block) != NULL
- && BLOCK_SUPERBLOCK (BLOCK_SUPERBLOCK (block)) == NULL)
- Py_RETURN_TRUE;
- Py_RETURN_FALSE;
- }
- /* Given a string, returns the gdb.Symbol representing that symbol in this
- block. If such a symbol does not exist, returns NULL with a Python
- exception. */
- static PyObject *
- blpy_getitem (PyObject *self, PyObject *key)
- {
- const struct block *block;
- BLPY_REQUIRE_VALID (self, block);
- gdb::unique_xmalloc_ptr<char> name = python_string_to_host_string (key);
- if (name == nullptr)
- return nullptr;
- lookup_name_info lookup_name (name.get(), symbol_name_match_type::FULL);
- /* We use ALL_BLOCK_SYMBOLS_WITH_NAME instead of block_lookup_symbol so
- that we can look up symbols irrespective of the domain, matching the
- iterator. It would be confusing if the iterator returns symbols you
- can't find via getitem. */
- struct block_iterator iter;
- struct symbol *sym = nullptr;
- ALL_BLOCK_SYMBOLS_WITH_NAME (block, lookup_name, iter, sym)
- {
- /* Just stop at the first match */
- break;
- }
- if (sym == nullptr)
- {
- PyErr_SetObject (PyExc_KeyError, key);
- return nullptr;
- }
- return symbol_to_symbol_object (sym);
- }
- static void
- blpy_dealloc (PyObject *obj)
- {
- block_object *block = (block_object *) obj;
- if (block->prev)
- block->prev->next = block->next;
- else if (block->objfile)
- {
- set_objfile_data (block->objfile, blpy_objfile_data_key,
- block->next);
- }
- if (block->next)
- block->next->prev = block->prev;
- block->block = NULL;
- Py_TYPE (obj)->tp_free (obj);
- }
- /* Given a block, and a block_object that has previously been
- allocated and initialized, populate the block_object with the
- struct block data. Also, register the block_object life-cycle
- with the life-cycle of the object file associated with this
- block, if needed. */
- static void
- set_block (block_object *obj, const struct block *block,
- struct objfile *objfile)
- {
- obj->block = block;
- obj->prev = NULL;
- if (objfile)
- {
- obj->objfile = objfile;
- obj->next = ((block_object *)
- objfile_data (objfile, blpy_objfile_data_key));
- if (obj->next)
- obj->next->prev = obj;
- set_objfile_data (objfile, blpy_objfile_data_key, obj);
- }
- else
- obj->next = NULL;
- }
- /* Create a new block object (gdb.Block) that encapsulates the struct
- block object from GDB. */
- PyObject *
- block_to_block_object (const struct block *block, struct objfile *objfile)
- {
- block_object *block_obj;
- block_obj = PyObject_New (block_object, &block_object_type);
- if (block_obj)
- set_block (block_obj, block, objfile);
- return (PyObject *) block_obj;
- }
- /* Return struct block reference that is wrapped by this object. */
- const struct block *
- block_object_to_block (PyObject *obj)
- {
- if (! PyObject_TypeCheck (obj, &block_object_type))
- return NULL;
- return ((block_object *) obj)->block;
- }
- /* Return a reference to the block iterator. */
- static PyObject *
- blpy_block_syms_iter (PyObject *self)
- {
- block_syms_iterator_object *iter_obj = (block_syms_iterator_object *) self;
- BLPY_ITER_REQUIRE_VALID (iter_obj->source);
- Py_INCREF (self);
- return self;
- }
- /* Return the next symbol in the iteration through the block's
- dictionary. */
- static PyObject *
- blpy_block_syms_iternext (PyObject *self)
- {
- block_syms_iterator_object *iter_obj = (block_syms_iterator_object *) self;
- struct symbol *sym;
- BLPY_ITER_REQUIRE_VALID (iter_obj->source);
- if (!iter_obj->initialized_p)
- {
- sym = block_iterator_first (iter_obj->block, &(iter_obj->iter));
- iter_obj->initialized_p = 1;
- }
- else
- sym = block_iterator_next (&(iter_obj->iter));
- if (sym == NULL)
- {
- PyErr_SetString (PyExc_StopIteration, _("Symbol is null."));
- return NULL;
- }
- return symbol_to_symbol_object (sym);
- }
- static void
- blpy_block_syms_dealloc (PyObject *obj)
- {
- block_syms_iterator_object *iter_obj = (block_syms_iterator_object *) obj;
- Py_XDECREF (iter_obj->source);
- Py_TYPE (obj)->tp_free (obj);
- }
- /* Implementation of gdb.Block.is_valid (self) -> Boolean.
- Returns True if this block object still exists in GDB. */
- static PyObject *
- blpy_is_valid (PyObject *self, PyObject *args)
- {
- const struct block *block;
- block = block_object_to_block (self);
- if (block == NULL)
- Py_RETURN_FALSE;
- Py_RETURN_TRUE;
- }
- /* Implementation of gdb.BlockIterator.is_valid (self) -> Boolean.
- Returns True if this block iterator object still exists in GDB */
- static PyObject *
- blpy_iter_is_valid (PyObject *self, PyObject *args)
- {
- block_syms_iterator_object *iter_obj =
- (block_syms_iterator_object *) self;
- if (iter_obj->source->block == NULL)
- Py_RETURN_FALSE;
- Py_RETURN_TRUE;
- }
- /* This function is called when an objfile is about to be freed.
- Invalidate the block as further actions on the block would result
- in bad data. All access to obj->symbol should be gated by
- BLPY_REQUIRE_VALID which will raise an exception on invalid
- blocks. */
- static void
- del_objfile_blocks (struct objfile *objfile, void *datum)
- {
- block_object *obj = (block_object *) datum;
- while (obj)
- {
- block_object *next = obj->next;
- obj->block = NULL;
- obj->objfile = NULL;
- obj->next = NULL;
- obj->prev = NULL;
- obj = next;
- }
- }
- void _initialize_py_block ();
- void
- _initialize_py_block ()
- {
- /* Register an objfile "free" callback so we can properly
- invalidate blocks when an object file is about to be
- deleted. */
- blpy_objfile_data_key
- = register_objfile_data_with_cleanup (NULL, del_objfile_blocks);
- }
- int
- gdbpy_initialize_blocks (void)
- {
- block_object_type.tp_new = PyType_GenericNew;
- if (PyType_Ready (&block_object_type) < 0)
- return -1;
- block_syms_iterator_object_type.tp_new = PyType_GenericNew;
- if (PyType_Ready (&block_syms_iterator_object_type) < 0)
- return -1;
- if (gdb_pymodule_addobject (gdb_module, "Block",
- (PyObject *) &block_object_type) < 0)
- return -1;
- return gdb_pymodule_addobject (gdb_module, "BlockIterator",
- (PyObject *) &block_syms_iterator_object_type);
- }
- static PyMethodDef block_object_methods[] = {
- { "is_valid", blpy_is_valid, METH_NOARGS,
- "is_valid () -> Boolean.\n\
- Return true if this block is valid, false if not." },
- {NULL} /* Sentinel */
- };
- static gdb_PyGetSetDef block_object_getset[] = {
- { "start", blpy_get_start, NULL, "Start address of the block.", NULL },
- { "end", blpy_get_end, NULL, "End address of the block.", NULL },
- { "function", blpy_get_function, NULL,
- "Symbol that names the block, or None.", NULL },
- { "superblock", blpy_get_superblock, NULL,
- "Block containing the block, or None.", NULL },
- { "global_block", blpy_get_global_block, NULL,
- "Block containing the global block.", NULL },
- { "static_block", blpy_get_static_block, NULL,
- "Block containing the static block.", NULL },
- { "is_static", blpy_is_static, NULL,
- "Whether this block is a static block.", NULL },
- { "is_global", blpy_is_global, NULL,
- "Whether this block is a global block.", NULL },
- { NULL } /* Sentinel */
- };
- static PyMappingMethods block_object_as_mapping = {
- NULL,
- blpy_getitem,
- NULL
- };
- PyTypeObject block_object_type = {
- PyVarObject_HEAD_INIT (NULL, 0)
- "gdb.Block", /*tp_name*/
- sizeof (block_object), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- blpy_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- &block_object_as_mapping, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT, /*tp_flags*/
- "GDB block object", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- blpy_iter, /* tp_iter */
- 0, /* tp_iternext */
- block_object_methods, /* tp_methods */
- 0, /* tp_members */
- block_object_getset /* tp_getset */
- };
- static PyMethodDef block_iterator_object_methods[] = {
- { "is_valid", blpy_iter_is_valid, METH_NOARGS,
- "is_valid () -> Boolean.\n\
- Return true if this block iterator is valid, false if not." },
- {NULL} /* Sentinel */
- };
- PyTypeObject block_syms_iterator_object_type = {
- PyVarObject_HEAD_INIT (NULL, 0)
- "gdb.BlockIterator", /*tp_name*/
- sizeof (block_syms_iterator_object), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- blpy_block_syms_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT, /*tp_flags*/
- "GDB block syms iterator object", /*tp_doc */
- 0, /*tp_traverse */
- 0, /*tp_clear */
- 0, /*tp_richcompare */
- 0, /*tp_weaklistoffset */
- blpy_block_syms_iter, /*tp_iter */
- blpy_block_syms_iternext, /*tp_iternext */
- block_iterator_object_methods /*tp_methods */
- };
|