diff mbox series

Fix dwarf-lineinfo inconsistency of inlined subroutines

Message ID VI1PR03MB452890F2CC34205AA836CAB2E46E0@VI1PR03MB4528.eurprd03.prod.outlook.com
State New
Headers show
Series Fix dwarf-lineinfo inconsistency of inlined subroutines | expand

Commit Message

Bernd Edlinger Oct. 20, 2019, 7:58 p.m. UTC
Hi,

this fixes an issue with the gdb step-over aka. "n" command.

It can be seen when you debug an optimized stage-3 cc1
it does not affect -O0 code, though.

This example debug session will explain the effect.

(gdb) b get_alias_set
Breakpoint 5 at 0xa099f0: file ../../gcc-trunk/gcc/alias.c, line 837.
(gdb) r
Breakpoint 5, get_alias_set (t=t@entry=0x7ffff7ff7ab0) at ../../gcc-trunk/gcc/alias.c:837
837	  if (t == error_mark_node
(gdb) n
839		  && (TREE_TYPE (t) == 0 || TREE_TYPE (t) == error_mark_node)))
(gdb) n
3382	  return __t;  <-- now we have a problem: wrong line info here
(gdb) bt
#0  get_alias_set (t=t@entry=0x7ffff7ff7ab0) at ../../gcc-trunk/gcc/tree.h:3382
#1  0x0000000000b25dfe in set_mem_attributes_minus_bitpos (ref=0x7ffff746f990, t=0x7ffff7ff7ab0, objectp=1, bitpos=...)
    at ../../gcc-trunk/gcc/emit-rtl.c:1957
#2  0x0000000001137a55 in make_decl_rtl (decl=0x7ffff7ff7ab0) at ../../gcc-trunk/gcc/varasm.c:1518
#3  0x000000000113b6e8 in assemble_variable (decl=0x7ffff7ff7ab0, top_level=<optimized out>, at_end=<optimized out>, 
    dont_output_data=0) at ../../gcc-trunk/gcc/varasm.c:2246
#4  0x000000000113f0ea in varpool_node::assemble_decl (this=0x7ffff745b000) at ../../gcc-trunk/gcc/varpool.c:584
#5  0x000000000113fa17 in varpool_node::assemble_decl (this=0x7ffff745b000) at ../../gcc-trunk/gcc/varpool.c:750


There are at least two problems here:

First you did not want to step into the TREE_TYPE, but it happens all
the time, even if you use "n" to step over it.

And secondly, from the call stack, you don't know where you are in get_alias_set.
But the code that is executing at this point is actually the x == 0 || x == error_mark_node
from alias.c, line 839, which contains the inlined body of the TREE_TYPE, but
the rest of the if.  So there is an inconsistency in the  

Contents of the .debug_info section:

 <2><4f686>: Abbrev Number: 12 (DW_TAG_inlined_subroutine)
    <4f687>   DW_AT_abstract_origin: <0x53d4e>
    <4f68b>   DW_AT_entry_pc    : 0x7280
    <4f693>   DW_AT_GNU_entry_view: 1
    <4f695>   DW_AT_ranges      : 0xb480
    <4f699>   DW_AT_call_file   : 8  <- alias.c
    <4f69a>   DW_AT_call_line   : 839
    <4f69c>   DW_AT_call_column : 8
    <4f69d>   DW_AT_sibling     : <0x4f717>

 The File Name Table (offset 0x253):
  8     2       0       0       alias.c
  10    2       0       0       tree.h

Contents of the .debug_ranges section:

    0000b480 0000000000007280 0000000000007291 
    0000b480 0000000000002764 000000000000277e 
    0000b480 <End of list>

The problem is at pc=0x7291 in the Line Number Section:

 Line Number Statements:

  [0x00008826]  Special opcode 61: advance Address by 4 to 0x7284 and Line by 0 to 3380
  [0x00008827]  Set is_stmt to 1
  [0x00008828]  Special opcode 189: advance Address by 13 to 0x7291 and Line by 2 to 3382 (*)
  [0x00008829]  Set is_stmt to 0 (**)
  [0x0000882a]  Copy (view 1)
  [0x0000882b]  Set File Name to entry 8 in the File Name Table <- back to alias.c
  [0x0000882d]  Set column to 8
  [0x0000882f]  Advance Line by -2543 to 839
  [0x00008832]  Copy (view 2)
  [0x00008833]  Set column to 27
  [0x00008835]  Special opcode 61: advance Address by 4 to 0x7295 and Line by 0 to 839
  [0x00008836]  Set column to 3
  [0x00008838]  Set is_stmt to 1 <-- next line info counts: alias.c:847
  [0x00008839]  Special opcode 153: advance Address by 10 to 0x729f and Line by 8 to 847
  [0x0000883a]  Set column to 7

(*) this line is tree.h:3382, but the program counter is *not* within the subroutine,
but exactly at the first instruction *after* the subroutine according to the debug_ranges.

What makes it worse, is that (**) makes gdb ignore the new location info alias.c:839,
which means, normally the n command would have continued to pc=0x729f, which is at alias.c:847.


The problem happens due to a block with only var
This patch fixes this problem by moving (**) to the first statement with a different line number.

In alias.c.316r.final this looks like that:

(note 2884 2883 1995 31 0x7f903a931ba0 NOTE_INSN_BLOCK_BEG)
(note 1995 2884 2885 31 ../../gcc-trunk/gcc/tree.h:3377 NOTE_INSN_INLINE_ENTRY)
(note 2885 1995 1996 31 0x7f903a931c00 NOTE_INSN_BLOCK_BEG)
[...]
(note 50 39 59 32 [bb 32] NOTE_INSN_BASIC_BLOCK)
(note 59 50 60 32 NOTE_INSN_DELETED)
(note 60 59 1997 32 NOTE_INSN_DELETED)
(note 1997 60 2239 32 ../../gcc-trunk/gcc/tree.h:3382 NOTE_INSN_BEGIN_STMT)
(note 2239 1997 2240 32 (var_location __tD.143911 (nil)) NOTE_INSN_VAR_LOCATION)
(note 2240 2239 2241 32 (var_location __sD.143912 (nil)) NOTE_INSN_VAR_LOCATION)
(note 2241 2240 2242 32 (var_location __fD.143913 (nil)) NOTE_INSN_VAR_LOCATION)
(note 2242 2241 2243 32 (var_location __lD.143914 (nil)) NOTE_INSN_VAR_LOCATION)
(note 2243 2242 2886 32 (var_location __gD.143915 (nil)) NOTE_INSN_VAR_LOCATION)
(note 2886 2243 2887 32 0x7f903a931c00 NOTE_INSN_BLOCK_END)
(note 2887 2886 57 32 0x7f903a931ba0 NOTE_INSN_BLOCK_END)
(insn:TI 57 2887 61 32 (set (reg/f:DI 0 ax [orig:87 _7 ] [87])
        (mem/f/j:DI (plus:DI (reg/f:DI 5 di [orig:83 t.85_2 ] [83])
                (const_int 8 [0x8])) [0 t.85_2->typedD.91322.typeD.90828+0 S8 A64])) "../../gcc-trunk/gcc/alias.c":839:108 66 {*movdi_internal}
     (nil))

So this patch detects the NOTE_INSN_VAR_LOCATION and makes the next location
with a different file&line info a statement location, which is hopefully
a real instruction, thus either part of the subroutine, or the first
instruction after the subroutine, which should have the correct location.
Once the same address has a second statement-type .loc info, gdb will ignore
the first one, and the stepping works as expected.

So this is a bit of a heuristic, but it appears to work quite well.

The test case g++.dg/guality/pr55541.C is the only test where this
change had an effect.  But it is not a regression, since previously
the test case was "unsupported" on any optimization mode, since there
was no breakpoint at line 11, now the breakpoint works, but the variable
value is wrong, but basically this was not working before.

I don't know how to make this test xfail when compiled with optimization,
but the do-skip-if is probably good enough for this kind of test case.


Bootstrapped and reg-tested on x86_64-pc-linux-gnu.
Is it OK for trunk?


Thanks
Bernd.

Comments

Bernd Edlinger Oct. 27, 2019, 8:14 a.m. UTC | #1
Ping...

I'd like to ping for this patch:
https://gcc.gnu.org/ml/gcc-patches/2019-10/msg01459.html


Thanks
Bernd.

On 10/20/19 9:58 PM, Bernd Edlinger wrote:
> Hi,
> 
> this fixes an issue with the gdb step-over aka. "n" command.
> 
> It can be seen when you debug an optimized stage-3 cc1
> it does not affect -O0 code, though.
> 
> This example debug session will explain the effect.
> 
> (gdb) b get_alias_set
> Breakpoint 5 at 0xa099f0: file ../../gcc-trunk/gcc/alias.c, line 837.
> (gdb) r
> Breakpoint 5, get_alias_set (t=t@entry=0x7ffff7ff7ab0) at ../../gcc-trunk/gcc/alias.c:837
> 837	  if (t == error_mark_node
> (gdb) n
> 839		  && (TREE_TYPE (t) == 0 || TREE_TYPE (t) == error_mark_node)))
> (gdb) n
> 3382	  return __t;  <-- now we have a problem: wrong line info here
> (gdb) bt
> #0  get_alias_set (t=t@entry=0x7ffff7ff7ab0) at ../../gcc-trunk/gcc/tree.h:3382
> #1  0x0000000000b25dfe in set_mem_attributes_minus_bitpos (ref=0x7ffff746f990, t=0x7ffff7ff7ab0, objectp=1, bitpos=...)
>     at ../../gcc-trunk/gcc/emit-rtl.c:1957
> #2  0x0000000001137a55 in make_decl_rtl (decl=0x7ffff7ff7ab0) at ../../gcc-trunk/gcc/varasm.c:1518
> #3  0x000000000113b6e8 in assemble_variable (decl=0x7ffff7ff7ab0, top_level=<optimized out>, at_end=<optimized out>, 
>     dont_output_data=0) at ../../gcc-trunk/gcc/varasm.c:2246
> #4  0x000000000113f0ea in varpool_node::assemble_decl (this=0x7ffff745b000) at ../../gcc-trunk/gcc/varpool.c:584
> #5  0x000000000113fa17 in varpool_node::assemble_decl (this=0x7ffff745b000) at ../../gcc-trunk/gcc/varpool.c:750
> 
> 
> There are at least two problems here:
> 
> First you did not want to step into the TREE_TYPE, but it happens all
> the time, even if you use "n" to step over it.
> 
> And secondly, from the call stack, you don't know where you are in get_alias_set.
> But the code that is executing at this point is actually the x == 0 || x == error_mark_node
> from alias.c, line 839, which contains the inlined body of the TREE_TYPE, but
> the rest of the if.  So there is an inconsistency in the  
> 
> Contents of the .debug_info section:
> 
>  <2><4f686>: Abbrev Number: 12 (DW_TAG_inlined_subroutine)
>     <4f687>   DW_AT_abstract_origin: <0x53d4e>
>     <4f68b>   DW_AT_entry_pc    : 0x7280
>     <4f693>   DW_AT_GNU_entry_view: 1
>     <4f695>   DW_AT_ranges      : 0xb480
>     <4f699>   DW_AT_call_file   : 8  <- alias.c
>     <4f69a>   DW_AT_call_line   : 839
>     <4f69c>   DW_AT_call_column : 8
>     <4f69d>   DW_AT_sibling     : <0x4f717>
> 
>  The File Name Table (offset 0x253):
>   8     2       0       0       alias.c
>   10    2       0       0       tree.h
> 
> Contents of the .debug_ranges section:
> 
>     0000b480 0000000000007280 0000000000007291 
>     0000b480 0000000000002764 000000000000277e 
>     0000b480 <End of list>
> 
> The problem is at pc=0x7291 in the Line Number Section:
> 
>  Line Number Statements:
> 
>   [0x00008826]  Special opcode 61: advance Address by 4 to 0x7284 and Line by 0 to 3380
>   [0x00008827]  Set is_stmt to 1
>   [0x00008828]  Special opcode 189: advance Address by 13 to 0x7291 and Line by 2 to 3382 (*)
>   [0x00008829]  Set is_stmt to 0 (**)
>   [0x0000882a]  Copy (view 1)
>   [0x0000882b]  Set File Name to entry 8 in the File Name Table <- back to alias.c
>   [0x0000882d]  Set column to 8
>   [0x0000882f]  Advance Line by -2543 to 839
>   [0x00008832]  Copy (view 2)
>   [0x00008833]  Set column to 27
>   [0x00008835]  Special opcode 61: advance Address by 4 to 0x7295 and Line by 0 to 839
>   [0x00008836]  Set column to 3
>   [0x00008838]  Set is_stmt to 1 <-- next line info counts: alias.c:847
>   [0x00008839]  Special opcode 153: advance Address by 10 to 0x729f and Line by 8 to 847
>   [0x0000883a]  Set column to 7
> 
> (*) this line is tree.h:3382, but the program counter is *not* within the subroutine,
> but exactly at the first instruction *after* the subroutine according to the debug_ranges.
> 
> What makes it worse, is that (**) makes gdb ignore the new location info alias.c:839,
> which means, normally the n command would have continued to pc=0x729f, which is at alias.c:847.
> 
> 
> The problem happens due to a block with only var
> This patch fixes this problem by moving (**) to the first statement with a different line number.
> 
> In alias.c.316r.final this looks like that:
> 
> (note 2884 2883 1995 31 0x7f903a931ba0 NOTE_INSN_BLOCK_BEG)
> (note 1995 2884 2885 31 ../../gcc-trunk/gcc/tree.h:3377 NOTE_INSN_INLINE_ENTRY)
> (note 2885 1995 1996 31 0x7f903a931c00 NOTE_INSN_BLOCK_BEG)
> [...]
> (note 50 39 59 32 [bb 32] NOTE_INSN_BASIC_BLOCK)
> (note 59 50 60 32 NOTE_INSN_DELETED)
> (note 60 59 1997 32 NOTE_INSN_DELETED)
> (note 1997 60 2239 32 ../../gcc-trunk/gcc/tree.h:3382 NOTE_INSN_BEGIN_STMT)
> (note 2239 1997 2240 32 (var_location __tD.143911 (nil)) NOTE_INSN_VAR_LOCATION)
> (note 2240 2239 2241 32 (var_location __sD.143912 (nil)) NOTE_INSN_VAR_LOCATION)
> (note 2241 2240 2242 32 (var_location __fD.143913 (nil)) NOTE_INSN_VAR_LOCATION)
> (note 2242 2241 2243 32 (var_location __lD.143914 (nil)) NOTE_INSN_VAR_LOCATION)
> (note 2243 2242 2886 32 (var_location __gD.143915 (nil)) NOTE_INSN_VAR_LOCATION)
> (note 2886 2243 2887 32 0x7f903a931c00 NOTE_INSN_BLOCK_END)
> (note 2887 2886 57 32 0x7f903a931ba0 NOTE_INSN_BLOCK_END)
> (insn:TI 57 2887 61 32 (set (reg/f:DI 0 ax [orig:87 _7 ] [87])
>         (mem/f/j:DI (plus:DI (reg/f:DI 5 di [orig:83 t.85_2 ] [83])
>                 (const_int 8 [0x8])) [0 t.85_2->typedD.91322.typeD.90828+0 S8 A64])) "../../gcc-trunk/gcc/alias.c":839:108 66 {*movdi_internal}
>      (nil))
> 
> So this patch detects the NOTE_INSN_VAR_LOCATION and makes the next location
> with a different file&line info a statement location, which is hopefully
> a real instruction, thus either part of the subroutine, or the first
> instruction after the subroutine, which should have the correct location.
> Once the same address has a second statement-type .loc info, gdb will ignore
> the first one, and the stepping works as expected.
> 
> So this is a bit of a heuristic, but it appears to work quite well.
> 
> The test case g++.dg/guality/pr55541.C is the only test where this
> change had an effect.  But it is not a regression, since previously
> the test case was "unsupported" on any optimization mode, since there
> was no breakpoint at line 11, now the breakpoint works, but the variable
> value is wrong, but basically this was not working before.
> 
> I don't know how to make this test xfail when compiled with optimization,
> but the do-skip-if is probably good enough for this kind of test case.
> 
> 
> Bootstrapped and reg-tested on x86_64-pc-linux-gnu.
> Is it OK for trunk?
> 
> 
> Thanks
> Bernd.
>
Bernd Edlinger Nov. 2, 2019, 6:49 a.m. UTC | #2
Ping...

On 10/27/19 9:14 AM, Bernd Edlinger wrote:
> Ping...
> 
> I'd like to ping for this patch:
> https://gcc.gnu.org/ml/gcc-patches/2019-10/msg01459.html
> 
> 
> Thanks
> Bernd.
> 
> On 10/20/19 9:58 PM, Bernd Edlinger wrote:
>> Hi,
>>
>> this fixes an issue with the gdb step-over aka. "n" command.
>>
>> It can be seen when you debug an optimized stage-3 cc1
>> it does not affect -O0 code, though.
>>
>> This example debug session will explain the effect.
>>
>> (gdb) b get_alias_set
>> Breakpoint 5 at 0xa099f0: file ../../gcc-trunk/gcc/alias.c, line 837.
>> (gdb) r
>> Breakpoint 5, get_alias_set (t=t@entry=0x7ffff7ff7ab0) at ../../gcc-trunk/gcc/alias.c:837
>> 837	  if (t == error_mark_node
>> (gdb) n
>> 839		  && (TREE_TYPE (t) == 0 || TREE_TYPE (t) == error_mark_node)))
>> (gdb) n
>> 3382	  return __t;  <-- now we have a problem: wrong line info here
>> (gdb) bt
>> #0  get_alias_set (t=t@entry=0x7ffff7ff7ab0) at ../../gcc-trunk/gcc/tree.h:3382
>> #1  0x0000000000b25dfe in set_mem_attributes_minus_bitpos (ref=0x7ffff746f990, t=0x7ffff7ff7ab0, objectp=1, bitpos=...)
>>     at ../../gcc-trunk/gcc/emit-rtl.c:1957
>> #2  0x0000000001137a55 in make_decl_rtl (decl=0x7ffff7ff7ab0) at ../../gcc-trunk/gcc/varasm.c:1518
>> #3  0x000000000113b6e8 in assemble_variable (decl=0x7ffff7ff7ab0, top_level=<optimized out>, at_end=<optimized out>, 
>>     dont_output_data=0) at ../../gcc-trunk/gcc/varasm.c:2246
>> #4  0x000000000113f0ea in varpool_node::assemble_decl (this=0x7ffff745b000) at ../../gcc-trunk/gcc/varpool.c:584
>> #5  0x000000000113fa17 in varpool_node::assemble_decl (this=0x7ffff745b000) at ../../gcc-trunk/gcc/varpool.c:750
>>
>>
>> There are at least two problems here:
>>
>> First you did not want to step into the TREE_TYPE, but it happens all
>> the time, even if you use "n" to step over it.
>>
>> And secondly, from the call stack, you don't know where you are in get_alias_set.
>> But the code that is executing at this point is actually the x == 0 || x == error_mark_node
>> from alias.c, line 839, which contains the inlined body of the TREE_TYPE, but
>> the rest of the if.  So there is an inconsistency in the  
>>
>> Contents of the .debug_info section:
>>
>>  <2><4f686>: Abbrev Number: 12 (DW_TAG_inlined_subroutine)
>>     <4f687>   DW_AT_abstract_origin: <0x53d4e>
>>     <4f68b>   DW_AT_entry_pc    : 0x7280
>>     <4f693>   DW_AT_GNU_entry_view: 1
>>     <4f695>   DW_AT_ranges      : 0xb480
>>     <4f699>   DW_AT_call_file   : 8  <- alias.c
>>     <4f69a>   DW_AT_call_line   : 839
>>     <4f69c>   DW_AT_call_column : 8
>>     <4f69d>   DW_AT_sibling     : <0x4f717>
>>
>>  The File Name Table (offset 0x253):
>>   8     2       0       0       alias.c
>>   10    2       0       0       tree.h
>>
>> Contents of the .debug_ranges section:
>>
>>     0000b480 0000000000007280 0000000000007291 
>>     0000b480 0000000000002764 000000000000277e 
>>     0000b480 <End of list>
>>
>> The problem is at pc=0x7291 in the Line Number Section:
>>
>>  Line Number Statements:
>>
>>   [0x00008826]  Special opcode 61: advance Address by 4 to 0x7284 and Line by 0 to 3380
>>   [0x00008827]  Set is_stmt to 1
>>   [0x00008828]  Special opcode 189: advance Address by 13 to 0x7291 and Line by 2 to 3382 (*)
>>   [0x00008829]  Set is_stmt to 0 (**)
>>   [0x0000882a]  Copy (view 1)
>>   [0x0000882b]  Set File Name to entry 8 in the File Name Table <- back to alias.c
>>   [0x0000882d]  Set column to 8
>>   [0x0000882f]  Advance Line by -2543 to 839
>>   [0x00008832]  Copy (view 2)
>>   [0x00008833]  Set column to 27
>>   [0x00008835]  Special opcode 61: advance Address by 4 to 0x7295 and Line by 0 to 839
>>   [0x00008836]  Set column to 3
>>   [0x00008838]  Set is_stmt to 1 <-- next line info counts: alias.c:847
>>   [0x00008839]  Special opcode 153: advance Address by 10 to 0x729f and Line by 8 to 847
>>   [0x0000883a]  Set column to 7
>>
>> (*) this line is tree.h:3382, but the program counter is *not* within the subroutine,
>> but exactly at the first instruction *after* the subroutine according to the debug_ranges.
>>
>> What makes it worse, is that (**) makes gdb ignore the new location info alias.c:839,
>> which means, normally the n command would have continued to pc=0x729f, which is at alias.c:847.
>>
>>
>> The problem happens due to a block with only var
>> This patch fixes this problem by moving (**) to the first statement with a different line number.
>>
>> In alias.c.316r.final this looks like that:
>>
>> (note 2884 2883 1995 31 0x7f903a931ba0 NOTE_INSN_BLOCK_BEG)
>> (note 1995 2884 2885 31 ../../gcc-trunk/gcc/tree.h:3377 NOTE_INSN_INLINE_ENTRY)
>> (note 2885 1995 1996 31 0x7f903a931c00 NOTE_INSN_BLOCK_BEG)
>> [...]
>> (note 50 39 59 32 [bb 32] NOTE_INSN_BASIC_BLOCK)
>> (note 59 50 60 32 NOTE_INSN_DELETED)
>> (note 60 59 1997 32 NOTE_INSN_DELETED)
>> (note 1997 60 2239 32 ../../gcc-trunk/gcc/tree.h:3382 NOTE_INSN_BEGIN_STMT)
>> (note 2239 1997 2240 32 (var_location __tD.143911 (nil)) NOTE_INSN_VAR_LOCATION)
>> (note 2240 2239 2241 32 (var_location __sD.143912 (nil)) NOTE_INSN_VAR_LOCATION)
>> (note 2241 2240 2242 32 (var_location __fD.143913 (nil)) NOTE_INSN_VAR_LOCATION)
>> (note 2242 2241 2243 32 (var_location __lD.143914 (nil)) NOTE_INSN_VAR_LOCATION)
>> (note 2243 2242 2886 32 (var_location __gD.143915 (nil)) NOTE_INSN_VAR_LOCATION)
>> (note 2886 2243 2887 32 0x7f903a931c00 NOTE_INSN_BLOCK_END)
>> (note 2887 2886 57 32 0x7f903a931ba0 NOTE_INSN_BLOCK_END)
>> (insn:TI 57 2887 61 32 (set (reg/f:DI 0 ax [orig:87 _7 ] [87])
>>         (mem/f/j:DI (plus:DI (reg/f:DI 5 di [orig:83 t.85_2 ] [83])
>>                 (const_int 8 [0x8])) [0 t.85_2->typedD.91322.typeD.90828+0 S8 A64])) "../../gcc-trunk/gcc/alias.c":839:108 66 {*movdi_internal}
>>      (nil))
>>
>> So this patch detects the NOTE_INSN_VAR_LOCATION and makes the next location
>> with a different file&line info a statement location, which is hopefully
>> a real instruction, thus either part of the subroutine, or the first
>> instruction after the subroutine, which should have the correct location.
>> Once the same address has a second statement-type .loc info, gdb will ignore
>> the first one, and the stepping works as expected.
>>
>> So this is a bit of a heuristic, but it appears to work quite well.
>>
>> The test case g++.dg/guality/pr55541.C is the only test where this
>> change had an effect.  But it is not a regression, since previously
>> the test case was "unsupported" on any optimization mode, since there
>> was no breakpoint at line 11, now the breakpoint works, but the variable
>> value is wrong, but basically this was not working before.
>>
>> I don't know how to make this test xfail when compiled with optimization,
>> but the do-skip-if is probably good enough for this kind of test case.
>>
>>
>> Bootstrapped and reg-tested on x86_64-pc-linux-gnu.
>> Is it OK for trunk?
>>
>>
>> Thanks
>> Bernd.
>>
Bernd Edlinger Nov. 9, 2019, 10:20 a.m. UTC | #3
Ping...

On 11/2/19 7:49 AM, Bernd Edlinger wrote:
> Ping...
> 
> On 10/27/19 9:14 AM, Bernd Edlinger wrote:
>> Ping...
>>
>> I'd like to ping for this patch:
>> https://gcc.gnu.org/ml/gcc-patches/2019-10/msg01459.html
>>
>>
>> Thanks
>> Bernd.
>>
>> On 10/20/19 9:58 PM, Bernd Edlinger wrote:
>>> Hi,
>>>
>>> this fixes an issue with the gdb step-over aka. "n" command.
>>>
>>> It can be seen when you debug an optimized stage-3 cc1
>>> it does not affect -O0 code, though.
>>>
>>> This example debug session will explain the effect.
>>>
>>> (gdb) b get_alias_set
>>> Breakpoint 5 at 0xa099f0: file ../../gcc-trunk/gcc/alias.c, line 837.
>>> (gdb) r
>>> Breakpoint 5, get_alias_set (t=t@entry=0x7ffff7ff7ab0) at ../../gcc-trunk/gcc/alias.c:837
>>> 837	  if (t == error_mark_node
>>> (gdb) n
>>> 839		  && (TREE_TYPE (t) == 0 || TREE_TYPE (t) == error_mark_node)))
>>> (gdb) n
>>> 3382	  return __t;  <-- now we have a problem: wrong line info here
>>> (gdb) bt
>>> #0  get_alias_set (t=t@entry=0x7ffff7ff7ab0) at ../../gcc-trunk/gcc/tree.h:3382
>>> #1  0x0000000000b25dfe in set_mem_attributes_minus_bitpos (ref=0x7ffff746f990, t=0x7ffff7ff7ab0, objectp=1, bitpos=...)
>>>     at ../../gcc-trunk/gcc/emit-rtl.c:1957
>>> #2  0x0000000001137a55 in make_decl_rtl (decl=0x7ffff7ff7ab0) at ../../gcc-trunk/gcc/varasm.c:1518
>>> #3  0x000000000113b6e8 in assemble_variable (decl=0x7ffff7ff7ab0, top_level=<optimized out>, at_end=<optimized out>, 
>>>     dont_output_data=0) at ../../gcc-trunk/gcc/varasm.c:2246
>>> #4  0x000000000113f0ea in varpool_node::assemble_decl (this=0x7ffff745b000) at ../../gcc-trunk/gcc/varpool.c:584
>>> #5  0x000000000113fa17 in varpool_node::assemble_decl (this=0x7ffff745b000) at ../../gcc-trunk/gcc/varpool.c:750
>>>
>>>
>>> There are at least two problems here:
>>>
>>> First you did not want to step into the TREE_TYPE, but it happens all
>>> the time, even if you use "n" to step over it.
>>>
>>> And secondly, from the call stack, you don't know where you are in get_alias_set.
>>> But the code that is executing at this point is actually the x == 0 || x == error_mark_node
>>> from alias.c, line 839, which contains the inlined body of the TREE_TYPE, but
>>> the rest of the if.  So there is an inconsistency in the  
>>>
>>> Contents of the .debug_info section:
>>>
>>>  <2><4f686>: Abbrev Number: 12 (DW_TAG_inlined_subroutine)
>>>     <4f687>   DW_AT_abstract_origin: <0x53d4e>
>>>     <4f68b>   DW_AT_entry_pc    : 0x7280
>>>     <4f693>   DW_AT_GNU_entry_view: 1
>>>     <4f695>   DW_AT_ranges      : 0xb480
>>>     <4f699>   DW_AT_call_file   : 8  <- alias.c
>>>     <4f69a>   DW_AT_call_line   : 839
>>>     <4f69c>   DW_AT_call_column : 8
>>>     <4f69d>   DW_AT_sibling     : <0x4f717>
>>>
>>>  The File Name Table (offset 0x253):
>>>   8     2       0       0       alias.c
>>>   10    2       0       0       tree.h
>>>
>>> Contents of the .debug_ranges section:
>>>
>>>     0000b480 0000000000007280 0000000000007291 
>>>     0000b480 0000000000002764 000000000000277e 
>>>     0000b480 <End of list>
>>>
>>> The problem is at pc=0x7291 in the Line Number Section:
>>>
>>>  Line Number Statements:
>>>
>>>   [0x00008826]  Special opcode 61: advance Address by 4 to 0x7284 and Line by 0 to 3380
>>>   [0x00008827]  Set is_stmt to 1
>>>   [0x00008828]  Special opcode 189: advance Address by 13 to 0x7291 and Line by 2 to 3382 (*)
>>>   [0x00008829]  Set is_stmt to 0 (**)
>>>   [0x0000882a]  Copy (view 1)
>>>   [0x0000882b]  Set File Name to entry 8 in the File Name Table <- back to alias.c
>>>   [0x0000882d]  Set column to 8
>>>   [0x0000882f]  Advance Line by -2543 to 839
>>>   [0x00008832]  Copy (view 2)
>>>   [0x00008833]  Set column to 27
>>>   [0x00008835]  Special opcode 61: advance Address by 4 to 0x7295 and Line by 0 to 839
>>>   [0x00008836]  Set column to 3
>>>   [0x00008838]  Set is_stmt to 1 <-- next line info counts: alias.c:847
>>>   [0x00008839]  Special opcode 153: advance Address by 10 to 0x729f and Line by 8 to 847
>>>   [0x0000883a]  Set column to 7
>>>
>>> (*) this line is tree.h:3382, but the program counter is *not* within the subroutine,
>>> but exactly at the first instruction *after* the subroutine according to the debug_ranges.
>>>
>>> What makes it worse, is that (**) makes gdb ignore the new location info alias.c:839,
>>> which means, normally the n command would have continued to pc=0x729f, which is at alias.c:847.
>>>
>>>
>>> The problem happens due to a block with only var
>>> This patch fixes this problem by moving (**) to the first statement with a different line number.
>>>
>>> In alias.c.316r.final this looks like that:
>>>
>>> (note 2884 2883 1995 31 0x7f903a931ba0 NOTE_INSN_BLOCK_BEG)
>>> (note 1995 2884 2885 31 ../../gcc-trunk/gcc/tree.h:3377 NOTE_INSN_INLINE_ENTRY)
>>> (note 2885 1995 1996 31 0x7f903a931c00 NOTE_INSN_BLOCK_BEG)
>>> [...]
>>> (note 50 39 59 32 [bb 32] NOTE_INSN_BASIC_BLOCK)
>>> (note 59 50 60 32 NOTE_INSN_DELETED)
>>> (note 60 59 1997 32 NOTE_INSN_DELETED)
>>> (note 1997 60 2239 32 ../../gcc-trunk/gcc/tree.h:3382 NOTE_INSN_BEGIN_STMT)
>>> (note 2239 1997 2240 32 (var_location __tD.143911 (nil)) NOTE_INSN_VAR_LOCATION)
>>> (note 2240 2239 2241 32 (var_location __sD.143912 (nil)) NOTE_INSN_VAR_LOCATION)
>>> (note 2241 2240 2242 32 (var_location __fD.143913 (nil)) NOTE_INSN_VAR_LOCATION)
>>> (note 2242 2241 2243 32 (var_location __lD.143914 (nil)) NOTE_INSN_VAR_LOCATION)
>>> (note 2243 2242 2886 32 (var_location __gD.143915 (nil)) NOTE_INSN_VAR_LOCATION)
>>> (note 2886 2243 2887 32 0x7f903a931c00 NOTE_INSN_BLOCK_END)
>>> (note 2887 2886 57 32 0x7f903a931ba0 NOTE_INSN_BLOCK_END)
>>> (insn:TI 57 2887 61 32 (set (reg/f:DI 0 ax [orig:87 _7 ] [87])
>>>         (mem/f/j:DI (plus:DI (reg/f:DI 5 di [orig:83 t.85_2 ] [83])
>>>                 (const_int 8 [0x8])) [0 t.85_2->typedD.91322.typeD.90828+0 S8 A64])) "../../gcc-trunk/gcc/alias.c":839:108 66 {*movdi_internal}
>>>      (nil))
>>>
>>> So this patch detects the NOTE_INSN_VAR_LOCATION and makes the next location
>>> with a different file&line info a statement location, which is hopefully
>>> a real instruction, thus either part of the subroutine, or the first
>>> instruction after the subroutine, which should have the correct location.
>>> Once the same address has a second statement-type .loc info, gdb will ignore
>>> the first one, and the stepping works as expected.
>>>
>>> So this is a bit of a heuristic, but it appears to work quite well.
>>>
>>> The test case g++.dg/guality/pr55541.C is the only test where this
>>> change had an effect.  But it is not a regression, since previously
>>> the test case was "unsupported" on any optimization mode, since there
>>> was no breakpoint at line 11, now the breakpoint works, but the variable
>>> value is wrong, but basically this was not working before.
>>>
>>> I don't know how to make this test xfail when compiled with optimization,
>>> but the do-skip-if is probably good enough for this kind of test case.
>>>
>>>
>>> Bootstrapped and reg-tested on x86_64-pc-linux-gnu.
>>> Is it OK for trunk?
>>>
>>>
>>> Thanks
>>> Bernd.
>>>
Bernd Edlinger Nov. 15, 2019, 3:47 p.m. UTC | #4
Ping...

FYI this jumping into fake inline frames happens rather often
when debugging, and is especially annoying once you know how
easy it is to fix it...


Bernd.

On 11/9/19 11:20 AM, Bernd Edlinger wrote:
> Ping...
> 
> On 11/2/19 7:49 AM, Bernd Edlinger wrote:
>> Ping...
>>
>> On 10/27/19 9:14 AM, Bernd Edlinger wrote:
>>> Ping...
>>>
>>> I'd like to ping for this patch:
>>> https://gcc.gnu.org/ml/gcc-patches/2019-10/msg01459.html
>>>
>>>
>>> Thanks
>>> Bernd.
>>>
>>> On 10/20/19 9:58 PM, Bernd Edlinger wrote:
>>>> Hi,
>>>>
>>>> this fixes an issue with the gdb step-over aka. "n" command.
>>>>
>>>> It can be seen when you debug an optimized stage-3 cc1
>>>> it does not affect -O0 code, though.
>>>>
>>>> This example debug session will explain the effect.
>>>>
>>>> (gdb) b get_alias_set
>>>> Breakpoint 5 at 0xa099f0: file ../../gcc-trunk/gcc/alias.c, line 837.
>>>> (gdb) r
>>>> Breakpoint 5, get_alias_set (t=t@entry=0x7ffff7ff7ab0) at ../../gcc-trunk/gcc/alias.c:837
>>>> 837	  if (t == error_mark_node
>>>> (gdb) n
>>>> 839		  && (TREE_TYPE (t) == 0 || TREE_TYPE (t) == error_mark_node)))
>>>> (gdb) n
>>>> 3382	  return __t;  <-- now we have a problem: wrong line info here
>>>> (gdb) bt
>>>> #0  get_alias_set (t=t@entry=0x7ffff7ff7ab0) at ../../gcc-trunk/gcc/tree.h:3382
>>>> #1  0x0000000000b25dfe in set_mem_attributes_minus_bitpos (ref=0x7ffff746f990, t=0x7ffff7ff7ab0, objectp=1, bitpos=...)
>>>>     at ../../gcc-trunk/gcc/emit-rtl.c:1957
>>>> #2  0x0000000001137a55 in make_decl_rtl (decl=0x7ffff7ff7ab0) at ../../gcc-trunk/gcc/varasm.c:1518
>>>> #3  0x000000000113b6e8 in assemble_variable (decl=0x7ffff7ff7ab0, top_level=<optimized out>, at_end=<optimized out>, 
>>>>     dont_output_data=0) at ../../gcc-trunk/gcc/varasm.c:2246
>>>> #4  0x000000000113f0ea in varpool_node::assemble_decl (this=0x7ffff745b000) at ../../gcc-trunk/gcc/varpool.c:584
>>>> #5  0x000000000113fa17 in varpool_node::assemble_decl (this=0x7ffff745b000) at ../../gcc-trunk/gcc/varpool.c:750
>>>>
>>>>
>>>> There are at least two problems here:
>>>>
>>>> First you did not want to step into the TREE_TYPE, but it happens all
>>>> the time, even if you use "n" to step over it.
>>>>
>>>> And secondly, from the call stack, you don't know where you are in get_alias_set.
>>>> But the code that is executing at this point is actually the x == 0 || x == error_mark_node
>>>> from alias.c, line 839, which contains the inlined body of the TREE_TYPE, but
>>>> the rest of the if.  So there is an inconsistency in the  
>>>>
>>>> Contents of the .debug_info section:
>>>>
>>>>  <2><4f686>: Abbrev Number: 12 (DW_TAG_inlined_subroutine)
>>>>     <4f687>   DW_AT_abstract_origin: <0x53d4e>
>>>>     <4f68b>   DW_AT_entry_pc    : 0x7280
>>>>     <4f693>   DW_AT_GNU_entry_view: 1
>>>>     <4f695>   DW_AT_ranges      : 0xb480
>>>>     <4f699>   DW_AT_call_file   : 8  <- alias.c
>>>>     <4f69a>   DW_AT_call_line   : 839
>>>>     <4f69c>   DW_AT_call_column : 8
>>>>     <4f69d>   DW_AT_sibling     : <0x4f717>
>>>>
>>>>  The File Name Table (offset 0x253):
>>>>   8     2       0       0       alias.c
>>>>   10    2       0       0       tree.h
>>>>
>>>> Contents of the .debug_ranges section:
>>>>
>>>>     0000b480 0000000000007280 0000000000007291 
>>>>     0000b480 0000000000002764 000000000000277e 
>>>>     0000b480 <End of list>
>>>>
>>>> The problem is at pc=0x7291 in the Line Number Section:
>>>>
>>>>  Line Number Statements:
>>>>
>>>>   [0x00008826]  Special opcode 61: advance Address by 4 to 0x7284 and Line by 0 to 3380
>>>>   [0x00008827]  Set is_stmt to 1
>>>>   [0x00008828]  Special opcode 189: advance Address by 13 to 0x7291 and Line by 2 to 3382 (*)
>>>>   [0x00008829]  Set is_stmt to 0 (**)
>>>>   [0x0000882a]  Copy (view 1)
>>>>   [0x0000882b]  Set File Name to entry 8 in the File Name Table <- back to alias.c
>>>>   [0x0000882d]  Set column to 8
>>>>   [0x0000882f]  Advance Line by -2543 to 839
>>>>   [0x00008832]  Copy (view 2)
>>>>   [0x00008833]  Set column to 27
>>>>   [0x00008835]  Special opcode 61: advance Address by 4 to 0x7295 and Line by 0 to 839
>>>>   [0x00008836]  Set column to 3
>>>>   [0x00008838]  Set is_stmt to 1 <-- next line info counts: alias.c:847
>>>>   [0x00008839]  Special opcode 153: advance Address by 10 to 0x729f and Line by 8 to 847
>>>>   [0x0000883a]  Set column to 7
>>>>
>>>> (*) this line is tree.h:3382, but the program counter is *not* within the subroutine,
>>>> but exactly at the first instruction *after* the subroutine according to the debug_ranges.
>>>>
>>>> What makes it worse, is that (**) makes gdb ignore the new location info alias.c:839,
>>>> which means, normally the n command would have continued to pc=0x729f, which is at alias.c:847.
>>>>
>>>>
>>>> The problem happens due to a block with only var
>>>> This patch fixes this problem by moving (**) to the first statement with a different line number.
>>>>
>>>> In alias.c.316r.final this looks like that:
>>>>
>>>> (note 2884 2883 1995 31 0x7f903a931ba0 NOTE_INSN_BLOCK_BEG)
>>>> (note 1995 2884 2885 31 ../../gcc-trunk/gcc/tree.h:3377 NOTE_INSN_INLINE_ENTRY)
>>>> (note 2885 1995 1996 31 0x7f903a931c00 NOTE_INSN_BLOCK_BEG)
>>>> [...]
>>>> (note 50 39 59 32 [bb 32] NOTE_INSN_BASIC_BLOCK)
>>>> (note 59 50 60 32 NOTE_INSN_DELETED)
>>>> (note 60 59 1997 32 NOTE_INSN_DELETED)
>>>> (note 1997 60 2239 32 ../../gcc-trunk/gcc/tree.h:3382 NOTE_INSN_BEGIN_STMT)
>>>> (note 2239 1997 2240 32 (var_location __tD.143911 (nil)) NOTE_INSN_VAR_LOCATION)
>>>> (note 2240 2239 2241 32 (var_location __sD.143912 (nil)) NOTE_INSN_VAR_LOCATION)
>>>> (note 2241 2240 2242 32 (var_location __fD.143913 (nil)) NOTE_INSN_VAR_LOCATION)
>>>> (note 2242 2241 2243 32 (var_location __lD.143914 (nil)) NOTE_INSN_VAR_LOCATION)
>>>> (note 2243 2242 2886 32 (var_location __gD.143915 (nil)) NOTE_INSN_VAR_LOCATION)
>>>> (note 2886 2243 2887 32 0x7f903a931c00 NOTE_INSN_BLOCK_END)
>>>> (note 2887 2886 57 32 0x7f903a931ba0 NOTE_INSN_BLOCK_END)
>>>> (insn:TI 57 2887 61 32 (set (reg/f:DI 0 ax [orig:87 _7 ] [87])
>>>>         (mem/f/j:DI (plus:DI (reg/f:DI 5 di [orig:83 t.85_2 ] [83])
>>>>                 (const_int 8 [0x8])) [0 t.85_2->typedD.91322.typeD.90828+0 S8 A64])) "../../gcc-trunk/gcc/alias.c":839:108 66 {*movdi_internal}
>>>>      (nil))
>>>>
>>>> So this patch detects the NOTE_INSN_VAR_LOCATION and makes the next location
>>>> with a different file&line info a statement location, which is hopefully
>>>> a real instruction, thus either part of the subroutine, or the first
>>>> instruction after the subroutine, which should have the correct location.
>>>> Once the same address has a second statement-type .loc info, gdb will ignore
>>>> the first one, and the stepping works as expected.
>>>>
>>>> So this is a bit of a heuristic, but it appears to work quite well.
>>>>
>>>> The test case g++.dg/guality/pr55541.C is the only test where this
>>>> change had an effect.  But it is not a regression, since previously
>>>> the test case was "unsupported" on any optimization mode, since there
>>>> was no breakpoint at line 11, now the breakpoint works, but the variable
>>>> value is wrong, but basically this was not working before.
>>>>
>>>> I don't know how to make this test xfail when compiled with optimization,
>>>> but the do-skip-if is probably good enough for this kind of test case.
>>>>
>>>>
>>>> Bootstrapped and reg-tested on x86_64-pc-linux-gnu.
>>>> Is it OK for trunk?
>>>>
>>>>
>>>> Thanks
>>>> Bernd.
>>>>
Richard Biener Nov. 18, 2019, 8:21 a.m. UTC | #5
On Fri, Nov 15, 2019 at 4:47 PM Bernd Edlinger
<bernd.edlinger@hotmail.de> wrote:
>
> Ping...
>
> FYI this jumping into fake inline frames happens rather often
> when debugging, and is especially annoying once you know how
> easy it is to fix it...

Alex, can you please chime in here?  I've looked at the patch twice now
and can't decide whether we are working around a gdb issue, whether
our is_stmt "interpretation" is wrong or whether we're simply messing
up tracking BLOCKs (not knowing how we should encode "scope change"
in the line info).

Besides that, another global variable is of course "ugly" (but follows
the rest of the pack).

So - if Alex says this is OK then consider it approved.

Thanks,
Richard.

>
> Bernd.
>
> On 11/9/19 11:20 AM, Bernd Edlinger wrote:
> > Ping...
> >
> > On 11/2/19 7:49 AM, Bernd Edlinger wrote:
> >> Ping...
> >>
> >> On 10/27/19 9:14 AM, Bernd Edlinger wrote:
> >>> Ping...
> >>>
> >>> I'd like to ping for this patch:
> >>> https://gcc.gnu.org/ml/gcc-patches/2019-10/msg01459.html
> >>>
> >>>
> >>> Thanks
> >>> Bernd.
> >>>
> >>> On 10/20/19 9:58 PM, Bernd Edlinger wrote:
> >>>> Hi,
> >>>>
> >>>> this fixes an issue with the gdb step-over aka. "n" command.
> >>>>
> >>>> It can be seen when you debug an optimized stage-3 cc1
> >>>> it does not affect -O0 code, though.
> >>>>
> >>>> This example debug session will explain the effect.
> >>>>
> >>>> (gdb) b get_alias_set
> >>>> Breakpoint 5 at 0xa099f0: file ../../gcc-trunk/gcc/alias.c, line 837.
> >>>> (gdb) r
> >>>> Breakpoint 5, get_alias_set (t=t@entry=0x7ffff7ff7ab0) at ../../gcc-trunk/gcc/alias.c:837
> >>>> 837          if (t == error_mark_node
> >>>> (gdb) n
> >>>> 839                  && (TREE_TYPE (t) == 0 || TREE_TYPE (t) == error_mark_node)))
> >>>> (gdb) n
> >>>> 3382         return __t;  <-- now we have a problem: wrong line info here
> >>>> (gdb) bt
> >>>> #0  get_alias_set (t=t@entry=0x7ffff7ff7ab0) at ../../gcc-trunk/gcc/tree.h:3382
> >>>> #1  0x0000000000b25dfe in set_mem_attributes_minus_bitpos (ref=0x7ffff746f990, t=0x7ffff7ff7ab0, objectp=1, bitpos=...)
> >>>>     at ../../gcc-trunk/gcc/emit-rtl.c:1957
> >>>> #2  0x0000000001137a55 in make_decl_rtl (decl=0x7ffff7ff7ab0) at ../../gcc-trunk/gcc/varasm.c:1518
> >>>> #3  0x000000000113b6e8 in assemble_variable (decl=0x7ffff7ff7ab0, top_level=<optimized out>, at_end=<optimized out>,
> >>>>     dont_output_data=0) at ../../gcc-trunk/gcc/varasm.c:2246
> >>>> #4  0x000000000113f0ea in varpool_node::assemble_decl (this=0x7ffff745b000) at ../../gcc-trunk/gcc/varpool.c:584
> >>>> #5  0x000000000113fa17 in varpool_node::assemble_decl (this=0x7ffff745b000) at ../../gcc-trunk/gcc/varpool.c:750
> >>>>
> >>>>
> >>>> There are at least two problems here:
> >>>>
> >>>> First you did not want to step into the TREE_TYPE, but it happens all
> >>>> the time, even if you use "n" to step over it.
> >>>>
> >>>> And secondly, from the call stack, you don't know where you are in get_alias_set.
> >>>> But the code that is executing at this point is actually the x == 0 || x == error_mark_node
> >>>> from alias.c, line 839, which contains the inlined body of the TREE_TYPE, but
> >>>> the rest of the if.  So there is an inconsistency in the
> >>>>
> >>>> Contents of the .debug_info section:
> >>>>
> >>>>  <2><4f686>: Abbrev Number: 12 (DW_TAG_inlined_subroutine)
> >>>>     <4f687>   DW_AT_abstract_origin: <0x53d4e>
> >>>>     <4f68b>   DW_AT_entry_pc    : 0x7280
> >>>>     <4f693>   DW_AT_GNU_entry_view: 1
> >>>>     <4f695>   DW_AT_ranges      : 0xb480
> >>>>     <4f699>   DW_AT_call_file   : 8  <- alias.c
> >>>>     <4f69a>   DW_AT_call_line   : 839
> >>>>     <4f69c>   DW_AT_call_column : 8
> >>>>     <4f69d>   DW_AT_sibling     : <0x4f717>
> >>>>
> >>>>  The File Name Table (offset 0x253):
> >>>>   8     2       0       0       alias.c
> >>>>   10    2       0       0       tree.h
> >>>>
> >>>> Contents of the .debug_ranges section:
> >>>>
> >>>>     0000b480 0000000000007280 0000000000007291
> >>>>     0000b480 0000000000002764 000000000000277e
> >>>>     0000b480 <End of list>
> >>>>
> >>>> The problem is at pc=0x7291 in the Line Number Section:
> >>>>
> >>>>  Line Number Statements:
> >>>>
> >>>>   [0x00008826]  Special opcode 61: advance Address by 4 to 0x7284 and Line by 0 to 3380
> >>>>   [0x00008827]  Set is_stmt to 1
> >>>>   [0x00008828]  Special opcode 189: advance Address by 13 to 0x7291 and Line by 2 to 3382 (*)
> >>>>   [0x00008829]  Set is_stmt to 0 (**)
> >>>>   [0x0000882a]  Copy (view 1)
> >>>>   [0x0000882b]  Set File Name to entry 8 in the File Name Table <- back to alias.c
> >>>>   [0x0000882d]  Set column to 8
> >>>>   [0x0000882f]  Advance Line by -2543 to 839
> >>>>   [0x00008832]  Copy (view 2)
> >>>>   [0x00008833]  Set column to 27
> >>>>   [0x00008835]  Special opcode 61: advance Address by 4 to 0x7295 and Line by 0 to 839
> >>>>   [0x00008836]  Set column to 3
> >>>>   [0x00008838]  Set is_stmt to 1 <-- next line info counts: alias.c:847
> >>>>   [0x00008839]  Special opcode 153: advance Address by 10 to 0x729f and Line by 8 to 847
> >>>>   [0x0000883a]  Set column to 7
> >>>>
> >>>> (*) this line is tree.h:3382, but the program counter is *not* within the subroutine,
> >>>> but exactly at the first instruction *after* the subroutine according to the debug_ranges.
> >>>>
> >>>> What makes it worse, is that (**) makes gdb ignore the new location info alias.c:839,
> >>>> which means, normally the n command would have continued to pc=0x729f, which is at alias.c:847.
> >>>>
> >>>>
> >>>> The problem happens due to a block with only var
> >>>> This patch fixes this problem by moving (**) to the first statement with a different line number.
> >>>>
> >>>> In alias.c.316r.final this looks like that:
> >>>>
> >>>> (note 2884 2883 1995 31 0x7f903a931ba0 NOTE_INSN_BLOCK_BEG)
> >>>> (note 1995 2884 2885 31 ../../gcc-trunk/gcc/tree.h:3377 NOTE_INSN_INLINE_ENTRY)
> >>>> (note 2885 1995 1996 31 0x7f903a931c00 NOTE_INSN_BLOCK_BEG)
> >>>> [...]
> >>>> (note 50 39 59 32 [bb 32] NOTE_INSN_BASIC_BLOCK)
> >>>> (note 59 50 60 32 NOTE_INSN_DELETED)
> >>>> (note 60 59 1997 32 NOTE_INSN_DELETED)
> >>>> (note 1997 60 2239 32 ../../gcc-trunk/gcc/tree.h:3382 NOTE_INSN_BEGIN_STMT)
> >>>> (note 2239 1997 2240 32 (var_location __tD.143911 (nil)) NOTE_INSN_VAR_LOCATION)
> >>>> (note 2240 2239 2241 32 (var_location __sD.143912 (nil)) NOTE_INSN_VAR_LOCATION)
> >>>> (note 2241 2240 2242 32 (var_location __fD.143913 (nil)) NOTE_INSN_VAR_LOCATION)
> >>>> (note 2242 2241 2243 32 (var_location __lD.143914 (nil)) NOTE_INSN_VAR_LOCATION)
> >>>> (note 2243 2242 2886 32 (var_location __gD.143915 (nil)) NOTE_INSN_VAR_LOCATION)
> >>>> (note 2886 2243 2887 32 0x7f903a931c00 NOTE_INSN_BLOCK_END)
> >>>> (note 2887 2886 57 32 0x7f903a931ba0 NOTE_INSN_BLOCK_END)
> >>>> (insn:TI 57 2887 61 32 (set (reg/f:DI 0 ax [orig:87 _7 ] [87])
> >>>>         (mem/f/j:DI (plus:DI (reg/f:DI 5 di [orig:83 t.85_2 ] [83])
> >>>>                 (const_int 8 [0x8])) [0 t.85_2->typedD.91322.typeD.90828+0 S8 A64])) "../../gcc-trunk/gcc/alias.c":839:108 66 {*movdi_internal}
> >>>>      (nil))
> >>>>
> >>>> So this patch detects the NOTE_INSN_VAR_LOCATION and makes the next location
> >>>> with a different file&line info a statement location, which is hopefully
> >>>> a real instruction, thus either part of the subroutine, or the first
> >>>> instruction after the subroutine, which should have the correct location.
> >>>> Once the same address has a second statement-type .loc info, gdb will ignore
> >>>> the first one, and the stepping works as expected.
> >>>>
> >>>> So this is a bit of a heuristic, but it appears to work quite well.
> >>>>
> >>>> The test case g++.dg/guality/pr55541.C is the only test where this
> >>>> change had an effect.  But it is not a regression, since previously
> >>>> the test case was "unsupported" on any optimization mode, since there
> >>>> was no breakpoint at line 11, now the breakpoint works, but the variable
> >>>> value is wrong, but basically this was not working before.
> >>>>
> >>>> I don't know how to make this test xfail when compiled with optimization,
> >>>> but the do-skip-if is probably good enough for this kind of test case.
> >>>>
> >>>>
> >>>> Bootstrapped and reg-tested on x86_64-pc-linux-gnu.
> >>>> Is it OK for trunk?
> >>>>
> >>>>
> >>>> Thanks
> >>>> Bernd.
> >>>>
Alexandre Oliva Nov. 19, 2019, 2:01 a.m. UTC | #6
Hello, Bernd,

Apologies for taking so long to respond.  I had not noticed your patch
before being explicitly copied on it.

IIUC you're describing a problem in GDB, that could be summed up as its
not paying attention to is_stmt and being unaware of location views, and
you appear to be proposing to work around that by changing what AFAICT
is a correct line number program into one that, though incorrect, will
get more desirable behavior out of current GDB.

If that is so, I'm inclined to disagree that this is a desirable change.
We should strive to generate correct, rather than incorrect debug
information.  It was foreseen and expected that statement frontiers and
location views would introduce occasional behavior regressions in
debuggers unable to consume this information; what was not expected was
that debuggers would lack support for it for so long.

I'd much rather make debug info incorrect, and instead introduce support
for the extended debug info in consumers.  I realize it would take a lot
more work to implement a proper fix there, however.  Unfortunately, I
don't know of anyone currently working on that counterpart
implementation, so the best recommendation I can offer to avoid this
problem is to disable statement frontiers (-gno-statement-frontiers) and
location views (-gno-variable-location-views).  This will get you line
number programs and location lists that do not exercise features that
GDB is not aware of.

Perhaps we should change our defaults, if the situation with GDB does
not change :-(
Bernd Edlinger Nov. 19, 2019, 4:01 p.m. UTC | #7
On 11/19/19 3:01 AM, Alexandre Oliva wrote:
> Hello, Bernd,
> 
> Apologies for taking so long to respond.  I had not noticed your patch
> before being explicitly copied on it.
> 
> IIUC you're describing a problem in GDB, that could be summed up as its
> not paying attention to is_stmt and being unaware of location views, and
> you appear to be proposing to work around that by changing what AFAICT
> is a correct line number program into one that, though incorrect, will
> get more desirable behavior out of current GDB.
> 
> If that is so, I'm inclined to disagree that this is a desirable change.
> We should strive to generate correct, rather than incorrect debug
> information.  It was foreseen and expected that statement frontiers and
> location views would introduce occasional behavior regressions in
> debuggers unable to consume this information; what was not expected was
> that debuggers would lack support for it for so long.
> 
> I'd much rather make debug info incorrect, and instead introduce support
> for the extended debug info in consumers.  I realize it would take a lot
> more work to implement a proper fix there, however.  Unfortunately, I
> don't know of anyone currently working on that counterpart
> implementation, so the best recommendation I can offer to avoid this
> problem is to disable statement frontiers (-gno-statement-frontiers) and
> location views (-gno-variable-location-views).  This will get you line
> number programs and location lists that do not exercise features that
> GDB is not aware of.
> 
> Perhaps we should change our defaults, if the situation with GDB does
> not change :-(
> 

I tried those options, and -gno-variable-location-views changes
nothing in the debug exprience, but -gno-statement-frontiers
makes gdb do this:

Breakpoint 1, get_alias_set (t=t@entry=0x7ffff7ff6c60) at ../../gcc-10-20191117/gcc/alias.c:829
829     {
(gdb) n
837       if (t == error_mark_node
(gdb) n
829     {
(gdb) n
838           || (! TYPE_P (t)
(gdb) n
839               && (TREE_TYPE (t) == 0 || TREE_TYPE (t) == error_mark_node)))
(gdb) n
851           STRIP_NOPS (t);
(gdb)


So while the inline function is skipped this time, the function prologue
is executed twice, and the code is probably more jumpy than before.

It is interesting that my previous attempt at fixing it in gdb resulted
in basically the same effect :-/


My question to you is this: can you explain, given the following debug info, extracted
by readelf from alias.c, why the address 0x6e11 is in the inlined subroutine
and *not* in the get_alias_set function?  If you can explain it to me, I can probably
explain it to gdb as well.


  [0x00008b37]  Special opcode 61: advance Address by 4 to 0x6e04 and Line by 0 to 3386
  [0x00008b38]  Set is_stmt to 1
  [0x00008b39]  Special opcode 189: advance Address by 13 to 0x6e11 and Line by 2 to 3388
  [0x00008b3a]  Set is_stmt to 0
  [0x00008b3b]  Copy (view 1)
  [0x00008b3c]  Set File Name to entry 5 in the File Name Table
  [0x00008b3e]  Set column to 8
  [0x00008b40]  Advance Line by -2549 to 839

 <2><45b53>: Abbrev Number: 14 (DW_TAG_inlined_subroutine)
    <45b54>   DW_AT_abstract_origin: <0x4c5b0>
    <45b58>   DW_AT_entry_pc    : 0x6e00
    <45b60>   DW_AT_GNU_entry_view: 1
    <45b62>   DW_AT_ranges      : 0x9d60
    <45b66>   DW_AT_call_file   : 5
    <45b67>   DW_AT_call_line   : 839
    <45b69>   DW_AT_call_column : 8
    <45b6a>   DW_AT_sibling     : <0x45be4>

    00009d60 0000000000006e00 0000000000006e11
    00009d60 0000000000001115 000000000000112f
    00009d60 <End of list>

So I read this: when pc==0x6e11, the location is line 3388 (in tree.h) it is a statement.
But the inlined subroutine "contains_struct_check" extends from 0x6e00..0x6e11 and from
0x1115..0x112f.  Therefore 0x6e11 is OUTSIDE the subroutine, and that is what the gdb
thinks there as well.


Thanks
Bernd.
Alexandre Oliva Nov. 21, 2019, 9:41 a.m. UTC | #8
On Nov 19, 2019, Bernd Edlinger <bernd.edlinger@hotmail.de> wrote:

> My question to you is this: can you explain, given the following debug
> info, extracted by readelf from alias.c, why the address 0x6e11 is in
> the inlined subroutine and *not* in the get_alias_set function?

The long version of the explanation is in
https://www.fsfla.org/~lxoliva/papers/sfn/

The long version is that this extension encodes multiple "source program
states" without an intervening instruction.

Consider, for example:

int f(int x) {
  int a = x * x;
  return a;
}

  ...
  z = 3;
  y = f(z);

Further consider that the function is inlined and everything is
optimized to

  mov ry, 9

We can still encode debug information to the effect that we assigned 3
to z, that we then entered the scope of the inlined function f binding x
to 3, that we assigned x * x to a, that we returned it, and that we
assigned the result to variable y held in register ry.

Without location views, you could encode all of this, but all the
debugger would see when you get to the instruction above is that you're
past the end of the scope of variables x and a, because f has already
returned, and that z holds the value 3 and y still holds whatever value
it had before.

With location views, you can encode all of these program states at the
instruction.  Say, you can have a #0 view before the assignment to z, a
#1 after the assignment to z, a #2 after entering the inline function f
and binding x to z, a #3 after computing a, and a #4 after returning
from f, back at the line of the assignment to y.

This is realized by outputting multiple views at the same PC, usually
for different source locations, and by augmenting location lists with
view numbers for each PC in the range, for a finer granularity in
specifying the range in which the expression is active.



>   [0x00008b39]  Special opcode 189: advance Address by 13 to 0x6e11 and Line by 2 to 3388

The above introduces view #0 for PC 0x6e11

>   [0x00008b3a]  Set is_stmt to 0
>   [0x00008b3b]  Copy (view 1)

and here's view #1

>   [0x00008b3c]  Set File Name to entry 5 in the File Name Table
>   [0x00008b3e]  Set column to 8
>   [0x00008b40]  Advance Line by -2549 to 839

and there is presumably a view #2 after this.

>     00009d60 0000000000006e00 0000000000006e11

> So I read this: when pc==0x6e11, the location is line 3388 (in tree.h)
> it is a statement.  But the inlined subroutine "contains_struct_check"
> extends from 0x6e00..0x6e11 and from 0x1115..0x112f.  Therefore 0x6e11
> is OUTSIDE the subroutine, and that is what the gdb thinks there as
> well.

Here's one of the points in which having multiple views per PC extends
DWARF: ending a code range at 0x6e11 doesn't necessarily mean there
isn't any view associated with that function at 0x6e11.  In this case,
there are, but it's still true that the range ends at that address,
because there are other views at that PC that are not part of the
function.

I realize now that I focused mainly on location lists, thinking the
implied scopes could be used to infer the ranges of the enclosing
functions, but perhaps aranges should have been augmented with view
numbers as well, so as to enable debug info consumers to tell more
directly (and precisely) where inlined functions start and end.
diff mbox series

Patch

2019-10-20  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* final.c (force_stmt_source_line): New variable.
	(final_scan_insn_1): Force stmt-type location info
	after a NOTE_INSN_VAR_LOCATION.

testsuite:
2019-10-20  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* g++.dg/guality/pr55541.C: Add dg-skip-if.

Index: gcc/final.c
===================================================================
--- gcc/final.c	(revision 277155)
+++ gcc/final.c	(working copy)
@@ -156,6 +156,9 @@  static int override_discriminator;
 /* Whether to force emission of a line note before the next insn.  */
 static bool force_source_line = false;
 
+/* Force emission of a stmt line note on next line info change.  */
+static bool force_stmt_source_line = false;
+
 extern const int length_unit_log; /* This is defined in insn-attrtab.c.  */
 
 /* Nonzero while outputting an `asm' with operands.
@@ -2412,6 +2415,7 @@  final_scan_insn_1 (rtx_insn *insn, FILE *file, int
 	    {
 	      debug_hooks->var_location (insn);
 	      set_next_view_needed (seen);
+	      force_stmt_source_line = true;
 	    }
 	  break;
 
@@ -2425,6 +2429,7 @@  final_scan_insn_1 (rtx_insn *insn, FILE *file, int
 					   last_filename, last_discriminator,
 					   true);
 	      clear_next_view_needed (seen);
+	      force_stmt_source_line = false;
 	    }
 	  break;
 
@@ -2529,7 +2534,7 @@  final_scan_insn_1 (rtx_insn *insn, FILE *file, int
 
 	if (MAY_HAVE_DEBUG_MARKER_INSNS && cfun->debug_nonbind_markers)
 	  {
-	    is_stmt = false;
+	    is_stmt = force_stmt_source_line;
 	    is_stmt_p = NULL;
 	  }
 	else
@@ -2648,6 +2653,7 @@  final_scan_insn_1 (rtx_insn *insn, FILE *file, int
 					 last_filename, last_discriminator,
 					 is_stmt);
 	    clear_next_view_needed (seen);
+	    force_stmt_source_line = false;
 	  }
 	else
 	  maybe_output_next_view (seen);
Index: gcc/testsuite/g++.dg/guality/pr55541.C
===================================================================
--- gcc/testsuite/g++.dg/guality/pr55541.C	(revision 277155)
+++ gcc/testsuite/g++.dg/guality/pr55541.C	(working copy)
@@ -1,7 +1,7 @@ 
 // PR debug/55541
 // { dg-do run }
 // { dg-options "-g" }
-
+// { dg-skip-if "" { *-*-* } { "*" } { "-O0" } }
 int
 main ()
 {