Re: [PATCH] gdb/python: Introduce gdb.lookup_all_static_symbols

Andrew Burgess
2019-10-15T23:32:07Z

This version:

1. Renames lookup_all_static_symbols to lookup_static_symbols,
2. Expands symtabs containing symbols with a matching name before
finding matches, and
3. Includes a test similar to Simon's the highlights the need for
the previous change.

Thanks,
Andrew

---

commit f9cd67c7287475e1cb0a654a6e4e1841e5a78bae
Author: Andrew Burgess <andrew.burgess@embecosm.com>
Date: Tue Oct 15 16:18:26 2019 +0100

gdb/python: Introduce gdb.lookup_static_symbols

If gdb.lookup_static_symbol is going to return a single symbol then it
makes sense (I think) for it to return a context sensitive choice of
symbol, that is the static symbol that would be visible to the program
at that point.

However, if the user of the python API wants to instead get a
consistent set of static symbols, no matter where they stop, then they
have to instead consider all static symbols with a given name - there
could be many. That is what this new API function offers, it returns
a list (possibly empty) of all static symbols matching a given
name (and optionally a given symbol domain).

gdb/ChangeLog:

* python/py-symbol.c (gdbpy_lookup_static_symbols): New
function.
* python/python-internal.h (gdbpy_lookup_static_symbols):
Declare new function.
* python/python.c (python_GdbMethods): Add
gdb.lookup_static_symbols method.

gdb/testsuite/ChangeLog:

* gdb.python/py-symbol.exp: Add test for
gdb.lookup_static_symbols.

gdb/doc/ChangeLog:

* python.texi (Symbols In Python): Add documentation for
gdb.lookup_static_symbols.

Change-Id: I1153b0ae5bcbc43b3dcf139043c7a48bf791e1a3

diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 0f12de94bba..a30c8ae4f03 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -4880,6 +4880,41 @@
information.
@end defun

+@findex gdb.lookup_global_symbol
+@defun gdb.lookup_global_symbol (name @r{[}, domain@r{]})
+This function searches for a global symbol by name.
+The search scope can be restricted to by the domain argument.
+
+@var{name} is the name of the symbol. It must be a string.
+The optional @var{domain} argument restricts the search to the domain type.
+The @var{domain} argument must be a domain constant defined in the @code{gdb}
+module and described later in this chapter.
+
+The result is a @code{gdb.Symbol} object or @code{None} if the symbol
+is not found.
+@end defun
+
+@findex gdb.lookup_static_symbols
+@defun gdb.lookup_static_symbols (name @r{[}, domain@r{]})
+Similar to @code{gdb.lookup_static_symbol}, this function searches for
+global symbols with static linkage by name, and optionally restricted
+by the domain argument. However, this function returns a list of all
+matching symbols found, not just the first one.
+
+@var{name} is the name of the symbol. It must be a string.
+The optional @var{domain} argument restricts the search to the domain type.
+The @var{domain} argument must be a domain constant defined in the @code{gdb}
+module and described later in this chapter.
+
+The result is a list of @code{gdb.Symbol} objects which could be empty
+if no matching symbols were found.
+
+Note that this function will not find function-scoped static variables. To look
+up such variables, iterate over the variables of the function's
+@code{gdb.Block} and check that @code{block.addr_class} is
+@code{gdb.SYMBOL_LOC_STATIC}.
+@end defun
+
A @code{gdb.Symbol} object has the following attributes:

@defvar Symbol.type
diff --git a/gdb/python/py-symbol.c b/gdb/python/py-symbol.c
index ae9aca6c5d0..119b1f2cbbf 100644
--- a/gdb/python/py-symbol.c
+++ b/gdb/python/py-symbol.c
@@ -23,6 +23,7 @@
#include "symtab.h"
#include "python-internal.h"
#include "objfiles.h"
+#include "symfile.h"

typedef struct sympy_symbol_object {
PyObject_HEAD
@@ -534,6 +535,66 @@ gdbpy_lookup_static_symbol (PyObject *self, PyObject *args, PyObject *kw)
return sym_obj;
}

+/* Implementation of
+ gdb.lookup_static_symbols (name [, domain) -> [symbol] or None.
+
+ Returns a list of all static symbols matching NAME in DOMAIN. */
+
+PyObject *
+gdbpy_lookup_static_symbols (PyObject *self, PyObject *args, PyObject *kw)
+{
+ const char *name;
+ int domain = VAR_DOMAIN;
+ static const char *keywords[] = { "name", "domain", NULL };
+
+ if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "s|i", keywords, &name,
+ &domain))
+ return NULL;
+
+ gdbpy_ref<> return_list (PyList_New (0));
+ if (return_list == NULL)
+ return NULL;
+
+ try
+ {
+ /* Expand any symtabs that contain potentially matching symbols. */
+ lookup_name_info lookup_name (name, symbol_name_match_type::FULL);
+ expand_symtabs_matching (NULL, lookup_name, NULL, NULL, ALL_DOMAIN);
+
+ for (objfile *objfile : current_program_space->objfiles ())
+ {
+ for (compunit_symtab *cust : objfile->compunits ())
+ {
+ const struct blockvector *bv;
+ const struct block *block;
+
+ bv = COMPUNIT_BLOCKVECTOR (cust);
+ block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+
+ if (block != nullptr)
+ {
+ symbol *symbol = lookup_symbol_in_static_block
+ (name, block, (domain_enum) domain).symbol;
+
+ if (symbol != nullptr)
+ {
+ PyObject *sym_obj
+ = symbol_to_symbol_object (symbol);
+ if (PyList_Append (return_list.get (), sym_obj) == -1)
+ return NULL;
+ }
+ }
+ }
+ }
+ }
+ catch (const gdb_exception &except)
+ {
+ GDB_PY_HANDLE_EXCEPTION (except);
+ }
+
+ return return_list.release ();
+}
+
/* This function is called when an objfile is about to be freed.
Invalidate the symbol as further actions on the symbol would result
in bad data. All access to obj->symbol should be gated by
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index c5578430cff..703c60032c0 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -426,6 +426,8 @@ PyObject *gdbpy_lookup_global_symbol (PyObject *self, PyObject *args,
PyObject *kw);
PyObject *gdbpy_lookup_static_symbol (PyObject *self, PyObject *args,
PyObject *kw);
+PyObject *gdbpy_lookup_static_symbols (PyObject *self, PyObject *args,
+ PyObject *kw);
PyObject *gdbpy_start_recording (PyObject *self, PyObject *args);
PyObject *gdbpy_current_recording (PyObject *self, PyObject *args);
PyObject *gdbpy_stop_recording (PyObject *self, PyObject *args);
diff --git a/gdb/python/python.c b/gdb/python/python.c
index ddf0e72d26f..f94214e1b24 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1994,6 +1994,10 @@ Return the symbol corresponding to the given name (or None)." },
METH_VARARGS | METH_KEYWORDS,
"lookup_static_symbol (name [, domain]) -> symbol\n\
Return the static-linkage symbol corresponding to the given name (or None)." },
+ { "lookup_static_symbols", (PyCFunction) gdbpy_lookup_static_symbols,
+ METH_VARARGS | METH_KEYWORDS,
+ "lookup_static_symbols (name [, domain]) -> symbol\n\
+Return a list of all static-linkage symbols corresponding to the given name." },

{ "lookup_objfile", (PyCFunction) gdbpy_lookup_objfile,
METH_VARARGS | METH_KEYWORDS,
diff --git a/gdb/testsuite/gdb.python/py-symbol.exp b/gdb/testsuite/gdb.python/py-symbol.exp
index 61960075565..ea41297f54f 100644
--- a/gdb/testsuite/gdb.python/py-symbol.exp
+++ b/gdb/testsuite/gdb.python/py-symbol.exp
@@ -29,6 +29,15 @@ if {[prepare_for_testing "failed to prepare" $testfile \
# Skip all tests if Python scripting is not enabled.
if { [skip_python_tests] } { continue }

+# Check that we find all static symbols before the inferior has
+# started, at which point some of the symtabs might not have been
+# expanded.
+gdb_test "python print (len (gdb.lookup_static_symbols ('rr')))" \
+ "2" "print (len (gdb.lookup_static_symbols ('rr')))"
+
+# Restart so we don't have expanded symtabs after the previous test.
+clean_restart ${binfile}
+
# Test looking up a global symbol before we runto_main as this is the
# point where we don't have a current frame, and we don't want to
# require one.
@@ -108,6 +117,10 @@ gdb_breakpoint "function_in_other_file"
gdb_continue_to_breakpoint "function_in_other_file"
gdb_test "python print (gdb.lookup_static_symbol ('rr').value ())" "99" \
"print value of rr from other file"
+gdb_test "python print (gdb.lookup_static_symbols ('rr')\[0\].value ())" "99" \
+ "print value of gdb.lookup_static_symbols ('rr')\[0\], from the other file"
+gdb_test "python print (gdb.lookup_static_symbols ('rr')\[1\].value ())" "42" \
+ "print value of gdb.lookup_static_symbols ('rr')\[1\], from the other file"

# Now continue back to the first source file.
set linenum [gdb_get_line_number "Break at end."]
@@ -119,6 +132,10 @@ gdb_py_test_silent_cmd "python frame = gdb.selected_frame()" "Get Frame" 0
# static symbol from the second source file.
gdb_test "python print (gdb.lookup_static_symbol ('rr').value ())" "42" \
"print value of rr from main file"
+gdb_test "python print (gdb.lookup_static_symbols ('rr')\[0\].value ())" "99" \
+ "print value of gdb.lookup_static_symbols ('rr')\[0\], from the main file"
+gdb_test "python print (gdb.lookup_static_symbols ('rr')\[1\].value ())" "42" \
+ "print value of gdb.lookup_static_symbols ('rr')\[1\], from the main file"

# Test is_variable attribute.
gdb_py_test_silent_cmd "python a = gdb.lookup_symbol(\'a\')" "Get variable a" 0