cmd/compile: some local variables are missing from DWARF #18247

Open
alandonovan opened this Issue Dec 8, 2016 · 10 comments

Comments

Projects
None yet
8 participants
@alandonovan
Contributor

alandonovan commented Dec 8, 2016

$ cat a.go
package main

func f(x int) {
        s := "string"
        for i := 0; i < x; i++ {
                println(i, s)
        }
}

func main() {
        f(10)
}
$ go build a.go
$ readelf -w a
...
 <1><1530f>: Abbrev Number: 2 (DW_TAG_subprogram)
    <15310>   DW_AT_name        : main.f        
    <15317>   DW_AT_low_pc      : 0x44cd50      
    <1531f>   DW_AT_high_pc     : 0x44cde4      
    <15327>   DW_AT_external    : 1     
 <2><15328>: Abbrev Number: 4 (DW_TAG_variable)
    <15329>   DW_AT_name        : i     
    <1532b>   DW_AT_location    : 4 byte block: 9c 11 68 22     (DW_OP_call_frame_cfa; DW_OP_consts: -24; DW_OP_plus)
    <15330>   DW_AT_type        : <0x16c15>     
 <2><15338>: Abbrev Number: 5 (DW_TAG_formal_parameter)
    <15339>   DW_AT_name        : x     
    <1533b>   DW_AT_location    : 1 byte block: 9c      (DW_OP_call_frame_cfa)
    <1533d>   DW_AT_type        : <0x16c15>     
 <2><15345>: Abbrev Number: 0
...

For function f, gc emits debug information about the formal parameter x and the local variable i, but not the local variable s. In this instance I imagine the reason is that s is effectively constant, but still it would improve the debug view if such variables were included. And in other programs, many other locals that are truly variable are omitted too.

(Is there a simple explanation for how the compiler currently decides which variables get a DW_TAG_variable record?)

@alandonovan

This comment has been minimized.

Show comment
Hide comment
@alandonovan

alandonovan Dec 8, 2016

Contributor

cc: @hyangah

Contributor

alandonovan commented Dec 8, 2016

cc: @hyangah

@ianlancetaylor ianlancetaylor changed the title from gc: some local variables are missing from DWARF to cmd/compile: some local variables are missing from DWARF Dec 8, 2016

@ianlancetaylor

This comment has been minimized.

Show comment
Hide comment

@ianlancetaylor ianlancetaylor added this to the Go1.9Maybe milestone Dec 8, 2016

@mdempsky

This comment has been minimized.

Show comment
Hide comment
@mdempsky

mdempsky Dec 8, 2016

Member

(Is there a simple explanation for how the compiler currently decides which variables get a DW_TAG_variable record?)

I believe the simple explanation is we emit DWARF records for parameters (including result parameters) and for user-declared local variables that are allocated stack frame space.

Member

mdempsky commented Dec 8, 2016

(Is there a simple explanation for how the compiler currently decides which variables get a DW_TAG_variable record?)

I believe the simple explanation is we emit DWARF records for parameters (including result parameters) and for user-declared local variables that are allocated stack frame space.

@alandonovan

This comment has been minimized.

Show comment
Hide comment
@alandonovan

alandonovan Dec 8, 2016

Contributor

Ah, thanks. So variable that are constant, are allocated to registers, are CSE'd, or escape to the heap will be missing from the debug view.

Contributor

alandonovan commented Dec 8, 2016

Ah, thanks. So variable that are constant, are allocated to registers, are CSE'd, or escape to the heap will be missing from the debug view.

@mdempsky

This comment has been minimized.

Show comment
Hide comment
@mdempsky

mdempsky Dec 8, 2016

Member

Oh, if a variable v escapes to heap, we don't emit DWARF records for v itself, but we will emit them for a synthesized &v pointer variable. There are also cases like if we decompose a composite type like string, you'll end up with separate s.len and s.ptr variables instead of a single s.

But I believe your other cases are correct: registerized and CSE'd variables are not mentioned in the DWARF output.

If it would help, I think we can easily emit records to at least declare that those variables exist in the source (e.g., so debuggers looking up an identifier don't mistakenly find a shadowed global variable instead). We're just not currently setup to track location any more fine-grained than a simple stack frame offset, so we can't emit DW_AT_location for them.

Member

mdempsky commented Dec 8, 2016

Oh, if a variable v escapes to heap, we don't emit DWARF records for v itself, but we will emit them for a synthesized &v pointer variable. There are also cases like if we decompose a composite type like string, you'll end up with separate s.len and s.ptr variables instead of a single s.

But I believe your other cases are correct: registerized and CSE'd variables are not mentioned in the DWARF output.

If it would help, I think we can easily emit records to at least declare that those variables exist in the source (e.g., so debuggers looking up an identifier don't mistakenly find a shadowed global variable instead). We're just not currently setup to track location any more fine-grained than a simple stack frame offset, so we can't emit DW_AT_location for them.

@aclements

This comment has been minimized.

Show comment
Hide comment
@aclements

aclements Dec 21, 2016

Member

But I believe your other cases are correct: registerized and CSE'd variables are not mentioned in the DWARF output.

Furthermore, if a variable is allocated a stack slot but is registerized at a particular PC, the DWARF information will only refer to the stack slot, so you can get a stale (or uninitialized?) value. Fixing that is probably part of fixing debug info for fully registerized variables. But now that the DWARF is being emitted by the compiler instead of the linker, there's at least a hope of doing this.

Member

aclements commented Dec 21, 2016

But I believe your other cases are correct: registerized and CSE'd variables are not mentioned in the DWARF output.

Furthermore, if a variable is allocated a stack slot but is registerized at a particular PC, the DWARF information will only refer to the stack slot, so you can get a stale (or uninitialized?) value. Fixing that is probably part of fixing debug info for fully registerized variables. But now that the DWARF is being emitted by the compiler instead of the linker, there's at least a hope of doing this.

@bcmills

This comment has been minimized.

Show comment
Hide comment
@bcmills

bcmills Jan 31, 2017

Member

I've also noticed that at some points in program execution, running info locals in GDB produces a giant dump of package-level variables. I'm not able to find a consistent repro with the current master branch, though; has that part of the DWARF info been fixed recently?

Member

bcmills commented Jan 31, 2017

I've also noticed that at some points in program execution, running info locals in GDB produces a giant dump of package-level variables. I'm not able to find a consistent repro with the current master branch, though; has that part of the DWARF info been fixed recently?

@mdempsky

This comment has been minimized.

Show comment
Hide comment
@mdempsky

mdempsky Jan 31, 2017

Member

@bcmills I can't think of any significant recent DWARF changes that would have that effect.

Member

mdempsky commented Jan 31, 2017

@bcmills I can't think of any significant recent DWARF changes that would have that effect.

@heschik heschik added the Debugging label Jul 17, 2017

@bradfitz bradfitz modified the milestones: Go1.9Maybe, Go1.10 Jul 20, 2017

@mdempsky mdempsky modified the milestones: Go1.10, Go1.11 Nov 30, 2017

@mdempsky

This comment has been minimized.

Show comment
Hide comment
@mdempsky

mdempsky Nov 30, 2017

Member

Would it be preferable that instead of emitting DWARF entries for the pseudo-variable &v, that we instead emit a DWARF entry for v using DW_OP_deref or whatever?

Member

mdempsky commented Nov 30, 2017

Would it be preferable that instead of emitting DWARF entries for the pseudo-variable &v, that we instead emit a DWARF entry for v using DW_OP_deref or whatever?

@aclements

This comment has been minimized.

Show comment
Hide comment
@aclements

aclements Nov 30, 2017

Member

Would it be preferable that instead of emitting DWARF entries for the pseudo-variable &v, that we instead emit a DWARF entry for v using DW_OP_deref or whatever?

Yes, definitely. :)

Member

aclements commented Nov 30, 2017

Would it be preferable that instead of emitting DWARF entries for the pseudo-variable &v, that we instead emit a DWARF entry for v using DW_OP_deref or whatever?

Yes, definitely. :)

@gopherbot gopherbot modified the milestones: Go1.11, Unplanned May 23, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment