Skip to content

omitting frame pointers breaks retrieving DWARF debug info for parameter values #11906

Closed

Description

@thestinger

Frame pointers should not be required for debugging, because the DWARF debug information can contain everything necessary. However, it seems we do not generate the expected location list for parameters. This causes the debuginfo/function-prologue-stepping-no-split-stack.rs test to break.

Activity

  1. nikomatsakis commented on Jan 29, 2014

    @nikomatsakis
    Contributor

    Updating title to include the keyword "DWARF"

  2. huonw commented on Aug 11, 2014

    @huonw
    Contributor
  3. steveklabnik commented on Sep 3, 2015

    @steveklabnik
    Contributor

    Triage: no change that I'm aware of. This bug is quite old, however, so I might have missed it.

  4. CryZe commented on Oct 16, 2016

    @CryZe
    Contributor

    This makes Rust's generated code look worse than it actually is on http://rust.godbolt.org, because -g is required for output colorization, but it also deactivates frame pointer elimination.

    ASM Output

    Compiler Explorer Issue:
    compiler-explorer/compiler-explorer#79

  5. nagisa commented on Nov 3, 2016

    @nagisa
    Member

    See also #9641.

    We still cannot omit frame pointers. Taking test src/test/debuginfo/function-arg-initialization.rs, the disassembly looks like this:

       0x00005555555599c0 <+0>: push   %rbp
       0x00005555555599c1 <+1>: mov    %rsp,%rbp
       0x00005555555599c4 <+4>: sub    $0x140,%rsp                 # breakpoint with `rbreak non_immediate` with frame pointer elimination enabled
       0x00005555555599cb <+11>:    mov    $0x40,%eax
       0x00005555555599d0 <+16>:    mov    %eax,%ecx
       0x00005555555599d2 <+18>:    lea    -0x80(%rbp),%rdx
       0x00005555555599d6 <+22>:    lea    -0x40(%rbp),%r8
       0x00005555555599da <+26>:    mov    %rdi,-0x110(%rbp)
       0x00005555555599e1 <+33>:    mov    %r8,%rdi
       0x00005555555599e4 <+36>:    mov    -0x110(%rbp),%r8
       0x00005555555599eb <+43>:    mov    %rsi,-0x118(%rbp)
       0x00005555555599f2 <+50>:    mov    %r8,%rsi
       0x00005555555599f5 <+53>:    mov    %rdx,-0x120(%rbp)
       0x00005555555599fc <+60>:    mov    %rcx,%rdx
       0x00005555555599ff <+63>:    mov    %rcx,-0x128(%rbp)
       0x0000555555559a06 <+70>:    callq  0x5555555595c0 <memcpy@plt> # argument a gets initialized
       0x0000555555559a0b <+75>:    mov    -0x118(%rbp),%rcx
       0x0000555555559a12 <+82>:    mov    -0x120(%rbp),%rdx
       0x0000555555559a19 <+89>:    mov    %rdx,%rdi
       0x0000555555559a1c <+92>:    mov    %rcx,%rsi
       0x0000555555559a1f <+95>:    mov    -0x128(%rbp),%rdx
       0x0000555555559a26 <+102>:   callq  0x5555555595c0 <memcpy@plt> # argument b gets initialized
       0x0000555555559a2b <+107>:   mov    $0x40,%eax
       0x0000555555559a30 <+112>:   mov    %eax,%ecx
       0x0000555555559a32 <+114>:   lea    -0x108(%rbp),%rdx
       0x0000555555559a39 <+121>:   lea    -0x80(%rbp),%rsi
       0x0000555555559a3d <+125>:   lea    -0xc8(%rbp),%rdi
       0x0000555555559a44 <+132>:   lea    -0x40(%rbp),%r8
       0x0000555555559a48 <+136>:   mov    %rsi,-0x130(%rbp)           # breakpoint with `rbreak non_immediate` with frame pointer elimination disabled
       0x0000555555559a4f <+143>:   mov    %r8,%rsi
       0x0000555555559a52 <+146>:   mov    %rdx,-0x138(%rbp)
       0x0000555555559a59 <+153>:   mov    %rcx,%rdx
       0x0000555555559a5c <+156>:   mov    %rcx,-0x140(%rbp)
       0x0000555555559a63 <+163>:   callq  0x5555555595c0 <memcpy@plt>
       0x0000555555559a68 <+168>:   mov    -0x130(%rbp),%rcx
       0x0000555555559a6f <+175>:   mov    -0x138(%rbp),%rdx
       0x0000555555559a76 <+182>:   mov    %rdx,%rdi
       0x0000555555559a79 <+185>:   mov    %rcx,%rsi
       0x0000555555559a7c <+188>:   mov    -0x140(%rbp),%rdx
       0x0000555555559a83 <+195>:   callq  0x5555555595c0 <memcpy@plt>
       0x0000555555559a88 <+200>:   callq  0x55555555a020 <function_arg_initialization::zzz>
       0x0000555555559a8d <+205>:   add    $0x140,%rsp
       0x0000555555559a94 <+212>:   pop    %rbp
       0x0000555555559a95 <+213>:   retq   
    
  6. mattgodbolt commented on Dec 23, 2016

    @mattgodbolt

    Is there another way to get the line-level information in the asm output, without passing -debug? Compiler Explorer runs rustc -g --emit asm to get the assembly, and then parses the .loc directive to marry input code with output code.

    Sadly the -g changes the code generation, which makes the output less useful.

    The equivalent flags for C++ compilation don't have the same effect.

  7. michaelwoerister commented on Dec 23, 2016

    @michaelwoerister
    Member

    -g is equivalent to -C debuginfo=2, meaning "full debuginfo". But there is also -C debuginfo=1 which means "just line-tables" and should have less of an impact on code generation.

  8. mattgodbolt commented on Dec 23, 2016

    @mattgodbolt

    That doesn't appear to be the case.

    (some lines removed from the below for clarity)

    /t/r $ cat test.rs
    pub fn square(num: i32) -> i32 {
      num * num
    }
    /t/r $ rustc --version
    rustc 1.14.0 (e8a012324 2016-12-16)
    /t/r $ rustc -O -C debuginfo=0 --emit asm test.rs --crate-type rlib
    /t/r $ cat test.s
    ...
    	.cfi_startproc
    	imull	%edi, %edi
    	movl	%edi, %eax
    	retq
    .Lfunc_end0:
    	.size	_ZN4test6square17h3872c4fac15ac3c4E, .Lfunc_end0-_ZN4test6square17h3872c4fac15ac3c4E
    	.cfi_endproc
    ...
    
    /t/r $ rustc -O -C debuginfo=1 --emit asm test.rs --crate-type rlib
    ...
    	.cfi_startproc
    	pushq	%rbp
    .Ltmp0:
    	.cfi_def_cfa_offset 16
    .Ltmp1:
    	.cfi_offset %rbp, -16
    	movq	%rsp, %rbp
    .Ltmp2:
    	.cfi_def_cfa_register %rbp
    .Ltmp3:
    	.loc	1 2 0 prologue_end
    	imull	%edi, %edi
    	.loc	1 3 0
    	movl	%edi, %eax
    	popq	%rbp
    	retq
    .Ltmp4:
    .Lfunc_end0:
    	.size	_ZN4test6square17h3872c4fac15ac3c4E, .Lfunc_end0-_ZN4test6square17h3872c4fac15ac3c4E
    	.cfi_endproc
    ...
    

    Note how adding the debuginfo=1 has caused code generation differences.

  9. mattgodbolt commented on Dec 23, 2016

    @mattgodbolt

    Apologies; you did say "less of an impact" - and maybe it does. I was ideally looking for "no code impact" - but I'll change to use this at least! Thanks for the reply; any further suggestions welcomed!

  10. retep998 commented on Apr 18, 2017

    @retep998
    Contributor

    I really hope we can get rid of these debuginfo only frame pointers. Some platforms cough 64bit windows cough have function tables such that unwinding and debugging can be done just fine without frame pointers so this would definitely help to squeeze out a bit more size and speed.

  11. dotdash commented on Dec 19, 2017

    @dotdash
    Contributor

    This seems largely solved by #44573 and #45380 , because by now we're actually using the incoming arguments and don't shadow them with locals by the same name (the test likely broke because it accessed the local instead of the actual argument). So the unoptimized assembly for the function above now is (I already compiled with debug info + frame pointer omission here):

    Dump of assembler code for function function_arg_initialization::non_immediate_args:
    => 0x0000555555559ff0 <+0>:	sub    $0x18,%rsp
       0x0000555555559ff4 <+4>:	mov    %rdi,0x10(%rsp)
       0x0000555555559ff9 <+9>:	mov    %rsi,0x8(%rsp)
       0x0000555555559ffe <+14>:	callq  0x55555555a4e0 <function_arg_initialization::zzz>
       0x000055555555a003 <+19>:	add    $0x18,%rsp
       0x000055555555a007 <+23>:	retq   
    

    And the result is as expected:

    (gdb) info args
    a = function_arg_initialization::BigStruct {a: 3, b: 4, c: 5, d: 6, e: 7, f: 8, g: 9, h: 10}
    b = function_arg_initialization::BigStruct {a: 11, b: 12, c: 13, d: 14, e: 15, f: 16, g: 17, h: 18}
    (gdb) info locals
    No locals.
    (gdb) print a
    $1 = function_arg_initialization::BigStruct {a: 3, b: 4, c: 5, d: 6, e: 7, f: 8, g: 9, h: 10}
    (gdb) print b
    $2 = function_arg_initialization::BigStruct {a: 11, b: 12, c: 13, d: 14, e: 15, f: 16, g: 17, h: 18}
    

    The only thing that still breaks right now seems to be code that uses pattern matching for function arguments. I'll try to look into that.

  12. michaelwoerister commented on Dec 19, 2017

    @michaelwoerister
    Member

    Awesome, thank you @dotdash!

  13. dotdash commented on Dec 20, 2017

    @dotdash
    Contributor
    <doener> eddyb: so you're saying that when I set a breakpoint 
             on a function foo((a, b): (i64, 64)), it would be fine to not 
             have anything in scope at the breakpoint?
    <eddyb> doener: yeah sure
    

    I disagree with this, but if others agree, we're done here once a scoping bug that @eddyb identified has been resolved.

  14. dotdash commented on Dec 20, 2017

    @dotdash
    Contributor

    "we're done" meaning that we should be fine to omit frame pointers in debug builds.

  15. 20 remaining items

  16. added a commit that references this issue on May 1, 2018
    5b800c2
  17. added a commit that references this issue on May 1, 2018
    0eb68b7
  18. added a commit that references this issue on Jul 25, 2022
    187bd7d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-debuginfoArea: Debugging information in compiled programs (DWARF, PDB, etc.)C-enhancementCategory: An issue proposing an enhancement or a PR with one.I-slowIssue: Problems and improvements with respect to performance of generated code.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions