golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
124.1k stars 17.68k forks source link

cmd/compile: bad DWARF location for variable #58813

Open aarzilli opened 1 year ago

aarzilli commented 1 year ago
$ go version
go version go1.20.1 linux/amd64

Given the following code:

package main

import "fmt"

func cul(row int64) bool {
    id := int((row >> 32) & 0x3fffffff)

    return id != 0
}

func main() {
    fmt.Println(cul(0))
}

Compiled with `-gcflags='all=-N -l', main.cul function compiles into:

  test.go:5     0x49c8c0        4883ec18        SUBQ $0x18, SP      
  test.go:5     0x49c8c4        48896c2410      MOVQ BP, 0x10(SP)   
  test.go:5     0x49c8c9        488d6c2410      LEAQ 0x10(SP), BP   
  test.go:5     0x49c8ce        4889442420      MOVQ AX, 0x20(SP)   
  test.go:5     0x49c8d3        c644240700      MOVB $0x0, 0x7(SP)  
  test.go:6     0x49c8d8        488b4c2420      MOVQ 0x20(SP), CX   
  test.go:6     0x49c8dd        48c1f920        SARQ $0x20, CX      
  test.go:6     0x49c8e1        81e1ffffff3f        ANDL $0x3fffffff, CX    
  test.go:8     0x49c8e7        4885c9          TESTQ CX, CX        
  test.go:8     0x49c8ea        0f95c0          SETNE AL        
  test.go:6     0x49c8ed        48894c2408      MOVQ CX, 0x8(SP)    
  test.go:8     0x49c8f2        88442407        MOVB AL, 0x7(SP)    
  test.go:8     0x49c8f6        488b6c2410      MOVQ 0x10(SP), BP   
  test.go:8     0x49c8fb        4883c418        ADDQ $0x18, SP      
  test.go:8     0x49c8ff        90          NOPL            
  test.go:8     0x49c900        c3          RET         

and the variable id has DW_OP_fbreg -0x18 has its location, however at instruction 0x49c8ea, which is the instruction picked for a breakpoint on line :8, the variable is stored on register rcx, not in its stack location (where it gets moved only later at instruction 0x49c8ed). Originally reported as https://github.com/go-delve/delve/issues/3290.

cc @dr2chase.

dmitshur commented 1 year ago

CC @golang/compiler.

mknyszek commented 1 year ago

@dr2chase assigned to you in triage since we want your input but feel free to unassign.

dr2chase commented 1 year ago

I think this "fixed itself" which is not happy-making. A more permanent fix would be, when assigning line numbers in -N compilation, to take note of assignments that should have happened earlier and be sure that they are actually completed to memory. I'd like to leave this open but bump it to the next release, since that fix is actually a little complicated.

ZekeLu commented 1 year ago

In case it helps, here is another case extracted from this stackoverflow question :

 1  package main
 2  
 3  func main() {
 4      a := f(1)
 5      b := 1
 6  
 7      c := a < b
 8      _ = c
 9  }
10  
11  func f(i int) int {
12      if i > 0 {
13          return i
14      }
15      return -i
16  }

And here is the output of a delve debug session:

(dlv) l
> main.main() ./main.go:7 (hits goroutine(1):1 total:1) (PC: 0x4608de)
     2: 
     3: func main() {
     4:     a := f(1)
     5:     b := 1
     6: 
=>   7:     c := a < b
     8:     _ = c
     9: }
    10: 
    11: func f(i int) int {
    12:     if i > 0 {
(dlv) disass
TEXT main.main(SB) /home/zeke/src/temp/76380802/main.go
    main.go:3   0x4608c0    493b6610        cmp rsp, qword ptr [r14+0x10]
    main.go:3   0x4608c4    7639            jbe 0x4608ff
    main.go:3   0x4608c6    4883ec28        sub rsp, 0x28
    main.go:3   0x4608ca    48896c2420      mov qword ptr [rsp+0x20], rbp
    main.go:3   0x4608cf    488d6c2420      lea rbp, ptr [rsp+0x20]
    main.go:4   0x4608d4    b801000000      mov eax, 0x1
    main.go:4   0x4608d9    e842000000      call $main.f
=>  main.go:7   0x4608de*   4883f801        cmp rax, 0x1
    main.go:4   0x4608e2    4889442418      mov qword ptr [rsp+0x18], rax
    main.go:5   0x4608e7    48c744241001000000  mov qword ptr [rsp+0x10], 0x1
    main.go:7   0x4608f0    0f9c44240f      setl byte ptr [rsp+0xf]
    main.go:9   0x4608f5    488b6c2420      mov rbp, qword ptr [rsp+0x20]
    main.go:9   0x4608fa    4883c428        add rsp, 0x28
    main.go:9   0x4608fe    c3          ret
    main.go:3   0x4608ff    90          nop
    main.go:3   0x460900    e83bccffff      call $runtime.morestack_noctxt
    main.go:3   0x460905    ebb9            jmp $main.main
(dlv) locals
a = 824633745824
b = 824633843808
aarzilli commented 1 year ago

Another example, this one on arm64:

package main

import "fmt"

func main() {
        SimpleMethodWithArgument(0)
}

//go:noinline
func SimpleMethodWithArgument(i int) {
        a := 5
        y := 10
        x := a + y + i // Breakpoint here
        fmt.Printf("a: %v, y: %v\n", a, y)
        _ = x
        return
}

SimpleMethodWithArguments compiles to:

test.go:10 S 0x4977c0 4c8d6424e8 LEAQ -0x18(SP), R12
test.go:10   0x4977c5 4d3b6610 CMPQ 0x10(R14), R12
test.go:10   0x4977c9 0f8615010000 JBE 0x4978e4
test.go:10   0x4977cf 55 PUSHL BP
test.go:10   0x4977d0 4889e5 MOVQ SP, BP
test.go:10 SP 0x4977d3 4881ec90000000 SUBQ $0x90, SP
test.go:10   0x4977da 48898424a0000000 MOVQ AX, 0xa0(SP)
test.go:11 S 0x4977e2 48c744243805000000 MOVQ $0x5, 0x38(SP)
test.go:12 S 0x4977eb 48c74424280a000000 MOVQ $0xa, 0x28(SP)
test.go:13 S 0x4977f4 488d480f LEAQ 0xf(AX), CX
test.go:13   0x4977f8 48894c2430 MOVQ CX, 0x30(SP)
test.go:14 S 0x4977fd 440f117c2470 MOVUPS X15, 0x70(SP)

at 0x4977d3, the first statement, the stack variables are not yet initialized.