Implement tp_richcompare for gdb.Block
[binutils-gdb.git] / gdb / python / py-block.c
blob3de6200e7c26096e1a979a1e589b47a6560d1647
1 /* Python interface to blocks.
3 Copyright (C) 2008-2024 Free Software Foundation, Inc.
5 This file is part of GDB.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 #include "block.h"
21 #include "dictionary.h"
22 #include "symtab.h"
23 #include "python-internal.h"
24 #include "objfiles.h"
26 struct block_object {
27 PyObject_HEAD
28 /* The GDB block structure that represents a frame's code block. */
29 const struct block *block;
30 /* The backing object file. There is no direct relationship in GDB
31 between a block and an object file. When a block is created also
32 store a pointer to the object file for later use. */
33 struct objfile *objfile;
34 /* Keep track of all blocks with a doubly-linked list. Needed for
35 block invalidation if the source object file has been freed. */
36 block_object *prev;
37 block_object *next;
40 struct block_syms_iterator_object {
41 PyObject_HEAD
42 /* The block. */
43 const struct block *block;
44 /* The iterator for that block. */
45 struct block_iterator iter;
46 /* Has the iterator been initialized flag. */
47 int initialized_p;
48 /* Pointer back to the original source block object. Needed to
49 check if the block is still valid, and has not been invalidated
50 when an object file has been freed. */
51 block_object *source;
54 /* Require a valid block. All access to block_object->block should be
55 gated by this call. */
56 #define BLPY_REQUIRE_VALID(block_obj, block) \
57 do { \
58 block = block_object_to_block (block_obj); \
59 if (block == NULL) \
60 { \
61 PyErr_SetString (PyExc_RuntimeError, \
62 _("Block is invalid.")); \
63 return NULL; \
64 } \
65 } while (0)
67 /* Require a valid block. This macro is called during block iterator
68 creation, and at each next call. */
69 #define BLPY_ITER_REQUIRE_VALID(block_obj) \
70 do { \
71 if (block_obj->block == NULL) \
72 { \
73 PyErr_SetString (PyExc_RuntimeError, \
74 _("Source block for iterator is invalid.")); \
75 return NULL; \
76 } \
77 } while (0)
79 /* This is called when an objfile is about to be freed.
80 Invalidate the block as further actions on the block would result
81 in bad data. All access to obj->symbol should be gated by
82 BLPY_REQUIRE_VALID which will raise an exception on invalid
83 blocks. */
84 struct blpy_deleter
86 void operator() (block_object *obj)
88 while (obj)
90 block_object *next = obj->next;
92 obj->block = NULL;
93 obj->objfile = NULL;
94 obj->next = NULL;
95 obj->prev = NULL;
97 obj = next;
102 extern PyTypeObject block_syms_iterator_object_type
103 CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("block_syms_iterator_object");
104 static const registry<objfile>::key<block_object, blpy_deleter>
105 blpy_objfile_data_key;
107 static PyObject *
108 blpy_iter (PyObject *self)
110 block_syms_iterator_object *block_iter_obj;
111 const struct block *block = NULL;
113 BLPY_REQUIRE_VALID (self, block);
115 block_iter_obj = PyObject_New (block_syms_iterator_object,
116 &block_syms_iterator_object_type);
117 if (block_iter_obj == NULL)
118 return NULL;
120 block_iter_obj->block = block;
121 block_iter_obj->initialized_p = 0;
122 Py_INCREF (self);
123 block_iter_obj->source = (block_object *) self;
125 return (PyObject *) block_iter_obj;
128 static PyObject *
129 blpy_get_start (PyObject *self, void *closure)
131 const struct block *block = NULL;
133 BLPY_REQUIRE_VALID (self, block);
135 return gdb_py_object_from_ulongest (block->start ()).release ();
138 static PyObject *
139 blpy_get_end (PyObject *self, void *closure)
141 const struct block *block = NULL;
143 BLPY_REQUIRE_VALID (self, block);
145 return gdb_py_object_from_ulongest (block->end ()).release ();
148 static PyObject *
149 blpy_get_function (PyObject *self, void *closure)
151 struct symbol *sym;
152 const struct block *block;
154 BLPY_REQUIRE_VALID (self, block);
156 sym = block->function ();
157 if (sym)
158 return symbol_to_symbol_object (sym);
160 Py_RETURN_NONE;
163 static PyObject *
164 blpy_get_superblock (PyObject *self, void *closure)
166 const struct block *block;
167 const struct block *super_block;
168 block_object *self_obj = (block_object *) self;
170 BLPY_REQUIRE_VALID (self, block);
172 super_block = block->superblock ();
173 if (super_block)
174 return block_to_block_object (super_block, self_obj->objfile);
176 Py_RETURN_NONE;
179 /* Return the global block associated to this block. */
181 static PyObject *
182 blpy_get_global_block (PyObject *self, void *closure)
184 const struct block *block;
185 const struct block *global_block;
186 block_object *self_obj = (block_object *) self;
188 BLPY_REQUIRE_VALID (self, block);
190 global_block = block->global_block ();
192 return block_to_block_object (global_block,
193 self_obj->objfile);
197 /* Return the static block associated to this block. Return None
198 if we cannot get the static block (this is the global block). */
200 static PyObject *
201 blpy_get_static_block (PyObject *self, void *closure)
203 const struct block *block;
204 const struct block *static_block;
205 block_object *self_obj = (block_object *) self;
207 BLPY_REQUIRE_VALID (self, block);
209 if (block->superblock () == NULL)
210 Py_RETURN_NONE;
212 static_block = block->static_block ();
214 return block_to_block_object (static_block, self_obj->objfile);
217 /* Implementation of gdb.Block.is_global (self) -> Boolean.
218 Returns True if this block object is a global block. */
220 static PyObject *
221 blpy_is_global (PyObject *self, void *closure)
223 const struct block *block;
225 BLPY_REQUIRE_VALID (self, block);
227 if (block->superblock ())
228 Py_RETURN_FALSE;
230 Py_RETURN_TRUE;
233 /* Implementation of gdb.Block.is_static (self) -> Boolean.
234 Returns True if this block object is a static block. */
236 static PyObject *
237 blpy_is_static (PyObject *self, void *closure)
239 const struct block *block;
241 BLPY_REQUIRE_VALID (self, block);
243 if (block->superblock () != NULL
244 && block->superblock ()->superblock () == NULL)
245 Py_RETURN_TRUE;
247 Py_RETURN_FALSE;
250 /* Given a string, returns the gdb.Symbol representing that symbol in this
251 block. If such a symbol does not exist, returns NULL with a Python
252 exception. */
254 static PyObject *
255 blpy_getitem (PyObject *self, PyObject *key)
257 const struct block *block;
259 BLPY_REQUIRE_VALID (self, block);
261 gdb::unique_xmalloc_ptr<char> name = python_string_to_host_string (key);
262 if (name == nullptr)
263 return nullptr;
265 lookup_name_info lookup_name (name.get(), symbol_name_match_type::FULL);
267 /* We use an iterator instead of block_lookup_symbol so that we can
268 look up symbols irrespective of the domain, matching the
269 iterator. It would be confusing if the iterator returns symbols
270 you can't find via getitem. */
271 for (struct symbol *sym : block_iterator_range (block, &lookup_name))
273 /* Just stop at the first match */
274 return symbol_to_symbol_object (sym);
277 PyErr_SetObject (PyExc_KeyError, key);
278 return nullptr;
281 static void
282 blpy_dealloc (PyObject *obj)
284 block_object *block = (block_object *) obj;
286 if (block->prev)
287 block->prev->next = block->next;
288 else if (block->objfile)
289 blpy_objfile_data_key.set (block->objfile, block->next);
290 if (block->next)
291 block->next->prev = block->prev;
292 block->block = NULL;
293 Py_TYPE (obj)->tp_free (obj);
296 /* Given a block, and a block_object that has previously been
297 allocated and initialized, populate the block_object with the
298 struct block data. Also, register the block_object life-cycle
299 with the life-cycle of the object file associated with this
300 block, if needed. */
301 static void
302 set_block (block_object *obj, const struct block *block,
303 struct objfile *objfile)
305 obj->block = block;
306 obj->prev = NULL;
307 if (objfile)
309 obj->objfile = objfile;
310 obj->next = blpy_objfile_data_key.get (objfile);
311 if (obj->next)
312 obj->next->prev = obj;
313 blpy_objfile_data_key.set (objfile, obj);
315 else
316 obj->next = NULL;
319 /* Create a new block object (gdb.Block) that encapsulates the struct
320 block object from GDB. */
321 PyObject *
322 block_to_block_object (const struct block *block, struct objfile *objfile)
324 block_object *block_obj;
326 block_obj = PyObject_New (block_object, &block_object_type);
327 if (block_obj)
328 set_block (block_obj, block, objfile);
330 return (PyObject *) block_obj;
333 /* Return struct block reference that is wrapped by this object. */
334 const struct block *
335 block_object_to_block (PyObject *obj)
337 if (! PyObject_TypeCheck (obj, &block_object_type))
338 return NULL;
339 return ((block_object *) obj)->block;
342 /* Return a reference to the block iterator. */
343 static PyObject *
344 blpy_block_syms_iter (PyObject *self)
346 block_syms_iterator_object *iter_obj = (block_syms_iterator_object *) self;
348 BLPY_ITER_REQUIRE_VALID (iter_obj->source);
350 Py_INCREF (self);
351 return self;
354 /* Return the next symbol in the iteration through the block's
355 dictionary. */
356 static PyObject *
357 blpy_block_syms_iternext (PyObject *self)
359 block_syms_iterator_object *iter_obj = (block_syms_iterator_object *) self;
360 struct symbol *sym;
362 BLPY_ITER_REQUIRE_VALID (iter_obj->source);
364 if (!iter_obj->initialized_p)
366 sym = block_iterator_first (iter_obj->block, &(iter_obj->iter));
367 iter_obj->initialized_p = 1;
369 else
370 sym = block_iterator_next (&(iter_obj->iter));
372 if (sym == NULL)
374 PyErr_SetString (PyExc_StopIteration, _("Symbol is null."));
375 return NULL;
378 return symbol_to_symbol_object (sym);
381 static void
382 blpy_block_syms_dealloc (PyObject *obj)
384 block_syms_iterator_object *iter_obj = (block_syms_iterator_object *) obj;
386 Py_XDECREF (iter_obj->source);
387 Py_TYPE (obj)->tp_free (obj);
390 /* Implementation of gdb.Block.is_valid (self) -> Boolean.
391 Returns True if this block object still exists in GDB. */
393 static PyObject *
394 blpy_is_valid (PyObject *self, PyObject *args)
396 const struct block *block;
398 block = block_object_to_block (self);
399 if (block == NULL)
400 Py_RETURN_FALSE;
402 Py_RETURN_TRUE;
405 /* Implementation of gdb.BlockIterator.is_valid (self) -> Boolean.
406 Returns True if this block iterator object still exists in GDB */
408 static PyObject *
409 blpy_iter_is_valid (PyObject *self, PyObject *args)
411 block_syms_iterator_object *iter_obj =
412 (block_syms_iterator_object *) self;
414 if (iter_obj->source->block == NULL)
415 Py_RETURN_FALSE;
417 Py_RETURN_TRUE;
420 /* __repr__ implementation for gdb.Block. */
422 static PyObject *
423 blpy_repr (PyObject *self)
425 const auto block = block_object_to_block (self);
426 if (block == nullptr)
427 return gdb_py_invalid_object_repr (self);
429 const auto name = block->function () ?
430 block->function ()->print_name () : "<anonymous>";
432 std::string str;
433 unsigned int written_symbols = 0;
434 const int len = mdict_size (block->multidict ());
435 static constexpr int SYMBOLS_TO_SHOW = 5;
436 for (struct symbol *symbol : block_iterator_range (block))
438 if (written_symbols == SYMBOLS_TO_SHOW)
440 const int remaining = len - SYMBOLS_TO_SHOW;
441 if (remaining == 1)
442 str += string_printf ("... (%d more symbol)", remaining);
443 else
444 str += string_printf ("... (%d more symbols)", remaining);
445 break;
447 str += symbol->print_name ();
448 if (++written_symbols < len)
449 str += ", ";
451 return PyUnicode_FromFormat ("<%s %s {%s}>", Py_TYPE (self)->tp_name,
452 name, str.c_str ());
455 /* Implements the equality comparison for Block objects. All other
456 comparison operators will throw NotImplemented, as they aren't
457 valid for blocks. */
459 static PyObject *
460 blpy_richcompare (PyObject *self, PyObject *other, int op)
462 if (!PyObject_TypeCheck (other, &block_object_type)
463 || (op != Py_EQ && op != Py_NE))
465 Py_INCREF (Py_NotImplemented);
466 return Py_NotImplemented;
469 block_object *self_block = (block_object *) self;
470 block_object *other_block = (block_object *) other;
472 bool expected = self_block->block == other_block->block;
473 bool equal = op == Py_EQ;
474 return PyBool_FromLong (equal == expected);
477 static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
478 gdbpy_initialize_blocks (void)
480 block_object_type.tp_new = PyType_GenericNew;
481 if (PyType_Ready (&block_object_type) < 0)
482 return -1;
484 block_syms_iterator_object_type.tp_new = PyType_GenericNew;
485 if (PyType_Ready (&block_syms_iterator_object_type) < 0)
486 return -1;
488 if (gdb_pymodule_addobject (gdb_module, "Block",
489 (PyObject *) &block_object_type) < 0)
490 return -1;
492 return gdb_pymodule_addobject (gdb_module, "BlockIterator",
493 (PyObject *) &block_syms_iterator_object_type);
496 GDBPY_INITIALIZE_FILE (gdbpy_initialize_blocks);
500 static PyMethodDef block_object_methods[] = {
501 { "is_valid", blpy_is_valid, METH_NOARGS,
502 "is_valid () -> Boolean.\n\
503 Return true if this block is valid, false if not." },
504 {NULL} /* Sentinel */
507 static gdb_PyGetSetDef block_object_getset[] = {
508 { "start", blpy_get_start, NULL, "Start address of the block.", NULL },
509 { "end", blpy_get_end, NULL, "End address of the block.", NULL },
510 { "function", blpy_get_function, NULL,
511 "Symbol that names the block, or None.", NULL },
512 { "superblock", blpy_get_superblock, NULL,
513 "Block containing the block, or None.", NULL },
514 { "global_block", blpy_get_global_block, NULL,
515 "Block containing the global block.", NULL },
516 { "static_block", blpy_get_static_block, NULL,
517 "Block containing the static block.", NULL },
518 { "is_static", blpy_is_static, NULL,
519 "Whether this block is a static block.", NULL },
520 { "is_global", blpy_is_global, NULL,
521 "Whether this block is a global block.", NULL },
522 { NULL } /* Sentinel */
525 static PyMappingMethods block_object_as_mapping = {
526 NULL,
527 blpy_getitem,
528 NULL
531 PyTypeObject block_object_type = {
532 PyVarObject_HEAD_INIT (NULL, 0)
533 "gdb.Block", /*tp_name*/
534 sizeof (block_object), /*tp_basicsize*/
535 0, /*tp_itemsize*/
536 blpy_dealloc, /*tp_dealloc*/
537 0, /*tp_print*/
538 0, /*tp_getattr*/
539 0, /*tp_setattr*/
540 0, /*tp_compare*/
541 blpy_repr, /*tp_repr*/
542 0, /*tp_as_number*/
543 0, /*tp_as_sequence*/
544 &block_object_as_mapping, /*tp_as_mapping*/
545 0, /*tp_hash */
546 0, /*tp_call*/
547 0, /*tp_str*/
548 0, /*tp_getattro*/
549 0, /*tp_setattro*/
550 0, /*tp_as_buffer*/
551 Py_TPFLAGS_DEFAULT, /*tp_flags*/
552 "GDB block object", /* tp_doc */
553 0, /* tp_traverse */
554 0, /* tp_clear */
555 blpy_richcompare, /* tp_richcompare */
556 0, /* tp_weaklistoffset */
557 blpy_iter, /* tp_iter */
558 0, /* tp_iternext */
559 block_object_methods, /* tp_methods */
560 0, /* tp_members */
561 block_object_getset /* tp_getset */
564 static PyMethodDef block_iterator_object_methods[] = {
565 { "is_valid", blpy_iter_is_valid, METH_NOARGS,
566 "is_valid () -> Boolean.\n\
567 Return true if this block iterator is valid, false if not." },
568 {NULL} /* Sentinel */
571 PyTypeObject block_syms_iterator_object_type = {
572 PyVarObject_HEAD_INIT (NULL, 0)
573 "gdb.BlockIterator", /*tp_name*/
574 sizeof (block_syms_iterator_object), /*tp_basicsize*/
575 0, /*tp_itemsize*/
576 blpy_block_syms_dealloc, /*tp_dealloc*/
577 0, /*tp_print*/
578 0, /*tp_getattr*/
579 0, /*tp_setattr*/
580 0, /*tp_compare*/
581 0, /*tp_repr*/
582 0, /*tp_as_number*/
583 0, /*tp_as_sequence*/
584 0, /*tp_as_mapping*/
585 0, /*tp_hash */
586 0, /*tp_call*/
587 0, /*tp_str*/
588 0, /*tp_getattro*/
589 0, /*tp_setattro*/
590 0, /*tp_as_buffer*/
591 Py_TPFLAGS_DEFAULT, /*tp_flags*/
592 "GDB block syms iterator object", /*tp_doc */
593 0, /*tp_traverse */
594 0, /*tp_clear */
595 0, /*tp_richcompare */
596 0, /*tp_weaklistoffset */
597 blpy_block_syms_iter, /*tp_iter */
598 blpy_block_syms_iternext, /*tp_iternext */
599 block_iterator_object_methods /*tp_methods */