什么是RUST_BACKTRACE应该告诉我的?

时间:2017-04-11 02:46:22

标签: debugging rust backtrace panic

我的程序很恐慌,所以我按照它的建议运行RUST_BACKTRACE=1,我得到了这个(只是一个小片段)。

1: 0x800c05b5 - std::sys::imp::backtrace::tracing::imp::write::hf33ae72d0baa11ed
            at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:42

2: 0x800c22ed - std::panicking::default_hook::{{closure}}::h59672b733cc6a455
            at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libstd/panicking.rs:351

如果程序发生恐慌,它会停止整个程序,那么我在哪里可以弄清楚它在恐慌的哪一行?

这一行告诉我第42行和第351行有问题吗?

整个回溯都在这张图片上,我觉得将它复制并粘贴在这里会很麻烦。

enter image description here

我从来没有听说过堆栈跟踪或后跟踪。我正在编写警告,但我不知道调试符号是什么。

1 个答案:

答案 0 :(得分:7)

什么是堆栈跟踪?

如果你的程序发生了恐慌,你遇到了一个bug,想要修复它;堆栈跟踪想在这里帮助你。当恐慌发生时,您想知道恐慌的原因(触发恐慌的功能)。但直接触发恐慌的功能通常不足以真正看到正在发生的事情。因此,我们还打印调用前一个函数的函数......依此类推。我们追溯所有导致恐慌的函数调用,直到main(),这是(几乎)被调用的第一个函数。

什么是调试符号?

当编译器生成机器代码时,它几乎只需要为CPU发出指令。问题在于,几乎不可能快速查看一组指令来自哪个Rust函数。因此,编译器可以将其他信息插入到CPU忽略的可执行文件中,但调试工具会使用该信息。

一个重要的部分是文件位置:编译器注释哪条指令来自哪一行的文件。这也意味着我们稍后可以看到定义特定功能的位置。如果我们没有调试符号,我们就不能。

在堆栈跟踪中,您可以看到几个文件位置:

1: 0x800c05b5 - std::sys::imp::backtrace::tracing::imp::write::hf33ae72d0baa11ed
        at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:42

Rust标准库附带调试符号。因此,我们可以看到函数的定义位置(gcc_s.rs第42行)。

如果以调试模式(rustccargo build)进行编译,则默认情况下会激活调试符号。但是,如果您在发布模式(rustc -Ocargo build --release)中进行编译,则默认情况下会禁用调试符号,因为它们会增加可执行文件的大小,并且...通常对最终用户来说并不重要。您可以使用Cargo.toml密钥调整特定profile sectiondebug中的调试符号是否正确。

这些奇怪的功能是什么?!

当您第一次看到堆栈跟踪时,您可能会对您看到的所有奇怪的函数名称感到困惑。别担心,这很正常!您感兴趣的是您的代码的哪一部分触发了恐慌,但堆栈跟踪显示了所涉及的所有功能。在您的示例中,您可以忽略前9个条目:这些条目只是处理恐慌并生成您看到的确切消息的函数。

条目10仍然不是您的代码,但也可能很有趣:恐慌是在index() Vec<T>函数中触发的,当您使用[]运算符时调用该函数。最后,条目11显示了定义的函数。但您可能已经注意到此条目缺少文件位置......上一节介绍了如何解决该问题。

堆栈跟踪怎么办? (TL; DR)

  1. 激活调试符号,如果您还没有(例如只是在调试模式下编译)。
  2. 忽略堆栈跟踪顶部的stdcore 中的所有功能。
  3. 查看您定义的第一个功能,找到文件中的相应位置并修复错误。
  4. 如果您还没有,请将所有camelCase功能和方法名称更改为snake_case以坚持社区范围的指南。