From e385593eef98ac92be57159e141f4b805dadbbb3 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil 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): [...] 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 out of line functions nested inside inline functions. So I have removed that xfail. gdb/ChangeLog 2016-05-30 Jan Kratochvil 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 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 + 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 + 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, ¤t_low, ¤t_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 . +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; }