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