Home | History | Annotate | Line # | Download | only in python
py-linetable.c revision 1.9.2.1
      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 
    452 static PyMethodDef linetable_object_methods[] = {
    453   { "line", ltpy_get_pcs_for_line, METH_VARARGS,
    454     "line (lineno) -> Tuple\n\
    455 Return executable locations for a given source line." },
    456   { "has_line", ltpy_has_line, METH_VARARGS,
    457     "has_line (lineno) -> Boolean\n\
    458 Return TRUE if this line has executable information, FALSE if not." },
    459   { "source_lines", ltpy_get_all_source_lines, METH_NOARGS,
    460     "source_lines () -> List\n\
    461 Return a list of all executable source lines." },
    462   { "is_valid", ltpy_is_valid, METH_NOARGS,
    463     "is_valid () -> Boolean.\n\
    464 Return True if this LineTable is valid, False if not." },
    465   {NULL}  /* Sentinel */
    466 };
    467 
    468 PyTypeObject linetable_object_type = {
    469   PyVarObject_HEAD_INIT (NULL, 0)
    470   "gdb.LineTable",	          /*tp_name*/
    471   sizeof (linetable_object),	  /*tp_basicsize*/
    472   0,				  /*tp_itemsize*/
    473   ltpy_dealloc,                   /*tp_dealloc*/
    474   0,				  /*tp_print*/
    475   0,				  /*tp_getattr*/
    476   0,				  /*tp_setattr*/
    477   0,				  /*tp_compare*/
    478   0,				  /*tp_repr*/
    479   0,				  /*tp_as_number*/
    480   0,				  /*tp_as_sequence*/
    481   0,				  /*tp_as_mapping*/
    482   0,				  /*tp_hash */
    483   0,				  /*tp_call*/
    484   0,				  /*tp_str*/
    485   0,				  /*tp_getattro*/
    486   0,				  /*tp_setattro*/
    487   0,				  /*tp_as_buffer*/
    488   Py_TPFLAGS_DEFAULT,             /*tp_flags*/
    489   "GDB line table object",	  /* tp_doc */
    490   0,				  /* tp_traverse */
    491   0,				  /* tp_clear */
    492   0,				  /* tp_richcompare */
    493   0,				  /* tp_weaklistoffset */
    494   ltpy_iter,			  /* tp_iter */
    495   0,				  /* tp_iternext */
    496   linetable_object_methods,	  /* tp_methods */
    497   0,				  /* tp_members */
    498   0,	                          /* tp_getset */
    499   0,				  /* tp_base */
    500   0,				  /* tp_dict */
    501   0,				  /* tp_descr_get */
    502   0,				  /* tp_descr_set */
    503   0,				  /* tp_dictoffset */
    504   0,    			  /* tp_init */
    505   0,				  /* tp_alloc */
    506 };
    507 
    508 static PyMethodDef ltpy_iterator_methods[] = {
    509   { "is_valid", ltpy_iter_is_valid, METH_NOARGS,
    510     "is_valid () -> Boolean.\n\
    511 Return True if this LineTable iterator is valid, False if not." },
    512   {NULL}  /* Sentinel */
    513 };
    514 
    515 PyTypeObject ltpy_iterator_object_type = {
    516   PyVarObject_HEAD_INIT (NULL, 0)
    517   "gdb.LineTableIterator",		  /*tp_name*/
    518   sizeof (ltpy_iterator_object),  /*tp_basicsize*/
    519   0,				  /*tp_itemsize*/
    520   ltpy_iterator_dealloc,	  /*tp_dealloc*/
    521   0,				  /*tp_print*/
    522   0,				  /*tp_getattr*/
    523   0,				  /*tp_setattr*/
    524   0,				  /*tp_compare*/
    525   0,				  /*tp_repr*/
    526   0,				  /*tp_as_number*/
    527   0,				  /*tp_as_sequence*/
    528   0,				  /*tp_as_mapping*/
    529   0,				  /*tp_hash */
    530   0,				  /*tp_call*/
    531   0,				  /*tp_str*/
    532   0,				  /*tp_getattro*/
    533   0,				  /*tp_setattro*/
    534   0,				  /*tp_as_buffer*/
    535   Py_TPFLAGS_DEFAULT,		  /*tp_flags*/
    536   "GDB line table iterator object",	      /*tp_doc */
    537   0,				  /*tp_traverse */
    538   0,				  /*tp_clear */
    539   0,				  /*tp_richcompare */
    540   0,				  /*tp_weaklistoffset */
    541   ltpy_iterator,                  /*tp_iter */
    542   ltpy_iternext,	          /*tp_iternext */
    543   ltpy_iterator_methods           /*tp_methods */
    544 };
    545 
    546 
    547 static gdb_PyGetSetDef linetable_entry_object_getset[] = {
    548   { "line", ltpy_entry_get_line, NULL,
    549     "The line number in the source file.", NULL },
    550   { "pc", ltpy_entry_get_pc, NULL,
    551     "The memory address for this line number.", NULL },
    552   { NULL }  /* Sentinel */
    553 };
    554 
    555 PyTypeObject linetable_entry_object_type = {
    556   PyVarObject_HEAD_INIT (NULL, 0)
    557   "gdb.LineTableEntry",	          /*tp_name*/
    558   sizeof (linetable_entry_object), /*tp_basicsize*/
    559   0,				  /*tp_itemsize*/
    560   0,                              /*tp_dealloc*/
    561   0,				  /*tp_print*/
    562   0,				  /*tp_getattr*/
    563   0,				  /*tp_setattr*/
    564   0,				  /*tp_compare*/
    565   0,				  /*tp_repr*/
    566   0,				  /*tp_as_number*/
    567   0,				  /*tp_as_sequence*/
    568   0,				  /*tp_as_mapping*/
    569   0,				  /*tp_hash */
    570   0,				  /*tp_call*/
    571   0,				  /*tp_str*/
    572   0,				  /*tp_getattro*/
    573   0,				  /*tp_setattro*/
    574   0,				  /*tp_as_buffer*/
    575   Py_TPFLAGS_DEFAULT,             /*tp_flags*/
    576   "GDB line table entry object",  /* tp_doc */
    577   0,				  /* tp_traverse */
    578   0,				  /* tp_clear */
    579   0,				  /* tp_richcompare */
    580   0,				  /* tp_weaklistoffset */
    581   0,			          /* tp_iter */
    582   0,				  /* tp_iternext */
    583   0,                              /* tp_methods */
    584   0,				  /* tp_members */
    585   linetable_entry_object_getset,  /* tp_getset */
    586   0,				  /* tp_base */
    587   0,				  /* tp_dict */
    588   0,				  /* tp_descr_get */
    589   0,				  /* tp_descr_set */
    590   0,				  /* tp_dictoffset */
    591   0,	                          /* tp_init */
    592   0,				  /* tp_alloc */
    593 };
    594