xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/python/py-block.c (revision 897be3a4bac39d8b2e92077bf29f4a2e67d31983)
1 /* Python interface to blocks.
2 
3    Copyright (C) 2008-2023 Free Software Foundation, Inc.
4 
5    This file is part of GDB.
6 
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.
11 
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.
16 
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/>.  */
19 
20 #include "defs.h"
21 #include "block.h"
22 #include "dictionary.h"
23 #include "symtab.h"
24 #include "python-internal.h"
25 #include "objfiles.h"
26 
27 struct block_object {
28   PyObject_HEAD
29   /* The GDB block structure that represents a frame's code block.  */
30   const struct block *block;
31   /* The backing object file.  There is no direct relationship in GDB
32      between a block and an object file.  When a block is created also
33      store a pointer to the object file for later use.  */
34   struct objfile *objfile;
35   /* Keep track of all blocks with a doubly-linked list.  Needed for
36      block invalidation if the source object file has been freed.  */
37   block_object *prev;
38   block_object *next;
39 };
40 
41 struct block_syms_iterator_object {
42   PyObject_HEAD
43   /* The block.  */
44   const struct block *block;
45   /* The iterator for that block.  */
46   struct block_iterator iter;
47   /* Has the iterator been initialized flag.  */
48   int initialized_p;
49   /* Pointer back to the original source block object.  Needed to
50      check if the block is still valid, and has not been invalidated
51      when an object file has been freed.  */
52   block_object *source;
53 };
54 
55 /* Require a valid block.  All access to block_object->block should be
56    gated by this call.  */
57 #define BLPY_REQUIRE_VALID(block_obj, block)		\
58   do {							\
59     block = block_object_to_block (block_obj);		\
60     if (block == NULL)					\
61       {							\
62 	PyErr_SetString (PyExc_RuntimeError,		\
63 			 _("Block is invalid."));	\
64 	return NULL;					\
65       }							\
66   } while (0)
67 
68 /* Require a valid block.  This macro is called during block iterator
69    creation, and at each next call.  */
70 #define BLPY_ITER_REQUIRE_VALID(block_obj)				\
71   do {									\
72     if (block_obj->block == NULL)					\
73       {									\
74 	PyErr_SetString (PyExc_RuntimeError,				\
75 			 _("Source block for iterator is invalid."));	\
76 	return NULL;							\
77       }									\
78   } while (0)
79 
80 /* This is called when an objfile is about to be freed.
81    Invalidate the block as further actions on the block would result
82    in bad data.  All access to obj->symbol should be gated by
83    BLPY_REQUIRE_VALID which will raise an exception on invalid
84    blocks.  */
85 struct blpy_deleter
86 {
87   void operator() (block_object *obj)
88   {
89     while (obj)
90       {
91 	block_object *next = obj->next;
92 
93 	obj->block = NULL;
94 	obj->objfile = NULL;
95 	obj->next = NULL;
96 	obj->prev = NULL;
97 
98 	obj = next;
99       }
100   }
101 };
102 
103 extern PyTypeObject block_syms_iterator_object_type
104     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("block_syms_iterator_object");
105 static const registry<objfile>::key<block_object, blpy_deleter>
106      blpy_objfile_data_key;
107 
108 static PyObject *
109 blpy_iter (PyObject *self)
110 {
111   block_syms_iterator_object *block_iter_obj;
112   const struct block *block = NULL;
113 
114   BLPY_REQUIRE_VALID (self, block);
115 
116   block_iter_obj = PyObject_New (block_syms_iterator_object,
117 				 &block_syms_iterator_object_type);
118   if (block_iter_obj == NULL)
119       return NULL;
120 
121   block_iter_obj->block = block;
122   block_iter_obj->initialized_p = 0;
123   Py_INCREF (self);
124   block_iter_obj->source = (block_object *) self;
125 
126   return (PyObject *) block_iter_obj;
127 }
128 
129 static PyObject *
130 blpy_get_start (PyObject *self, void *closure)
131 {
132   const struct block *block = NULL;
133 
134   BLPY_REQUIRE_VALID (self, block);
135 
136   return gdb_py_object_from_ulongest (block->start ()).release ();
137 }
138 
139 static PyObject *
140 blpy_get_end (PyObject *self, void *closure)
141 {
142   const struct block *block = NULL;
143 
144   BLPY_REQUIRE_VALID (self, block);
145 
146   return gdb_py_object_from_ulongest (block->end ()).release ();
147 }
148 
149 static PyObject *
150 blpy_get_function (PyObject *self, void *closure)
151 {
152   struct symbol *sym;
153   const struct block *block;
154 
155   BLPY_REQUIRE_VALID (self, block);
156 
157   sym = block->function ();
158   if (sym)
159     return symbol_to_symbol_object (sym);
160 
161   Py_RETURN_NONE;
162 }
163 
164 static PyObject *
165 blpy_get_superblock (PyObject *self, void *closure)
166 {
167   const struct block *block;
168   const struct block *super_block;
169   block_object *self_obj  = (block_object *) self;
170 
171   BLPY_REQUIRE_VALID (self, block);
172 
173   super_block = block->superblock ();
174   if (super_block)
175     return block_to_block_object (super_block, self_obj->objfile);
176 
177   Py_RETURN_NONE;
178 }
179 
180 /* Return the global block associated to this block.  */
181 
182 static PyObject *
183 blpy_get_global_block (PyObject *self, void *closure)
184 {
185   const struct block *block;
186   const struct block *global_block;
187   block_object *self_obj  = (block_object *) self;
188 
189   BLPY_REQUIRE_VALID (self, block);
190 
191   global_block = block_global_block (block);
192 
193   return block_to_block_object (global_block,
194 				self_obj->objfile);
195 
196 }
197 
198 /* Return the static block associated to this block.  Return None
199    if we cannot get the static block (this is the global block).  */
200 
201 static PyObject *
202 blpy_get_static_block (PyObject *self, void *closure)
203 {
204   const struct block *block;
205   const struct block *static_block;
206   block_object *self_obj  = (block_object *) self;
207 
208   BLPY_REQUIRE_VALID (self, block);
209 
210   if (block->superblock () == NULL)
211     Py_RETURN_NONE;
212 
213   static_block = block_static_block (block);
214 
215   return block_to_block_object (static_block, self_obj->objfile);
216 }
217 
218 /* Implementation of gdb.Block.is_global (self) -> Boolean.
219    Returns True if this block object is a global block.  */
220 
221 static PyObject *
222 blpy_is_global (PyObject *self, void *closure)
223 {
224   const struct block *block;
225 
226   BLPY_REQUIRE_VALID (self, block);
227 
228   if (block->superblock ())
229     Py_RETURN_FALSE;
230 
231   Py_RETURN_TRUE;
232 }
233 
234 /* Implementation of gdb.Block.is_static (self) -> Boolean.
235    Returns True if this block object is a static block.  */
236 
237 static PyObject *
238 blpy_is_static (PyObject *self, void *closure)
239 {
240   const struct block *block;
241 
242   BLPY_REQUIRE_VALID (self, block);
243 
244   if (block->superblock () != NULL
245      && block->superblock ()->superblock () == NULL)
246     Py_RETURN_TRUE;
247 
248   Py_RETURN_FALSE;
249 }
250 
251 /* Given a string, returns the gdb.Symbol representing that symbol in this
252    block.  If such a symbol does not exist, returns NULL with a Python
253    exception.  */
254 
255 static PyObject *
256 blpy_getitem (PyObject *self, PyObject *key)
257 {
258   const struct block *block;
259 
260   BLPY_REQUIRE_VALID (self, block);
261 
262   gdb::unique_xmalloc_ptr<char> name = python_string_to_host_string (key);
263   if (name == nullptr)
264     return nullptr;
265 
266   lookup_name_info lookup_name (name.get(), symbol_name_match_type::FULL);
267 
268   /* We use ALL_BLOCK_SYMBOLS_WITH_NAME instead of block_lookup_symbol so
269      that we can look up symbols irrespective of the domain, matching the
270      iterator. It would be confusing if the iterator returns symbols you
271      can't find via getitem.  */
272   struct block_iterator iter;
273   struct symbol *sym = nullptr;
274   ALL_BLOCK_SYMBOLS_WITH_NAME (block, lookup_name, iter, sym)
275     {
276       /* Just stop at the first match */
277       break;
278     }
279 
280   if (sym == nullptr)
281     {
282       PyErr_SetObject (PyExc_KeyError, key);
283       return nullptr;
284     }
285   return symbol_to_symbol_object (sym);
286 }
287 
288 static void
289 blpy_dealloc (PyObject *obj)
290 {
291   block_object *block = (block_object *) obj;
292 
293   if (block->prev)
294     block->prev->next = block->next;
295   else if (block->objfile)
296     blpy_objfile_data_key.set (block->objfile, block->next);
297   if (block->next)
298     block->next->prev = block->prev;
299   block->block = NULL;
300   Py_TYPE (obj)->tp_free (obj);
301 }
302 
303 /* Given a block, and a block_object that has previously been
304    allocated and initialized, populate the block_object with the
305    struct block data.  Also, register the block_object life-cycle
306    with the life-cycle of the object file associated with this
307    block, if needed.  */
308 static void
309 set_block (block_object *obj, const struct block *block,
310 	   struct objfile *objfile)
311 {
312   obj->block = block;
313   obj->prev = NULL;
314   if (objfile)
315     {
316       obj->objfile = objfile;
317       obj->next = blpy_objfile_data_key.get (objfile);
318       if (obj->next)
319 	obj->next->prev = obj;
320       blpy_objfile_data_key.set (objfile, obj);
321     }
322   else
323     obj->next = NULL;
324 }
325 
326 /* Create a new block object (gdb.Block) that encapsulates the struct
327    block object from GDB.  */
328 PyObject *
329 block_to_block_object (const struct block *block, struct objfile *objfile)
330 {
331   block_object *block_obj;
332 
333   block_obj = PyObject_New (block_object, &block_object_type);
334   if (block_obj)
335     set_block (block_obj, block, objfile);
336 
337   return (PyObject *) block_obj;
338 }
339 
340 /* Return struct block reference that is wrapped by this object.  */
341 const struct block *
342 block_object_to_block (PyObject *obj)
343 {
344   if (! PyObject_TypeCheck (obj, &block_object_type))
345     return NULL;
346   return ((block_object *) obj)->block;
347 }
348 
349 /* Return a reference to the block iterator.  */
350 static PyObject *
351 blpy_block_syms_iter (PyObject *self)
352 {
353   block_syms_iterator_object *iter_obj = (block_syms_iterator_object *) self;
354 
355   BLPY_ITER_REQUIRE_VALID (iter_obj->source);
356 
357   Py_INCREF (self);
358   return self;
359 }
360 
361 /* Return the next symbol in the iteration through the block's
362    dictionary.  */
363 static PyObject *
364 blpy_block_syms_iternext (PyObject *self)
365 {
366   block_syms_iterator_object *iter_obj = (block_syms_iterator_object *) self;
367   struct symbol *sym;
368 
369   BLPY_ITER_REQUIRE_VALID (iter_obj->source);
370 
371   if (!iter_obj->initialized_p)
372     {
373       sym = block_iterator_first (iter_obj->block,  &(iter_obj->iter));
374       iter_obj->initialized_p = 1;
375     }
376   else
377     sym = block_iterator_next (&(iter_obj->iter));
378 
379   if (sym == NULL)
380     {
381       PyErr_SetString (PyExc_StopIteration, _("Symbol is null."));
382       return NULL;
383     }
384 
385   return symbol_to_symbol_object (sym);
386 }
387 
388 static void
389 blpy_block_syms_dealloc (PyObject *obj)
390 {
391   block_syms_iterator_object *iter_obj = (block_syms_iterator_object *) obj;
392 
393   Py_XDECREF (iter_obj->source);
394   Py_TYPE (obj)->tp_free (obj);
395 }
396 
397 /* Implementation of gdb.Block.is_valid (self) -> Boolean.
398    Returns True if this block object still exists in GDB.  */
399 
400 static PyObject *
401 blpy_is_valid (PyObject *self, PyObject *args)
402 {
403   const struct block *block;
404 
405   block = block_object_to_block (self);
406   if (block == NULL)
407     Py_RETURN_FALSE;
408 
409   Py_RETURN_TRUE;
410 }
411 
412 /* Implementation of gdb.BlockIterator.is_valid (self) -> Boolean.
413    Returns True if this block iterator object still exists in GDB  */
414 
415 static PyObject *
416 blpy_iter_is_valid (PyObject *self, PyObject *args)
417 {
418   block_syms_iterator_object *iter_obj =
419     (block_syms_iterator_object *) self;
420 
421   if (iter_obj->source->block == NULL)
422     Py_RETURN_FALSE;
423 
424   Py_RETURN_TRUE;
425 }
426 
427 int
428 gdbpy_initialize_blocks (void)
429 {
430   block_object_type.tp_new = PyType_GenericNew;
431   if (PyType_Ready (&block_object_type) < 0)
432     return -1;
433 
434   block_syms_iterator_object_type.tp_new = PyType_GenericNew;
435   if (PyType_Ready (&block_syms_iterator_object_type) < 0)
436     return -1;
437 
438   if (gdb_pymodule_addobject (gdb_module, "Block",
439 			      (PyObject *) &block_object_type) < 0)
440     return -1;
441 
442   return gdb_pymodule_addobject (gdb_module, "BlockIterator",
443 				 (PyObject *) &block_syms_iterator_object_type);
444 }
445 
446 
447 
448 static PyMethodDef block_object_methods[] = {
449   { "is_valid", blpy_is_valid, METH_NOARGS,
450     "is_valid () -> Boolean.\n\
451 Return true if this block is valid, false if not." },
452   {NULL}  /* Sentinel */
453 };
454 
455 static gdb_PyGetSetDef block_object_getset[] = {
456   { "start", blpy_get_start, NULL, "Start address of the block.", NULL },
457   { "end", blpy_get_end, NULL, "End address of the block.", NULL },
458   { "function", blpy_get_function, NULL,
459     "Symbol that names the block, or None.", NULL },
460   { "superblock", blpy_get_superblock, NULL,
461     "Block containing the block, or None.", NULL },
462   { "global_block", blpy_get_global_block, NULL,
463     "Block containing the global block.", NULL },
464   { "static_block", blpy_get_static_block, NULL,
465     "Block containing the static block.", NULL },
466   { "is_static", blpy_is_static, NULL,
467     "Whether this block is a static block.", NULL },
468   { "is_global", blpy_is_global, NULL,
469     "Whether this block is a global block.", NULL },
470   { NULL }  /* Sentinel */
471 };
472 
473 static PyMappingMethods block_object_as_mapping = {
474   NULL,
475   blpy_getitem,
476   NULL
477 };
478 
479 PyTypeObject block_object_type = {
480   PyVarObject_HEAD_INIT (NULL, 0)
481   "gdb.Block",			  /*tp_name*/
482   sizeof (block_object),	  /*tp_basicsize*/
483   0,				  /*tp_itemsize*/
484   blpy_dealloc,                   /*tp_dealloc*/
485   0,				  /*tp_print*/
486   0,				  /*tp_getattr*/
487   0,				  /*tp_setattr*/
488   0,				  /*tp_compare*/
489   0,				  /*tp_repr*/
490   0,				  /*tp_as_number*/
491   0,				  /*tp_as_sequence*/
492   &block_object_as_mapping,	  /*tp_as_mapping*/
493   0,				  /*tp_hash */
494   0,				  /*tp_call*/
495   0,				  /*tp_str*/
496   0,				  /*tp_getattro*/
497   0,				  /*tp_setattro*/
498   0,				  /*tp_as_buffer*/
499   Py_TPFLAGS_DEFAULT,		  /*tp_flags*/
500   "GDB block object",		  /* tp_doc */
501   0,				  /* tp_traverse */
502   0,				  /* tp_clear */
503   0,				  /* tp_richcompare */
504   0,				  /* tp_weaklistoffset */
505   blpy_iter,			  /* tp_iter */
506   0,				  /* tp_iternext */
507   block_object_methods,		  /* tp_methods */
508   0,				  /* tp_members */
509   block_object_getset		  /* tp_getset */
510 };
511 
512 static PyMethodDef block_iterator_object_methods[] = {
513   { "is_valid", blpy_iter_is_valid, METH_NOARGS,
514     "is_valid () -> Boolean.\n\
515 Return true if this block iterator is valid, false if not." },
516   {NULL}  /* Sentinel */
517 };
518 
519 PyTypeObject block_syms_iterator_object_type = {
520   PyVarObject_HEAD_INIT (NULL, 0)
521   "gdb.BlockIterator",		  /*tp_name*/
522   sizeof (block_syms_iterator_object),	      /*tp_basicsize*/
523   0,				  /*tp_itemsize*/
524   blpy_block_syms_dealloc,	  /*tp_dealloc*/
525   0,				  /*tp_print*/
526   0,				  /*tp_getattr*/
527   0,				  /*tp_setattr*/
528   0,				  /*tp_compare*/
529   0,				  /*tp_repr*/
530   0,				  /*tp_as_number*/
531   0,				  /*tp_as_sequence*/
532   0,				  /*tp_as_mapping*/
533   0,				  /*tp_hash */
534   0,				  /*tp_call*/
535   0,				  /*tp_str*/
536   0,				  /*tp_getattro*/
537   0,				  /*tp_setattro*/
538   0,				  /*tp_as_buffer*/
539   Py_TPFLAGS_DEFAULT,		  /*tp_flags*/
540   "GDB block syms iterator object",	      /*tp_doc */
541   0,				  /*tp_traverse */
542   0,				  /*tp_clear */
543   0,				  /*tp_richcompare */
544   0,				  /*tp_weaklistoffset */
545   blpy_block_syms_iter,           /*tp_iter */
546   blpy_block_syms_iternext,	  /*tp_iternext */
547   block_iterator_object_methods   /*tp_methods */
548 };
549