堆栈跟踪跳过函数

Stack trace skipping functions

我正在查看 F# 中生成的堆栈跟踪,它们正在跳过函数。一个测试用例:

let foo() =
    failwithf "foo"

[<EntryPoint>]
let main argv =
    foo()
    0

使用调试信息编译,运行:

(torch) C:\t>fsc -g test.fs
Microsoft (R) F# Compiler version 10.8.0.0 for F# 4.7
Copyright (c) Microsoft Corporation. All Rights Reserved.

(torch) C:\t>test

Unhandled Exception: System.Exception: foo
   at Microsoft.FSharp.Core.PrintfModule.PrintFormatToStringThenFail@1637.Invoke(String message)
   at Test.main(String[] argv) in C:\t\test.fs:line 7

它说异常是从 main 生成的,但没有提到 foo 实际生成的位置。

如何获取完整的堆栈跟踪,包括实际生成异常的函数?

您一直是优化的受害者,这使得在任何工具链中进行调试变得困难。

请注意 fsc,优化是 turned on by default。 他们是:

内联

foo() 甚至没有被调用——它是一个简单的静态方法,可以很容易地内联。 生成的 IL 等效于:

let main argv =
    PrintfModule.PrintFormatToStringThenFail(new PrintfFormat<_>("foo"));
    0

我们可以用 --optimize-

关闭它
fsc -g --optimize- Program.fs

但这还不够。因为...

尾调用优化

尾调用优化可让您避免为函数分配新的堆栈帧。 foo 是一个简化 main 的简单函数。由于没有堆栈框架,您不会在堆栈跟踪中看到它。

我们可以用 --tailcalls- 关闭它。

要获得完整的调试体验,请使用 VS 为 DEBUG 所做的基本操作:

fsc --debug:full --define:DEBUG --define:TRACE --optimize- --tailcalls- Program.fs

现在,如果我们 运行 我们的目标,我们将按预期获得堆栈跟踪:

Unhandled Exception: System.Exception: foo
   at Microsoft.FSharp.Core.PrintfModule.PrintFormatToStringThenFail@1639.Invoke(String message)
   at Program.foo[a]() in Program.fs:line 4
   at Program.main(String[] argv) in Program.fs:line 13