[PR,symtab/18258] Fix.

Message ID yjt24mofipup.fsf@ruffy.mtv.corp.google.com
State New, archived
Headers

Commit Message

Doug Evans April 17, 2015, 12:02 a.m. UTC
  Hi.

This patch fixes pr 18258.
https://sourceware.org/bugzilla/show_bug.cgi?id=18258

The problem is described pretty well in the PR.
Basically, we need to include the opaque-type test while we're
iterating over compunit_symtab->includes.

Regression tested on amd64-linux.

2015-04-16  Doug Evans  <dje@google.com>

	PR symtab/18258
	* block.c (block_find_symbol): New function.
	(block_find_non_opaque_type): Ditto.
	(block_find_non_opaque_type_preferred): Ditto.
	* block.h (block_symbol_matcher_ftype): New typedef.
	(block_find_symbol): Declare.
	(block_find_non_opaque_type): Ditto.
	(block_find_non_opaque_type_preferred): Ditto.
	* dwarf2read.c (dw2_lookup_symbol): Call block_find_symbol.
	* psymtab.c (psym_lookup_symbol): Ditto.
	* symtab.c (basic_lookup_transparent_type_1): New function.
	(basic_lookup_transparent_type): Call it.

	testsuite/
	PR symtab/18258
	* gdb.dwarf2/opaque-type-lookup-2.c: New file.
	* gdb.dwarf2/opaque-type-lookup.c: New file.
	* gdb.dwarf2/opaque-type-lookup.exp: New file.
  

Comments

Doug Evans May 27, 2015, 6:54 p.m. UTC | #1
On Thu, Apr 16, 2015 at 5:02 PM, Doug Evans <dje@google.com> wrote:
> Hi.
>
> This patch fixes pr 18258.
> https://sourceware.org/bugzilla/show_bug.cgi?id=18258
>
> The problem is described pretty well in the PR.
> Basically, we need to include the opaque-type test while we're
> iterating over compunit_symtab->includes.
>
> Regression tested on amd64-linux.
>
> 2015-04-16  Doug Evans  <dje@google.com>
>
>         PR symtab/18258
>         * block.c (block_find_symbol): New function.
>         (block_find_non_opaque_type): Ditto.
>         (block_find_non_opaque_type_preferred): Ditto.
>         * block.h (block_symbol_matcher_ftype): New typedef.
>         (block_find_symbol): Declare.
>         (block_find_non_opaque_type): Ditto.
>         (block_find_non_opaque_type_preferred): Ditto.
>         * dwarf2read.c (dw2_lookup_symbol): Call block_find_symbol.
>         * psymtab.c (psym_lookup_symbol): Ditto.
>         * symtab.c (basic_lookup_transparent_type_1): New function.
>         (basic_lookup_transparent_type): Call it.
>
>         testsuite/
>         PR symtab/18258
>         * gdb.dwarf2/opaque-type-lookup-2.c: New file.
>         * gdb.dwarf2/opaque-type-lookup.c: New file.
>         * gdb.dwarf2/opaque-type-lookup.exp: New file.

Committed.
  

Patch

diff --git a/gdb/block.c b/gdb/block.c
index 00a7012..79a8f19 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -797,3 +797,50 @@  block_lookup_symbol_primary (const struct block *block, const char *name,
 
   return NULL;
 }
+
+/* See block.h.  */
+
+struct symbol *
+block_find_symbol (const struct block *block, const char *name,
+		   const domain_enum domain,
+		   block_symbol_matcher_ftype *matcher, void *data)
+{
+  struct block_iterator iter;
+  struct symbol *sym;
+
+  /* Verify BLOCK is STATIC_BLOCK or GLOBAL_BLOCK.  */
+  gdb_assert (BLOCK_SUPERBLOCK (block) == NULL
+	      || BLOCK_SUPERBLOCK (BLOCK_SUPERBLOCK (block)) == NULL);
+
+  ALL_BLOCK_SYMBOLS_WITH_NAME (block, name, iter, sym)
+    {
+      /* MATCHER is deliberately called second here so that it never sees
+	 a non-domain-matching symbol.  */
+      if (symbol_matches_domain (SYMBOL_LANGUAGE (sym),
+				 SYMBOL_DOMAIN (sym), domain)
+	  && matcher (sym, data))
+	return sym;
+    }
+  return NULL;
+}
+
+/* See block.h.  */
+
+int
+block_find_non_opaque_type (struct symbol *sym, void *data)
+{
+  return !TYPE_IS_OPAQUE (SYMBOL_TYPE (sym));
+}
+
+/* See block.h.  */
+
+int
+block_find_non_opaque_type_preferred (struct symbol *sym, void *data)
+{
+  struct symbol **best = data;
+
+  if (!TYPE_IS_OPAQUE (SYMBOL_TYPE (sym)))
+    return 1;
+  *best = sym;
+  return 0;
+}
diff --git a/gdb/block.h b/gdb/block.h
index bdc5888..d8ad343 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -292,6 +292,40 @@  extern struct symbol *block_lookup_symbol_primary (const struct block *block,
 						   const char *name,
 						   const domain_enum domain);
 
+/* The type of the MATCHER argument to block_find_symbol.  */
+
+typedef int (block_symbol_matcher_ftype) (struct symbol *, void *);
+
+/* Find symbol NAME in BLOCK and in DOMAIN that satisfies MATCHER.
+   DATA is passed unchanged to MATCHER.
+   BLOCK must be STATIC_BLOCK or GLOBAL_BLOCK.  */
+
+extern struct symbol *block_find_symbol (const struct block *block,
+					 const char *name,
+					 const domain_enum domain,
+					 block_symbol_matcher_ftype *matcher,
+					 void *data);
+
+/* A matcher function for block_find_symbol to find only symbols with
+   non-opaque types.  */
+
+extern int block_find_non_opaque_type (struct symbol *sym, void *data);
+
+/* A matcher function for block_find_symbol to prefer symbols with
+   non-opaque types.  The way to use this function is as follows:
+
+   struct symbol *with_opaque = NULL;
+   struct symbol *sym
+     = block_find_symbol (block, name, domain,
+                          block_find_non_opaque_type_preferred, &with_opaque);
+
+   At this point if SYM is non-NULL then a non-opaque type has been found.
+   Otherwise, if WITH_OPAQUE is non-NULL then an opaque type has been found.
+   Otherwise, the symbol was not found.  */
+
+extern int block_find_non_opaque_type_preferred (struct symbol *sym,
+						 void *data);
+
 /* Macro to loop through all symbols in BLOCK, in no particular
    order.  ITER helps keep track of the iteration, and must be a
    struct block_iterator.  SYM points to the current symbol.  */
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index b91fbf5..85e4b28 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -3663,23 +3663,25 @@  dw2_lookup_symbol (struct objfile *objfile, int block_index,
 
       while ((per_cu = dw2_symtab_iter_next (&iter)) != NULL)
 	{
-	  struct symbol *sym = NULL;
+	  struct symbol *sym, *with_opaque = NULL;
 	  struct compunit_symtab *stab = dw2_instantiate_symtab (per_cu);
 	  const struct blockvector *bv = COMPUNIT_BLOCKVECTOR (stab);
 	  struct block *block = BLOCKVECTOR_BLOCK (bv, block_index);
 
+	  sym = block_find_symbol (block, name, domain,
+				   block_find_non_opaque_type_preferred,
+				   &with_opaque);
+
 	  /* Some caution must be observed with overloaded functions
 	     and methods, since the index will not contain any overload
 	     information (but NAME might contain it).  */
-	  sym = block_lookup_symbol (block, name, domain);
-
-	  if (sym && strcmp_iw (SYMBOL_SEARCH_NAME (sym), name) == 0)
-	    {
-	      if (!TYPE_IS_OPAQUE (SYMBOL_TYPE (sym)))
-		return stab;
 
-	      stab_best = stab;
-	    }
+	  if (sym != NULL
+	      && strcmp_iw (SYMBOL_SEARCH_NAME (sym), name) == 0)
+	    return stab;
+	  if (with_opaque != NULL
+	      && strcmp_iw (SYMBOL_SEARCH_NAME (with_opaque), name) == 0)
+	    stab_best = stab;
 
 	  /* Keep looking through other CUs.  */
 	}
diff --git a/gdb/psymtab.c b/gdb/psymtab.c
index 383e4c4..9ee6ed1 100644
--- a/gdb/psymtab.c
+++ b/gdb/psymtab.c
@@ -516,7 +516,7 @@  psym_lookup_symbol (struct objfile *objfile,
     if (!ps->readin && lookup_partial_symbol (objfile, ps, name,
 					      psymtab_index, domain))
       {
-	struct symbol *sym = NULL;
+	struct symbol *sym, *with_opaque = NULL;
 	struct compunit_symtab *stab = psymtab_to_symtab (objfile, ps);
 	/* Note: While psymtab_to_symtab can return NULL if the partial symtab
 	   is empty, we can assume it won't here because lookup_partial_symbol
@@ -524,18 +524,20 @@  psym_lookup_symbol (struct objfile *objfile,
 	const struct blockvector *bv = COMPUNIT_BLOCKVECTOR (stab);
 	struct block *block = BLOCKVECTOR_BLOCK (bv, block_index);
 
+	sym = block_find_symbol (block, name, domain,
+				 block_find_non_opaque_type_preferred,
+				 &with_opaque);
+
 	/* Some caution must be observed with overloaded functions
-	   and methods, since the psymtab will not contain any overload
+	   and methods, since the index will not contain any overload
 	   information (but NAME might contain it).  */
-	sym = block_lookup_symbol (block, name, domain);
-
-	if (sym && strcmp_iw (SYMBOL_SEARCH_NAME (sym), name) == 0)
-	  {
-	    if (!TYPE_IS_OPAQUE (SYMBOL_TYPE (sym)))
-	      return stab;
 
-	    stab_best = stab;
-	  }
+	if (sym != NULL
+	    && strcmp_iw (SYMBOL_SEARCH_NAME (sym), name) == 0)
+	  return stab;
+	if (with_opaque != NULL
+	    && strcmp_iw (SYMBOL_SEARCH_NAME (with_opaque), name) == 0)
+	  stab_best = stab;
 
 	/* Keep looking through other psymtabs.  */
       }
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 72df872..6693930 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -2804,12 +2804,39 @@  basic_lookup_transparent_type_quick (struct objfile *objfile, int block_index,
 
   bv = COMPUNIT_BLOCKVECTOR (cust);
   block = BLOCKVECTOR_BLOCK (bv, block_index);
-  sym = block_lookup_symbol (block, name, STRUCT_DOMAIN);
-  if (!sym)
+  sym = block_find_symbol (block, name, STRUCT_DOMAIN,
+			   block_find_non_opaque_type, NULL);
+  if (sym == NULL)
     error_in_psymtab_expansion (block_index, name, cust);
+  gdb_assert (!TYPE_IS_OPAQUE (SYMBOL_TYPE (sym)));
+  return SYMBOL_TYPE (sym);
+}
+
+/* Subroutine of basic_lookup_transparent_type to simplify it.
+   Look up the non-opaque definition of NAME in BLOCK_INDEX of OBJFILE.
+   BLOCK_INDEX is either GLOBAL_BLOCK or STATIC_BLOCK.  */
 
-  if (!TYPE_IS_OPAQUE (SYMBOL_TYPE (sym)))
-    return SYMBOL_TYPE (sym);
+static struct type *
+basic_lookup_transparent_type_1 (struct objfile *objfile, int block_index,
+				 const char *name)
+{
+  const struct compunit_symtab *cust;
+  const struct blockvector *bv;
+  const struct block *block;
+  const struct symbol *sym;
+
+  ALL_OBJFILE_COMPUNITS (objfile, cust)
+    {
+      bv = COMPUNIT_BLOCKVECTOR (cust);
+      block = BLOCKVECTOR_BLOCK (bv, block_index);
+      sym = block_find_symbol (block, name, STRUCT_DOMAIN,
+			       block_find_non_opaque_type, NULL);
+      if (sym != NULL)
+	{
+	  gdb_assert (!TYPE_IS_OPAQUE (SYMBOL_TYPE (sym)));
+	  return SYMBOL_TYPE (sym);
+	}
+    }
 
   return NULL;
 }
@@ -2837,16 +2864,9 @@  basic_lookup_transparent_type (const char *name)
 
   ALL_OBJFILES (objfile)
   {
-    ALL_OBJFILE_COMPUNITS (objfile, cust)
-      {
-	bv = COMPUNIT_BLOCKVECTOR (cust);
-	block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
-	sym = block_lookup_symbol (block, name, STRUCT_DOMAIN);
-	if (sym && !TYPE_IS_OPAQUE (SYMBOL_TYPE (sym)))
-	  {
-	    return SYMBOL_TYPE (sym);
-	  }
-      }
+    t = basic_lookup_transparent_type_1 (objfile, GLOBAL_BLOCK, name);
+    if (t)
+      return t;
   }
 
   ALL_OBJFILES (objfile)
@@ -2865,16 +2885,9 @@  basic_lookup_transparent_type (const char *name)
 
   ALL_OBJFILES (objfile)
   {
-    ALL_OBJFILE_COMPUNITS (objfile, cust)
-      {
-	bv = COMPUNIT_BLOCKVECTOR (cust);
-	block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
-	sym = block_lookup_symbol (block, name, STRUCT_DOMAIN);
-	if (sym && !TYPE_IS_OPAQUE (SYMBOL_TYPE (sym)))
-	  {
-	    return SYMBOL_TYPE (sym);
-	  }
-      }
+    t = basic_lookup_transparent_type_1 (objfile, STATIC_BLOCK, name);
+    if (t)
+      return t;
   }
 
   ALL_OBJFILES (objfile)
diff --git a/gdb/testsuite/gdb.dwarf2/opaque-type-lookup-2.c b/gdb/testsuite/gdb.dwarf2/opaque-type-lookup-2.c
new file mode 100644
index 0000000..948e26d
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/opaque-type-lookup-2.c
@@ -0,0 +1,24 @@ 
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2015 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/>.  */
+
+/* These are actually struct struct_{a,b}, but that's handled by the dwarf
+   in opaque-type-lookup.exp.
+   IWBN to give these a different name than what's in the dwarf so that minsym
+   lookup doesn't interfere with the testing.  However, that currently doesn't
+   work (we don't record the linkage name of the symbol).  */
+char variable_a = 'a';
+char variable_b = 'b';
diff --git a/gdb/testsuite/gdb.dwarf2/opaque-type-lookup.c b/gdb/testsuite/gdb.dwarf2/opaque-type-lookup.c
new file mode 100644
index 0000000..7cfe08e
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/opaque-type-lookup.c
@@ -0,0 +1,23 @@ 
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2015 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
+main()
+{
+  asm ("main_label: .globl main_label");
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.dwarf2/opaque-type-lookup.exp b/gdb/testsuite/gdb.dwarf2/opaque-type-lookup.exp
new file mode 100644
index 0000000..67f6dbf
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/opaque-type-lookup.exp
@@ -0,0 +1,200 @@ 
+# Copyright 2013-2015 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/>.
+
+# Test PR 18258.
+
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+    return 0
+}
+
+standard_testfile opaque-type-lookup.c opaque-type-lookup-1.S opaque-type-lookup-2.c
+
+# Create the DWARF.
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    declare_labels partial_unit_defining_a partial_unit_defining_b
+    declare_labels partial_unit_with_opaque
+    declare_labels struct_a_label struct_b_label
+    declare_labels opaque_struct_a_label opaque_struct_b_label
+    declare_labels char_type1_label char_type2_label
+    global srcdir subdir srcfile
+
+    extern main
+
+    # The partial units are laid out so we're not dependent on the order that
+    # they appear in compunit_symtab.includes.  We need the one with the
+    # opaque definition to appear first to gdb, so we put it in the middle.
+    # Either the handling of variable_a or variable_b will be broken (in an
+    # unpatched gdb).
+    #
+    # However, once a partial unit with a non-opaque type is read in we can
+    # no longer see the bug as gdb will keep looking until it eventually gets
+    # to the defining partial unit, setting aside the symbol lookup cache.
+    # So heads up!
+
+    cu {} {
+	compile_unit {
+	    {language @DW_LANG_C}
+	    {name opaque_before}
+	} {
+	    imported_unit {
+		{import $partial_unit_with_opaque ref_addr}
+	    }
+
+	    imported_unit {
+		{import $partial_unit_defining_a ref_addr}
+	    }
+	}
+    }
+
+    cu {} {
+	compile_unit {
+	    {language @DW_LANG_C}
+	    {name opaque_after}
+	} {
+	    imported_unit {
+		{import $partial_unit_defining_b ref_addr}
+	    }
+
+	    imported_unit {
+		{import $partial_unit_with_opaque ref_addr}
+	    }
+	}
+    }
+
+    cu {} {
+	partial_unit_with_opaque: partial_unit {
+	    {name "partial_unit_with_opaque"}
+	} {
+	    # Normally gdb doesn't add opaque types to the symbol table
+	    # but there are times when it will, and in order to exercise
+	    # this bug we need this entry in the symbol table.
+	    # By giving it a size of 1 we achieve this.
+
+	    opaque_struct_a_label: structure_type {
+		{name struct_a}
+		{declaration 1 flag}
+		{byte_size 1 DW_FORM_sdata}
+	    }
+
+	    opaque_struct_b_label: structure_type {
+		{name struct_b}
+		{declaration 1 flag}
+		{byte_size 1 DW_FORM_sdata}
+	    }
+
+	    DW_TAG_variable {
+		{name variable_a}
+		{type :$opaque_struct_a_label}
+		{external 1 flag}
+		{declaration 1 flag}
+	    }
+
+	    DW_TAG_variable {
+		{name variable_b}
+		{type :$opaque_struct_b_label}
+		{external 1 flag}
+		{declaration 1 flag}
+	    }
+	}
+    }
+
+    cu {} {
+	partial_unit_defining_a: partial_unit {
+	    {name "partial_unit_defining_a"}
+	} {
+	    char_type1_label: base_type {
+		{name "signed char"}
+		{encoding @DW_ATE_signed}
+		{byte_size 1 DW_FORM_sdata}
+	    }
+
+	    struct_a_label: structure_type {
+		{name struct_a}
+		{byte_size 1 DW_FORM_sdata}
+	    } {
+		member {
+		    {name xyz}
+		    {type :$char_type1_label}
+		    {data_member_location 0 DW_FORM_sdata}
+		}
+	    }
+
+	    DW_TAG_variable {
+		{name variable_a}
+		{type :$struct_a_label}
+		{external 1 flag}
+		{linkage_name variable_a}
+	    }
+	}
+    }
+
+    cu {} {
+	partial_unit_defining_b: partial_unit {
+	    {name "partial_unit_defining_b"}
+	} {
+	    char_type2_label: base_type {
+		{name "signed char"}
+		{encoding @DW_ATE_signed}
+		{byte_size 1 DW_FORM_sdata}
+	    }
+
+	    struct_b_label: structure_type {
+		{name struct_b}
+		{byte_size 1 DW_FORM_sdata}
+	    } {
+		member {
+		    {name xyz}
+		    {type :$char_type2_label}
+		    {data_member_location 0 DW_FORM_sdata}
+		}
+	    }
+
+	    DW_TAG_variable {
+		{name variable_b}
+		{type :$struct_b_label}
+		{external 1 flag}
+		{linkage_name variable_b}
+	    }
+	}
+    }
+
+    # GDB expands the symbol table with main at start up,
+    # so keep this separate.
+    cu {} {
+	compile_unit {
+	    {language @DW_LANG_C}
+	    {name main}
+	} {
+	    subprogram {
+ 		{MACRO_AT_func { main ${srcdir}/${subdir}/${srcfile} }}
+	    }
+	}
+    }
+}
+
+if [prepare_for_testing ${testfile}.exp $testfile "${asm_file} ${srcfile} ${srcfile3}" {nodebug}] {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+gdb_test "p variable_a" " = {xyz = 97 'a'}"
+gdb_test "p variable_b" " = {xyz = 98 'b'}"