[gdb/symtab] Prefer def over decl (inter-CU case)
authorTom de Vries <tdevries@suse.de>
Thu, 23 Apr 2020 13:42:47 +0000 (15:42 +0200)
committerTom de Vries <tdevries@suse.de>
Thu, 23 Apr 2020 13:42:47 +0000 (15:42 +0200)
When running test-case gdb.threads/tls.exp with target board -readnow, we
have:
...
(gdb) print a_thread_local^M
Cannot find thread-local storage for process 0, executable file tls/tls:^M
Cannot find thread-local variables on this target^M
(gdb) FAIL: gdb.threads/tls.exp: print a_thread_local
...
while with native we have:
...
(gdb) print a_thread_local^M
Cannot read `a_thread_local' without registers^M
(gdb) PASS: gdb.threads/tls.exp: print a_thread_local
...

The difference in behaviour can be explained as follows.  Without -readnow, we
have two a_thread_locals, the def and the decl, each in a different CU:
...
$ gdb -batch outputs/gdb.threads/tls/tls \
    -ex "maint expand-symtabs" \
    -ex "print a_thread_local" \
    -ex "maint print symbols" \
    | grep "a_thread_local;"
Cannot read `a_thread_local' without registers
 int a_thread_local; computed at runtime
 int a_thread_local; unresolved
...
and with -readnow, we have the opposite order:
...
$ gdb -readnow -batch outputs/gdb.threads/tls/tls  \
    -ex "maint expand-symtabs" \
    -ex "print a_thread_local" \
    -ex "maint print symbols" \
    | grep "a_thread_local;"
Cannot find thread-local storage for process 0, executable file tls/tls:
Cannot find thread-local variables on this target
 int a_thread_local; unresolved
 int a_thread_local; computed at runtime
...

Fix the FAIL by preferring the def over the decl (something we already do
intra-CU since the fix for PR24971, commit 93e55f0a03 "[gdb/symtab] Prefer var
def over decl").

Build and reg-tested on x86_64-linux.

gdb/ChangeLog:

2020-04-23  Tom de Vries  <tdevries@suse.de>

PR symtab/25807
* block.c (best_symbol, better_symbol): Promote to external.
* block.h (best_symbol, better_symbol): Declare.
* symtab.c (lookup_symbol_in_objfile_symtabs): Prefer def over
decl.

gdb/testsuite/ChangeLog:

2020-04-23  Tom de Vries  <tdevries@suse.de>

* gdb.base/decl-before-def-decl.c: New test.
* gdb.base/decl-before-def-def.c: New test.
* gdb.base/decl-before-def.exp: New file.

gdb/ChangeLog
gdb/block.c
gdb/block.h
gdb/symtab.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/decl-before-def-decl.c [new file with mode: 0644]
gdb/testsuite/gdb.base/decl-before-def-def.c [new file with mode: 0644]
gdb/testsuite/gdb.base/decl-before-def.exp [new file with mode: 0644]

index cbe2693719835e59005de28d44f5b0031d6ea587..f1ebf09ff468067947f29585198f85d6590bd32e 100644 (file)
@@ -1,3 +1,11 @@
+2020-04-23  Tom de Vries  <tdevries@suse.de>
+
+       PR symtab/25807
+       * block.c (best_symbol, better_symbol): Promote to external.
+       * block.h (best_symbol, better_symbol): Declare.
+       * symtab.c (lookup_symbol_in_objfile_symtabs): Prefer def over
+       decl.
+
 2020-04-23  Tom Tromey  <tromey@adacore.com>
 
        PR ada/25837:
index 9b582433e48b8684f272d424ea2c9dbf997f0bca..597d6d5d875a9b7a12af20d9e9780b42deef4ef3 100644 (file)
@@ -657,19 +657,18 @@ block_iter_match_next (const lookup_name_info &name,
   return block_iter_match_step (iterator, name, 0);
 }
 
-/* Return true if symbol A is the best match possible for DOMAIN.  */
+/* See block.h.  */
 
-static bool
+bool
 best_symbol (struct symbol *a, const domain_enum domain)
 {
   return (SYMBOL_DOMAIN (a) == domain
          && SYMBOL_CLASS (a) != LOC_UNRESOLVED);
 }
 
-/* Return symbol B if it is a better match than symbol A for DOMAIN.
-   Otherwise return A.  */
+/* See block.h.  */
 
-static struct symbol *
+struct symbol *
 better_symbol (struct symbol *a, struct symbol *b, const domain_enum domain)
 {
   if (a == NULL)
index 7c0b2d36966ae0054fc5dd462edda87ca8a063cc..50ab049f8e61b171c93048bc08a5f62ca640ef64 100644 (file)
@@ -342,6 +342,16 @@ extern struct symbol *block_iter_match_first (const struct block *block,
 extern struct symbol *block_iter_match_next
   (const lookup_name_info &name, struct block_iterator *iterator);
 
+/* Return true if symbol A is the best match possible for DOMAIN.  */
+
+extern bool best_symbol (struct symbol *a, const domain_enum domain);
+
+/* Return symbol B if it is a better match than symbol A for DOMAIN.
+   Otherwise return A.  */
+
+extern struct symbol *better_symbol (struct symbol *a, struct symbol *b,
+                                    const domain_enum domain);
+
 /* Search BLOCK for symbol NAME in DOMAIN.  */
 
 extern struct symbol *block_lookup_symbol (const struct block *block,
index dc079efbc2717f858d486bea13e6e7fd05c7f784..1eef97837e8b0f71a47e7d9c4a2dc9bcea0745ad 100644 (file)
@@ -2285,6 +2285,8 @@ lookup_symbol_in_objfile_symtabs (struct objfile *objfile,
                          name, domain_name (domain));
     }
 
+  struct block_symbol other;
+  other.symbol = NULL;
   for (compunit_symtab *cust : objfile->compunits ())
     {
       const struct blockvector *bv;
@@ -2295,18 +2297,36 @@ lookup_symbol_in_objfile_symtabs (struct objfile *objfile,
       block = BLOCKVECTOR_BLOCK (bv, block_index);
       result.symbol = block_lookup_symbol_primary (block, name, domain);
       result.block = block;
-      if (result.symbol != NULL)
+      if (result.symbol == NULL)
+       continue;
+      if (best_symbol (result.symbol, domain))
        {
-         if (symbol_lookup_debug > 1)
+         other = result;
+         break;
+       }
+      if (symbol_matches_domain (result.symbol->language (),
+                                SYMBOL_DOMAIN (result.symbol), domain))
+       {
+         struct symbol *better
+           = better_symbol (other.symbol, result.symbol, domain);
+         if (better != other.symbol)
            {
-             fprintf_unfiltered (gdb_stdlog, " = %s (block %s)\n",
-                                 host_address_to_string (result.symbol),
-                                 host_address_to_string (block));
+             other.symbol = better;
+             other.block = block;
            }
-         result.symbol = fixup_symbol_section (result.symbol, objfile);
-         return result;
+       }
+    }
 
+  if (other.symbol != NULL)
+    {
+      if (symbol_lookup_debug > 1)
+       {
+         fprintf_unfiltered (gdb_stdlog, " = %s (block %s)\n",
+                             host_address_to_string (other.symbol),
+                             host_address_to_string (other.block));
        }
+      other.symbol = fixup_symbol_section (other.symbol, objfile);
+      return other;
     }
 
   if (symbol_lookup_debug > 1)
index 7e6bf73fa41bc8cd28658f5d4219ad7d8326f30f..e37aca2b5af2e92bf3a2293aa50b7e1aa0aecac5 100644 (file)
@@ -1,3 +1,9 @@
+2020-04-23  Tom de Vries  <tdevries@suse.de>
+
+       * gdb.base/decl-before-def-decl.c: New test.
+       * gdb.base/decl-before-def-def.c: New test.
+       * gdb.base/decl-before-def.exp: New file.
+
 2020-04-23  Tom de Vries  <tdevries@suse.de>
 
        * gdb.base/readnever.exp: Skip if GDBFLAGS contain -readnow/--readnow.
diff --git a/gdb/testsuite/gdb.base/decl-before-def-decl.c b/gdb/testsuite/gdb.base/decl-before-def-decl.c
new file mode 100644 (file)
index 0000000..3e4e6d7
--- /dev/null
@@ -0,0 +1,25 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2020 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+extern int a[];
+
+int
+main (void)
+{
+  a[0] = 1;
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/decl-before-def-def.c b/gdb/testsuite/gdb.base/decl-before-def-def.c
new file mode 100644 (file)
index 0000000..4d25248
--- /dev/null
@@ -0,0 +1,18 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2020 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+int a[2] = { 1, 2 };
diff --git a/gdb/testsuite/gdb.base/decl-before-def.exp b/gdb/testsuite/gdb.base/decl-before-def.exp
new file mode 100644 (file)
index 0000000..feb2084
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+standard_testfile decl-before-def-decl.c decl-before-def-def.c
+set sources [list $srcfile $srcfile2]
+
+if {[prepare_for_testing "failed to prepare" $testfile $sources]} {
+    return -1
+}
+
+# This is required due to PR25764.
+gdb_test "maint expand-symtabs"
+
+gdb_test "p a" { = \{1, 2\}}