无法使用 delve 评估 Go 调试中的函数

Unable to evaluate functions in Go debugging using delve

提问人:user38643 提问时间:1/25/2023 最后编辑:Zeke Luuser38643 更新时间:5/13/2023 访问量:966

问:

我在 M1 Mac(ARM64 芯片)上,但仍然无法通过使用 DLV 后端的 VSCode 中的调试器调用函数。

调试控制台

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'

我正在使用最新的 DLV:

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

我错过了什么?

visual-studio-code 死代码 delve dlv

评论

0赞 xarantolus 1/25/2023
您使用哪个命令来编译程序?也许你不小心剥离了一些符号
0赞 user38643 1/25/2023
嗯,我只是点击调试按钮。你对一些设置有什么建议吗?

答:

0赞 Bill Burdick 2/21/2023 #1

如果你的函数在一个文件中,除非你的一个函数调用它,否则它实际上可能并不存在——我发现我的代码也是如此。test*_test.goTest*

似乎可能正在剥离测试代码未调用的函数。go

0赞 Zeke Lu 5/13/2023 #2

这很可能是由于死代码消除造成的。接下来是从 cmd/link/internal/ld/deadcode.go 复制的文档:

消除死代码的基础是符号的泛滥, 搬迁后,从 .*flagEntrySymbol

此泛滥填充包装在用于修剪未使用方法的逻辑中。 所有方法都通过其接收器上的重定位来提及。 这些重定位由编译器专门定义 因此,我们可以在这里检测和操纵它们。*rtypeR_METHODOFF

可访问类型的方法有三种方式:

  1. 直接通话
  2. 通过可访问的接口类型
  3. 反映。Value.Method(或 MethodByName)或 reflect。Type.Method (或 MethodByName)

第一种情况由洪水填充处理,这是一种直接调用的方法 标记为可访问。

第二种情况是通过分解所有可访问的接口来处理的 类型添加到方法签名中。比较遇到的每种方法 针对接口方法签名,如果匹配,则标记 可访问。这是非常保守的,但简单而正确。

第三种情况是通过查看是否有任何一种情况来处理的:

  • reflect.Value.Method或可访问MethodByName
  • reflect.Type.Method或被调用(通过编译器标记的属性)。MethodByNameREFLECTMETHOD

如果发生上述任何一种情况,则所有赌注都将关闭,所有导出的方法都将关闭 的可访问类型标记为可访问。

将从 ctxt 中删除任何未到达的文本符号。文本。

例如,下面的 func 是死代码,将被删除。test

package main

import (
    "fmt"
)

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

func test() string {
    return "test"
}

我们可以通过以下方式验证消除: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

在这种情况下失败了。call test()

现在让我们添加:var _ = test()

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

然后再试一次:

$ 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

这次我们有了这个符号。并工作:main.testcall test()

$ 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"