[3/5,dap,&,linetable] : Change gdb.LineTableEntry & Add gdb.lookup_linetable

Message ID 20240116191305.126345-3-simon.farre.cx@gmail.com
State New
Headers
Series [1/5,dap,&,linetable] : Add column to linetable entry |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm fail Testing failed

Commit Message

Simon Farre Jan. 16, 2024, 7:13 p.m. UTC
  This patch changes the Python type `LineTableEntry` by adding the
`column` accessor which returns the newly added `column` value from the
internal linetable_entry.

It also exposes a new "module function": gdb.lookup_linetable which
searches all symbtabs using a string; comparing it with the symtabs
'fullname' and returning the linetable of the (first) symtab that
matches.

To search for a linetable from python:

lt = gdb.lookup_linetable("main.cpp")

And like before (as per current documentation), one can use that like so:

for lte in lt:
  print(f"line:col={lte.line}:{lte.column}; pc = {hex(lte.pc)}")
---
 gdb/python/py-linetable.c    | 35 ++++++++++++++++++++++++-----------
 gdb/python/py-symtab.c       | 33 +++++++++++++++++++++++++++++++++
 gdb/python/python-internal.h |  2 ++
 gdb/python/python.c          |  2 ++
 gdb/symtab.c                 | 19 ++++++++++++++++++-
 gdb/symtab.h                 |  3 +++
 6 files changed, 82 insertions(+), 12 deletions(-)
  

Patch

diff --git a/gdb/python/py-linetable.c b/gdb/python/py-linetable.c
index 788a6e1e24b..ba96c663027 100644
--- a/gdb/python/py-linetable.c
+++ b/gdb/python/py-linetable.c
@@ -24,6 +24,8 @@  struct linetable_entry_object {
   PyObject_HEAD
   /* The line table source line.  */
   int line;
+  /* The line table source column.  */
+  int col;
   /* The pc associated with the source line.  */
   CORE_ADDR pc;
 };
@@ -99,7 +101,7 @@  symtab_to_linetable_object (PyObject *symtab)
    and an address.  */
 
 static PyObject *
-build_linetable_entry (int line, CORE_ADDR address)
+build_linetable_entry (int line, int col, CORE_ADDR address)
 {
   linetable_entry_object *obj;
 
@@ -109,6 +111,7 @@  build_linetable_entry (int line, CORE_ADDR address)
     {
       obj->line = line;
       obj->pc = address;
+      obj->col = col;
     }
 
   return (PyObject *) obj;
@@ -121,7 +124,7 @@  build_linetable_entry (int line, CORE_ADDR address)
    address.  */
 
 static PyObject *
-build_line_table_tuple_from_pcs (int line, const std::vector<CORE_ADDR> &pcs)
+build_line_table_tuple_from_pcs (int line, const symtab& sym, const std::vector<linetable_entry> &pcs)
 {
   int i;
 
@@ -133,10 +136,11 @@  build_line_table_tuple_from_pcs (int line, const std::vector<CORE_ADDR> &pcs)
   if (tuple == NULL)
     return NULL;
 
+  const auto of = sym.compunit ()->objfile ();
   for (i = 0; i < pcs.size (); ++i)
     {
-      CORE_ADDR pc = pcs[i];
-      gdbpy_ref<> obj (build_linetable_entry (line, pc));
+      const auto& lte = pcs[i];
+      gdbpy_ref<> obj (build_linetable_entry (line, lte.col, lte.pc (of)));
 
       if (obj == NULL)
 	return NULL;
@@ -152,12 +156,10 @@  build_line_table_tuple_from_pcs (int line, const std::vector<CORE_ADDR> &pcs)
    in the line table.  */
 
 static PyObject *
-ltpy_get_pcs_for_line (PyObject *self, PyObject *args)
+ltpy_get_ltes_for_line (PyObject *self, PyObject *args)
 {
   struct symtab *symtab;
   gdb_py_longest py_line;
-  const linetable_entry *best_entry = nullptr;
-  std::vector<CORE_ADDR> pcs;
 
   LTPY_REQUIRE_VALID (self, symtab);
 
@@ -166,14 +168,15 @@  ltpy_get_pcs_for_line (PyObject *self, PyObject *args)
 
   try
     {
-      pcs = find_pcs_for_symtab_line (symtab, py_line, &best_entry);
+      const auto ltes = find_ltes_for_symtab_line (*symtab, py_line);
+      return build_line_table_tuple_from_pcs (py_line, *symtab, ltes);
     }
   catch (const gdb_exception &except)
     {
       GDB_PY_HANDLE_EXCEPTION (except);
     }
 
-  return build_line_table_tuple_from_pcs (py_line, pcs);
+  Py_RETURN_NONE;
 }
 
 /* Implementation of gdb.LineTable.has_line (self, line) -> Boolean.
@@ -327,6 +330,14 @@  ltpy_entry_get_line (PyObject *self, void *closure)
   return gdb_py_object_from_longest (obj->line).release ();
 }
 
+static PyObject *
+ltpy_entry_get_column (PyObject *self, void *closure)
+{
+  linetable_entry_object *obj = (linetable_entry_object *) self;
+
+  return gdb_py_object_from_longest (obj->col).release ();
+}
+
 /* Implementation of gdb.LineTableEntry.pc (self) -> Long.  Returns a
    a long integer associated with the PC of the line table entry.  */
 
@@ -422,7 +433,7 @@  ltpy_iternext (PyObject *self)
     }
 
   struct objfile *objfile = symtab->compunit ()->objfile ();
-  obj = build_linetable_entry (item->line, item->pc (objfile));
+  obj = build_linetable_entry (item->line, item->col, item->pc (objfile));
   iter_obj->current_index++;
 
   return obj;
@@ -451,7 +462,7 @@  GDBPY_INITIALIZE_FILE (gdbpy_initialize_linetable);
 
 
 static PyMethodDef linetable_object_methods[] = {
-  { "line", ltpy_get_pcs_for_line, METH_VARARGS,
+  { "line", ltpy_get_ltes_for_line, METH_VARARGS,
     "line (lineno) -> Tuple\n\
 Return executable locations for a given source line." },
   { "has_line", ltpy_has_line, METH_VARARGS,
@@ -548,6 +559,8 @@  PyTypeObject ltpy_iterator_object_type = {
 static gdb_PyGetSetDef linetable_entry_object_getset[] = {
   { "line", ltpy_entry_get_line, NULL,
     "The line number in the source file.", NULL },
+  { "column", ltpy_entry_get_column, NULL,
+    "The column number in the source file", NULL },
   { "pc", ltpy_entry_get_pc, NULL,
     "The memory address for this line number.", NULL },
   { NULL }  /* Sentinel */
diff --git a/gdb/python/py-symtab.c b/gdb/python/py-symtab.c
index b28f6ca8b48..e23c02aa0e4 100644
--- a/gdb/python/py-symtab.c
+++ b/gdb/python/py-symtab.c
@@ -475,6 +475,39 @@  symtab_to_symtab_object (struct symtab *symtab)
   return (PyObject *) symtab_obj;
 }
 
+/* Search for a symtab whose fullname contains FILENAME and return it's
+   linetable.  */
+PyObject *
+gdbpy_lookup_linetable_by_filename (PyObject *, PyObject *args, PyObject *kw)
+{
+  const char *arg = nullptr;
+  static const char *keywords[] = { "filename", nullptr };
+
+  if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "s", keywords, &arg))
+    {
+      return nullptr;
+    }
+
+  for (objfile *objfile : current_program_space->objfiles ())
+    for (compunit_symtab *cu : objfile->compunits ())
+      for (symtab *s : cu->filetabs ())
+	{
+	  const auto name = symtab_to_fullname (s);
+
+	  if (strstr (name, arg))
+	    {
+	      auto symtab_pyobj = symtab_to_symtab_object (s);
+	      if (!symtab_pyobj)
+		Py_RETURN_NONE;
+	      auto lt_obj = symtab_to_linetable_object (symtab_pyobj);
+	      if (!lt_obj)
+		Py_RETURN_NONE;
+	      return lt_obj;
+	    }
+	}
+  Py_RETURN_NONE;
+}
+
 /* Create a new symtab and line (gdb.Symtab_and_line) object
    that encapsulates the symtab_and_line structure from GDB.  */
 PyObject *
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 7c05007cbab..dcfc03e3beb 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -408,6 +408,8 @@  PyObject *gdbpy_convenience_variable (PyObject *self, PyObject *args);
 PyObject *gdbpy_set_convenience_variable (PyObject *self, PyObject *args);
 PyObject *gdbpy_breakpoints (PyObject *, PyObject *);
 PyObject *gdbpy_frame_stop_reason_string (PyObject *, PyObject *);
+PyObject *gdbpy_lookup_linetable_by_filename (PyObject *, PyObject* args,
+					      PyObject *kw);
 PyObject *gdbpy_lookup_symbol (PyObject *self, PyObject *args, PyObject *kw);
 PyObject *gdbpy_lookup_global_symbol (PyObject *self, PyObject *args,
 				      PyObject *kw);
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 1d406392bd3..3d7c70fed09 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -2573,6 +2573,8 @@  gdbpy_initialized (const struct extension_language_defn *extlang)
 
 PyMethodDef python_GdbMethods[] =
 {
+  { "lookup_linetable", (PyCFunction) gdbpy_lookup_linetable_by_filename,
+    METH_VARARGS | METH_KEYWORDS },
   { "history", gdbpy_history, METH_VARARGS,
     "Get a value from history" },
   { "add_history", gdbpy_add_history, METH_VARARGS,
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 7c0a69108d4..e206ba9cada 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -3519,7 +3519,24 @@  find_pcs_for_symtab_line (struct symtab *symtab, int line,
   return result;
 }
 
-
+/**  Return line table entries for SYMTAB at LINE.  */
+
+std::vector<linetable_entry>
+find_ltes_for_symtab_line (const symtab &symtab, int line)
+{
+  auto lte = symtab.linetable ();
+  if (lte == nullptr)
+    return {};
+
+  std::vector<linetable_entry> result;
+  for (auto i = 0; i < lte->nitems; ++i)
+    {
+      if (lte->item[i].line == line)
+	result.push_back (lte->item[i]);
+    }
+  return result;
+}
+
 /* Set the PC value for a given source file and line number and return true.
    Returns false for invalid line number (and sets the PC to 0).
    The source file is specified with a struct symtab.  */
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 38d08fe8599..9098822c90b 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -2772,6 +2772,9 @@  void iterate_over_symtabs (const char *name,
 std::vector<CORE_ADDR> find_pcs_for_symtab_line
     (struct symtab *symtab, int line, const linetable_entry **best_entry);
 
+std::vector<linetable_entry> find_ltes_for_symtab_line
+    (const symtab &symtab, int line);
+
 /* Prototype for callbacks for LA_ITERATE_OVER_SYMBOLS.  The callback
    is called once per matching symbol SYM.  The callback should return
    true to indicate that LA_ITERATE_OVER_SYMBOLS should continue