xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/python/py-linetable.c (revision 627f7eb200a4419d89b531d55fccd2ee3ffdcde0)
1 /* Python interface to line tables.
2 
3    Copyright (C) 2013-2019 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 typedef struct {
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 } linetable_entry_object;
30 
31 extern PyTypeObject linetable_entry_object_type
32     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("linetable_entry_object");
33 
34 typedef struct {
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 } linetable_object;
41 
42 extern PyTypeObject linetable_object_type
43     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("linetable_object");
44 
45 typedef struct {
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 } ltpy_iterator_object;
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 (except, RETURN_MASK_ALL)
172     {
173       GDB_PY_HANDLE_EXCEPTION (except);
174     }
175   END_CATCH
176 
177   return build_line_table_tuple_from_pcs (py_line, pcs);
178 }
179 
180 /* Implementation of gdb.LineTable.has_line (self, line) -> Boolean.
181    Returns a Python Boolean indicating whether a source line has any
182    line table entries corresponding to it.  */
183 
184 static PyObject *
185 ltpy_has_line (PyObject *self, PyObject *args)
186 {
187   struct symtab *symtab;
188   gdb_py_longest py_line;
189   int index;
190 
191   LTPY_REQUIRE_VALID (self, symtab);
192 
193   if (! PyArg_ParseTuple (args, GDB_PY_LL_ARG, &py_line))
194     return NULL;
195 
196   if (SYMTAB_LINETABLE (symtab) == NULL)
197     {
198       PyErr_SetString (PyExc_RuntimeError,
199 		       _("Linetable information not found in symbol table"));
200       return NULL;
201     }
202 
203   for (index = 0; index < SYMTAB_LINETABLE (symtab)->nitems; index++)
204     {
205       struct linetable_entry *item = &(SYMTAB_LINETABLE (symtab)->item[index]);
206       if (item->line == py_line)
207 	  Py_RETURN_TRUE;
208     }
209 
210   Py_RETURN_FALSE;
211 }
212 
213 /* Implementation of gdb.LineTable.source_lines (self) -> List.
214    Returns a Python List that contains source line entries in the
215    line table.  This function will just return the source lines
216    without corresponding addresses.  */
217 
218 static PyObject *
219 ltpy_get_all_source_lines (PyObject *self, PyObject *args)
220 {
221   struct symtab *symtab;
222   Py_ssize_t index;
223   struct linetable_entry *item;
224 
225   LTPY_REQUIRE_VALID (self, symtab);
226 
227   if (SYMTAB_LINETABLE (symtab) == NULL)
228     {
229       PyErr_SetString (PyExc_RuntimeError,
230 		       _("Linetable information not found in symbol table"));
231       return NULL;
232     }
233 
234   gdbpy_ref<> source_dict (PyDict_New ());
235   if (source_dict == NULL)
236     return NULL;
237 
238   for (index = 0; index < SYMTAB_LINETABLE (symtab)->nitems; index++)
239     {
240       item = &(SYMTAB_LINETABLE (symtab)->item[index]);
241 
242       /* 0 is used to signify end of line table information.  Do not
243 	 include in the source set. */
244       if (item->line > 0)
245 	{
246 	  gdbpy_ref<> line = gdb_py_object_from_longest (item->line);
247 
248 	  if (line == NULL)
249 	    return NULL;
250 
251 	  if (PyDict_SetItem (source_dict.get (), line.get (), Py_None) == -1)
252 	    return NULL;
253 	}
254     }
255 
256   return PyDict_Keys (source_dict.get ());
257 }
258 
259 /* Implementation of gdb.LineTable.is_valid (self) -> Boolean.
260    Returns True if this line table object still exists in GDB.  */
261 
262 static PyObject *
263 ltpy_is_valid (PyObject *self, PyObject *args)
264 {
265   struct symtab *symtab = NULL;
266 
267   symtab = symtab_object_to_symtab (get_symtab (self));
268 
269   if (symtab == NULL)
270     Py_RETURN_FALSE;
271 
272   Py_RETURN_TRUE;
273 }
274 
275 /* Deconstructor for the line table object.  Decrement the reference
276    to the symbol table object before calling the default free.  */
277 
278 static void
279 ltpy_dealloc (PyObject *self)
280 {
281   linetable_object *obj = (linetable_object *) self;
282 
283   Py_DECREF (obj->symtab);
284   Py_TYPE (self)->tp_free (self);
285 }
286 
287 /* Initialize LineTable, LineTableEntry and LineTableIterator
288    objects.  */
289 
290 int
291 gdbpy_initialize_linetable (void)
292 {
293   if (PyType_Ready (&linetable_object_type) < 0)
294     return -1;
295   if (PyType_Ready (&linetable_entry_object_type) < 0)
296     return -1;
297   if (PyType_Ready (&ltpy_iterator_object_type) < 0)
298     return -1;
299 
300   Py_INCREF (&linetable_object_type);
301   Py_INCREF (&linetable_entry_object_type);
302   Py_INCREF (&ltpy_iterator_object_type);
303 
304   if (gdb_pymodule_addobject (gdb_module, "LineTable",
305 			      (PyObject *) &linetable_object_type) < 0)
306     return -1;
307 
308   if (gdb_pymodule_addobject (gdb_module, "LineTableEntry",
309 			      (PyObject *) &linetable_entry_object_type) < 0)
310     return -1;
311 
312   if (gdb_pymodule_addobject (gdb_module, "LineTableIterator",
313 			      (PyObject *) &ltpy_iterator_object_type) < 0)
314     return -1;
315 
316   return 0;
317 }
318 
319 /* LineTable entry object get functions.  */
320 
321 /* Implementation of gdb.LineTableEntry.line (self) -> Long.  Returns
322    a long integer associated with the line table entry.  */
323 
324 static PyObject *
325 ltpy_entry_get_line (PyObject *self, void *closure)
326 {
327   linetable_entry_object *obj = (linetable_entry_object *) self;
328 
329   return gdb_py_object_from_longest (obj->line).release ();
330 }
331 
332 /* Implementation of gdb.LineTableEntry.pc (self) -> Long.  Returns a
333    a long integer associated with the PC of the line table entry.  */
334 
335 static PyObject *
336 ltpy_entry_get_pc (PyObject *self, void *closure)
337 {
338   linetable_entry_object *obj = (linetable_entry_object *) self;
339 
340   return  gdb_py_object_from_longest (obj->pc).release ();
341 }
342 
343 /* LineTable iterator functions.  */
344 
345 /* Return a new line table iterator.  */
346 
347 static PyObject *
348 ltpy_iter (PyObject *self)
349 {
350   ltpy_iterator_object *ltpy_iter_obj;
351   struct symtab *symtab = NULL;
352 
353   LTPY_REQUIRE_VALID (self, symtab);
354 
355   ltpy_iter_obj = PyObject_New (ltpy_iterator_object,
356 				&ltpy_iterator_object_type);
357   if (ltpy_iter_obj == NULL)
358     return NULL;
359 
360   ltpy_iter_obj->current_index = 0;
361   ltpy_iter_obj->source = self;
362 
363   Py_INCREF (self);
364   return (PyObject *) ltpy_iter_obj;
365 }
366 
367 static void
368 ltpy_iterator_dealloc (PyObject *obj)
369 {
370   ltpy_iterator_object *iter_obj = (ltpy_iterator_object *) obj;
371 
372   Py_DECREF (iter_obj->source);
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 (symtab)->nitems)
403     {
404       PyErr_SetNone (PyExc_StopIteration);
405       return NULL;
406     }
407 
408   item = &(SYMTAB_LINETABLE (symtab)->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 (symtab)->nitems)
418 	{
419 	  PyErr_SetNone (PyExc_StopIteration);
420 	  return NULL;
421 	}
422       item = &(SYMTAB_LINETABLE (symtab)->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 | Py_TPFLAGS_HAVE_ITER,  /*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