Home | History | Annotate | Line # | Download | only in python
py-linetable.c revision 1.8
      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 
    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 | Py_TPFLAGS_HAVE_ITER,  /*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