| /* Python interface to line tables. | 
 |  | 
 |    Copyright (C) 2013-2021 Free Software Foundation, Inc. | 
 |  | 
 |    This file is part of GDB. | 
 |  | 
 |    This program is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3 of the License, or | 
 |    (at your option) any later version. | 
 |  | 
 |    This program is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |    GNU General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #include "defs.h" | 
 | #include "python-internal.h" | 
 |  | 
 | struct linetable_entry_object { | 
 |   PyObject_HEAD | 
 |   /* The line table source line.  */ | 
 |   int line; | 
 |   /* The pc associated with the source line.  */ | 
 |   CORE_ADDR pc; | 
 | }; | 
 |  | 
 | extern PyTypeObject linetable_entry_object_type | 
 |     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("linetable_entry_object"); | 
 |  | 
 | struct linetable_object { | 
 |   PyObject_HEAD | 
 |   /* The symtab python object.  We store the Python object here as the | 
 |      underlying symtab can become invalid, and we have to run validity | 
 |      checks on it.  */ | 
 |   PyObject *symtab; | 
 | }; | 
 |  | 
 | extern PyTypeObject linetable_object_type | 
 |     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("linetable_object"); | 
 |  | 
 | struct ltpy_iterator_object { | 
 |   PyObject_HEAD | 
 |   /* The current entry in the line table for the iterator  */ | 
 |   int current_index; | 
 |   /* Pointer back to the original source line table object.  Needed to | 
 |      check if the line table is still valid, and has not been invalidated | 
 |      when an object file has been freed.  */ | 
 |   PyObject *source; | 
 | }; | 
 |  | 
 | extern PyTypeObject ltpy_iterator_object_type | 
 |     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("ltpy_iterator_object"); | 
 |  | 
 | /* Internal helper function to extract gdb.Symtab from a gdb.LineTable | 
 |    object.  */ | 
 |  | 
 | static PyObject * | 
 | get_symtab (PyObject *linetable) | 
 | { | 
 |   linetable_object *lt = (linetable_object *) linetable; | 
 |  | 
 |   return lt->symtab; | 
 | } | 
 |  | 
 | #define LTPY_REQUIRE_VALID(lt_obj, symtab)				\ | 
 |   do {									\ | 
 |     symtab = symtab_object_to_symtab (get_symtab (lt_obj));		\ | 
 |     if (symtab == NULL)							\ | 
 |       {									\ | 
 | 	  PyErr_SetString (PyExc_RuntimeError,				\ | 
 | 			   _("Symbol Table in line table is invalid."));\ | 
 | 	  return NULL;							\ | 
 | 	}								\ | 
 |   } while (0) | 
 |  | 
 |  | 
 | /* Helper function to create a line table object that wraps a | 
 |    gdb.Symtab object.  */ | 
 |  | 
 | PyObject * | 
 | symtab_to_linetable_object (PyObject *symtab) | 
 | { | 
 |   linetable_object *ltable; | 
 |  | 
 |   ltable = PyObject_New (linetable_object, &linetable_object_type); | 
 |   if (ltable != NULL) | 
 |     { | 
 |       ltable->symtab = symtab; | 
 |       Py_INCREF (symtab); | 
 |     } | 
 |   return (PyObject *) ltable; | 
 | } | 
 |  | 
 | /* Internal helper function to build a line table object from a line | 
 |    and an address.  */ | 
 |  | 
 | static PyObject * | 
 | build_linetable_entry (int line, CORE_ADDR address) | 
 | { | 
 |   linetable_entry_object *obj; | 
 |  | 
 |   obj = PyObject_New (linetable_entry_object, | 
 | 		      &linetable_entry_object_type); | 
 |   if (obj != NULL) | 
 |     { | 
 |       obj->line = line; | 
 |       obj->pc = address; | 
 |     } | 
 |  | 
 |   return (PyObject *) obj; | 
 | } | 
 |  | 
 | /* Internal helper function to build a Python Tuple from a vector. | 
 |    A line table entry can have multiple PCs for a given source line. | 
 |    Construct a Tuple of all entries for the given source line, LINE | 
 |    from the line table PCS.  Construct one line table entry object per | 
 |    address.  */ | 
 |  | 
 | static PyObject * | 
 | build_line_table_tuple_from_pcs (int line, const std::vector<CORE_ADDR> &pcs) | 
 | { | 
 |   int i; | 
 |  | 
 |   if (pcs.size () < 1) | 
 |     Py_RETURN_NONE; | 
 |  | 
 |   gdbpy_ref<> tuple (PyTuple_New (pcs.size ())); | 
 |  | 
 |   if (tuple == NULL) | 
 |     return NULL; | 
 |  | 
 |   for (i = 0; i < pcs.size (); ++i) | 
 |     { | 
 |       CORE_ADDR pc = pcs[i]; | 
 |       gdbpy_ref<> obj (build_linetable_entry (line, pc)); | 
 |  | 
 |       if (obj == NULL) | 
 | 	return NULL; | 
 |       else if (PyTuple_SetItem (tuple.get (), i, obj.release ()) != 0) | 
 | 	return NULL; | 
 |     } | 
 |  | 
 |   return tuple.release (); | 
 | } | 
 |  | 
 | /* Implementation of gdb.LineTable.line (self) -> Tuple.  Returns a | 
 |    tuple of LineTableEntry objects associated with this line from the | 
 |    in the line table.  */ | 
 |  | 
 | static PyObject * | 
 | ltpy_get_pcs_for_line (PyObject *self, PyObject *args) | 
 | { | 
 |   struct symtab *symtab; | 
 |   gdb_py_longest py_line; | 
 |   struct linetable_entry *best_entry = NULL; | 
 |   std::vector<CORE_ADDR> pcs; | 
 |  | 
 |   LTPY_REQUIRE_VALID (self, symtab); | 
 |  | 
 |   if (! PyArg_ParseTuple (args, GDB_PY_LL_ARG, &py_line)) | 
 |     return NULL; | 
 |  | 
 |   try | 
 |     { | 
 |       pcs = find_pcs_for_symtab_line (symtab, py_line, &best_entry); | 
 |     } | 
 |   catch (const gdb_exception &except) | 
 |     { | 
 |       GDB_PY_HANDLE_EXCEPTION (except); | 
 |     } | 
 |  | 
 |   return build_line_table_tuple_from_pcs (py_line, pcs); | 
 | } | 
 |  | 
 | /* Implementation of gdb.LineTable.has_line (self, line) -> Boolean. | 
 |    Returns a Python Boolean indicating whether a source line has any | 
 |    line table entries corresponding to it.  */ | 
 |  | 
 | static PyObject * | 
 | ltpy_has_line (PyObject *self, PyObject *args) | 
 | { | 
 |   struct symtab *symtab; | 
 |   gdb_py_longest py_line; | 
 |   int index; | 
 |  | 
 |   LTPY_REQUIRE_VALID (self, symtab); | 
 |  | 
 |   if (! PyArg_ParseTuple (args, GDB_PY_LL_ARG, &py_line)) | 
 |     return NULL; | 
 |  | 
 |   if (SYMTAB_LINETABLE (symtab) == NULL) | 
 |     { | 
 |       PyErr_SetString (PyExc_RuntimeError, | 
 | 		       _("Linetable information not found in symbol table")); | 
 |       return NULL; | 
 |     } | 
 |  | 
 |   for (index = 0; index < SYMTAB_LINETABLE (symtab)->nitems; index++) | 
 |     { | 
 |       struct linetable_entry *item = &(SYMTAB_LINETABLE (symtab)->item[index]); | 
 |       if (item->line == py_line) | 
 | 	  Py_RETURN_TRUE; | 
 |     } | 
 |  | 
 |   Py_RETURN_FALSE; | 
 | } | 
 |  | 
 | /* Implementation of gdb.LineTable.source_lines (self) -> List. | 
 |    Returns a Python List that contains source line entries in the | 
 |    line table.  This function will just return the source lines | 
 |    without corresponding addresses.  */ | 
 |  | 
 | static PyObject * | 
 | ltpy_get_all_source_lines (PyObject *self, PyObject *args) | 
 | { | 
 |   struct symtab *symtab; | 
 |   Py_ssize_t index; | 
 |   struct linetable_entry *item; | 
 |  | 
 |   LTPY_REQUIRE_VALID (self, symtab); | 
 |  | 
 |   if (SYMTAB_LINETABLE (symtab) == NULL) | 
 |     { | 
 |       PyErr_SetString (PyExc_RuntimeError, | 
 | 		       _("Linetable information not found in symbol table")); | 
 |       return NULL; | 
 |     } | 
 |  | 
 |   gdbpy_ref<> source_dict (PyDict_New ()); | 
 |   if (source_dict == NULL) | 
 |     return NULL; | 
 |  | 
 |   for (index = 0; index < SYMTAB_LINETABLE (symtab)->nitems; index++) | 
 |     { | 
 |       item = &(SYMTAB_LINETABLE (symtab)->item[index]); | 
 |  | 
 |       /* 0 is used to signify end of line table information.  Do not | 
 | 	 include in the source set. */ | 
 |       if (item->line > 0) | 
 | 	{ | 
 | 	  gdbpy_ref<> line = gdb_py_object_from_longest (item->line); | 
 |  | 
 | 	  if (line == NULL) | 
 | 	    return NULL; | 
 |  | 
 | 	  if (PyDict_SetItem (source_dict.get (), line.get (), Py_None) == -1) | 
 | 	    return NULL; | 
 | 	} | 
 |     } | 
 |  | 
 |   return PyDict_Keys (source_dict.get ()); | 
 | } | 
 |  | 
 | /* Implementation of gdb.LineTable.is_valid (self) -> Boolean. | 
 |    Returns True if this line table object still exists in GDB.  */ | 
 |  | 
 | static PyObject * | 
 | ltpy_is_valid (PyObject *self, PyObject *args) | 
 | { | 
 |   struct symtab *symtab = NULL; | 
 |  | 
 |   symtab = symtab_object_to_symtab (get_symtab (self)); | 
 |  | 
 |   if (symtab == NULL) | 
 |     Py_RETURN_FALSE; | 
 |  | 
 |   Py_RETURN_TRUE; | 
 | } | 
 |  | 
 | /* Deconstructor for the line table object.  Decrement the reference | 
 |    to the symbol table object before calling the default free.  */ | 
 |  | 
 | static void | 
 | ltpy_dealloc (PyObject *self) | 
 | { | 
 |   linetable_object *obj = (linetable_object *) self; | 
 |  | 
 |   Py_DECREF (obj->symtab); | 
 |   Py_TYPE (self)->tp_free (self); | 
 | } | 
 |  | 
 | /* Initialize LineTable, LineTableEntry and LineTableIterator | 
 |    objects.  */ | 
 |  | 
 | int | 
 | gdbpy_initialize_linetable (void) | 
 | { | 
 |   if (PyType_Ready (&linetable_object_type) < 0) | 
 |     return -1; | 
 |   if (PyType_Ready (&linetable_entry_object_type) < 0) | 
 |     return -1; | 
 |   if (PyType_Ready (<py_iterator_object_type) < 0) | 
 |     return -1; | 
 |  | 
 |   Py_INCREF (&linetable_object_type); | 
 |   Py_INCREF (&linetable_entry_object_type); | 
 |   Py_INCREF (<py_iterator_object_type); | 
 |  | 
 |   if (gdb_pymodule_addobject (gdb_module, "LineTable", | 
 | 			      (PyObject *) &linetable_object_type) < 0) | 
 |     return -1; | 
 |  | 
 |   if (gdb_pymodule_addobject (gdb_module, "LineTableEntry", | 
 | 			      (PyObject *) &linetable_entry_object_type) < 0) | 
 |     return -1; | 
 |  | 
 |   if (gdb_pymodule_addobject (gdb_module, "LineTableIterator", | 
 | 			      (PyObject *) <py_iterator_object_type) < 0) | 
 |     return -1; | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | /* LineTable entry object get functions.  */ | 
 |  | 
 | /* Implementation of gdb.LineTableEntry.line (self) -> Long.  Returns | 
 |    a long integer associated with the line table entry.  */ | 
 |  | 
 | static PyObject * | 
 | ltpy_entry_get_line (PyObject *self, void *closure) | 
 | { | 
 |   linetable_entry_object *obj = (linetable_entry_object *) self; | 
 |  | 
 |   return gdb_py_object_from_longest (obj->line).release (); | 
 | } | 
 |  | 
 | /* Implementation of gdb.LineTableEntry.pc (self) -> Long.  Returns a | 
 |    a long integer associated with the PC of the line table entry.  */ | 
 |  | 
 | static PyObject * | 
 | ltpy_entry_get_pc (PyObject *self, void *closure) | 
 | { | 
 |   linetable_entry_object *obj = (linetable_entry_object *) self; | 
 |  | 
 |   return gdb_py_object_from_ulongest (obj->pc).release (); | 
 | } | 
 |  | 
 | /* LineTable iterator functions.  */ | 
 |  | 
 | /* Return a new line table iterator.  */ | 
 |  | 
 | static PyObject * | 
 | ltpy_iter (PyObject *self) | 
 | { | 
 |   ltpy_iterator_object *ltpy_iter_obj; | 
 |   struct symtab *symtab = NULL; | 
 |  | 
 |   LTPY_REQUIRE_VALID (self, symtab); | 
 |  | 
 |   ltpy_iter_obj = PyObject_New (ltpy_iterator_object, | 
 | 				<py_iterator_object_type); | 
 |   if (ltpy_iter_obj == NULL) | 
 |     return NULL; | 
 |  | 
 |   ltpy_iter_obj->current_index = 0; | 
 |   ltpy_iter_obj->source = self; | 
 |  | 
 |   Py_INCREF (self); | 
 |   return (PyObject *) ltpy_iter_obj; | 
 | } | 
 |  | 
 | static void | 
 | ltpy_iterator_dealloc (PyObject *obj) | 
 | { | 
 |   ltpy_iterator_object *iter_obj = (ltpy_iterator_object *) obj; | 
 |  | 
 |   Py_DECREF (iter_obj->source); | 
 |   Py_TYPE (obj)->tp_free (obj); | 
 | } | 
 |  | 
 | /* Return a reference to the line table iterator.  */ | 
 |  | 
 | static PyObject * | 
 | ltpy_iterator (PyObject *self) | 
 | { | 
 |   ltpy_iterator_object *iter_obj = (ltpy_iterator_object *) self; | 
 |   struct symtab *symtab; | 
 |  | 
 |   LTPY_REQUIRE_VALID (iter_obj->source, symtab); | 
 |  | 
 |   Py_INCREF (self); | 
 |   return self; | 
 | } | 
 |  | 
 | /* Return the next line table entry in the iteration through the line | 
 |    table data structure.  */ | 
 |  | 
 | static PyObject * | 
 | ltpy_iternext (PyObject *self) | 
 | { | 
 |   ltpy_iterator_object *iter_obj = (ltpy_iterator_object *) self; | 
 |   struct symtab *symtab; | 
 |   PyObject *obj; | 
 |   struct linetable_entry *item; | 
 |  | 
 |   LTPY_REQUIRE_VALID (iter_obj->source, symtab); | 
 |  | 
 |   if (iter_obj->current_index >= SYMTAB_LINETABLE (symtab)->nitems) | 
 |     { | 
 |       PyErr_SetNone (PyExc_StopIteration); | 
 |       return NULL; | 
 |     } | 
 |  | 
 |   item = &(SYMTAB_LINETABLE (symtab)->item[iter_obj->current_index]); | 
 |  | 
 |   /* Skip over internal entries such as 0.  0 signifies the end of | 
 |      line table data and is not useful to the API user.  */ | 
 |   while (item->line < 1) | 
 |     { | 
 |       iter_obj->current_index++; | 
 |  | 
 |       /* Exit if the internal value is the last item in the line table.  */ | 
 |       if (iter_obj->current_index >= SYMTAB_LINETABLE (symtab)->nitems) | 
 | 	{ | 
 | 	  PyErr_SetNone (PyExc_StopIteration); | 
 | 	  return NULL; | 
 | 	} | 
 |       item = &(SYMTAB_LINETABLE (symtab)->item[iter_obj->current_index]); | 
 |     } | 
 |  | 
 |   obj = build_linetable_entry (item->line, item->pc); | 
 |   iter_obj->current_index++; | 
 |  | 
 |   return obj; | 
 | } | 
 |  | 
 | /* Implementation of gdb.LineTableIterator.is_valid (self) -> Boolean. | 
 |    Returns True if this line table iterator object still exists in | 
 |    GDB.  */ | 
 |  | 
 | static PyObject * | 
 | ltpy_iter_is_valid (PyObject *self, PyObject *args) | 
 | { | 
 |   struct symtab *symtab = NULL; | 
 |   ltpy_iterator_object *iter_obj = (ltpy_iterator_object *) self; | 
 |  | 
 |   symtab = symtab_object_to_symtab (get_symtab (iter_obj->source)); | 
 |  | 
 |   if (symtab == NULL) | 
 |     Py_RETURN_FALSE; | 
 |  | 
 |   Py_RETURN_TRUE; | 
 | } | 
 |  | 
 |  | 
 |  | 
 | static PyMethodDef linetable_object_methods[] = { | 
 |   { "line", ltpy_get_pcs_for_line, METH_VARARGS, | 
 |     "line (lineno) -> Tuple\n\ | 
 | Return executable locations for a given source line." }, | 
 |   { "has_line", ltpy_has_line, METH_VARARGS, | 
 |     "has_line (lineno) -> Boolean\n\ | 
 | Return TRUE if this line has executable information, FALSE if not." }, | 
 |   { "source_lines", ltpy_get_all_source_lines, METH_NOARGS, | 
 |     "source_lines () -> List\n\ | 
 | Return a list of all executable source lines." }, | 
 |   { "is_valid", ltpy_is_valid, METH_NOARGS, | 
 |     "is_valid () -> Boolean.\n\ | 
 | Return True if this LineTable is valid, False if not." }, | 
 |   {NULL}  /* Sentinel */ | 
 | }; | 
 |  | 
 | PyTypeObject linetable_object_type = { | 
 |   PyVarObject_HEAD_INIT (NULL, 0) | 
 |   "gdb.LineTable",	          /*tp_name*/ | 
 |   sizeof (linetable_object),	  /*tp_basicsize*/ | 
 |   0,				  /*tp_itemsize*/ | 
 |   ltpy_dealloc,                   /*tp_dealloc*/ | 
 |   0,				  /*tp_print*/ | 
 |   0,				  /*tp_getattr*/ | 
 |   0,				  /*tp_setattr*/ | 
 |   0,				  /*tp_compare*/ | 
 |   0,				  /*tp_repr*/ | 
 |   0,				  /*tp_as_number*/ | 
 |   0,				  /*tp_as_sequence*/ | 
 |   0,				  /*tp_as_mapping*/ | 
 |   0,				  /*tp_hash */ | 
 |   0,				  /*tp_call*/ | 
 |   0,				  /*tp_str*/ | 
 |   0,				  /*tp_getattro*/ | 
 |   0,				  /*tp_setattro*/ | 
 |   0,				  /*tp_as_buffer*/ | 
 |   Py_TPFLAGS_DEFAULT,             /*tp_flags*/ | 
 |   "GDB line table object",	  /* tp_doc */ | 
 |   0,				  /* tp_traverse */ | 
 |   0,				  /* tp_clear */ | 
 |   0,				  /* tp_richcompare */ | 
 |   0,				  /* tp_weaklistoffset */ | 
 |   ltpy_iter,			  /* tp_iter */ | 
 |   0,				  /* tp_iternext */ | 
 |   linetable_object_methods,	  /* tp_methods */ | 
 |   0,				  /* tp_members */ | 
 |   0,	                          /* tp_getset */ | 
 |   0,				  /* tp_base */ | 
 |   0,				  /* tp_dict */ | 
 |   0,				  /* tp_descr_get */ | 
 |   0,				  /* tp_descr_set */ | 
 |   0,				  /* tp_dictoffset */ | 
 |   0,    			  /* tp_init */ | 
 |   0,				  /* tp_alloc */ | 
 | }; | 
 |  | 
 | static PyMethodDef ltpy_iterator_methods[] = { | 
 |   { "is_valid", ltpy_iter_is_valid, METH_NOARGS, | 
 |     "is_valid () -> Boolean.\n\ | 
 | Return True if this LineTable iterator is valid, False if not." }, | 
 |   {NULL}  /* Sentinel */ | 
 | }; | 
 |  | 
 | PyTypeObject ltpy_iterator_object_type = { | 
 |   PyVarObject_HEAD_INIT (NULL, 0) | 
 |   "gdb.LineTableIterator",		  /*tp_name*/ | 
 |   sizeof (ltpy_iterator_object),  /*tp_basicsize*/ | 
 |   0,				  /*tp_itemsize*/ | 
 |   ltpy_iterator_dealloc,	  /*tp_dealloc*/ | 
 |   0,				  /*tp_print*/ | 
 |   0,				  /*tp_getattr*/ | 
 |   0,				  /*tp_setattr*/ | 
 |   0,				  /*tp_compare*/ | 
 |   0,				  /*tp_repr*/ | 
 |   0,				  /*tp_as_number*/ | 
 |   0,				  /*tp_as_sequence*/ | 
 |   0,				  /*tp_as_mapping*/ | 
 |   0,				  /*tp_hash */ | 
 |   0,				  /*tp_call*/ | 
 |   0,				  /*tp_str*/ | 
 |   0,				  /*tp_getattro*/ | 
 |   0,				  /*tp_setattro*/ | 
 |   0,				  /*tp_as_buffer*/ | 
 |   Py_TPFLAGS_DEFAULT,		  /*tp_flags*/ | 
 |   "GDB line table iterator object",	      /*tp_doc */ | 
 |   0,				  /*tp_traverse */ | 
 |   0,				  /*tp_clear */ | 
 |   0,				  /*tp_richcompare */ | 
 |   0,				  /*tp_weaklistoffset */ | 
 |   ltpy_iterator,                  /*tp_iter */ | 
 |   ltpy_iternext,	          /*tp_iternext */ | 
 |   ltpy_iterator_methods           /*tp_methods */ | 
 | }; | 
 |  | 
 |  | 
 | static gdb_PyGetSetDef linetable_entry_object_getset[] = { | 
 |   { "line", ltpy_entry_get_line, NULL, | 
 |     "The line number in the source file.", NULL }, | 
 |   { "pc", ltpy_entry_get_pc, NULL, | 
 |     "The memory address for this line number.", NULL }, | 
 |   { NULL }  /* Sentinel */ | 
 | }; | 
 |  | 
 | PyTypeObject linetable_entry_object_type = { | 
 |   PyVarObject_HEAD_INIT (NULL, 0) | 
 |   "gdb.LineTableEntry",	          /*tp_name*/ | 
 |   sizeof (linetable_entry_object), /*tp_basicsize*/ | 
 |   0,				  /*tp_itemsize*/ | 
 |   0,                              /*tp_dealloc*/ | 
 |   0,				  /*tp_print*/ | 
 |   0,				  /*tp_getattr*/ | 
 |   0,				  /*tp_setattr*/ | 
 |   0,				  /*tp_compare*/ | 
 |   0,				  /*tp_repr*/ | 
 |   0,				  /*tp_as_number*/ | 
 |   0,				  /*tp_as_sequence*/ | 
 |   0,				  /*tp_as_mapping*/ | 
 |   0,				  /*tp_hash */ | 
 |   0,				  /*tp_call*/ | 
 |   0,				  /*tp_str*/ | 
 |   0,				  /*tp_getattro*/ | 
 |   0,				  /*tp_setattro*/ | 
 |   0,				  /*tp_as_buffer*/ | 
 |   Py_TPFLAGS_DEFAULT,             /*tp_flags*/ | 
 |   "GDB line table entry object",  /* tp_doc */ | 
 |   0,				  /* tp_traverse */ | 
 |   0,				  /* tp_clear */ | 
 |   0,				  /* tp_richcompare */ | 
 |   0,				  /* tp_weaklistoffset */ | 
 |   0,			          /* tp_iter */ | 
 |   0,				  /* tp_iternext */ | 
 |   0,                              /* tp_methods */ | 
 |   0,				  /* tp_members */ | 
 |   linetable_entry_object_getset,  /* tp_getset */ | 
 |   0,				  /* tp_base */ | 
 |   0,				  /* tp_dict */ | 
 |   0,				  /* tp_descr_get */ | 
 |   0,				  /* tp_descr_set */ | 
 |   0,				  /* tp_dictoffset */ | 
 |   0,	                          /* tp_init */ | 
 |   0,				  /* tp_alloc */ | 
 | }; |