Unable to evaluate functions in Go debugging using delve

1.7k views Asked by At

I'm on an M1 Mac (ARM64 chip) and still unable to invoke functions via the debugger in VSCode which is using the DLV backend.

Debug Console

call test()
Unable to evaluate expression: could not find symbol value for test

test()
Unable to evaluate expression: function calls not allowed without using 'call'

I'm using the latest DLV:

~ ❯ dlv version                                                                                                                                                     
Delve Debugger
Version: 1.20.1
Build: $Id: 96e65b6c615845d42e0e31d903f6475b0e4ece6e

What am I missing?

2

There are 2 answers

0
Bill Burdick On

If your test function is in a *_test.go file, it may not actually exist unless one of your Test* functions calls it -- I found this to be true for my code.

It seems like go may be stripping out functions that aren't called by test code.

0
Zeke Lu On

This is most likely due to dead code elimination. Next is the doc copied from cmd/link/internal/ld/deadcode.go:

The basis of the dead code elimination is a flood fill of symbols, following their relocations, beginning at *flagEntrySymbol.

This flood fill is wrapped in logic for pruning unused methods. All methods are mentioned by relocations on their receiver's *rtype. These relocations are specially defined as R_METHODOFF by the compiler so we can detect and manipulated them here.

There are three ways a method of a reachable type can be invoked:

  1. direct call
  2. through a reachable interface type
  3. reflect.Value.Method (or MethodByName), or reflect.Type.Method (or MethodByName)

The first case is handled by the flood fill, a directly called method is marked as reachable.

The second case is handled by decomposing all reachable interface types into method signatures. Each encountered method is compared against the interface method signatures, if it matches it is marked as reachable. This is extremely conservative, but easy and correct.

The third case is handled by looking to see if any of:

  • reflect.Value.Method or MethodByName is reachable
  • reflect.Type.Method or MethodByName is called (through the REFLECTMETHOD attribute marked by the compiler).

If any of these happen, all bets are off and all exported methods of reachable types are marked reachable.

Any unreached text symbols are removed from ctxt.Textp.

For example, the test func below is dead code and will be eliminated.

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Hello world!")
}

func test() string {
    return "test"
}

We can verify the elimination with go tool nm:

$ go build -gcflags="all=-N -l" -o main main.go
$ go tool nm main | grep -F " main."
  524000 D main..inittask
  49cbc0 T main.main

And call test() failed in this case.

Now let's add var _ = test():

+ var _ = test()
  func test() string {
    return "test"
  }

And try again:

$ go build -gcflags="all=-N -l" -o main main.go
go tool nm main | grep -F " main."
  524720 D main..inittask
  49cc80 T main.init
  49cbc0 T main.main
  49cc40 T main.test

We have the symbol main.test this time. And call test() works:

$ dlv debug main.go                                                                                                                                        36s 00:36:33
Type 'help' for list of commands.
(dlv) c main.main
Breakpoint 1 set at 0x49cbc6 for main.main() ./main.go:7
> main.main() ./main.go:7 (hits goroutine(1):1 total:1) (PC: 0x49cbc6)
     2: 
     3: import (
     4:     "fmt"
     5: )
     6: 
=>   7: func main() {
     8:     fmt.Println("Hello world!")
     9: }
    10: 
    11: var _ = test()
    12: func test() string {
(dlv) n
> main.main() ./main.go:8 (PC: 0x49cbd4)
     3: import (
     4:     "fmt"
     5: )
     6: 
     7: func main() {
=>   8:     fmt.Println("Hello world!")
     9: }
    10: 
    11: var _ = test()
    12: func test() string {
    13:     return "test"
(dlv) call test()
> main.main() ./main.go:8 (PC: 0x49cbd4)
Values returned:
    ~r0: "test"