Blob Blame History Raw
From e385593eef98ac92be57159e141f4b805dadbbb3 Mon Sep 17 00:00:00 2001
From: Jan Kratochvil <jan.kratochvil@redhat.com>
Date: Mon, 30 May 2016 14:14:43 +0200
Subject: [PATCH 2/2] PR 15231: import bare DW_TAG_lexical_block

Local variables in lambdas are not accessible
https://sourceware.org/bugzilla/show_bug.cgi?id=15231

GDB: read_lexical_block_scope
  /* Ignore blocks with missing or invalid low and high pc attributes.  */
[...]
  if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu, NULL))
    return;

But sometimes there is:

FAIL: gcc-5.3.1-6.fc23.x86_64
 <2><92>: Abbrev Number: 11 (DW_TAG_lexical_block)
 <3><9c>: Abbrev Number: 13 (DW_TAG_structure_type)
    <9d>   DW_AT_name        : (indirect string, offset: 0x3c): <lambda()>
    [...]

Where DW_TAG_lexical_block has no attributes.  Such whole subtree is currently
dropped by GDB while I think it should just import all its children DIEs.

It even XFAIL->XPASSes gdb.ada/out_of_line_in_inlined.exp:
	commit 0fa7fe506c242b459c4c05d331e7c7d66fb52390
	Author: Joel Brobecker <brobecker@adacore.com>
	    out of line functions nested inside inline functions.
So I have removed that xfail.

gdb/ChangeLog
2016-05-30  Jan Kratochvil  <jan.kratochvil@redhat.com>

	PR c++/15231
	* dwarf2read.c (enum pc_bounds_kind): Add PC_BOUNDS_INVALID.
	(process_psymtab_comp_unit_reader, read_func_scope): Adjust callers.
	(read_lexical_block_scope): Import DIEs from bare DW_TAG_lexical_block.
	(read_call_site_scope): Adjust callers.
	(dwarf2_get_pc_bounds): Implement pc_bounds_invalid.
	(dwarf2_get_subprogram_pc_bounds, get_scope_pc_bounds): Adjust callers.

gdb/testsuite/ChangeLog
2016-05-30  Jan Kratochvil  <jan.kratochvil@redhat.com>

	PR c++/15231
	* gdb.ada/out_of_line_in_inlined.exp: Remove xfails.
	* gdb.dwarf2/dw2-lexical-block-bare.exp: New file.
---
 gdb/ChangeLog                                      | 10 ++++
 gdb/dwarf2read.c                                   | 53 ++++++++++------
 gdb/testsuite/ChangeLog                            |  6 ++
 gdb/testsuite/gdb.ada/out_of_line_in_inlined.exp   |  6 --
 .../gdb.dwarf2/dw2-lexical-block-bare.exp          | 70 ++++++++++++++++++++++
 5 files changed, 120 insertions(+), 25 deletions(-)
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-lexical-block-bare.exp

### a/gdb/ChangeLog
### b/gdb/ChangeLog
## -1,5 +1,15 @@
 2016-05-30  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
+	PR c++/15231
+	* dwarf2read.c (enum pc_bounds_kind): Add PC_BOUNDS_INVALID.
+	(process_psymtab_comp_unit_reader, read_func_scope): Adjust callers.
+	(read_lexical_block_scope): Import DIEs from bare DW_TAG_lexical_block.
+	(read_call_site_scope): Adjust callers.
+	(dwarf2_get_pc_bounds): Implement pc_bounds_invalid.
+	(dwarf2_get_subprogram_pc_bounds, get_scope_pc_bounds): Adjust callers.
+
+2016-05-30  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
 	Code cleanup: dwarf2_get_pc_bounds: -1/0/+1 -> enum
 	* dwarf2read.c (enum pc_bounds_kind) New.
 	(dwarf2_get_pc_bounds): Use it in the declaration.
Index: gdb-7.6.1/gdb/dwarf2read.c
===================================================================
--- gdb-7.6.1.orig/gdb/dwarf2read.c	2016-05-30 15:07:34.285853679 +0200
+++ gdb-7.6.1/gdb/dwarf2read.c	2016-05-30 15:08:13.485197538 +0200
@@ -1486,13 +1486,16 @@
 			       struct dwarf2_cu *, struct partial_symtab *);
 
 /* How dwarf2_get_pc_bounds constructed its *LOWPC and *HIGHPC return
-   values.  */
+   values.  Keep the items ordered with increasing constraints compliance.  */
 enum pc_bounds_kind
 {
-  /* No valid combination of DW_AT_low_pc, DW_AT_high_pc or DW_AT_ranges
-     was found.  */
+  /* No attribute DW_AT_low_pc, DW_AT_high_pc or DW_AT_ranges was found.  */
   PC_BOUNDS_NOT_PRESENT,
 
+  /* Some of the attributes DW_AT_low_pc, DW_AT_high_pc or DW_AT_ranges
+     were present but they do not form a valid range of PC addresses.  */
+  PC_BOUNDS_INVALID,
+
   /* Discontiguous range was found - that is DW_AT_ranges was found.  */
   PC_BOUNDS_RANGES,
 
@@ -5027,7 +5030,7 @@
       first_die = load_partial_dies (reader, info_ptr, 1);
 
       scan_partial_symbols (first_die, &lowpc, &highpc,
-			    cu_bounds_kind == PC_BOUNDS_NOT_PRESENT, cu);
+			    cu_bounds_kind <= PC_BOUNDS_INVALID, cu);
 
       /* If we didn't find a lowpc, set it to highpc to avoid
 	 complaints from `maint check'.	 */
@@ -5036,7 +5039,7 @@
 
       /* If the compilation unit didn't have an explicit address range,
 	 then use the information extracted from its child dies.  */
-      if (cu_bounds_kind == PC_BOUNDS_NOT_PRESENT)
+      if (cu_bounds_kind <= PC_BOUNDS_INVALID)
 	{
 	  best_lowpc = lowpc;
 	  best_highpc = highpc;
@@ -9606,7 +9609,7 @@
 
   /* Ignore functions with missing or invalid low and high pc attributes.  */
   if (dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu, NULL)
-      == PC_BOUNDS_NOT_PRESENT)
+      <= PC_BOUNDS_INVALID)
     {
       attr = dwarf2_attr (die, DW_AT_external, cu);
       if (!attr || !DW_UNSND (attr))
@@ -9763,9 +9766,20 @@
      as multiple lexical blocks?  Handling children in a sane way would
      be nasty.  Might be easier to properly extend generic blocks to
      describe ranges.  */
-  if (dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu, NULL)
-      == PC_BOUNDS_NOT_PRESENT)
-    return;
+  switch (dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu, NULL))
+    {
+    case PC_BOUNDS_NOT_PRESENT:
+      /* DW_TAG_lexical_block has no attributes, process its children as if
+	 there was no wrapping by that DW_TAG_lexical_block.
+	 GCC does no longer produces such DWARF since GCC r224161.  */
+      for (child_die = die->child;
+	   child_die != NULL && child_die->tag;
+	   child_die = sibling_die (child_die))
+	process_die (child_die, cu);
+      return;
+    case PC_BOUNDS_INVALID:
+      return;
+    }
   lowpc += baseaddr;
   highpc += baseaddr;
 
@@ -9970,7 +9984,7 @@
 
 	  /* DW_AT_entry_pc should be preferred.  */
 	  if (dwarf2_get_pc_bounds (target_die, &lowpc, NULL, target_cu, NULL)
-	      == PC_BOUNDS_NOT_PRESENT)
+	      <= PC_BOUNDS_INVALID)
 	    complaint (&symfile_complaints,
 		       _("DW_AT_GNU_call_site_target target DIE has invalid "
 		         "low pc, for referencing DIE 0x%x [in module %s]"),
@@ -10249,7 +10263,7 @@
 
 /* Get low and high pc attributes from a die.  See enum pc_bounds_kind
    definition for the return value.  *LOWPC and *HIGHPC are set iff
-   PC_BOUNDS_NOT_PRESENT is not returned.  */
+   neither PC_BOUNDS_NOT_PRESENT nor PC_BOUNDS_INVALID are returned.  */
 
 static enum pc_bounds_kind
 dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
@@ -10260,7 +10274,7 @@
   struct attribute *attr_high;
   CORE_ADDR low = 0;
   CORE_ADDR high = 0;
-  enum pc_bounds_kind ret = PC_BOUNDS_NOT_PRESENT;
+  enum pc_bounds_kind ret;
 
   attr_high = dwarf2_attr (die, DW_AT_high_pc, cu);
   if (attr_high)
@@ -10277,7 +10291,7 @@
 	}
       else
 	/* Found high w/o low attribute.  */
-	return PC_BOUNDS_NOT_PRESENT;
+	return PC_BOUNDS_INVALID;
 
       /* Found consecutive range of addresses.  */
       ret = PC_BOUNDS_HIGH_LOW;
@@ -10299,15 +10313,17 @@
 	  /* Value of the DW_AT_ranges attribute is the offset in the
 	     .debug_ranges section.  */
 	  if (!dwarf2_ranges_read (ranges_offset, &low, &high, cu, pst))
-	    return PC_BOUNDS_NOT_PRESENT;
+	    return PC_BOUNDS_INVALID;
 	  /* Found discontinuous range of addresses.  */
 	  ret = PC_BOUNDS_RANGES;
 	}
+      else
+	return PC_BOUNDS_NOT_PRESENT;
     }
 
   /* read_partial_die has also the strict LOW < HIGH requirement.  */
   if (high <= low)
-    return PC_BOUNDS_NOT_PRESENT;
+    return PC_BOUNDS_INVALID;
 
   /* When using the GNU linker, .gnu.linkonce. sections are used to
      eliminate duplicate copies of functions and vtables and such.
@@ -10318,7 +10334,7 @@
      If this is a discarded function, mark the pc bounds as invalid,
      so that GDB will ignore it.  */
   if (low == 0 && !dwarf2_per_objfile->has_section_at_zero)
-    return PC_BOUNDS_NOT_PRESENT;
+    return PC_BOUNDS_INVALID;
 
   *lowpc = low;
   if (highpc)
@@ -10339,8 +10355,7 @@
   CORE_ADDR low, high;
   struct die_info *child = die->child;
 
-  if (dwarf2_get_pc_bounds (die, &low, &high, cu, NULL)
-      != PC_BOUNDS_NOT_PRESENT)
+  if (dwarf2_get_pc_bounds (die, &low, &high, cu, NULL) >= PC_BOUNDS_RANGES)
     {
       *lowpc = min (*lowpc, low);
       *highpc = max (*highpc, high);
@@ -10378,7 +10393,7 @@
   CORE_ADDR current_low, current_high;
 
   if (dwarf2_get_pc_bounds (die, &current_low, &current_high, cu, NULL)
-      != PC_BOUNDS_NOT_PRESENT)
+      >= PC_BOUNDS_RANGES)
     {
       best_low = current_low;
       best_high = current_high;
--- /dev/null	2016-05-30 15:04:01.916990766 +0200
+++ gdb-7.6.1/gdb/testsuite/gdb.dwarf2/dw2-lexical-block-bare.exp	2016-05-30 15:19:22.236042134 +0200
@@ -0,0 +1,32 @@
+# Copyright 2016 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/>.
+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 .S main.c
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} \
+			  [list $srcfile2 $srcfile] {nodebug}] } {
+    return -1
+}
+
+runto_main
+
+# FAILing GDB did print: No symbol "testvar" in current context.
+gdb_test "p testvar" { = -?[0-9]+}
--- /dev/null	2016-05-30 15:04:01.916990766 +0200
+++ gdb-7.6.1/gdb/testsuite/gdb.dwarf2/dw2-lexical-block-bare.S	2016-05-30 15:17:42.580173290 +0200
@@ -0,0 +1,89 @@
+        .section .debug_info
+.Lcu1_begin:
+        .4byte        .Lcu1_end - .Lcu1_start
+.Lcu1_start:
+        .2byte        4                 /* Version */
+        .4byte        .Labbrev1_begin   /* Abbrevs */
+        .byte        4                  /* Pointer size */
+        .uleb128        2               /* Abbrev (DW_TAG_compile_unit) */
+        .4byte        main_label
+        .4byte        main_label+0x10000
+.Llabel1:
+        .uleb128        3               /* Abbrev (DW_TAG_base_type) */
+        .sleb128        4
+        .sleb128        0x5
+        .ascii        "integer\0"
+        .uleb128        4               /* Abbrev (DW_TAG_subprogram) */
+        .ascii        "main\0"
+        .byte        1
+        .4byte        main_label
+        .4byte        main_label+0x10000
+        .uleb128        5               /* Abbrev (DW_TAG_lexical_block) */
+        .uleb128        6               /* Abbrev (DW_TAG_variable) */
+        .ascii        "testvar\0"
+        .4byte        .Llabel1 - .Lcu1_begin
+        .byte        1
+        .uleb128        .Lexpr_end3 - .Lexpr_start2/* expression */
+.Lexpr_start2:
+        .byte        0x03               /* DW_OP_addr */
+        .4byte        main
+.Lexpr_end3:
+        .byte        0x0                /* Terminate children */
+        .byte        0x0                /* Terminate children */
+        .byte        0x0                /* Terminate children */
+.Lcu1_end:
+        .section .debug_abbrev
+.Labbrev1_begin:
+        .uleb128        2               /* Abbrev start */
+        .uleb128        0x11            /* DW_TAG_compile_unit */
+        .byte        1                  /* has_children */
+        .uleb128        0x11            /* DW_AT_low_pc */
+        .uleb128        0x01            /* DW_FORM_addr */
+        .uleb128        0x12            /* DW_AT_high_pc */
+        .uleb128        0x01            /* DW_FORM_addr */
+        .byte        0x0                /* Terminator */
+        .byte        0x0                /* Terminator */
+        .uleb128        3               /* Abbrev start */
+        .uleb128        0x24            /* DW_TAG_base_type */
+        .byte        0                  /* has_children */
+        .uleb128        0x0b            /* DW_AT_byte_size */
+        .uleb128        0x0d            /* DW_FORM_sdata */
+        .uleb128        0x3e            /* DW_AT_encoding */
+        .uleb128        0x0d            /* DW_FORM_sdata */
+        .uleb128        0x03            /* DW_AT_name */
+        .uleb128        0x08            /* DW_FORM_string */
+        .byte        0x0                /* Terminator */
+        .byte        0x0                /* Terminator */
+        .uleb128        4               /* Abbrev start */
+        .uleb128        0x2e            /* DW_TAG_subprogram */
+        .byte        1                  /* has_children */
+        .uleb128        0x03            /* DW_AT_name */
+        .uleb128        0x08            /* DW_FORM_string */
+        .uleb128        0x3f            /* DW_AT_external */
+        .uleb128        0x0c            /* DW_FORM_flag */
+        .uleb128        0x11            /* DW_AT_low_pc */
+        .uleb128        0x01            /* DW_FORM_addr */
+        .uleb128        0x12            /* DW_AT_high_pc */
+        .uleb128        0x01            /* DW_FORM_addr */
+        .byte        0x0                /* Terminator */
+        .byte        0x0                /* Terminator */
+        .uleb128        5               /* Abbrev start */
+        .uleb128        0x0b            /* DW_TAG_lexical_block */
+        .byte        1                  /* has_children */
+        .byte        0x0                /* Terminator */
+        .byte        0x0                /* Terminator */
+        .uleb128        6               /* Abbrev start */
+        .uleb128        0x34            /* DW_TAG_variable */
+        .byte        0                  /* has_children */
+        .uleb128        0x03            /* DW_AT_name */
+        .uleb128        0x08            /* DW_FORM_string */
+        .uleb128        0x49            /* DW_AT_type */
+        .uleb128        0x13            /* DW_FORM_ref4 */
+        .uleb128        0x3f            /* DW_AT_external */
+        .uleb128        0x0c            /* DW_FORM_flag */
+        .uleb128        0x02            /* DW_AT_location */
+        .uleb128        0x09            /* SPECIAL_expr */
+        .byte        0x0                /* Terminator */
+        .byte        0x0                /* Terminator */
+        .byte        0x0                /* Terminator */
+        .byte        0x0                /* Terminator */
diff -dup -rup gdb-7.6.1/gdb/testsuite/gdb.dwarf2/main.c gdb-7.6.1-orig/gdb/testsuite/gdb.dwarf2/main.c
--- gdb-7.6.1/gdb/testsuite/gdb.dwarf2/main.c	2013-01-01 07:41:22.000000000 +0100
+++ gdb-7.6.1-orig/gdb/testsuite/gdb.dwarf2/main.c	2017-03-08 22:20:21.085438961 +0100
@@ -20,5 +20,6 @@
 int
 main()
 {
+  asm ("main_label: .globl main_label");
   return 0;
 }