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

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

Checks

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

Commit Message

Simon Farre Jan. 22, 2024, 1:31 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)}")

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31271
---
 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(-)
  

Comments

Tom Tromey Feb. 7, 2024, 8:05 p.m. UTC | #1
>>>>> "Simon" == Simon Farre <simon.farre.cx@gmail.com> writes:

Thanks for the patch.

Simon>  static PyObject *
Simon> -build_line_table_tuple_from_pcs (int line, const std::vector<CORE_ADDR> &pcs)
Simon> +build_line_table_tuple_from_pcs (int line, const symtab& sym, const std::vector<linetable_entry> &pcs)

gdb uses a line length around 80, so this should be split.
Also the "&" attaches to the "sym", not "symtab" -- this is also true
for "*" in gdb, there's a few instances of this around.

Simon> +/* Search for a symtab whose fullname contains FILENAME and return it's
Simon> +   linetable.  */
Simon> +PyObject *
Simon> +gdbpy_lookup_linetable_by_filename (PyObject *, PyObject *args, PyObject *kw)
Simon> +{
Simon> +  const char *arg = nullptr;
Simon> +  static const char *keywords[] = { "filename", nullptr };
Simon> +
Simon> +  if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "s", keywords, &arg))
Simon> +    {
Simon> +      return nullptr;
Simon> +    }

Don't need the braces here.

Simon> +
Simon> +  for (objfile *objfile : current_program_space->objfiles ())
Simon> +    for (compunit_symtab *cu : objfile->compunits ())
Simon> +      for (symtab *s : cu->filetabs ())
Simon> +	{
Simon> +	  const auto name = symtab_to_fullname (s);
Simon> +
Simon> +	  if (strstr (name, arg))

This doesn't seem like a great approach to me.
Substring matching isn't how this kind of thing works elsewhere in gdb.

Also this looping approach means that the symtab must somehow have
already been expanded.

Right now, the breakpointLocations request works by calling MI's
-symbol-list-lines.  This calls lookup_symtab, which in the end will try
expanding CUs to find the desired symtab.

Tom
  

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