out of line functions nested inside inline functions.
authorJoel Brobecker <brobecker@adacore.com>
Tue, 21 Apr 2015 17:34:04 +0000 (10:34 -0700)
committerJoel Brobecker <brobecker@adacore.com>
Tue, 5 May 2015 18:08:14 +0000 (11:08 -0700)
This patch improves the handling of out-of-line functions nested
inside functions that have been inlined.

Consider for instance a situation where function Foo_O224_021
has a function Child1 declared in it, which itself has a function
Child2 nested inside Child1. After compiling the program with
optimization on, Child1 gets inlined, but not Child2.

After inserting a breakpoint on Child2, and running the program
until reaching that breakpoint, we get the following backtrace:

    % gdb foo_o224_021
    (gdb) break foo_o224_021.child1.child2
    (gdb) run
    [...]
    Breakpoint 1, foo_o224_021 () at foo_o224_021.adb:28
    28          Child1;
    (gdb) bt
    #0  0x0000000000402400 in foo_o224_021 () at foo_o224_021.adb:28
    #1  0x00000000004027a4 in foo_o224_021.child1 () at foo_o224_021.adb:23
    #2  0x00000000004027a4 in foo_o224_021 () at foo_o224_021.adb:28

GDB reports the wrong function name for frame #0. We also get the same
kind of error in the "Breakpoint 1, foo_o224_021 () [...]" message.
In both cases, the function name should be foo_o224_021.child1.child2,
and the parameters should be "s=...".

What happens is that the inlined frame handling does not handle well
the case where an inlined function is calling an out-of-line function
which was declared inside the inlined function's scope.

In particular, looking first at the inlined-frame sniffer when applying
to frame #0:

        /* Calculate DEPTH, the number of inlined functions at this
           location.  */
        depth = 0;
        cur_block = frame_block;
        while (BLOCK_SUPERBLOCK (cur_block))
          {
            if (block_inlined_p (cur_block))
              depth++;
            cur_block = BLOCK_SUPERBLOCK (cur_block);
          }

What happens is that cur_block starts as the block associated
to child2, which is not inlined. We shoud be stopping here, but
instead, we keep walking the superblock chain, which takes us
all the way to Foo_O224_021's block, via Child2's block. And
since Child1 was inlined, we end up with a depth count of 1,
wrongly making GDB think that frame #0 is an inlined frame.

Same kind of issue inside skip_inline_frames.

The fix is to stop checking for inlined frames as soon as we see
a block corresponding to a function which is not inlined.  This is
the behavior we now obtain:

    (gdb) run
    [...]
    Breakpoint 1, foo_o224_021.child1.child2 (s=...) at foo_o224_021.adb:9
    9               function Child2 (S : String) return Boolean is
    (gdb) bt
    #0  0x0000000000402400 in foo_o224_021.child1.child2 (s=...)
        at foo_o224_021.adb:9
    #1  0x00000000004027a4 in foo_o224_021.child1 () at foo_o224_021.adb:23
    #2  0x00000000004027a4 in foo_o224_021 () at foo_o224_021.adb:28

gdb/ChangeLog:

        * inline-frame.c (inline_frame_sniffer, skip_inline_frames):
        Stop counting inlined frames as soon as an out-of-line function
        is found.

gdb/testsuite/ChangeLog:

        * gdb.ada/out_of_line_in_inlined.exp: Add run and "bt" tests.

gdb/ChangeLog
gdb/inline-frame.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.ada/out_of_line_in_inlined.exp

index b4bcef156df44f95ce61e428a3305568ec977cc3..f36a7626f6412924a86adafe4e181c95647afa65 100644 (file)
@@ -1,3 +1,9 @@
+2015-05-05  Joel Brobecker  <brobecker@adacore.com>
+
+       * inline-frame.c (inline_frame_sniffer, skip_inline_frames):
+       Stop counting inlined frames as soon as an out-of-line function
+       is found.
+
 2014-05-05  Pierre-Marie de Rodat  <derodat@adacore.com>
 
        * dwarf2read.c (inherit_abstract_dies): Skip
index eec44d8d677961806cfbcc2d8fcc863a4b116c95..e5d7360f989f965f592898067a7bf8a34b2bd53f 100644 (file)
@@ -225,6 +225,8 @@ inline_frame_sniffer (const struct frame_unwind *self,
     {
       if (block_inlined_p (cur_block))
        depth++;
+      else if (BLOCK_FUNCTION (cur_block) != NULL)
+       break;
 
       cur_block = BLOCK_SUPERBLOCK (cur_block);
     }
@@ -331,6 +333,9 @@ skip_inline_frames (ptid_t ptid)
              else
                break;
            }
+         else if (BLOCK_FUNCTION (cur_block) != NULL)
+           break;
+
          cur_block = BLOCK_SUPERBLOCK (cur_block);
        }
     }
index 66a87c8f6c2ac7ac33823a918d7bba0a8a101f54..63c4bf386f548707b25e66271589dbeacd7c0e86 100644 (file)
@@ -1,3 +1,7 @@
+2015-05-05  Joel Brobecker  <brobecker@adacore.com>
+
+       * gdb.ada/out_of_line_in_inlined.exp: Add run and "bt" tests.
+
 2015-05-05  Joel Brobecker  <brobecker@adacore.com>
 
        * gdb.ada/out_of_line_in_inlined: New testcase.
index ebebb6cac74d2090ffcc9e7e4e53f60b9d4983c2..5301b4fc28312c8ad5f3bc5ed1498aeb5183acd2 100644 (file)
@@ -29,3 +29,15 @@ clean_restart ${testfile}
 setup_xfail "*-*-*"
 gdb_test "break foo_o224_021.child1.child2" \
          "Breakpoint \[0-9\]+ at.*: file .*foo_o224_021.adb, line \[0-9\]+."
+
+gdb_run_cmd
+setup_xfail "*-*-*"
+gdb_test "" \
+         "Breakpoint $decimal, foo_o224_021\\.child1\\.child2 \\(s=\\.\\.\\.\\).*"
+
+set opt_addr_in "($hex in)?"
+setup_xfail "*-*-*"
+gdb_test "bt" \
+    [multi_line "#0 +$opt_addr_in +foo_o224_021\\.child1\\.child2 \\(s=\\.\\.\\.\\).*" \
+                "#1 +$opt_addr_in +foo_o224_021\\.child1 \\(\\).*" \
+                "#2 +$opt_addr_in +foo_o224_021 \\(\\).*" ]