]>
Commit | Line | Data |
---|---|---|
f3e9a817 PM |
1 | /* Python interface to blocks. |
2 | ||
4a94e368 | 3 | Copyright (C) 2008-2022 Free Software Foundation, Inc. |
f3e9a817 PM |
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" | |
f3e9a817 | 26 | |
f99b5177 | 27 | struct block_object { |
f3e9a817 PM |
28 | PyObject_HEAD |
29 | /* The GDB block structure that represents a frame's code block. */ | |
9df2fbc4 | 30 | const struct block *block; |
f3e9a817 PM |
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. */ | |
f99b5177 TT |
37 | block_object *prev; |
38 | block_object *next; | |
39 | }; | |
f3e9a817 | 40 | |
f99b5177 | 41 | struct block_syms_iterator_object { |
f3e9a817 | 42 | PyObject_HEAD |
8157b174 TT |
43 | /* The block. */ |
44 | const struct block *block; | |
45 | /* The iterator for that block. */ | |
46 | struct block_iterator iter; | |
f3e9a817 PM |
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. */ | |
f99b5177 TT |
52 | block_object *source; |
53 | }; | |
f3e9a817 PM |
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 | ||
08b8a139 TT |
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 | ||
e36122e9 | 103 | extern PyTypeObject block_syms_iterator_object_type |
62eec1a5 | 104 | CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("block_syms_iterator_object"); |
08b8a139 TT |
105 | static const registry<objfile>::key<block_object, blpy_deleter> |
106 | blpy_objfile_data_key; | |
f3e9a817 PM |
107 | |
108 | static PyObject * | |
109 | blpy_iter (PyObject *self) | |
110 | { | |
111 | block_syms_iterator_object *block_iter_obj; | |
9df2fbc4 | 112 | const struct block *block = NULL; |
f3e9a817 PM |
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 | ||
8157b174 | 121 | block_iter_obj->block = block; |
f3e9a817 PM |
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 | { | |
9df2fbc4 | 132 | const struct block *block = NULL; |
f3e9a817 PM |
133 | |
134 | BLPY_REQUIRE_VALID (self, block); | |
135 | ||
4b8791e1 | 136 | return gdb_py_object_from_ulongest (block->start ()).release (); |
f3e9a817 PM |
137 | } |
138 | ||
139 | static PyObject * | |
140 | blpy_get_end (PyObject *self, void *closure) | |
141 | { | |
9df2fbc4 | 142 | const struct block *block = NULL; |
f3e9a817 PM |
143 | |
144 | BLPY_REQUIRE_VALID (self, block); | |
145 | ||
4b8791e1 | 146 | return gdb_py_object_from_ulongest (block->end ()).release (); |
f3e9a817 PM |
147 | } |
148 | ||
149 | static PyObject * | |
150 | blpy_get_function (PyObject *self, void *closure) | |
151 | { | |
152 | struct symbol *sym; | |
9df2fbc4 | 153 | const struct block *block; |
f3e9a817 PM |
154 | |
155 | BLPY_REQUIRE_VALID (self, block); | |
156 | ||
6c00f721 | 157 | sym = block->function (); |
f3e9a817 PM |
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 | { | |
9df2fbc4 PM |
167 | const struct block *block; |
168 | const struct block *super_block; | |
f3e9a817 PM |
169 | block_object *self_obj = (block_object *) self; |
170 | ||
171 | BLPY_REQUIRE_VALID (self, block); | |
172 | ||
f135fe72 | 173 | super_block = block->superblock (); |
f3e9a817 PM |
174 | if (super_block) |
175 | return block_to_block_object (super_block, self_obj->objfile); | |
176 | ||
177 | Py_RETURN_NONE; | |
178 | } | |
179 | ||
9df2fbc4 PM |
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 | ||
f135fe72 | 210 | if (block->superblock () == NULL) |
9df2fbc4 PM |
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 | ||
f135fe72 | 228 | if (block->superblock ()) |
9df2fbc4 PM |
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 | ||
f135fe72 SM |
244 | if (block->superblock () != NULL |
245 | && block->superblock ()->superblock () == NULL) | |
9df2fbc4 PM |
246 | Py_RETURN_TRUE; |
247 | ||
248 | Py_RETURN_FALSE; | |
249 | } | |
250 | ||
0b27c27d CB |
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 | ||
f3e9a817 PM |
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) | |
08b8a139 | 296 | blpy_objfile_data_key.set (block->objfile, block->next); |
f3e9a817 PM |
297 | if (block->next) |
298 | block->next->prev = block->prev; | |
299 | block->block = NULL; | |
2e953aca | 300 | Py_TYPE (obj)->tp_free (obj); |
f3e9a817 PM |
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 | |
b021a221 | 306 | with the life-cycle of the object file associated with this |
f3e9a817 PM |
307 | block, if needed. */ |
308 | static void | |
9df2fbc4 | 309 | set_block (block_object *obj, const struct block *block, |
f3e9a817 PM |
310 | struct objfile *objfile) |
311 | { | |
312 | obj->block = block; | |
313 | obj->prev = NULL; | |
314 | if (objfile) | |
315 | { | |
316 | obj->objfile = objfile; | |
08b8a139 | 317 | obj->next = blpy_objfile_data_key.get (objfile); |
f3e9a817 PM |
318 | if (obj->next) |
319 | obj->next->prev = obj; | |
08b8a139 | 320 | blpy_objfile_data_key.set (objfile, obj); |
f3e9a817 PM |
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 * | |
9df2fbc4 | 329 | block_to_block_object (const struct block *block, struct objfile *objfile) |
f3e9a817 PM |
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. */ | |
9df2fbc4 | 341 | const struct block * |
f3e9a817 PM |
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 | { | |
8157b174 | 373 | sym = block_iterator_first (iter_obj->block, &(iter_obj->iter)); |
f3e9a817 PM |
374 | iter_obj->initialized_p = 1; |
375 | } | |
376 | else | |
8157b174 | 377 | sym = block_iterator_next (&(iter_obj->iter)); |
f3e9a817 PM |
378 | |
379 | if (sym == NULL) | |
380 | { | |
044c0f87 | 381 | PyErr_SetString (PyExc_StopIteration, _("Symbol is null.")); |
f3e9a817 PM |
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; | |
d59b6f6c | 392 | |
f3e9a817 | 393 | Py_XDECREF (iter_obj->source); |
2e953aca | 394 | Py_TYPE (obj)->tp_free (obj); |
f3e9a817 PM |
395 | } |
396 | ||
29703da4 PM |
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 | { | |
9df2fbc4 | 403 | const struct block *block; |
29703da4 PM |
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 | ||
999633ed | 427 | int |
f3e9a817 PM |
428 | gdbpy_initialize_blocks (void) |
429 | { | |
430 | block_object_type.tp_new = PyType_GenericNew; | |
431 | if (PyType_Ready (&block_object_type) < 0) | |
999633ed | 432 | return -1; |
f3e9a817 PM |
433 | |
434 | block_syms_iterator_object_type.tp_new = PyType_GenericNew; | |
435 | if (PyType_Ready (&block_syms_iterator_object_type) < 0) | |
999633ed | 436 | return -1; |
f3e9a817 | 437 | |
aa36459a TT |
438 | if (gdb_pymodule_addobject (gdb_module, "Block", |
439 | (PyObject *) &block_object_type) < 0) | |
999633ed | 440 | return -1; |
f3e9a817 | 441 | |
aa36459a TT |
442 | return gdb_pymodule_addobject (gdb_module, "BlockIterator", |
443 | (PyObject *) &block_syms_iterator_object_type); | |
f3e9a817 PM |
444 | } |
445 | ||
446 | \f | |
447 | ||
29703da4 PM |
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 | ||
0d1f4ceb | 455 | static gdb_PyGetSetDef block_object_getset[] = { |
f3e9a817 PM |
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 }, | |
9df2fbc4 PM |
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 }, | |
f3e9a817 PM |
470 | { NULL } /* Sentinel */ |
471 | }; | |
472 | ||
0b27c27d CB |
473 | static PyMappingMethods block_object_as_mapping = { |
474 | NULL, | |
475 | blpy_getitem, | |
476 | NULL | |
477 | }; | |
478 | ||
f3e9a817 | 479 | PyTypeObject block_object_type = { |
9a27f2c6 | 480 | PyVarObject_HEAD_INIT (NULL, 0) |
f3e9a817 PM |
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*/ | |
0b27c27d | 492 | &block_object_as_mapping, /*tp_as_mapping*/ |
f3e9a817 PM |
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*/ | |
0b233e34 | 499 | Py_TPFLAGS_DEFAULT, /*tp_flags*/ |
f3e9a817 PM |
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 */ | |
29703da4 | 507 | block_object_methods, /* tp_methods */ |
f3e9a817 PM |
508 | 0, /* tp_members */ |
509 | block_object_getset /* tp_getset */ | |
510 | }; | |
511 | ||
29703da4 PM |
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 | ||
e36122e9 | 519 | PyTypeObject block_syms_iterator_object_type = { |
9a27f2c6 | 520 | PyVarObject_HEAD_INIT (NULL, 0) |
f3e9a817 PM |
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*/ | |
0b233e34 | 539 | Py_TPFLAGS_DEFAULT, /*tp_flags*/ |
f3e9a817 PM |
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 */ | |
29703da4 | 547 | block_iterator_object_methods /*tp_methods */ |
f3e9a817 | 548 | }; |