[RFC v2 18/21] gdb/python: add more attributes to gdb.LinetableEntry objects
Jan Vrany
jan.vrany@labware.com
Thu Nov 21 12:47:11 GMT 2024
This commit adds is_stmt, prologue_end and epilogue_begin attributes
to linetable entry objects.
This prompted change in gdb.Linetable.line() (ltpy_get_pcs_for_line).
In order to fill initialize new attributes we need complete entries
matching the line, not only PCs.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
---
gdb/doc/python.texi | 17 ++++
gdb/python/py-linetable.c | 101 +++++++++++++++++++---
gdb/testsuite/gdb.python/py-linetable.exp | 10 +++
3 files changed, 116 insertions(+), 12 deletions(-)
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 43109dc6554..9fe7e182bdb 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -6674,6 +6674,23 @@ executable code for that source line resides in memory. This
attribute is not writable.
@end defvar
+@defvar LineTableEntry.is_stmt
+True if pc (associated with this entry) is a good location to place
+a breakpoint for line (associated with this entry). This attribute is not
+writable.
+@end defvar
+
+@defvar LineTableEntry.prologue_end
+True if pc (associated with this entry) is a good location to place
+a breakpoint after a function prologue. This attribute is not
+writable.
+@end defvar
+
+@defvar LineTableEntry.epilogue_begin
+True if pc (associated with this entry) marks the start of the epilogue.
+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
diff --git a/gdb/python/py-linetable.c b/gdb/python/py-linetable.c
index fc57f369606..8b6806a2484 100644
--- a/gdb/python/py-linetable.c
+++ b/gdb/python/py-linetable.c
@@ -25,6 +25,12 @@ struct linetable_entry_object {
int line;
/* The pc associated with the source line. */
CORE_ADDR pc;
+ /* See is_stmt in stuct linetable_entry. */
+ bool is_stmt : 1;
+ /* See prologue_end in stuct linetable_entry. */
+ bool prologue_end : 1;
+ /* See epilogue_begin in struct linetable_entry. */
+ bool epilogue_begin : 1;
};
extern PyTypeObject linetable_entry_object_type
@@ -98,7 +104,8 @@ symtab_to_linetable_object (PyObject *symtab)
and an address. */
static PyObject *
-build_linetable_entry (int line, CORE_ADDR address)
+build_linetable_entry (int line, CORE_ADDR address, bool is_stmt,
+ bool prologue_end, bool epilogue_begin)
{
linetable_entry_object *obj;
@@ -108,6 +115,9 @@ build_linetable_entry (int line, CORE_ADDR address)
{
obj->line = line;
obj->pc = address;
+ obj->is_stmt = is_stmt;
+ obj->prologue_end = prologue_end;
+ obj->epilogue_begin = epilogue_begin;
}
return (PyObject *) obj;
@@ -120,22 +130,26 @@ 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_entries (
+ const struct objfile *objfile,
+ const std::vector<const linetable_entry *> &entries)
{
int i;
- if (pcs.size () < 1)
+ if (entries.size () < 1)
Py_RETURN_NONE;
- gdbpy_ref<> tuple (PyTuple_New (pcs.size ()));
+ gdbpy_ref<> tuple (PyTuple_New (entries.size ()));
if (tuple == NULL)
return NULL;
- for (i = 0; i < pcs.size (); ++i)
+ for (i = 0; i < entries.size (); ++i)
{
- CORE_ADDR pc = pcs[i];
- gdbpy_ref<> obj (build_linetable_entry (line, pc));
+ auto entry = entries[i];
+ gdbpy_ref<> obj (build_linetable_entry (
+ entry->line, entry->pc (objfile), entry->is_stmt,
+ entry->prologue_end, entry->epilogue_begin));
if (obj == NULL)
return NULL;
@@ -155,24 +169,35 @@ ltpy_get_pcs_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;
+ std::vector<const linetable_entry*> entries;
LTPY_REQUIRE_VALID (self, symtab);
if (! PyArg_ParseTuple (args, GDB_PY_LL_ARG, &py_line))
return NULL;
+ if (! symtab->linetable ())
+ Py_RETURN_NONE;
+
try
{
- pcs = find_pcs_for_symtab_line (symtab, py_line, &best_entry);
+ const linetable_entry *entry;
+ int i;
+ for (entry = symtab->linetable ()->item, i = 0;
+ i < symtab->linetable ()->nitems;
+ entry++, i++)
+ {
+ if (entry->line == py_line)
+ entries.push_back (entry);
+ }
}
catch (const gdb_exception &except)
{
return gdbpy_handle_gdb_exception (nullptr, except);
}
- return build_line_table_tuple_from_pcs (py_line, pcs);
+ struct objfile *objfile = symtab->compunit ()->objfile ();
+ return build_line_table_tuple_from_entries (objfile, entries);
}
/* Implementation of gdb.LineTable.has_line (self, line) -> Boolean.
@@ -321,6 +346,50 @@ ltpy_entry_get_pc (PyObject *self, void *closure)
return gdb_py_object_from_ulongest (obj->pc).release ();
}
+/* Implementation of gdb.LineTableEntry.is_stmt (self) -> bool. Returns
+ True if associated PC is a good location to place a breakpoint for
+ associatated LINE. */
+
+static PyObject *
+ltpy_entry_get_is_stmt (PyObject *self, void *closure)
+{
+ linetable_entry_object *obj = (linetable_entry_object *) self;
+
+ if (obj->is_stmt != 0)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+/* Implementation of gdb.LineTableEntry.prologue_end (self) -> bool. Returns
+ True if associated PC is a good location to place a breakpoint after a
+ function prologue. */
+
+static PyObject *
+ltpy_entry_get_prologue_end (PyObject *self, void *closure)
+{
+ linetable_entry_object *obj = (linetable_entry_object *) self;
+
+ if (obj->prologue_end)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+/* Implementation of gdb.LineTableEntry.prologue_end (self) -> bool. Returns
+ True if this location marks the start of the epilogue. */
+
+static PyObject *
+ltpy_entry_get_epilogue_begin (PyObject *self, void *closure)
+{
+ linetable_entry_object *obj = (linetable_entry_object *) self;
+
+ if (obj->epilogue_begin)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
/* LineTable iterator functions. */
/* Return a new line table iterator. */
@@ -406,7 +475,8 @@ 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->pc (objfile), item->is_stmt,
+ item->prologue_end, item->epilogue_begin );
iter_obj->current_index++;
return obj;
@@ -534,9 +604,16 @@ static gdb_PyGetSetDef linetable_entry_object_getset[] = {
"The line number in the source file.", NULL },
{ "pc", ltpy_entry_get_pc, NULL,
"The memory address for this line number.", NULL },
+ { "is_stmt", ltpy_entry_get_is_stmt, NULL,
+ "Whether this is a good location to place a breakpoint for associated LINE.", NULL },
+ { "prologue_end", ltpy_entry_get_prologue_end, NULL,
+ "Whether this is a good location to place a breakpoint after method prologue.", NULL },
+ { "epilogue_begin", ltpy_entry_get_epilogue_begin, NULL,
+ "True if this location marks the start of the epilogue.", NULL },
{ NULL } /* Sentinel */
};
+
PyTypeObject linetable_entry_object_type = {
PyVarObject_HEAD_INIT (NULL, 0)
"gdb.LineTableEntry", /*tp_name*/
diff --git a/gdb/testsuite/gdb.python/py-linetable.exp b/gdb/testsuite/gdb.python/py-linetable.exp
index 5caa7c445c4..0f591e1ff99 100644
--- a/gdb/testsuite/gdb.python/py-linetable.exp
+++ b/gdb/testsuite/gdb.python/py-linetable.exp
@@ -53,6 +53,16 @@ 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"
+gdb_test "python print(next(iter(lt)).is_stmt)" \
+ "(True|False)" \
+ "Test is_stmt"
+gdb_test "python print(next(iter(lt)).prologue_end)" \
+ "(True|False)" \
+ "Test prologue_end"
+gdb_test "python print(next(iter(lt)).epilogue_begin)" \
+ "(True|False)" \
+ "Test epilogue_begin"
+
# Test gdb.Linetable.sourcelines ()
gdb_py_test_silent_cmd "python fset = lt.source_lines()" \
--
2.45.2
More information about the Gdb-patches
mailing list