public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [patch][python] 1/3 Python representation of GDB line tables (Python code)
@ 2013-10-08 12:04 Phil Muldoon
  2013-10-23 20:46 ` Tom Tromey
  0 siblings, 1 reply; 8+ messages in thread
From: Phil Muldoon @ 2013-10-08 12:04 UTC (permalink / raw)
  To: gdb-patches

This patch series (three emails) introduces GDB line table representation
to Python.

This first email contains the GDB and Python code to represent the line
table data as Python objects.

What do you think?

Cheers,

Phil

2013-10-08  Phil Muldoon  <pmuldoon@redhat.com>

	* Makefile.in (SUBDIR_PYTHON_OBS): Add py-linetable entries.
	* python/py-linetable.c: New file.
	* python/py-symtab.c (stpy_get_linetable): New function.
	* python/python-internal.h (symtab_to_linetable_object): Declare.
	(gdbpy_initialize_linetable): Ditto.
	* python/python.c (_initialize_python): Call
	gdbpy_initialize_linetable.

---

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 6b8927a..53ba8f9 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -296,6 +296,7 @@ SUBDIR_PYTHON_OBS = \
 	py-inferior.o \
 	py-infthread.o \
 	py-lazy-string.o \
+	py-linetable.o \
 	py-newobjfileevent.o \
 	py-objfile.o \
 	py-param.o \
@@ -331,6 +332,7 @@ SUBDIR_PYTHON_SRCS = \
 	python/py-inferior.c \
 	python/py-infthread.c \
 	python/py-lazy-string.c \
+	python/py-linetable.c \
 	python/py-newobjfileevent.c \
 	python/py-objfile.c \
 	python/py-param.c \
@@ -2210,6 +2212,10 @@ py-lazy-string.o: $(srcdir)/python/py-lazy-string.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-lazy-string.c
 	$(POSTCOMPILE)
 
+py-linetable.o: $(srcdir)/python/py-linetable.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-linetable.c
+	$(POSTCOMPILE)
+
 py-newobjfileevent.o: $(srcdir)/python/py-newobjfileevent.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-newobjfileevent.c
 	$(POSTCOMPILE)
diff --git a/gdb/python/py-linetable.c b/gdb/python/py-linetable.c
new file mode 100644
index 0000000..c62c906
--- /dev/null
+++ b/gdb/python/py-linetable.c
@@ -0,0 +1,594 @@
+/* Python interface to line tables.
+
+   Copyright (C) 2013 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"
+#include "exceptions.h"
+
+typedef struct {
+  PyObject_HEAD
+  /* The line table source line.  */
+  gdb_py_longest line;
+  /* The pc associated with the source line.  */
+  CORE_ADDR pc;
+} linetable_entry_object;
+
+static PyTypeObject linetable_entry_object_type
+    CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("linetable_entry_object");
+
+typedef struct {
+  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;
+} linetable_object;
+
+static PyTypeObject linetable_object_type
+    CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("linetable_object");
+
+typedef struct {
+  PyObject_HEAD
+  /* The current entry in the line table for the iterator  */
+  int current_line;
+  /* 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.  Extract from this the symtab
+     in a lazy fashion.  */
+  PyObject *source;
+} ltpy_iterator_object;
+
+static 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 (gdb_py_longest 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 GDB 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 VEC.  Construct one line table entry object per
+   address.  */
+
+static PyObject *
+build_tuple_from_vector (gdb_py_longest line, VEC (CORE_ADDR) *vec)
+{
+  int vec_len = 0;
+  PyObject *tuple;
+  CORE_ADDR pc;
+  int i;
+  volatile struct gdb_exception except;
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      vec_len = VEC_length (CORE_ADDR, vec);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  if (vec_len < 1)
+    return Py_None;
+
+  tuple = PyTuple_New (vec_len);
+
+  if (tuple == NULL)
+    return NULL;
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+
+      for (i = 0; VEC_iterate (CORE_ADDR, vec, i, pc); ++i)
+	{
+	  PyObject *obj = build_linetable_entry (line, pc);
+
+	  if (obj == NULL)
+	    {
+	      Py_DECREF (tuple);
+	      tuple = NULL;
+	      break;
+	    }
+	  else if (PyTuple_SetItem (tuple, i, obj) != 0)
+	    {
+	      Py_DECREF (obj);
+	      Py_XDECREF (tuple);
+	      tuple = NULL;
+	      break;
+	    }
+	}
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  return tuple;
+}
+
+/* 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;
+  linetable_entry_object *result;
+  VEC (CORE_ADDR) *pcs = NULL;
+  PyObject *tuple;
+  volatile struct gdb_exception except;
+
+  LTPY_REQUIRE_VALID (self, symtab);
+
+  if (! PyArg_ParseTuple (args, GDB_PY_LLU_ARG, &py_line))
+    return NULL;
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      pcs = find_pcs_for_symtab_line (symtab, py_line, &best_entry);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  tuple = build_tuple_from_vector (py_line, pcs);
+
+  return tuple;
+}
+
+/* Implementation of gdb.LineTable.has_pcs (self, line) -> Boolean.
+   Returns a Python Boolean indicating whether a source line has any
+   line table entries corresponding to it.  */
+
+static PyObject *
+ltpy_has_pcs (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_LLU_ARG, &py_line))
+    return NULL;
+
+  for (index = 0; index <= symtab->linetable->nitems; index++)
+    {
+      struct linetable_entry *item = &(symtab->linetable->item[index]);
+      if (item->line == py_line)
+	  Py_RETURN_TRUE;
+    }
+
+  Py_RETURN_FALSE;
+}
+
+/* Implementation of gdb.LineTable.source_lines (self) -> FrozenSet.
+   Returns a Python FrozenSet 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;
+  PyObject *source_list, *line, *fset;
+  struct linetable_entry *item;
+
+  LTPY_REQUIRE_VALID (self, symtab);
+
+  source_list = PyList_New (0);
+
+  if (source_list == NULL)
+    return NULL;
+
+  for (index = 0; index <= symtab->linetable->nitems; index++)
+    {
+      item = &(symtab->linetable->item[index]);
+
+      /* 0 is used to signify end of line table information.  Do not
+	 include in the source set. */
+      if (item->line > 0)
+	{
+	  line = PyLong_FromUnsignedLongLong (item->line);
+
+	  if (line == NULL)
+	    {
+	      Py_DECREF (source_list);
+	      return NULL;
+	    }
+
+	  if (PyList_Append (source_list, line) == -1)
+	    {
+	      Py_DECREF (line);
+	      Py_DECREF (source_list);
+	      return NULL;
+	    }
+
+	  Py_DECREF (line);
+	}
+    }
+
+  /* Return a frozen set to remove duplicated line numbers in the case
+     where a source line has more than one instruction and more than one
+     entry in the line table.  */
+  fset = PyFrozenSet_New (source_list);
+  Py_DECREF (source_list);
+
+  return fset;
+}
+
+static void
+ltpy_dealloc (PyObject *self)
+{
+  linetable_object *obj = (linetable_object *) self;
+
+  Py_DECREF (obj->symtab);
+  Py_TYPE (self)->tp_free (self);
+  return;
+}
+
+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 (&ltpy_iterator_object_type) < 0)
+    return -1;
+
+  Py_INCREF (&linetable_object_type);
+  Py_INCREF (&linetable_entry_object_type);
+  Py_INCREF (&ltpy_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 *) &ltpy_iterator_object_type) < 0)
+    return -1;
+
+  return 0;
+}
+
+/* Linetable entry object get functions.  */
+
+/* Implementation of gdb.LineTableEntry.line (self) -> Unsigned Long.
+   Returns an unsigned long 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 PyLong_FromUnsignedLongLong (obj->line);
+}
+
+/* Implementation of gdb.LineTableEntry.pc (self) -> Unsigned Long.
+   Returns an unsigned long associated with the PC of the line table
+   entry.  */
+
+static PyObject *
+ltpy_entry_get_pcs (PyObject *self, void *closure)
+{
+  linetable_entry_object *obj = (linetable_entry_object *) self;
+  return PyLong_FromUnsignedLongLong (obj->pc);
+}
+
+/* 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,
+				&ltpy_iterator_object_type);
+  if (ltpy_iter_obj == NULL)
+      return NULL;
+
+  ltpy_iter_obj->current_line = 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_XDECREF (iter_obj->source);
+}
+
+/* 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;
+  int index;
+  PyObject *obj;
+  struct linetable_entry *item;
+
+  LTPY_REQUIRE_VALID (iter_obj->source, symtab);
+
+  if (iter_obj->current_line >= symtab->linetable->nitems)
+    goto stop_iteration;
+
+  item = &(symtab->linetable->item[iter_obj->current_line]);
+
+  /* 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_line++;
+
+      /* Exit if the internal value is the last item in the line table.  */
+      if (iter_obj->current_line >= symtab->linetable->nitems)
+	goto stop_iteration;
+      item = &(symtab->linetable->item[iter_obj->current_line]);
+    }
+
+  obj = build_linetable_entry (item->line, item->pc);
+  iter_obj->current_line++;
+
+  return obj;
+
+ stop_iteration:
+  PyErr_SetNone (PyExc_StopIteration);
+  return NULL;
+}
+
+/* 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;
+
+  LTPY_REQUIRE_VALID (iter_obj->source, symtab);
+
+  if (symtab == NULL)
+    Py_RETURN_FALSE;
+
+  Py_RETURN_TRUE;
+}
+
+\f
+
+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_pcs", ltpy_has_pcs, METH_VARARGS,
+    "has_pcs (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 () -> FrozenSet\n\
+Return a frozen set of all executable source lines." },
+  {NULL}  /* Sentinel */
+};
+
+static 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 */
+};
+
+static 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 | Py_TPFLAGS_HAVE_ITER,  /*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 PyGetSetDef linetable_entry_object_getset[] = {
+  { "line", ltpy_entry_get_line, NULL,
+    "The line number in the source file.", NULL },
+  { "pc", ltpy_entry_get_pcs, NULL,
+    "The memory address for this line number.", NULL },
+  { NULL }  /* Sentinel */
+};
+
+static 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 */
+};
diff --git a/gdb/python/py-symtab.c b/gdb/python/py-symtab.c
index 006946c..1920b59 100644
--- a/gdb/python/py-symtab.c
+++ b/gdb/python/py-symtab.c
@@ -187,6 +187,16 @@ stpy_static_block (PyObject *self, PyObject *args)
 }
 
 static PyObject *
+stpy_get_linetable (PyObject *self, PyObject *args)
+{
+  struct symtab *symtab = NULL;
+
+  STPY_REQUIRE_VALID (self, symtab);
+
+  return symtab_to_linetable_object (self);
+}
+
+static PyObject *
 salpy_str (PyObject *self)
 {
   char *s;
@@ -532,6 +542,9 @@ Return the global block of the symbol table." },
   { "static_block", stpy_static_block, METH_NOARGS,
     "static_block () -> gdb.Block.\n\
 Return the static block of the symbol table." },
+    { "linetable", stpy_get_linetable, METH_NOARGS,
+    "linetable () -> gdb.Linetable.\n\
+Return the Linetable associated with this symbol table" },
   {NULL}  /* Sentinel */
 };
 
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index d947be6..7d8c4ad 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -311,7 +311,7 @@ PyObject *block_to_block_object (const struct block *block,
 PyObject *value_to_value_object (struct value *v);
 PyObject *type_to_type_object (struct type *);
 PyObject *frame_info_to_frame_object (struct frame_info *frame);
-
+PyObject *symtab_to_linetable_object (PyObject *symtab);`
 PyObject *pspace_to_pspace_object (struct program_space *)
     CPYCHECKER_RETURNS_BORROWED_REF;
 PyObject *pspy_get_printers (PyObject *, void *);
@@ -371,6 +371,8 @@ int gdbpy_initialize_finishbreakpoints (void)
   CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 int gdbpy_initialize_lazy_string (void)
   CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_linetable (void)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 int gdbpy_initialize_parameters (void)
   CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 int gdbpy_initialize_thread (void)
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 00092c7..55fbdcb 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1673,6 +1673,7 @@ message == an error message without a stack will be printed."),
       || gdbpy_initialize_breakpoints () < 0
       || gdbpy_initialize_finishbreakpoints () < 0
       || gdbpy_initialize_lazy_string () < 0
+      || gdbpy_initialize_linetable () < 0
       || gdbpy_initialize_thread () < 0
       || gdbpy_initialize_inferior () < 0
       || gdbpy_initialize_events () < 0
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [patch][python] 1/3 Python representation of GDB line tables (Python code)
  2013-10-08 12:04 [patch][python] 1/3 Python representation of GDB line tables (Python code) Phil Muldoon
@ 2013-10-23 20:46 ` Tom Tromey
  2013-11-07 16:35   ` Phil Muldoon
  0 siblings, 1 reply; 8+ messages in thread
From: Tom Tromey @ 2013-10-23 20:46 UTC (permalink / raw)
  To: Phil Muldoon; +Cc: gdb-patches

>>>>> "Phil" == Phil Muldoon <pmuldoon@redhat.com> writes:

Phil> This patch series (three emails) introduces GDB line table representation
Phil> to Python.

Phil> This first email contains the GDB and Python code to represent the line
Phil> table data as Python objects.

Phil> What do you think?

Thanks, Phil.

Really just nits here.

Phil> +typedef struct {
Phil> +  PyObject_HEAD
Phil> +  /* The symtab python object.  We store the Python object here as the
Phil> +  underlying symtab can become invalid, and we have to run validity
Phil> +  checks on it.  */
Phil> +  PyObject *symtab;

The formatting is wrong in this comment.
Subsequent lines should be indented.

Phil> +     when an object file has been freed.  Extract from this the symtab
Phil> +     in a lazy fashion.  */

This sentence reads strangely.

Phil> +static PyObject *
Phil> +get_symtab (PyObject *linetable)
Phil> +{
Phil> +  linetable_object *lt = (linetable_object *) linetable;
Phil> +  return lt->symtab;

Empty line between declarations and code.

Phil> +  return (PyObject *)ltable;

Space after close paren.

Phil> +static PyObject *
Phil> +build_tuple_from_vector (gdb_py_longest line, VEC (CORE_ADDR) *vec)
Phil> +{
Phil> +  int vec_len = 0;
Phil> +  PyObject *tuple;
Phil> +  CORE_ADDR pc;
Phil> +  int i;
Phil> +  volatile struct gdb_exception except;
Phil> +
Phil> +  TRY_CATCH (except, RETURN_MASK_ALL)
Phil> +    {
Phil> +      vec_len = VEC_length (CORE_ADDR, vec);
Phil> +    }
Phil> +  GDB_PY_HANDLE_EXCEPTION (except);

VEC_length cannot throw, so the exception handling isn't needed here.

Phil> +  if (vec_len < 1)
Phil> +    return Py_None;

Py_RETURN_NONE

Phil> +  TRY_CATCH (except, RETURN_MASK_ALL)
Phil> +    {

I don't think anything in this loop can throw, either.
You can rely on VEC_iterate not throwing.
So I think this TRY_CATCH can be removed as well.

Phil> +	  else if (PyTuple_SetItem (tuple, i, obj) != 0)
Phil> +	    {
Phil> +	      Py_DECREF (obj);
Phil> +	      Py_XDECREF (tuple);

I don't think you need Py_XDECREF here.
Just Py_DECREF will do.  Using Py_XDECREF isn't harmful, but is maybe
mildly confusing as it implies that tuple could possibly be NULL at this
point.

Phil> +static PyObject *
Phil> +ltpy_get_pcs_for_line (PyObject *self, PyObject *args)
...
Phil> +  gdb_py_longest py_line;
...
Phil> +  if (! PyArg_ParseTuple (args, GDB_PY_LLU_ARG, &py_line))
Phil> +    return NULL;

I think this should use GDB_PY_LL_ARG instead, as py_line is signed.

This function never frees the 'pcs' VEC.

Phil> +static PyObject *
Phil> +ltpy_has_pcs (PyObject *self, PyObject *args)
...
Phil> +  if (! PyArg_ParseTuple (args, GDB_PY_LLU_ARG, &py_line))
Phil> +    return NULL;

Ditto for GDB_PY_LL_ARG.

Phil> +  for (index = 0; index <= symtab->linetable->nitems; index++)

I think it's preferred to use the LINETABLE accessor.

This function must account for the possibility that symtab->linetable is
NULL.

Phil> +    {
Phil> +      struct linetable_entry *item = &(symtab->linetable->item[index]);

Accessor.

Phil> +static PyObject *
Phil> +ltpy_get_all_source_lines (PyObject *self, PyObject *args)
Phil> +{
...
Phil> +  for (index = 0; index <= symtab->linetable->nitems; index++)

Accessor plus NULL check.

Phil> +      item = &(symtab->linetable->item[index]);

Accessor.

Phil> +  /* Return a frozen set to remove duplicated line numbers in the case
Phil> +     where a source line has more than one instruction and more than one
Phil> +     entry in the line table.  */
Phil> +  fset = PyFrozenSet_New (source_list);
Phil> +  Py_DECREF (source_list);

PyFrozenSet_New is new in 2.5.

I think it's cheaper, and no more difficult, to just build a set object
from the start rather than make a list and the convert it.  I'm not sure
what to about Python 2.4 though.

Phil> +static void
Phil> +ltpy_dealloc (PyObject *self)

Need some header comment.

Phil> +{
Phil> +  linetable_object *obj = (linetable_object *) self;
Phil> +
Phil> +  Py_DECREF (obj->symtab);
Phil> +  Py_TYPE (self)->tp_free (self);
Phil> +  return;

Don't need that return.

Phil> +int
Phil> +gdbpy_initialize_linetable (void)
Phil> +{

Header comment.

Phil> +static PyObject *
Phil> +ltpy_entry_get_line (PyObject *self, void *closure)
Phil> +{
Phil> +  linetable_entry_object *obj = (linetable_entry_object *) self;
Phil> +  return PyLong_FromUnsignedLongLong (obj->line);
Phil> +}
Phil> +

Blank line between declarations and code.

Phil> +/* Implementation of gdb.LineTableEntry.pc (self) -> Unsigned Long.
Phil> +   Returns an unsigned long associated with the PC of the line table
Phil> +   entry.  */
Phil> +
Phil> +static PyObject *
Phil> +ltpy_entry_get_pcs (PyObject *self, void *closure)
Phil> +{
Phil> +  linetable_entry_object *obj = (linetable_entry_object *) self;
Phil> +  return PyLong_FromUnsignedLongLong (obj->pc);
Phil> +}
Phil> +

Blank line between declarations and code.

Phil> +static PyObject *
Phil> +ltpy_iter (PyObject *self)
...
Phil> +  if (ltpy_iter_obj == NULL)
Phil> +      return NULL;

Wrong indentation.

Phil> +static void
Phil> +ltpy_iterator_dealloc (PyObject *obj)

Header comment.

Phil> +{
Phil> +  ltpy_iterator_object *iter_obj = (ltpy_iterator_object *) obj;
Phil> +
Phil> +  Py_XDECREF (iter_obj->source);

Can this ever be NULL?
If not, s/X//.
If so -- how?

Phil> +static PyObject *
Phil> +ltpy_iternext (PyObject *self)
Phil> +{
...
Phil> +  if (iter_obj->current_line >= symtab->linetable->nitems)
Phil> +    goto stop_iteration;
Phil> +
Phil> +  item = &(symtab->linetable->item[iter_obj->current_line]);

Accessor in two spots.

"current_line" seems to be a misnomer as the value actually seems to
index into the line table.  So it should be "current_index" or something
along those lines.

Phil> +      if (iter_obj->current_line >= symtab->linetable->nitems)
Phil> +	goto stop_iteration;
Phil> +      item = &(symtab->linetable->item[iter_obj->current_line]);

Accessors.

Phil> +static PyObject *
Phil> +ltpy_iter_is_valid (PyObject *self, PyObject *args)
Phil> +{
Phil> +  struct symtab *symtab = NULL;
Phil> +  ltpy_iterator_object *iter_obj = (ltpy_iterator_object *) self;
Phil> +
Phil> +  LTPY_REQUIRE_VALID (iter_obj->source, symtab);

It's wrong to use LTPY_REQUIRE_VALID here.
This function shouldn't throw an exception if the underling object is
invalid; it should just return False.

Phil> +static PyMethodDef linetable_object_methods[] = {

I think a line table should also have an is_valid method.

 
Phil>  static PyObject *
Phil> +stpy_get_linetable (PyObject *self, PyObject *args)
Phil> +{

Header comment.

Tom

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [patch][python] 1/3 Python representation of GDB line tables (Python code)
  2013-10-23 20:46 ` Tom Tromey
@ 2013-11-07 16:35   ` Phil Muldoon
  2013-11-07 17:08     ` Tom Tromey
  2013-11-07 20:42     ` Doug Evans
  0 siblings, 2 replies; 8+ messages in thread
From: Phil Muldoon @ 2013-11-07 16:35 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On 23/10/13 21:46, Tom Tromey wrote:
>>>>>> "Phil" == Phil Muldoon <pmuldoon@redhat.com> writes:
> 
> Phil> This patch series (three emails) introduces GDB line table representation
> Phil> to Python.
> 
> Phil> This first email contains the GDB and Python code to represent the line
> Phil> table data as Python objects.
> 
> Phil> What do you think?
> 
> Thanks, Phil.
> 
> Really just nits here.

Fixed up nits.
 
> Phil> +  /* Return a frozen set to remove duplicated line numbers in the case
> Phil> +     where a source line has more than one instruction and more than one
> Phil> +     entry in the line table.  */
> Phil> +  fset = PyFrozenSet_New (source_list);
> Phil> +  Py_DECREF (source_list);
> 
> PyFrozenSet_New is new in 2.5.
> 
> I think it's cheaper, and no more difficult, to just build a set object
> from the start rather than make a list and the convert it.  I'm not sure
> what to about Python 2.4 though.

All API access to sets is new in 2.5 (sets appeared in the Python
default library in 2.3)

I elected here just to use a dictionary to ensure unique line numbers
only.

Modified patch follows,

Cheers,

Phil

--

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index fc2a3af..85d43f9 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -299,6 +299,7 @@ SUBDIR_PYTHON_OBS = \
 	py-inferior.o \
 	py-infthread.o \
 	py-lazy-string.o \
+	py-linetable.o \
 	py-newobjfileevent.o \
 	py-objfile.o \
 	py-param.o \
@@ -334,6 +335,7 @@ SUBDIR_PYTHON_SRCS = \
 	python/py-inferior.c \
 	python/py-infthread.c \
 	python/py-lazy-string.c \
+	python/py-linetable.c \
 	python/py-newobjfileevent.c \
 	python/py-objfile.c \
 	python/py-param.c \
@@ -2219,6 +2221,10 @@ py-lazy-string.o: $(srcdir)/python/py-lazy-string.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-lazy-string.c
 	$(POSTCOMPILE)
 
+py-linetable.o: $(srcdir)/python/py-linetable.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-linetable.c
+	$(POSTCOMPILE)
+
 py-newobjfileevent.o: $(srcdir)/python/py-newobjfileevent.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-newobjfileevent.c
 	$(POSTCOMPILE)
diff --git a/gdb/NEWS b/gdb/NEWS
index 10834df..c27b7fe 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -35,7 +35,8 @@
 * Python scripting
 
   ** Frame filters and frame decorators have been added.
-
+  ** Linetable representation has been added.
+  
 * New targets
 
 Nios II ELF 			nios2*-*-elf
diff --git a/gdb/python/py-linetable.c b/gdb/python/py-linetable.c
new file mode 100644
index 0000000..9cde481
--- /dev/null
+++ b/gdb/python/py-linetable.c
@@ -0,0 +1,621 @@
+/* Python interface to line tables.
+
+   Copyright (C) 2013 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"
+#include "exceptions.h"
+
+typedef struct {
+  PyObject_HEAD
+  /* The line table source line.  */
+  gdb_py_longest line;
+  /* The pc associated with the source line.  */
+  CORE_ADDR pc;
+} linetable_entry_object;
+
+static PyTypeObject linetable_entry_object_type
+    CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("linetable_entry_object");
+
+typedef struct {
+  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;
+} linetable_object;
+
+static PyTypeObject linetable_object_type
+    CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("linetable_object");
+
+typedef struct {
+  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;
+} ltpy_iterator_object;
+
+static 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 (gdb_py_longest 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 GDB 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 VEC.  Construct one line table entry object per
+   address.  */
+
+static PyObject *
+build_tuple_from_vector (gdb_py_longest line, VEC (CORE_ADDR) *vec)
+{
+  int vec_len = 0;
+  PyObject *tuple;
+  CORE_ADDR pc;
+  int i;
+
+  vec_len = VEC_length (CORE_ADDR, vec);
+  if (vec_len < 1)
+    Py_RETURN_NONE;
+
+  tuple = PyTuple_New (vec_len);
+
+  if (tuple == NULL)
+    return NULL;
+
+  for (i = 0; VEC_iterate (CORE_ADDR, vec, i, pc); ++i)
+    {
+      PyObject *obj = build_linetable_entry (line, pc);
+
+      if (obj == NULL)
+	{
+	  Py_DECREF (tuple);
+	  tuple = NULL;
+	  break;
+	}
+      else if (PyTuple_SetItem (tuple, i, obj) != 0)
+	{
+	  Py_DECREF (obj);
+	  Py_DECREF (tuple);
+	  tuple = NULL;
+	  break;
+	}
+    }
+
+  return tuple;
+}
+
+/* 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;
+  linetable_entry_object *result;
+  VEC (CORE_ADDR) *pcs = NULL;
+  PyObject *tuple;
+  volatile struct gdb_exception except;
+
+  LTPY_REQUIRE_VALID (self, symtab);
+
+  if (! PyArg_ParseTuple (args, GDB_PY_LL_ARG, &py_line))
+    return NULL;
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      pcs = find_pcs_for_symtab_line (symtab, py_line, &best_entry);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  tuple = build_tuple_from_vector (py_line, pcs);
+  VEC_free (CORE_ADDR, pcs);
+
+  return tuple;
+}
+
+/* Implementation of gdb.LineTable.has_pcs (self, line) -> Boolean.
+   Returns a Python Boolean indicating whether a source line has any
+   line table entries corresponding to it.  */
+
+static PyObject *
+ltpy_has_pcs (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 (LINETABLE (symtab) == NULL)
+    {
+      PyErr_SetString (PyExc_RuntimeError,
+		       _("Linetable information not found in symbol table"));
+      return NULL;
+    }
+
+  for (index = 0; index <= LINETABLE (symtab)->nitems; index++)
+    {
+      struct linetable_entry *item = &(symtab->linetable->item[index]);
+      if (item->line == py_line)
+	  Py_RETURN_TRUE;
+    }
+
+  Py_RETURN_FALSE;
+}
+
+/* Implementation of gdb.LineTable.source_lines (self) -> FrozenSet.
+   Returns a Python FrozenSet 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;
+  PyObject *source_list, *source_dict, *line;
+  struct linetable_entry *item;
+  Py_ssize_t list_size;
+
+  LTPY_REQUIRE_VALID (self, symtab);
+
+  if (LINETABLE (symtab) == NULL)
+    {
+      PyErr_SetString (PyExc_RuntimeError,
+		       _("Linetable information not found in symbol table"));
+      return NULL;
+    }
+
+  source_dict = PyDict_New ();
+  if (source_dict == NULL)
+    return NULL;
+
+  for (index = 0; index <= LINETABLE (symtab)->nitems; index++)
+    {
+      item = &(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)
+	{
+	  line = PyLong_FromUnsignedLongLong (item->line);
+
+	  if (line == NULL)
+	    {
+	      Py_DECREF (source_dict);
+	      return NULL;
+	    }
+
+	  if (PyDict_SetItem (source_dict, line, Py_None) == -1)
+	    {
+	      Py_DECREF (line);
+	      Py_DECREF (source_dict);
+	      return NULL;
+	    }
+
+	  Py_DECREF (line);
+	}
+    }
+
+
+  source_list = PyDict_Keys (source_dict);
+  Py_DECREF (source_dict);
+
+  return source_list;
+}
+
+/* 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;
+  linetable_object *obj = (linetable_object *) self;
+
+  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 (&ltpy_iterator_object_type) < 0)
+    return -1;
+
+  Py_INCREF (&linetable_object_type);
+  Py_INCREF (&linetable_entry_object_type);
+  Py_INCREF (&ltpy_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 *) &ltpy_iterator_object_type) < 0)
+    return -1;
+
+  return 0;
+}
+
+/* Linetable entry object get functions.  */
+
+/* Implementation of gdb.LineTableEntry.line (self) -> Unsigned Long.
+   Returns an unsigned long 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 PyLong_FromUnsignedLongLong (obj->line);
+}
+
+/* Implementation of gdb.LineTableEntry.pc (self) -> Unsigned Long.
+   Returns an unsigned long associated with the PC of the line table
+   entry.  */
+
+static PyObject *
+ltpy_entry_get_pcs (PyObject *self, void *closure)
+{
+  linetable_entry_object *obj = (linetable_entry_object *) self;
+
+  return PyLong_FromUnsignedLongLong (obj->pc);
+}
+
+/* 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,
+				&ltpy_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);
+}
+
+/* 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;
+  int index;
+  PyObject *obj;
+  struct linetable_entry *item;
+
+  LTPY_REQUIRE_VALID (iter_obj->source, symtab);
+
+  if (iter_obj->current_index >= LINETABLE (symtab)->nitems)
+    goto stop_iteration;
+
+  item = &(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->nitems)
+	goto stop_iteration;
+      item = &(symtab->linetable->item[iter_obj->current_index]);
+    }
+
+  obj = build_linetable_entry (item->line, item->pc);
+  iter_obj->current_index++;
+
+  return obj;
+
+ stop_iteration:
+  PyErr_SetNone (PyExc_StopIteration);
+  return NULL;
+}
+
+/* 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;
+}
+
+\f
+
+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_pcs", ltpy_has_pcs, METH_VARARGS,
+    "has_pcs (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 () -> FrozenSet\n\
+Return a frozen set 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 */
+};
+
+static 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 */
+};
+
+static 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 | Py_TPFLAGS_HAVE_ITER,  /*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 PyGetSetDef linetable_entry_object_getset[] = {
+  { "line", ltpy_entry_get_line, NULL,
+    "The line number in the source file.", NULL },
+  { "pc", ltpy_entry_get_pcs, NULL,
+    "The memory address for this line number.", NULL },
+  { NULL }  /* Sentinel */
+};
+
+static 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 */
+};
diff --git a/gdb/python/py-symtab.c b/gdb/python/py-symtab.c
index 006946c..c4a3fea 100644
--- a/gdb/python/py-symtab.c
+++ b/gdb/python/py-symtab.c
@@ -186,6 +186,20 @@ stpy_static_block (PyObject *self, PyObject *args)
   return block_to_block_object (block, symtab->objfile);
 }
 
+/* Implementation of gdb.Symtab.linetable (self) -> gdb.Linetable.
+   Returns a gdb.Linetable object corresponding to this symbol
+   table.  */
+
+static PyObject *
+stpy_get_linetable (PyObject *self, PyObject *args)
+{
+  struct symtab *symtab = NULL;
+
+  STPY_REQUIRE_VALID (self, symtab);
+
+  return symtab_to_linetable_object (self);
+}
+
 static PyObject *
 salpy_str (PyObject *self)
 {
@@ -532,6 +546,9 @@ Return the global block of the symbol table." },
   { "static_block", stpy_static_block, METH_NOARGS,
     "static_block () -> gdb.Block.\n\
 Return the static block of the symbol table." },
+    { "linetable", stpy_get_linetable, METH_NOARGS,
+    "linetable () -> gdb.Linetable.\n\
+Return the Linetable associated with this symbol table" },
   {NULL}  /* Sentinel */
 };
 
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index d947be6..7d8c4ad 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -311,7 +311,7 @@ PyObject *block_to_block_object (const struct block *block,
 PyObject *value_to_value_object (struct value *v);
 PyObject *type_to_type_object (struct type *);
 PyObject *frame_info_to_frame_object (struct frame_info *frame);
-
+PyObject *symtab_to_linetable_object (PyObject *symtab);
 PyObject *pspace_to_pspace_object (struct program_space *)
     CPYCHECKER_RETURNS_BORROWED_REF;
 PyObject *pspy_get_printers (PyObject *, void *);
@@ -371,6 +371,8 @@ int gdbpy_initialize_finishbreakpoints (void)
   CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 int gdbpy_initialize_lazy_string (void)
   CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_linetable (void)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 int gdbpy_initialize_parameters (void)
   CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 int gdbpy_initialize_thread (void)
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 542c2d1..7cdf8a7 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1673,6 +1673,7 @@ message == an error message without a stack will be printed."),
       || gdbpy_initialize_breakpoints () < 0
       || gdbpy_initialize_finishbreakpoints () < 0
       || gdbpy_initialize_lazy_string () < 0
+      || gdbpy_initialize_linetable () < 0
       || gdbpy_initialize_thread () < 0
       || gdbpy_initialize_inferior () < 0
       || gdbpy_initialize_events () < 0
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [patch][python] 1/3 Python representation of GDB line tables (Python code)
  2013-11-07 16:35   ` Phil Muldoon
@ 2013-11-07 17:08     ` Tom Tromey
  2013-11-07 20:42     ` Doug Evans
  1 sibling, 0 replies; 8+ messages in thread
From: Tom Tromey @ 2013-11-07 17:08 UTC (permalink / raw)
  To: Phil Muldoon; +Cc: gdb-patches

>> I think it's cheaper, and no more difficult, to just build a set object
>> from the start rather than make a list and the convert it.  I'm not sure
>> what to about Python 2.4 though.

Phil> All API access to sets is new in 2.5 (sets appeared in the Python
Phil> default library in 2.3)

Phil> I elected here just to use a dictionary to ensure unique line numbers
Phil> only.

Thanks, Phil.  Python 2.4 support is getting to be a pain.

Phil> +      if (item->line > 0)
Phil> +	{
Phil> +	  line = PyLong_FromUnsignedLongLong (item->line);

This should use gdb_py_object_from_longest.

Phil> +static PyObject *
Phil> +ltpy_entry_get_line (PyObject *self, void *closure)
Phil> +{
Phil> +  linetable_entry_object *obj = (linetable_entry_object *) self;
Phil> +
Phil> +  return PyLong_FromUnsignedLongLong (obj->line);

This one too.

Phil> +static PyObject *
Phil> +ltpy_entry_get_pcs (PyObject *self, void *closure)
Phil> +{
Phil> +  linetable_entry_object *obj = (linetable_entry_object *) self;
Phil> +
Phil> +  return PyLong_FromUnsignedLongLong (obj->pc);

I think this one should use gdb_py_long_from_ulongest.

The patch is ok with those changes.

Tom

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [patch][python] 1/3 Python representation of GDB line tables (Python code)
  2013-11-07 16:35   ` Phil Muldoon
  2013-11-07 17:08     ` Tom Tromey
@ 2013-11-07 20:42     ` Doug Evans
  2013-11-08 14:42       ` Phil Muldoon
  1 sibling, 1 reply; 8+ messages in thread
From: Doug Evans @ 2013-11-07 20:42 UTC (permalink / raw)
  To: Phil Muldoon; +Cc: Tom Tromey, gdb-patches

Phil Muldoon writes:
 > On 23/10/13 21:46, Tom Tromey wrote:
 > >>>>>> "Phil" == Phil Muldoon <pmuldoon@redhat.com> writes:
 > > 
 > > Phil> This patch series (three emails) introduces GDB line table representation
 > > Phil> to Python.
 > > 
 > > Phil> This first email contains the GDB and Python code to represent the line
 > > Phil> table data as Python objects.
 > > 
 > > Phil> What do you think?
 > > 
 > > Thanks, Phil.
 > > 
 > > Really just nits here.
 > 
 > Fixed up nits.
 >  
 > > Phil> +  /* Return a frozen set to remove duplicated line numbers in the case
 > > Phil> +     where a source line has more than one instruction and more than one
 > > Phil> +     entry in the line table.  */
 > > Phil> +  fset = PyFrozenSet_New (source_list);
 > > Phil> +  Py_DECREF (source_list);
 > > 
 > > PyFrozenSet_New is new in 2.5.
 > > 
 > > I think it's cheaper, and no more difficult, to just build a set object
 > > from the start rather than make a list and the convert it.  I'm not sure
 > > what to about Python 2.4 though.
 > 
 > All API access to sets is new in 2.5 (sets appeared in the Python
 > default library in 2.3)
 > 
 > I elected here just to use a dictionary to ensure unique line numbers
 > only.
 > 
 > Modified patch follows,
 > 
 > Cheers,
 > 
 > Phil

Hi.  I have some nits too.  Sorry!
Fortunately they're all just nits.

 > diff --git a/gdb/python/py-linetable.c b/gdb/python/py-linetable.c
 > new file mode 100644
 > index 0000000..9cde481
 > --- /dev/null
 > +++ b/gdb/python/py-linetable.c
 > @@ -0,0 +1,621 @@
 > +/* Python interface to line tables.
 > +
 > +   Copyright (C) 2013 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"
 > +#include "exceptions.h"
 > +
 > +typedef struct {
 > +  PyObject_HEAD
 > +  /* The line table source line.  */
 > +  gdb_py_longest line;

Can this be an int?

symtab_and_line and linetable_entry use int, thus I'm guessing most/all
of the API in gdb proper uses int.
Using different types looks weird and I'm left with asking "Why?"

I think int will be enough - if not other places will
notice sooner than the Python API will. :-)

 > +  /* The pc associated with the source line.  */
 > +  CORE_ADDR pc;
 > +} linetable_entry_object;
 > [...]
 > +
 > +/* Internal helper function to build a Python Tuple from a GDB 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 VEC.  Construct one line table entry object per
 > +   address.  */
 > +
 > +static PyObject *
 > +build_tuple_from_vector (gdb_py_longest line, VEC (CORE_ADDR) *vec)

Can this function be renamed?
I read this at the call site below and wondered how a general purpose
vector-to-tuple routine was the right solution.
Then I scolled back up and saw this isn't a general purpose routine,
rather it takes a line number and vector of addresses and returns a tuple
of line table entries.

build_line_table_tuple_from_pcs or whatever works for me,
just something that makes it more explicit what it's doing.

 > +/* Implementation of gdb.LineTable.has_pcs (self, line) -> Boolean.
 > +   Returns a Python Boolean indicating whether a source line has any
 > +   line table entries corresponding to it.  */
 > +
 > +static PyObject *
 > +ltpy_has_pcs (PyObject *self, PyObject *args)

Can this function be renamed too?
I read "has_pcs" and think it takes a list of pcs (plural) as an argument.
I now understand how the name is intended to be read here, but
it took a bit.

Since the inputs are a line table and a line number, and the result
is a boolean indicating if the line number is in the table -->

ltpy_has_line or some such?

 > +/* Implementation of gdb.LineTableEntry.pc (self) -> Unsigned Long.
 > +   Returns an unsigned long associated with the PC of the line table
 > +   entry.  */
 > +
 > +static PyObject *
 > +ltpy_entry_get_pcs (PyObject *self, void *closure)

Sorry again.  Can this function be renamed too?
I read "get_pcs" and think plural.

ltpy_entry_get_pc ?

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [patch][python] 1/3 Python representation of GDB line tables (Python code)
  2013-11-07 20:42     ` Doug Evans
@ 2013-11-08 14:42       ` Phil Muldoon
  2013-11-08 17:08         ` Doug Evans
  0 siblings, 1 reply; 8+ messages in thread
From: Phil Muldoon @ 2013-11-08 14:42 UTC (permalink / raw)
  To: Doug Evans; +Cc: Tom Tromey, gdb-patches

On 07/11/13 20:08, Doug Evans wrote:
> Phil Muldoon writes:
>  > 
>  > Modified patch follows,
>  > 
>  > Cheers,
>  > 
>  > Phil
> 
> Hi.  I have some nits too.  Sorry!
> Fortunately they're all just nits.

Hi all,

I've made the requested changes.  For the sake of brevity I have just
included the three file diffs this time around instead of mailing the
whole series.

This OK?

Cheers

Phil

--

diff --git a/gdb/python/py-linetable.c b/gdb/python/py-linetable.c
new file mode 100644
index 0000000..d32eecb
--- /dev/null
+++ b/gdb/python/py-linetable.c
@@ -0,0 +1,620 @@
+/* Python interface to line tables.
+
+   Copyright (C) 2013 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"
+#include "exceptions.h"
+
+typedef struct {
+  PyObject_HEAD
+  /* The line table source line.  */
+  int line;
+  /* The pc associated with the source line.  */
+  CORE_ADDR pc;
+} linetable_entry_object;
+
+static PyTypeObject linetable_entry_object_type
+    CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("linetable_entry_object");
+
+typedef struct {
+  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;
+} linetable_object;
+
+static PyTypeObject linetable_object_type
+    CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("linetable_object");
+
+typedef struct {
+  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;
+} ltpy_iterator_object;
+
+static 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 GDB 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 VEC.  Construct one line table entry object per
+   address.  */
+
+static PyObject *
+build_line_table_tuple_from_pcs (int line, VEC (CORE_ADDR) *vec)
+{
+  int vec_len = 0;
+  PyObject *tuple;
+  CORE_ADDR pc;
+  int i;
+
+  vec_len = VEC_length (CORE_ADDR, vec);
+  if (vec_len < 1)
+    Py_RETURN_NONE;
+
+  tuple = PyTuple_New (vec_len);
+
+  if (tuple == NULL)
+    return NULL;
+
+  for (i = 0; VEC_iterate (CORE_ADDR, vec, i, pc); ++i)
+    {
+      PyObject *obj = build_linetable_entry (line, pc);
+
+      if (obj == NULL)
+	{
+	  Py_DECREF (tuple);
+	  tuple = NULL;
+	  break;
+	}
+      else if (PyTuple_SetItem (tuple, i, obj) != 0)
+	{
+	  Py_DECREF (obj);
+	  Py_DECREF (tuple);
+	  tuple = NULL;
+	  break;
+	}
+    }
+
+  return tuple;
+}
+
+/* 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;
+  int py_line;
+  struct linetable_entry *best_entry = NULL;
+  linetable_entry_object *result;
+  VEC (CORE_ADDR) *pcs = NULL;
+  PyObject *tuple;
+  volatile struct gdb_exception except;
+
+  LTPY_REQUIRE_VALID (self, symtab);
+
+  if (! PyArg_ParseTuple (args, GDB_PY_LL_ARG, &py_line))
+    return NULL;
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      pcs = find_pcs_for_symtab_line (symtab, py_line, &best_entry);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  tuple = build_line_table_tuple_from_pcs (py_line, pcs);
+  VEC_free (CORE_ADDR, pcs);
+
+  return tuple;
+}
+
+/* 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;
+  int py_line;
+  int index;
+
+  LTPY_REQUIRE_VALID (self, symtab);
+
+  if (! PyArg_ParseTuple (args, GDB_PY_LL_ARG, &py_line))
+    return NULL;
+
+  if (LINETABLE (symtab) == NULL)
+    {
+      PyErr_SetString (PyExc_RuntimeError,
+		       _("Linetable information not found in symbol table"));
+      return NULL;
+    }
+
+  for (index = 0; index <= LINETABLE (symtab)->nitems; index++)
+    {
+      struct linetable_entry *item = &(symtab->linetable->item[index]);
+      if (item->line == py_line)
+	  Py_RETURN_TRUE;
+    }
+
+  Py_RETURN_FALSE;
+}
+
+/* Implementation of gdb.LineTable.source_lines (self) -> FrozenSet.
+   Returns a Python FrozenSet 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;
+  PyObject *source_list, *source_dict, *line;
+  struct linetable_entry *item;
+  Py_ssize_t list_size;
+
+  LTPY_REQUIRE_VALID (self, symtab);
+
+  if (LINETABLE (symtab) == NULL)
+    {
+      PyErr_SetString (PyExc_RuntimeError,
+		       _("Linetable information not found in symbol table"));
+      return NULL;
+    }
+
+  source_dict = PyDict_New ();
+  if (source_dict == NULL)
+    return NULL;
+
+  for (index = 0; index <= LINETABLE (symtab)->nitems; index++)
+    {
+      item = &(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)
+	{
+	  line = gdb_py_object_from_longest (item->line);
+
+	  if (line == NULL)
+	    {
+	      Py_DECREF (source_dict);
+	      return NULL;
+	    }
+
+	  if (PyDict_SetItem (source_dict, line, Py_None) == -1)
+	    {
+	      Py_DECREF (line);
+	      Py_DECREF (source_dict);
+	      return NULL;
+	    }
+
+	  Py_DECREF (line);
+	}
+    }
+
+
+  source_list = PyDict_Keys (source_dict);
+  Py_DECREF (source_dict);
+
+  return source_list;
+}
+
+/* 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;
+  linetable_object *obj = (linetable_object *) self;
+
+  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 (&ltpy_iterator_object_type) < 0)
+    return -1;
+
+  Py_INCREF (&linetable_object_type);
+  Py_INCREF (&linetable_entry_object_type);
+  Py_INCREF (&ltpy_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 *) &ltpy_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);
+}
+
+/* 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_longest (obj->pc);
+}
+
+/* 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,
+				&ltpy_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);
+}
+
+/* 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;
+  int index;
+  PyObject *obj;
+  struct linetable_entry *item;
+
+  LTPY_REQUIRE_VALID (iter_obj->source, symtab);
+
+  if (iter_obj->current_index >= LINETABLE (symtab)->nitems)
+    goto stop_iteration;
+
+  item = &(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->nitems)
+	goto stop_iteration;
+      item = &(symtab->linetable->item[iter_obj->current_index]);
+    }
+
+  obj = build_linetable_entry (item->line, item->pc);
+  iter_obj->current_index++;
+
+  return obj;
+
+ stop_iteration:
+  PyErr_SetNone (PyExc_StopIteration);
+  return NULL;
+}
+
+/* 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;
+}
+
+\f
+
+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 () -> FrozenSet\n\
+Return a frozen set 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 */
+};
+
+static 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 */
+};
+
+static 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 | Py_TPFLAGS_HAVE_ITER,  /*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 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 */
+};
+
+static 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 */
+};
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 44fb174..1e0d854 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -23431,6 +23431,7 @@ optional arguments while skipping others.  Example:
 * Blocks In Python::            Accessing blocks from Python.
 * Symbols In Python::           Python representation of symbols.
 * Symbol Tables In Python::     Python representation of symbol tables.
+* Line Tables In Python::       Python representation of line tables.
 * Breakpoints In Python::       Manipulating breakpoints using Python.
 * Finish Breakpoints in Python:: Setting Breakpoints on function return
                                 using Python.
@@ -26964,6 +26965,89 @@ Return the static block of the underlying symbol table.
 @xref{Blocks In Python}.
 @end defun
 
+@defun Symtab.linetable ()
+Return the line table associated with the symbol table.
+@xref{Line Tables In Python}.
+@end defun
+
+@node Line Tables In Python
+@subsubsection Manipulating line tables using Python
+
+@cindex line tables in python
+@tindex gdb.LineTable
+
+Python code can request and inspect line table information from a
+symbol table that is loaded in @value{GDBN}.  A line table is a
+mapping of source lines to their executable locations in memory.  To
+acquire the line table information for a particular symbol table, use
+the @code{linetable} function (@pxref{Symbol Tables In Python}).
+
+A @code{gdb.LineTable} is iterable.  The iterator returns
+@code{LineTableEntry} objects that correspond to the source line and
+address for each line table entry.  @code{LineTableEntry} objects have
+the following attributes:
+
+@defvar LineTableEntry.line
+The source line number for this line table entry.  This number
+corresponds to the actual line of source.  This attribute is not
+writable.
+@end defvar
+
+@defvar LineTableEntry.pc
+The address that is associated with the line table entry where the
+executable code for that source line resides in memory.  This
+attribute is not writable.
+@end defvar
+
+As there can be multiple addresses for a single source line, you may
+receive multiple @code{LineTableEntry} objects with matching
+@code{line} attributes, but with different @code{pc} attributes.  The
+iterator is sorted in ascending @code{pc} order.  Here is a small
+example illustrating iterating over a line table.
+
+@smallexample
+symtab = gdb.selected_frame().find_sal().symtab
+linetable = symtab.linetable()
+for line in linetable:
+   print "Line: "+str(line.line)+" Address: "+hex(line.pc)
+@end smallexample
+
+This will have the following output:
+
+@smallexample
+Line: 33 Address: 0x4005c8L
+Line: 37 Address: 0x4005caL
+Line: 39 Address: 0x4005d2L
+Line: 40 Address: 0x4005f8L
+Line: 42 Address: 0x4005ffL
+Line: 44 Address: 0x400608L
+Line: 42 Address: 0x40060cL
+Line: 45 Address: 0x400615L
+@end smallexample
+
+In addition to being able to iterate over a @code{LineTable}, it also
+has the following direct access methods:
+
+@defun LineTable.line (line)
+Return a Python @code{Tuple} of @code{LineTableEntry} objects for any
+entries in the line table for the given @var{line}.  @var{line} refers
+to the source code line.  If there are no entries for that source code
+@var{line}, the Python @code{None} is returned.
+@end defun
+
+@defun LineTable.has_line (line)
+Return a Python @code{Boolean} indicating whether there is an entry in
+the line table for this source line.  Return @code{True} if an entry
+is found, or @code{False} if not.
+@end defun
+
+@defun LineTable.source_lines ()
+Return a Python @code{List} of the source line numbers in the symbol
+table.  Only lines with executable code locations are returned.  The
+contents of the @code{List} will just be the source line entries
+represented as Python @code{Long} values.
+@end defun
+
 @node Breakpoints In Python
 @subsubsection Manipulating breakpoints using Python
 
diff --git a/gdb/testsuite/gdb.python/py-linetable.exp b/gdb/testsuite/gdb.python/py-linetable.exp
new file mode 100644
index 0000000..b26b0d0
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-linetable.exp
@@ -0,0 +1,76 @@
+# Copyright 2013 Free Software Foundation, Inc.
+
+# 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/>.
+
+load_lib gdb-python.exp
+set opts {}
+standard_testfile .S
+
+if [info exists COMPILE] {
+    # make check RUNTESTFLAGS="gdb.python/py-linetable.exp COMPILE=1"
+    standard_testfile
+    lappend opts debug optimize=-O2
+} elseif { ![istarget x86_64-*-* ] || ![is_lp64_target] } {
+    verbose "Skipping ${testfile}."
+    return
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} $opts] } {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+# Skip all tests if Python scripting is not enabled.
+if { [skip_python_tests] } { continue }
+
+gdb_py_test_silent_cmd "python lt = gdb.selected_frame().find_sal().symtab.linetable()" \
+    "get instruction" 0
+
+gdb_py_test_multiple "input simple command" \
+  "python" "" \
+  "def list_lines():" "" \
+  "   for l in lt:" "" \
+  "     print 'L' +str(l.line)+' A '+hex(l.pc)" "" \
+  "end" ""
+
+gdb_test "python list_lines()" \
+    "L20 A $hex.*L21 A $hex.*L22 A $hex.*L24 A $hex.*L25 A $hex.*L40 A $hex.*L42 A $hex.*L44 A $hex.*L42 A $hex.*L46 A $hex.*" \
+    "test linetable iterator addr"
+gdb_test "python print len(lt.line(42))" "2" \
+    "Test length of a multiple pc line"
+gdb_test "python print len(lt.line(20))" "1" \
+    "Test length of a single pc line"
+gdb_test "python print lt.line(1)" "None" \
+    "Test None returned for line with no pc"
+
+# Test gdb.Linetable.sourcelines ()
+gdb_py_test_silent_cmd "python fset = lt.source_lines()" \
+    "Get all source lines into a frozen set" 0
+gdb_test "python print sorted(fset)" \
+    "\[20L, 21L, 22L, 24L, 25L, 28L, 29L, 30L, 32L, 33L, 37L, 39L, 40L, 42L, 44L, 45L, 46L\].*" \
+    "Test frozen set contains line numbers"
+
+# Test gdb.Linetable.has_line ()
+gdb_test "python print lt.has_line(20)" \
+    "True.*" \
+    "Test has_pcs at line 20"
+gdb_test "python print lt.has_line(44)" \
+    "True.*" \
+    "Test has_pcs at line 40"
+gdb_test "python print lt.has_line(10)" \
+    "False.*" \
+    "Test has_pcs at line 10"


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [patch][python] 1/3 Python representation of GDB line tables (Python code)
  2013-11-08 14:42       ` Phil Muldoon
@ 2013-11-08 17:08         ` Doug Evans
  2013-11-11 21:03           ` Phil Muldoon
  0 siblings, 1 reply; 8+ messages in thread
From: Doug Evans @ 2013-11-08 17:08 UTC (permalink / raw)
  To: Phil Muldoon; +Cc: Tom Tromey, gdb-patches

Phil Muldoon writes:
 > I've made the requested changes.  For the sake of brevity I have just
 > included the three file diffs this time around instead of mailing the
 > whole series.
 > 
 > This OK?

Thanks.

"works for me"

[I missed a few things in my previous review.  Blech.  Mea culpa.
There's a couple of function comments that don't have a blank
line between them and their function.  How could I have missed that??? :-)
Ok with those changes, no need for another iteration on my account.

Thanks again.



 > +/* Deconstructor for the line table object.  Decrement the reference
 > +   to the symbol table object before calling the default free.  */

Here.

 > +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.  */

Here.

 > +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 (&ltpy_iterator_object_type) < 0)
 > +    return -1;
 > +
 > +  Py_INCREF (&linetable_object_type);
 > +  Py_INCREF (&linetable_entry_object_type);
 > +  Py_INCREF (&ltpy_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 *) &ltpy_iterator_object_type) < 0)
 > +    return -1;
 > +
 > +  return 0;
 > +}

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [patch][python] 1/3 Python representation of GDB line tables (Python code)
  2013-11-08 17:08         ` Doug Evans
@ 2013-11-11 21:03           ` Phil Muldoon
  0 siblings, 0 replies; 8+ messages in thread
From: Phil Muldoon @ 2013-11-11 21:03 UTC (permalink / raw)
  To: Doug Evans; +Cc: Tom Tromey, gdb-patches

On 08/11/13 17:02, Doug Evans wrote:
> Phil Muldoon writes:
>  > I've made the requested changes.  For the sake of brevity I have just
>  > included the three file diffs this time around instead of mailing the
>  > whole series.
>  > 
>  > This OK?
> 
> Thanks.
> 
> "works for me"
> 
> [I missed a few things in my previous review.  Blech.  Mea culpa.
> There's a couple of function comments that don't have a blank
> line between them and their function.  How could I have missed that??? :-)
> Ok with those changes, no need for another iteration on my account.
> 
> Thanks again.

So committed, with the two header newlines.

Cheers,

Phil

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2013-11-11 19:54 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-10-08 12:04 [patch][python] 1/3 Python representation of GDB line tables (Python code) Phil Muldoon
2013-10-23 20:46 ` Tom Tromey
2013-11-07 16:35   ` Phil Muldoon
2013-11-07 17:08     ` Tom Tromey
2013-11-07 20:42     ` Doug Evans
2013-11-08 14:42       ` Phil Muldoon
2013-11-08 17:08         ` Doug Evans
2013-11-11 21:03           ` Phil Muldoon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).