[PATCH] Handle block-local names for Ada

Tom Tromey tromey@adacore.com
Tue Nov 10 16:55:03 GMT 2020


GNAT can generate a mangled name with "B_N" (where N is a number) in
the middle, like "hello__B_1__fourth.0".  This is used for names local
to a block.  This patch changes gdb to handle these names.

This patch updates the wild name matcher in a straightforward way.
For the full matcher, it changes gdb to build a regular expression to
match the symbol name.  The hash function is updated to ensure that
this works.

One possible concern here is performance, but testing on a large Ada
program showed that, while the slowdown was perhaps bad in percentage
terms, in absolute terms it seems fine:

For the test of "break nosuch.function", "maint time 1" reports:

before: Command execution time: 0.101233 (cpu), 0.101482 (wall)
after : Command execution time: 0.136016 (cpu), 0.136306 (wall)

This result is typical, so about 4/100 of a second slowdown.

gdb/ChangeLog
2020-11-10  Tom Tromey  <tromey@adacore.com>

	* ada-lang.c (advance_wild_match): Ignore "B".
	(full_match): Remove.
	(ada_lookup_name_info::match_regex): New method.
	(do_full_match): Rewrite.
	* dictionary.c (language_defn::search_name_hash): Ignore "B".
	* gdb_regex.c (~compiled_regex): Check m_owned.
	* gdb_regex.h (compiled_regex): Add move constructor.
	<m_owned>: New member.
	* symtab.h (ada_lookup_name_info::match_regex): Declare
	new method.
	(ada_lookup_name_info::m_full_regex): New member.

gdb/testsuite/ChangeLog
2020-11-10  Tom Tromey  <tromey@adacore.com>

	* gdb.ada/nested.exp: Add new tests.
	* gdb.ada/nested/hello.adb (Fourth): New procedure.
---
 gdb/ChangeLog                          | 14 ++++++
 gdb/ada-lang.c                         | 59 ++++++++++++++++----------
 gdb/dictionary.c                       |  7 +++
 gdb/gdb_regex.c                        |  3 +-
 gdb/gdb_regex.h                        |  8 ++++
 gdb/symtab.h                           |  7 +++
 gdb/testsuite/ChangeLog                |  5 +++
 gdb/testsuite/gdb.ada/nested.exp       |  7 +++
 gdb/testsuite/gdb.ada/nested/hello.adb | 10 ++++-
 9 files changed, 94 insertions(+), 26 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index fe3ea7009a6..7aa738b9187 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -6034,6 +6034,13 @@ advance_wild_match (const char **namep, const char *name0, char target0)
 	      name += 2;
 	      break;
 	    }
+	  else if (t1 == '_' && name[2] == 'B' && name[3] == '_')
+	    {
+	      /* Names like "pkg__B_N__name", where N is a number, are
+		 block-local.  We can handle these by simply skipping
+		 the "B_" here.  */
+	      name += 4;
+	    }
 	  else
 	    return 0;
 	}
@@ -6078,28 +6085,6 @@ wild_match (const char *name, const char *patn)
     }
 }
 
-/* Returns true iff symbol name SYM_NAME matches SEARCH_NAME, ignoring
-   any trailing suffixes that encode debugging information or leading
-   _ada_ on SYM_NAME (see is_name_suffix commentary for the debugging
-   information that is ignored).  */
-
-static bool
-full_match (const char *sym_name, const char *search_name)
-{
-  size_t search_name_len = strlen (search_name);
-
-  if (strncmp (sym_name, search_name, search_name_len) == 0
-      && is_name_suffix (sym_name + search_name_len))
-    return true;
-
-  if (startswith (sym_name, "_ada_")
-      && strncmp (sym_name + 5, search_name, search_name_len) == 0
-      && is_name_suffix (sym_name + search_name_len + 5))
-    return true;
-
-  return false;
-}
-
 /* Add symbols from BLOCK matching LOOKUP_NAME in DOMAIN to vector
    *defn_symbols, updating the list of symbols in OBSTACKP (if
    necessary).  OBJFILE is the section containing BLOCK.  */
@@ -13634,6 +13619,26 @@ do_wild_match (const char *symbol_search_name,
   return wild_match (symbol_search_name, ada_lookup_name (lookup_name));
 }
 
+/* See symtab.h.  */
+
+compiled_regex &
+ada_lookup_name_info::match_regex () const
+{
+  if (!m_full_regex.has_value ())
+    {
+      std::string rx = "^(_ada_)?" + m_encoded_name;
+
+      auto where = rx.rfind ("__");
+      if (where != std::string::npos)
+	rx.insert (where, "(__B_[0-9]*)?");
+
+      m_full_regex.emplace (rx.c_str (), REG_EXTENDED,
+			    "could not convert search name to regular expression");
+    }
+
+  return *m_full_regex;
+}
+
 /* symbol_name_matcher_ftype adapter for full_match.  */
 
 static bool
@@ -13641,7 +13646,15 @@ do_full_match (const char *symbol_search_name,
 	       const lookup_name_info &lookup_name,
 	       completion_match_result *comp_match_res)
 {
-  return full_match (symbol_search_name, ada_lookup_name (lookup_name));
+  compiled_regex &rx = lookup_name.ada ().match_regex ();
+
+  regmatch_t matches[2];
+  if (rx.exec (symbol_search_name, 2, matches, 0) != 0)
+    return false;
+
+  if (is_name_suffix (symbol_search_name + matches[0].rm_eo))
+    return true;
+  return false;
 }
 
 /* symbol_name_matcher_ftype for exact (verbatim) matches.  */
diff --git a/gdb/dictionary.c b/gdb/dictionary.c
index c94a49ee373..d51f209e715 100644
--- a/gdb/dictionary.c
+++ b/gdb/dictionary.c
@@ -761,6 +761,13 @@ language_defn::search_name_hash (const char *string0) const
 	    {
 	      int c = string[2];
 
+	      if (c == 'B' && string[3] == '_')
+		{
+		  for (string += 4; ISDIGIT (*string); ++string)
+		    ;
+		  continue;
+		}
+
 	      if ((c < 'a' || c > 'z') && c != 'O')
 		return hash;
 	      hash = 0;
diff --git a/gdb/gdb_regex.c b/gdb/gdb_regex.c
index 063c68b097b..7d991d520fd 100644
--- a/gdb/gdb_regex.c
+++ b/gdb/gdb_regex.c
@@ -38,7 +38,8 @@ compiled_regex::compiled_regex (const char *regex, int cflags,
 
 compiled_regex::~compiled_regex ()
 {
-  regfree (&m_pattern);
+  if (m_owned)
+    regfree (&m_pattern);
 }
 
 int
diff --git a/gdb/gdb_regex.h b/gdb/gdb_regex.h
index 311cb3fd89d..1a1d3d1b378 100644
--- a/gdb/gdb_regex.h
+++ b/gdb/gdb_regex.h
@@ -45,6 +45,12 @@ class compiled_regex
 
   DISABLE_COPY_AND_ASSIGN (compiled_regex);
 
+  explicit compiled_regex (compiled_regex &&other)
+    : m_pattern (other.m_pattern)
+  {
+    other.m_owned = false;
+  }
+
   /* Wrapper around ::regexec.  */
   int exec (const char *string,
 	    size_t nmatch, regmatch_t pmatch[],
@@ -56,6 +62,8 @@ class compiled_regex
 	      int range, struct re_registers *regs);
 
 private:
+  bool m_owned = true;
+
   /* The compiled pattern.  */
   regex_t m_pattern;
 };
diff --git a/gdb/symtab.h b/gdb/symtab.h
index dd67f864f3e..49a880dcdf2 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -120,10 +120,17 @@ class ada_lookup_name_info final
   bool verbatim_p () const
   { return m_verbatim_p; }
 
+  compiled_regex &match_regex () const;
+
 private:
   /* The Ada-encoded lookup name.  */
   std::string m_encoded_name;
 
+  /* A regular expression that matches the full name of a symbol.
+     This is lazily constructed and only used when doing full
+     matches.  */
+  mutable gdb::optional<compiled_regex> m_full_regex;
+
   /* Whether the user-provided lookup name was Ada encoded.  If so,
      then return encoded names in the 'matches' method's 'completion
      match result' output.  */
diff --git a/gdb/testsuite/gdb.ada/nested.exp b/gdb/testsuite/gdb.ada/nested.exp
index ea4bb4de355..ca146f95786 100644
--- a/gdb/testsuite/gdb.ada/nested.exp
+++ b/gdb/testsuite/gdb.ada/nested.exp
@@ -34,3 +34,10 @@ gdb_test "break first" \
          "Breakpoint $any_nb at $any_addr: file .*hello.adb, line $any_nb." \
          "break on nested function First"
 
+gdb_test "break fourth" \
+    "Breakpoint $any_nb at $any_addr: file .*hello.adb, line $any_nb." \
+    "break on nested function fourth"
+
+gdb_test "break hello.fourth" \
+    "Breakpoint $any_nb at $any_addr: file .*hello.adb, line $any_nb." \
+    "full-qualified break on nested function fourth"
diff --git a/gdb/testsuite/gdb.ada/nested/hello.adb b/gdb/testsuite/gdb.ada/nested/hello.adb
index 2d1e532e47d..d335ee43fc3 100644
--- a/gdb/testsuite/gdb.ada/nested/hello.adb
+++ b/gdb/testsuite/gdb.ada/nested/hello.adb
@@ -31,6 +31,12 @@ procedure Hello is
    end Third;
 
 begin
-   Third;
+   declare
+      procedure Fourth is
+      begin
+         Third;
+      end Fourth;
+   begin
+      Fourth;
+   end;
 end Hello;
-
-- 
2.26.2



More information about the Gdb-patches mailing list