xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/python/py-linetable.c (revision 8b657b0747480f8989760d71343d6dd33f8d4cf9)
1 /* Python interface to line tables.
2 
3    Copyright (C) 2013-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 "python-internal.h"
22 
23 struct linetable_entry_object {
24   PyObject_HEAD
25   /* The line table source line.  */
26   int line;
27   /* The pc associated with the source line.  */
28   CORE_ADDR pc;
29 };
30 
31 extern PyTypeObject linetable_entry_object_type
32     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("linetable_entry_object");
33 
34 struct linetable_object {
35   PyObject_HEAD
36   /* The symtab python object.  We store the Python object here as the
37      underlying symtab can become invalid, and we have to run validity
38      checks on it.  */
39   PyObject *symtab;
40 };
41 
42 extern PyTypeObject linetable_object_type
43     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("linetable_object");
44 
45 struct ltpy_iterator_object {
46   PyObject_HEAD
47   /* The current entry in the line table for the iterator  */
48   int current_index;
49   /* Pointer back to the original source line table object.  Needed to
50      check if the line table is still valid, and has not been invalidated
51      when an object file has been freed.  */
52   PyObject *source;
53 };
54 
55 extern PyTypeObject ltpy_iterator_object_type
56     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("ltpy_iterator_object");
57 
58 /* Internal helper function to extract gdb.Symtab from a gdb.LineTable
59    object.  */
60 
61 static PyObject *
62 get_symtab (PyObject *linetable)
63 {
64   linetable_object *lt = (linetable_object *) linetable;
65 
66   return lt->symtab;
67 }
68 
69 #define LTPY_REQUIRE_VALID(lt_obj, symtab)				\
70   do {									\
71     symtab = symtab_object_to_symtab (get_symtab (lt_obj));		\
72     if (symtab == NULL)							\
73       {									\
74 	  PyErr_SetString (PyExc_RuntimeError,				\
75 			   _("Symbol Table in line table is invalid."));\
76 	  return NULL;							\
77 	}								\
78   } while (0)
79 
80 
81 /* Helper function to create a line table object that wraps a
82    gdb.Symtab object.  */
83 
84 PyObject *
85 symtab_to_linetable_object (PyObject *symtab)
86 {
87   linetable_object *ltable;
88 
89   ltable = PyObject_New (linetable_object, &linetable_object_type);
90   if (ltable != NULL)
91     {
92       ltable->symtab = symtab;
93       Py_INCREF (symtab);
94     }
95   return (PyObject *) ltable;
96 }
97 
98 /* Internal helper function to build a line table object from a line
99    and an address.  */
100 
101 static PyObject *
102 build_linetable_entry (int line, CORE_ADDR address)
103 {
104   linetable_entry_object *obj;
105 
106   obj = PyObject_New (linetable_entry_object,
107 		      &linetable_entry_object_type);
108   if (obj != NULL)
109     {
110       obj->line = line;
111       obj->pc = address;
112     }
113 
114   return (PyObject *) obj;
115 }
116 
117 /* Internal helper function to build a Python Tuple from a vector.
118    A line table entry can have multiple PCs for a given source line.
119    Construct a Tuple of all entries for the given source line, LINE
120    from the line table PCS.  Construct one line table entry object per
121    address.  */
122 
123 static PyObject *
124 build_line_table_tuple_from_pcs (int line, const std::vector<CORE_ADDR> &pcs)
125 {
126   int i;
127 
128   if (pcs.size () < 1)
129     Py_RETURN_NONE;
130 
131   gdbpy_ref<> tuple (PyTuple_New (pcs.size ()));
132 
133   if (tuple == NULL)
134     return NULL;
135 
136   for (i = 0; i < pcs.size (); ++i)
137     {
138       CORE_ADDR pc = pcs[i];
139       gdbpy_ref<> obj (build_linetable_entry (line, pc));
140 
141       if (obj == NULL)
142 	return NULL;
143       else if (PyTuple_SetItem (tuple.get (), i, obj.release ()) != 0)
144 	return NULL;
145     }
146 
147   return tuple.release ();
148 }
149 
150 /* Implementation of gdb.LineTable.line (self) -> Tuple.  Returns a
151    tuple of LineTableEntry objects associated with this line from the
152    in the line table.  */
153 
154 static PyObject *
155 ltpy_get_pcs_for_line (PyObject *self, PyObject *args)
156 {
157   struct symtab *symtab;
158   gdb_py_longest py_line;
159   struct linetable_entry *best_entry = NULL;
160   std::vector<CORE_ADDR> pcs;
161 
162   LTPY_REQUIRE_VALID (self, symtab);
163 
164   if (! PyArg_ParseTuple (args, GDB_PY_LL_ARG, &py_line))
165     return NULL;
166 
167   try
168     {
169       pcs = find_pcs_for_symtab_line (symtab, py_line, &best_entry);
170     }
171   catch (const gdb_exception &except)
172     {
173       GDB_PY_HANDLE_EXCEPTION (except);
174     }
175 
176   return build_line_table_tuple_from_pcs (py_line, pcs);
177 }
178 
179 /* Implementation of gdb.LineTable.has_line (self, line) -> Boolean.
180    Returns a Python Boolean indicating whether a source line has any
181    line table entries corresponding to it.  */
182 
183 static PyObject *
184 ltpy_has_line (PyObject *self, PyObject *args)
185 {
186   struct symtab *symtab;
187   gdb_py_longest py_line;
188   int index;
189 
190   LTPY_REQUIRE_VALID (self, symtab);
191 
192   if (! PyArg_ParseTuple (args, GDB_PY_LL_ARG, &py_line))
193     return NULL;
194 
195   if (symtab->linetable () == NULL)
196     {
197       PyErr_SetString (PyExc_RuntimeError,
198 		       _("Linetable information not found in symbol table"));
199       return NULL;
200     }
201 
202   for (index = 0; index < symtab->linetable ()->nitems; index++)
203     {
204       struct linetable_entry *item = &(symtab->linetable ()->item[index]);
205       if (item->line == py_line)
206 	  Py_RETURN_TRUE;
207     }
208 
209   Py_RETURN_FALSE;
210 }
211 
212 /* Implementation of gdb.LineTable.source_lines (self) -> List.
213    Returns a Python List that contains source line entries in the
214    line table.  This function will just return the source lines
215    without corresponding addresses.  */
216 
217 static PyObject *
218 ltpy_get_all_source_lines (PyObject *self, PyObject *args)
219 {
220   struct symtab *symtab;
221   Py_ssize_t index;
222   struct linetable_entry *item;
223 
224   LTPY_REQUIRE_VALID (self, symtab);
225 
226   if (symtab->linetable () == NULL)
227     {
228       PyErr_SetString (PyExc_RuntimeError,
229 		       _("Linetable information not found in symbol table"));
230       return NULL;
231     }
232 
233   gdbpy_ref<> source_dict (PyDict_New ());
234   if (source_dict == NULL)
235     return NULL;
236 
237   for (index = 0; index < symtab->linetable ()->nitems; index++)
238     {
239       item = &(symtab->linetable ()->item[index]);
240 
241       /* 0 is used to signify end of line table information.  Do not
242 	 include in the source set. */
243       if (item->line > 0)
244 	{
245 	  gdbpy_ref<> line = gdb_py_object_from_longest (item->line);
246 
247 	  if (line == NULL)
248 	    return NULL;
249 
250 	  if (PyDict_SetItem (source_dict.get (), line.get (), Py_None) == -1)
251 	    return NULL;
252 	}
253     }
254 
255   return PyDict_Keys (source_dict.get ());
256 }
257 
258 /* Implementation of gdb.LineTable.is_valid (self) -> Boolean.
259    Returns True if this line table object still exists in GDB.  */
260 
261 static PyObject *
262 ltpy_is_valid (PyObject *self, PyObject *args)
263 {
264   struct symtab *symtab = NULL;
265 
266   symtab = symtab_object_to_symtab (get_symtab (self));
267 
268   if (symtab == NULL)
269     Py_RETURN_FALSE;
270 
271   Py_RETURN_TRUE;
272 }
273 
274 /* Deconstructor for the line table object.  Decrement the reference
275    to the symbol table object before calling the default free.  */
276 
277 static void
278 ltpy_dealloc (PyObject *self)
279 {
280   linetable_object *obj = (linetable_object *) self;
281 
282   Py_DECREF (obj->symtab);
283   Py_TYPE (self)->tp_free (self);
284 }
285 
286 /* Initialize LineTable, LineTableEntry and LineTableIterator
287    objects.  */
288 
289 int
290 gdbpy_initialize_linetable (void)
291 {
292   if (PyType_Ready (&linetable_object_type) < 0)
293     return -1;
294   if (PyType_Ready (&linetable_entry_object_type) < 0)
295     return -1;
296   if (PyType_Ready (&ltpy_iterator_object_type) < 0)
297     return -1;
298 
299   Py_INCREF (&linetable_object_type);
300   Py_INCREF (&linetable_entry_object_type);
301   Py_INCREF (&ltpy_iterator_object_type);
302 
303   if (gdb_pymodule_addobject (gdb_module, "LineTable",
304 			      (PyObject *) &linetable_object_type) < 0)
305     return -1;
306 
307   if (gdb_pymodule_addobject (gdb_module, "LineTableEntry",
308 			      (PyObject *) &linetable_entry_object_type) < 0)
309     return -1;
310 
311   if (gdb_pymodule_addobject (gdb_module, "LineTableIterator",
312 			      (PyObject *) &ltpy_iterator_object_type) < 0)
313     return -1;
314 
315   return 0;
316 }
317 
318 /* LineTable entry object get functions.  */
319 
320 /* Implementation of gdb.LineTableEntry.line (self) -> Long.  Returns
321    a long integer associated with the line table entry.  */
322 
323 static PyObject *
324 ltpy_entry_get_line (PyObject *self, void *closure)
325 {
326   linetable_entry_object *obj = (linetable_entry_object *) self;
327 
328   return gdb_py_object_from_longest (obj->line).release ();
329 }
330 
331 /* Implementation of gdb.LineTableEntry.pc (self) -> Long.  Returns a
332    a long integer associated with the PC of the line table entry.  */
333 
334 static PyObject *
335 ltpy_entry_get_pc (PyObject *self, void *closure)
336 {
337   linetable_entry_object *obj = (linetable_entry_object *) self;
338 
339   return gdb_py_object_from_ulongest (obj->pc).release ();
340 }
341 
342 /* LineTable iterator functions.  */
343 
344 /* Return a new line table iterator.  */
345 
346 static PyObject *
347 ltpy_iter (PyObject *self)
348 {
349   ltpy_iterator_object *ltpy_iter_obj;
350   struct symtab *symtab = NULL;
351 
352   LTPY_REQUIRE_VALID (self, symtab);
353 
354   ltpy_iter_obj = PyObject_New (ltpy_iterator_object,
355 				&ltpy_iterator_object_type);
356   if (ltpy_iter_obj == NULL)
357     return NULL;
358 
359   ltpy_iter_obj->current_index = 0;
360   ltpy_iter_obj->source = self;
361 
362   Py_INCREF (self);
363   return (PyObject *) ltpy_iter_obj;
364 }
365 
366 static void
367 ltpy_iterator_dealloc (PyObject *obj)
368 {
369   ltpy_iterator_object *iter_obj = (ltpy_iterator_object *) obj;
370 
371   Py_DECREF (iter_obj->source);
372   Py_TYPE (obj)->tp_free (obj);
373 }
374 
375 /* Return a reference to the line table iterator.  */
376 
377 static PyObject *
378 ltpy_iterator (PyObject *self)
379 {
380   ltpy_iterator_object *iter_obj = (ltpy_iterator_object *) self;
381   struct symtab *symtab;
382 
383   LTPY_REQUIRE_VALID (iter_obj->source, symtab);
384 
385   Py_INCREF (self);
386   return self;
387 }
388 
389 /* Return the next line table entry in the iteration through the line
390    table data structure.  */
391 
392 static PyObject *
393 ltpy_iternext (PyObject *self)
394 {
395   ltpy_iterator_object *iter_obj = (ltpy_iterator_object *) self;
396   struct symtab *symtab;
397   PyObject *obj;
398   struct linetable_entry *item;
399 
400   LTPY_REQUIRE_VALID (iter_obj->source, symtab);
401 
402   if (iter_obj->current_index >= symtab->linetable ()->nitems)
403     {
404       PyErr_SetNone (PyExc_StopIteration);
405       return NULL;
406     }
407 
408   item = &(symtab->linetable ()->item[iter_obj->current_index]);
409 
410   /* Skip over internal entries such as 0.  0 signifies the end of
411      line table data and is not useful to the API user.  */
412   while (item->line < 1)
413     {
414       iter_obj->current_index++;
415 
416       /* Exit if the internal value is the last item in the line table.  */
417       if (iter_obj->current_index >= symtab->linetable ()->nitems)
418 	{
419 	  PyErr_SetNone (PyExc_StopIteration);
420 	  return NULL;
421 	}
422       item = &(symtab->linetable ()->item[iter_obj->current_index]);
423     }
424 
425   obj = build_linetable_entry (item->line, item->pc);
426   iter_obj->current_index++;
427 
428   return obj;
429 }
430 
431 /* Implementation of gdb.LineTableIterator.is_valid (self) -> Boolean.
432    Returns True if this line table iterator object still exists in
433    GDB.  */
434 
435 static PyObject *
436 ltpy_iter_is_valid (PyObject *self, PyObject *args)
437 {
438   struct symtab *symtab = NULL;
439   ltpy_iterator_object *iter_obj = (ltpy_iterator_object *) self;
440 
441   symtab = symtab_object_to_symtab (get_symtab (iter_obj->source));
442 
443   if (symtab == NULL)
444     Py_RETURN_FALSE;
445 
446   Py_RETURN_TRUE;
447 }
448 
449 
450 
451 static PyMethodDef linetable_object_methods[] = {
452   { "line", ltpy_get_pcs_for_line, METH_VARARGS,
453     "line (lineno) -> Tuple\n\
454 Return executable locations for a given source line." },
455   { "has_line", ltpy_has_line, METH_VARARGS,
456     "has_line (lineno) -> Boolean\n\
457 Return TRUE if this line has executable information, FALSE if not." },
458   { "source_lines", ltpy_get_all_source_lines, METH_NOARGS,
459     "source_lines () -> List\n\
460 Return a list of all executable source lines." },
461   { "is_valid", ltpy_is_valid, METH_NOARGS,
462     "is_valid () -> Boolean.\n\
463 Return True if this LineTable is valid, False if not." },
464   {NULL}  /* Sentinel */
465 };
466 
467 PyTypeObject linetable_object_type = {
468   PyVarObject_HEAD_INIT (NULL, 0)
469   "gdb.LineTable",	          /*tp_name*/
470   sizeof (linetable_object),	  /*tp_basicsize*/
471   0,				  /*tp_itemsize*/
472   ltpy_dealloc,                   /*tp_dealloc*/
473   0,				  /*tp_print*/
474   0,				  /*tp_getattr*/
475   0,				  /*tp_setattr*/
476   0,				  /*tp_compare*/
477   0,				  /*tp_repr*/
478   0,				  /*tp_as_number*/
479   0,				  /*tp_as_sequence*/
480   0,				  /*tp_as_mapping*/
481   0,				  /*tp_hash */
482   0,				  /*tp_call*/
483   0,				  /*tp_str*/
484   0,				  /*tp_getattro*/
485   0,				  /*tp_setattro*/
486   0,				  /*tp_as_buffer*/
487   Py_TPFLAGS_DEFAULT,             /*tp_flags*/
488   "GDB line table object",	  /* tp_doc */
489   0,				  /* tp_traverse */
490   0,				  /* tp_clear */
491   0,				  /* tp_richcompare */
492   0,				  /* tp_weaklistoffset */
493   ltpy_iter,			  /* tp_iter */
494   0,				  /* tp_iternext */
495   linetable_object_methods,	  /* tp_methods */
496   0,				  /* tp_members */
497   0,	                          /* tp_getset */
498   0,				  /* tp_base */
499   0,				  /* tp_dict */
500   0,				  /* tp_descr_get */
501   0,				  /* tp_descr_set */
502   0,				  /* tp_dictoffset */
503   0,    			  /* tp_init */
504   0,				  /* tp_alloc */
505 };
506 
507 static PyMethodDef ltpy_iterator_methods[] = {
508   { "is_valid", ltpy_iter_is_valid, METH_NOARGS,
509     "is_valid () -> Boolean.\n\
510 Return True if this LineTable iterator is valid, False if not." },
511   {NULL}  /* Sentinel */
512 };
513 
514 PyTypeObject ltpy_iterator_object_type = {
515   PyVarObject_HEAD_INIT (NULL, 0)
516   "gdb.LineTableIterator",		  /*tp_name*/
517   sizeof (ltpy_iterator_object),  /*tp_basicsize*/
518   0,				  /*tp_itemsize*/
519   ltpy_iterator_dealloc,	  /*tp_dealloc*/
520   0,				  /*tp_print*/
521   0,				  /*tp_getattr*/
522   0,				  /*tp_setattr*/
523   0,				  /*tp_compare*/
524   0,				  /*tp_repr*/
525   0,				  /*tp_as_number*/
526   0,				  /*tp_as_sequence*/
527   0,				  /*tp_as_mapping*/
528   0,				  /*tp_hash */
529   0,				  /*tp_call*/
530   0,				  /*tp_str*/
531   0,				  /*tp_getattro*/
532   0,				  /*tp_setattro*/
533   0,				  /*tp_as_buffer*/
534   Py_TPFLAGS_DEFAULT,		  /*tp_flags*/
535   "GDB line table iterator object",	      /*tp_doc */
536   0,				  /*tp_traverse */
537   0,				  /*tp_clear */
538   0,				  /*tp_richcompare */
539   0,				  /*tp_weaklistoffset */
540   ltpy_iterator,                  /*tp_iter */
541   ltpy_iternext,	          /*tp_iternext */
542   ltpy_iterator_methods           /*tp_methods */
543 };
544 
545 
546 static gdb_PyGetSetDef linetable_entry_object_getset[] = {
547   { "line", ltpy_entry_get_line, NULL,
548     "The line number in the source file.", NULL },
549   { "pc", ltpy_entry_get_pc, NULL,
550     "The memory address for this line number.", NULL },
551   { NULL }  /* Sentinel */
552 };
553 
554 PyTypeObject linetable_entry_object_type = {
555   PyVarObject_HEAD_INIT (NULL, 0)
556   "gdb.LineTableEntry",	          /*tp_name*/
557   sizeof (linetable_entry_object), /*tp_basicsize*/
558   0,				  /*tp_itemsize*/
559   0,                              /*tp_dealloc*/
560   0,				  /*tp_print*/
561   0,				  /*tp_getattr*/
562   0,				  /*tp_setattr*/
563   0,				  /*tp_compare*/
564   0,				  /*tp_repr*/
565   0,				  /*tp_as_number*/
566   0,				  /*tp_as_sequence*/
567   0,				  /*tp_as_mapping*/
568   0,				  /*tp_hash */
569   0,				  /*tp_call*/
570   0,				  /*tp_str*/
571   0,				  /*tp_getattro*/
572   0,				  /*tp_setattro*/
573   0,				  /*tp_as_buffer*/
574   Py_TPFLAGS_DEFAULT,             /*tp_flags*/
575   "GDB line table entry object",  /* tp_doc */
576   0,				  /* tp_traverse */
577   0,				  /* tp_clear */
578   0,				  /* tp_richcompare */
579   0,				  /* tp_weaklistoffset */
580   0,			          /* tp_iter */
581   0,				  /* tp_iternext */
582   0,                              /* tp_methods */
583   0,				  /* tp_members */
584   linetable_entry_object_getset,  /* tp_getset */
585   0,				  /* tp_base */
586   0,				  /* tp_dict */
587   0,				  /* tp_descr_get */
588   0,				  /* tp_descr_set */
589   0,				  /* tp_dictoffset */
590   0,	                          /* tp_init */
591   0,				  /* tp_alloc */
592 };
593