User account creation filtered due to spam.

Bug 51358 - incorrect/missing location for function arg, -O0, without VTA
Summary: incorrect/missing location for function arg, -O0, without VTA
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: debug (show other bugs)
Version: 4.7.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-debug
Depends on:
Blocks:
 
Reported: 2011-11-30 16:33 UTC by Mark Wielaard
Modified: 2017-03-24 20:28 UTC (History)
8 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2012-08-06 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Mark Wielaard 2011-11-30 16:33:22 UTC
This is related to the following systemtap bug report:
http://sourceware.org/bugzilla/show_bug.cgi?id=13420

This is using g++ (GCC) 4.7.0 20111130 (experimental), but can be reproduced with other versions (g++ (GCC) 4.5.1 20100924 (Red Hat 4.5.1-4) in particular).

Compiling the following with g++ -gdwarf-4 -o length length.cxx

#include <string>

size_t
length(const std::string& str)
{
    int res = str.length();
    return res;
}

int
main()
{
    std::string hello = "Hello World!";
    return 12 != length(hello);
}


Produces:

00000000 00000014 00000000 CIE
  Version:               1
  Augmentation:          "zR"
  Code alignment factor: 1
  Data alignment factor: -8
  Return address column: 16
  Augmentation data:     1b

  DW_CFA_def_cfa: r7 (rsp) ofs 8
  DW_CFA_offset: r16 (rip) at cfa-8
  DW_CFA_nop
  DW_CFA_nop

00000018 0000001c 0000001c FDE cie=00000000 pc=0040088c..004008ae
  DW_CFA_advance_loc: 1 to 0040088d
  DW_CFA_def_cfa_offset: 16
  DW_CFA_offset: r6 (rbp) at cfa-16
  DW_CFA_advance_loc: 3 to 00400890
  DW_CFA_def_cfa_register: r6 (rbp)
  DW_CFA_advance_loc: 29 to 004008ad
  DW_CFA_def_cfa: r7 (rsp) ofs 8
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop

and

 <1><a86>: Abbrev Number: 95 (DW_TAG_subprogram)
    <a87>   DW_AT_external    : 1       
    <a87>   DW_AT_name        : (indirect string, offset: 0x1aec): length       
    <a8b>   DW_AT_decl_file   : 1       
    <a8c>   DW_AT_decl_line   : 4       
    <a8d>   DW_AT_linkage_name: (indirect string, offset: 0x293): _Z6lengthRKSs 
    <a91>   DW_AT_type        : <0x2e2> 
    <a95>   DW_AT_low_pc      : 0x40088c        
    <a9d>   DW_AT_high_pc     : 0x4008ae        
    <aa5>   DW_AT_frame_base  : 1 byte block: 9c        (DW_OP_call_frame_cfa)
    <aa7>   Unknown AT value: 2116: 1   
    <aa7>   DW_AT_sibling     : <0xada> 
 <2><aab>: Abbrev Number: 96 (DW_TAG_formal_parameter)
    <aac>   DW_AT_name        : str     
    <ab0>   DW_AT_decl_file   : 1       
    <ab1>   DW_AT_decl_line   : 4       
    <ab2>   DW_AT_type        : <0xada> 
    <ab6>   DW_AT_location    : 2 byte block: 91 58     (DW_OP_fbreg: -40)

Which seems to suggest that the formal_parameter "str" can always be accessed through fbreg -40. But this isn't true as you can see by looking at the generated code:

Dump of assembler code for function length(std::string const&):
   0x000000000040088c <+0>:	push   %rbp
   0x000000000040088d <+1>:	mov    %rsp,%rbp
   0x0000000000400890 <+4>:	sub    $0x20,%rsp
   0x0000000000400894 <+8>:	mov    %rdi,-0x18(%rbp)
   0x0000000000400898 <+12>:	mov    -0x18(%rbp),%rax
   0x000000000040089c <+16>:	mov    %rax,%rdi
   0x000000000040089f <+19>:	callq  0x4006c0 <_ZNKSs6lengthEv@plt>
   0x00000000004008a4 <+24>:	mov    %eax,-0x4(%rbp)
   0x00000000004008a7 <+27>:	mov    -0x4(%rbp),%eax
   0x00000000004008aa <+30>:	cltq   
   0x00000000004008ac <+32>:	leaveq 
   0x00000000004008ad <+33>:	retq   
End of assembler dump.

The argument was actually in %rdi, which isn't pushed on the stack till 400894, so when we probe at the start of the function (40088c) we will see garbage when trying to extract the str parameter.

Is there a way a dwarf consumer could have known that?

GCC also doesn't seem to produce line table prologue markers, so it also doesn't help trying to search for the end of prologue.
Comment 1 Jan Kratochvil 2011-11-30 20:46:54 UTC
(In reply to comment #0)
> Compiling the following with g++ -gdwarf-4 -o length length.cxx
[...]
>     <aa5>   DW_AT_frame_base  : 1 byte block: 9c        (DW_OP_call_frame_cfa)
[...]
>     <ab6>   DW_AT_location    : 2 byte block: 91 58     (DW_OP_fbreg: -40)
> 
> Which seems to suggest that the formal_parameter "str" can always be accessed
> through fbreg -40. But this isn't true as you can see by looking at the
> generated code:
> 
> Dump of assembler code for function length(std::string const&):
>    0x000000000040088c <+0>:    push   %rbp
>    0x000000000040088d <+1>:    mov    %rsp,%rbp
>    0x0000000000400890 <+4>:    sub    $0x20,%rsp
>    0x0000000000400894 <+8>:    mov    %rdi,-0x18(%rbp)
[...]
> The argument was actually in %rdi, which isn't pushed on the stack till
> 400894, so when we probe at the start of the function (40088c) we will see
> garbage when trying to extract the str parameter.
> 
> Is there a way a dwarf consumer could have known that?

This is AFAIK correct.  With -O0 there is no location tracking and the consumer must skip the prologue first before considering DW_AT_location content.

See GDB symtab->locations_valid detection so that GDB at least knows the cases when it does not have to skip the prologue.

locations_valid detection should be further extended by detecting -O>=1 in DW_AT_producer for some rare cases where the current GDB detection would not work.  But -grecord-gcc-switches is not default in FSF GCC so the DW_AT_producer may not be so useful for FSF GCC builds.


> GCC also doesn't seem to produce line table prologue markers, so it also
> doesn't help trying to search for the end of prologue.

(a) GDB reliably detects the prologue end by skipping the first source line.
    GCC even supports this by producing 0-line advance in some cases.
(b) I cannot find the Bug now but my request for DW_LNS_set_prologue_end has
    been declined as the current source-line based detection works correctly
    and DW_LNS_set_prologue_end would just needlessly increase the debug info
    size.
Comment 2 Jakub Jelinek 2011-12-01 11:07:44 UTC
See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42801#c2
Comment 3 Richard Biener 2012-08-06 18:35:35 UTC
I also recently ran into this ... why can't GCC simply provide no location
information for the prologue?  Thus, properly restrict the PC range the
fb-based locations are valid?  At the moment GCC simply lies.

Confirmed.
Comment 4 Jan Kratochvil 2012-08-12 18:37:26 UTC
It would not be helpful, systemtap would then see no data (just not wrong data).

Also at that time location list will need to be used and currently GDB when it sees any location list it thinks it no longer needs to skip the prologue.
OTOH GDB could look at -grecord-gcc-switches first which it currently does not so I should just finally implement -grecord-gcc-switches in GDB in such case.
Comment 5 Frank Ch. Eigler 2012-08-12 20:21:24 UTC
(In reply to comment #4)
> It would not be helpful, systemtap would then see no data [...]

Not quite; systemtap can search the PC ranges/line tables for a nearby address where a corrected location list would cover.
Comment 6 Mark Wielaard 2012-08-12 20:30:36 UTC
(In reply to comment #5)
> (In reply to comment #4)
> > It would not be helpful, systemtap would then see no data [...]
> 
> Not quite; systemtap can search the PC ranges/line tables for a nearby address
> where a corrected location list would cover.

And at least systemtap could give an error/warning to the user the data isn't available instead of providing bogus values...
Comment 7 Richard Biener 2012-08-13 08:55:05 UTC
(In reply to comment #4)
> It would not be helpful, systemtap would then see no data (just not wrong
> data).
> 
> Also at that time location list will need to be used and currently GDB when it
> sees any location list it thinks it no longer needs to skip the prologue.
> OTOH GDB could look at -grecord-gcc-switches first which it currently does not
> so I should just finally implement -grecord-gcc-switches in GDB in such case.

I think seeing wrong data, thus, wrong-debug is never superior over "no debug
info / no data".
Comment 8 Andrew Pinski 2012-11-18 04:13:17 UTC
This has now become an user visible regression as dwarf4 is now default.
Comment 9 Jakub Jelinek 2012-11-19 09:09:59 UTC
I don't see the link between the bugreport and dwarf4, why do you think this is a regression?
Comment 10 Richard Biener 2012-12-06 16:21:33 UTC
Don't see that either.
Comment 11 Frank Ch. Eigler 2013-12-26 00:21:35 UTC
This problem continues to hit in gcc 4.8.2.
Comment 12 Mark Wielaard 2016-04-26 20:57:43 UTC
Having to parse line information to skip the prologue us somewhat inconvenient. Especially since GCC doesn't actually emit DW_LNS_set_prologue_end, you have to use some heuristic to determine whether you have reach the end of the prologue.

As an alternative it might be nice if GCC could emit a DW_AT_GNU_entry_breakpoint that indicates where the "valid scope" of the function starts (it could either be an address or a constant to be added to low_pc).
Comment 13 Ben Woodard 2017-03-24 20:28:30 UTC
This adds some additional complexity to a feature request in https://sourceware.org/bugzilla/show_bug.cgi?id=19949. It would be helpful it were resolved.