This is the mail archive of the gdb-cvs@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[binutils-gdb] DWARF: cannot break on out-of-line function nested inside inlined function.


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=3ea89b92fb0765075a27a3a0239552ae880722ff

commit 3ea89b92fb0765075a27a3a0239552ae880722ff
Author: Pierre-Marie de Rodat <derodat@adacore.com>
Date:   Mon Apr 20 17:53:00 2015 +0200

    DWARF: cannot break on out-of-line function nested inside inlined function.
    
    Consider the following code, which defines a function, Child2,
    which is itself nested inside Child1:
    
        procedure Foo_O224_021 is
            O1 : constant Object_Type := Get_Str ("Foo");
            procedure Child1 is
                O2 : constant Object_Type := Get_Str ("Foo");
                function Child2 (S : String) return Boolean is -- STOP
                begin
                    for C of S loop
                        Do_Nothing (C);
                        if C = 'o' then
                            return True;
                        end if;
                    end loop;
                    return False;
                end Child2;
                R : Boolean;
            begin
                R := Child2 ("Foo");
                R := Child2 ("Bar");
                R := Child2 ("Foobar");
            end Child1;
        begin
            Child1;
        end Foo_O224_021;
    
    On x86_64-linux, when compiled at -O2, GDB is unable to insert
    a breakpoint on Child2:
    
        % gnatmake -g -O2 foo_o224_021
        % gdb foo_o224_021
        (gdb) b child2
        Function "child2" not defined.
        (gdb) b foo_o224_021.child1.child2
        Function "foo_o224_021.child1.child2" not defined.
    
    The problem is caused by the fact that GDB did not create a symbol
    for Child2, and this, in turn, is caused by the fact that the compiler
    decided to inline Child1, but not Child2. The DWARF debugging info
    first provides an abstract instance tree for Child1...
    
     <3><1b7b>: Abbrev Number: 29 (DW_TAG_subprogram)
        <1b7c>   DW_AT_name        : (indirect string, offset: 0x23f8): foo_o224_021__child1
        <1b82>   DW_AT_inline      : 1      (inlined)
        <1b83>   DW_AT_sibling     : <0x1c01>
    
    ... where that subprogram is given the DW_AT_inline attribute.
    Inside that function there is a lexical block which has no PC
    range (corresponding to the fact that this is the abstract tree):
    
     <4><1b87>: Abbrev Number: 30 (DW_TAG_lexical_block)
    
    ... inside which our subprogram Child2 is described:
    
     <5><1b92>: Abbrev Number: 32 (DW_TAG_subprogram)
        <1b93>   DW_AT_name        : (indirect string, offset: 0x2452): foo_o224_021__child1__child2
        <1b99>   DW_AT_type        : <0x1ab1>
        <1b9d>   DW_AT_low_pc      : 0x402300
        <1ba5>   DW_AT_high_pc     : 0x57
        [...]
    
    Then, later on, we get the concrete instance tree, starting at:
    
     <3><1c5e>: Abbrev Number: 41 (DW_TAG_inlined_subroutine)
        <1c5f>   DW_AT_abstract_origin: <0x1b7b>
        <1c63>   DW_AT_entry_pc    : 0x4025fd
        <1c6b>   DW_AT_ranges      : 0x150
    
    ... which refers to Child1. One of that inlined subroutine children
    is the concrete instance of the empty lexical block we saw above
    (in the abstract instance tree), which gives the actual address
    range for this inlined instance:
    
     <5><1c7a>: Abbrev Number: 43 (DW_TAG_lexical_block)
        <1c7b>   DW_AT_abstract_origin: <0x1b87>
        <1c7f>   DW_AT_ranges      : 0x180
    
    This is the DIE which provides the context inside which we can
    record Child2. But unfortunately, GDB does not take the abstract
    origin into account when handling lexical blocks, causing it
    to miss the fact that this block contains some symbols described
    in the abstract instance tree. This is the first half of this patch:
    modifying GDB to follow DW_AT_abstract_origin attributes for
    lexical blocks.
    
    But this not enough to fix the issue, as we're still unable to
    break on Child2 with just that change. The second issue can be
    traced to the way inherit_abstract_dies determines the list of
    DIEs to inherit from. For that, it iterates over all the DIEs in
    the concrete instance tree, and finds the list of DIEs from the
    abstract instance tree that are not referenced from the concrete
    instance tree. As it happens, there is one type of DIE in the
    concrete instance tree which does reference Child2's DIE, but
    in fact does otherwise define a concrete instance of the reference
    DIE; that's (where <0x1b92> is Child2's DIE):
    
     <6><1d3c>: Abbrev Number: 35 (DW_TAG_GNU_call_site)
        <1d3d>   DW_AT_low_pc      : 0x4026a4
        <1d45>   DW_AT_abstract_origin: <0x1b92>
    
    So, the second part of the patch is to modify inherit_abstract_dies
    to ignore DW_TAG_GNU_call_site DIEs when iterating over the concrete
    instance tree.
    
    This patch also includes a testcase which can be used to reproduce
    the issue. Unfortunately, for it to actually pass, a smal patch in
    GCC is also necessary to make sure that GCC provides lexical blocks'
    DW_AT_abstract_origin attributes from the concrete tree back to
    the abstract tree. We hope to be able to submit and integrate that
    patch in the GCC tree soon. Meanwhile, a setup_xfail has been added.
    
    gdb/ChangeLog:
    
    	2014-05-05  Pierre-Marie de Rodat  <derodat@adacore.com>
    	* dwarf2read.c (inherit_abstract_dies): Skip
    	DW_TAG_GNU_call_site dies while inheriting children of an
    	abstract DIE into a scope.
    	(read_lexical_block_scope): Inherit abstract DIE's for
    	lexical scopes.
    
    gdb/testsuite/ChangeLog:
    
            * gdb.ada/out_of_line_in_inlined: New testcase.

Diff:
---
 gdb/ChangeLog                                      |  8 ++++
 gdb/dwarf2read.c                                   | 23 ++++++++---
 gdb/testsuite/ChangeLog                            |  4 ++
 gdb/testsuite/gdb.ada/out_of_line_in_inlined.exp   | 31 +++++++++++++++
 .../gdb.ada/out_of_line_in_inlined/bar.adb         | 28 ++++++++++++++
 .../gdb.ada/out_of_line_in_inlined/bar.ads         | 27 +++++++++++++
 .../out_of_line_in_inlined/foo_o224_021.adb        | 44 ++++++++++++++++++++++
 7 files changed, 159 insertions(+), 6 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e01b98b..b4bcef1 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,11 @@
+2014-05-05  Pierre-Marie de Rodat  <derodat@adacore.com>
+
+	* dwarf2read.c (inherit_abstract_dies): Skip
+	DW_TAG_GNU_call_site dies while inheriting children of an
+	abstract DIE into a scope.
+	(read_lexical_block_scope): Inherit abstract DIE's for
+	lexical scopes.
+
 2015-05-05  Joel Brobecker  <brobecker@adacore.com>
 
 	* ada-valprint.c (val_print_packed_array_elements): Delete
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index b91fbf5..4982922 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -11216,17 +11216,28 @@ inherit_abstract_dies (struct die_info *die, struct dwarf2_cu *cu)
   cleanups = make_cleanup (xfree, offsets);
 
   offsets_end = offsets;
-  child_die = die->child;
-  while (child_die && child_die->tag)
+  for (child_die = die->child;
+       child_die && child_die->tag;
+       child_die = sibling_die (child_die))
     {
+      struct die_info *child_origin_die;
+      struct dwarf2_cu *child_origin_cu;
+
+      /* We are trying to process concrete instance entries:
+	 DW_TAG_GNU_call_site DIEs indeed have a DW_AT_abstract_origin tag, but
+	 it's not relevant to our analysis here. i.e. detecting DIEs that are
+	 present in the abstract instance but not referenced in the concrete
+	 one.  */
+      if (child_die->tag == DW_TAG_GNU_call_site)
+	continue;
+
       /* For each CHILD_DIE, find the corresponding child of
 	 ORIGIN_DIE.  If there is more than one layer of
 	 DW_AT_abstract_origin, follow them all; there shouldn't be,
 	 but GCC versions at least through 4.4 generate this (GCC PR
 	 40573).  */
-      struct die_info *child_origin_die = child_die;
-      struct dwarf2_cu *child_origin_cu = cu;
-
+      child_origin_die = child_die;
+      child_origin_cu = cu;
       while (1)
 	{
 	  attr = dwarf2_attr (child_origin_die, DW_AT_abstract_origin,
@@ -11256,7 +11267,6 @@ inherit_abstract_dies (struct die_info *die, struct dwarf2_cu *cu)
 	  else
 	    *offsets_end++ = child_origin_die->offset;
 	}
-      child_die = sibling_die (child_die);
     }
   qsort (offsets, offsets_end - offsets, sizeof (*offsets),
 	 unsigned_int_compar);
@@ -11503,6 +11513,7 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu)
 	  child_die = sibling_die (child_die);
 	}
     }
+  inherit_abstract_dies (die, cu);
   newobj = pop_context ();
 
   if (local_symbols != NULL || using_directives != NULL)
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index c0b51be..66a87c8 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2015-05-05  Joel Brobecker  <brobecker@adacore.com>
 
+	* gdb.ada/out_of_line_in_inlined: New testcase.
+
+2015-05-05  Joel Brobecker  <brobecker@adacore.com>
+
 	* gdb.ada/var_rec_arr: New testcase.
 
 2015-04-30  Yao Qi  <yao.qi@linaro.org>
diff --git a/gdb/testsuite/gdb.ada/out_of_line_in_inlined.exp b/gdb/testsuite/gdb.ada/out_of_line_in_inlined.exp
new file mode 100644
index 0000000..ebebb6c
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/out_of_line_in_inlined.exp
@@ -0,0 +1,31 @@
+# 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/>.
+
+load_lib "ada.exp"
+
+standard_ada_testfile foo_o224_021
+
+if {[gdb_compile_ada "${srcfile}" "${binfile}" executable {debug optimize=-O2}] != ""} {
+    return -1
+}
+
+clean_restart ${testfile}
+
+# GCC currently is missing a DW_AT_origin attribute in one of the
+# lexical blocks, preventing GDB from creating a symbol for the
+# subprogram we want to break on.
+setup_xfail "*-*-*"
+gdb_test "break foo_o224_021.child1.child2" \
+         "Breakpoint \[0-9\]+ at.*: file .*foo_o224_021.adb, line \[0-9\]+."
diff --git a/gdb/testsuite/gdb.ada/out_of_line_in_inlined/bar.adb b/gdb/testsuite/gdb.ada/out_of_line_in_inlined/bar.adb
new file mode 100644
index 0000000..a7178cc
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/out_of_line_in_inlined/bar.adb
@@ -0,0 +1,28 @@
+--  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/>.
+
+package body Bar is
+
+    procedure Do_Nothing (C : Character) is
+    begin
+        null;
+    end Do_Nothing;
+
+    function Get_Str (S1 : String; S2 : String := "") return Object_Type is
+    begin
+        return (Ada.Finalization.Controlled with Value => True);
+    end Get_Str;
+
+end Bar;
diff --git a/gdb/testsuite/gdb.ada/out_of_line_in_inlined/bar.ads b/gdb/testsuite/gdb.ada/out_of_line_in_inlined/bar.ads
new file mode 100644
index 0000000..81a249c
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/out_of_line_in_inlined/bar.ads
@@ -0,0 +1,27 @@
+--  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/>.
+
+with Ada.Finalization;
+
+package Bar is
+
+    type Object_Type is new Ada.Finalization.Controlled with record
+        Value : Boolean;
+    end record;
+
+    function Get_Str (S1 : String; S2 : String := "") return Object_Type;
+    procedure Do_Nothing (C : Character);
+
+end Bar;
diff --git a/gdb/testsuite/gdb.ada/out_of_line_in_inlined/foo_o224_021.adb b/gdb/testsuite/gdb.ada/out_of_line_in_inlined/foo_o224_021.adb
new file mode 100644
index 0000000..15e108d
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/out_of_line_in_inlined/foo_o224_021.adb
@@ -0,0 +1,44 @@
+--  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/>.
+
+with Bar; use Bar;
+
+procedure Foo_O224_021 is
+    O1 : constant Object_Type := Get_Str ("Foo");
+
+    procedure Child1 is
+        O2 : constant Object_Type := Get_Str ("Foo");
+
+        function Child2 (S : String) return Boolean is -- STOP
+        begin
+            for C of S loop
+                Do_Nothing (C);
+                if C = 'o' then
+                    return True;
+                end if;
+            end loop;
+            return False;
+        end Child2;
+
+        R : Boolean;
+
+    begin
+        R := Child2 ("Foo");
+        R := Child2 ("Bar");
+        R := Child2 ("Foobar");
+    end Child1;
+begin
+    Child1;
+end Foo_O224_021;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]