RUST_BACKTRACE 应该告诉我什么?
What is RUST_BACKTRACE supposed to tell me?
我的程序出现了 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 行有问题?
整个backtrace都在这张图上,我觉得复制粘贴到这里会很乱
我从未听说过堆栈跟踪或回溯。我正在编译时出现警告,但我不知道调试符号是什么。
什么是堆栈跟踪?
如果您的程序崩溃,说明您遇到了错误并希望修复它;堆栈跟踪想在这里帮助你。当恐慌发生时,您想知道恐慌的原因(触发恐慌的函数)。但是直接触发 panic 的函数通常不足以真正看到发生了什么。因此我们还打印了调用前一个函数的函数……等等。我们追溯所有导致恐慌的函数调用,直到 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 行)。
如果您在调试模式下编译(rustc
或 cargo build
),默认情况下会激活调试符号。但是,如果您在发布模式下编译(rustc -O
或 cargo build --release
),则默认情况下禁用调试符号,因为它们会增加可执行文件的大小并且...通常对最终用户而言并不重要。您可以使用 debug
键调整特定 profile
section 中的 Cargo.toml
中是否需要调试符号。
这些奇怪的功能是什么?!
当您第一次查看堆栈跟踪时,您可能会对看到的所有奇怪的函数名称感到困惑。别担心,这很正常!您对 您的 代码的哪一部分触发了恐慌感兴趣,但堆栈跟踪显示了所有以某种方式涉及的函数。在您的示例中,您可以忽略前 9 个条目:这些只是处理恐慌并生成您所看到的确切消息的函数。
条目 10 仍然不是您的代码,但可能也很有趣:恐慌是在 Vec<T>
的 index()
函数中触发的,当您使用 []
操作员。最后,条目 11 显示了定义的函数 you。但是您可能已经注意到此条目缺少文件位置...上一节介绍了如何解决该问题。
堆栈跟踪有什么用? (tl;博士)
- 如果您还没有激活调试符号(例如,只需在调试模式下编译)。
- 忽略堆栈跟踪顶部
std
和 core
中的所有函数。
- 查看你定义的第一个函数,在你的文件中找到相应的位置并修复错误。
- 如果您还没有,请将所有
camelCase
函数和方法名称更改为 snake_case
以遵循社区范围的风格指南。
我的程序出现了 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 行有问题?
整个backtrace都在这张图上,我觉得复制粘贴到这里会很乱
我从未听说过堆栈跟踪或回溯。我正在编译时出现警告,但我不知道调试符号是什么。
什么是堆栈跟踪?
如果您的程序崩溃,说明您遇到了错误并希望修复它;堆栈跟踪想在这里帮助你。当恐慌发生时,您想知道恐慌的原因(触发恐慌的函数)。但是直接触发 panic 的函数通常不足以真正看到发生了什么。因此我们还打印了调用前一个函数的函数……等等。我们追溯所有导致恐慌的函数调用,直到 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 行)。
如果您在调试模式下编译(rustc
或 cargo build
),默认情况下会激活调试符号。但是,如果您在发布模式下编译(rustc -O
或 cargo build --release
),则默认情况下禁用调试符号,因为它们会增加可执行文件的大小并且...通常对最终用户而言并不重要。您可以使用 debug
键调整特定 profile
section 中的 Cargo.toml
中是否需要调试符号。
这些奇怪的功能是什么?!
当您第一次查看堆栈跟踪时,您可能会对看到的所有奇怪的函数名称感到困惑。别担心,这很正常!您对 您的 代码的哪一部分触发了恐慌感兴趣,但堆栈跟踪显示了所有以某种方式涉及的函数。在您的示例中,您可以忽略前 9 个条目:这些只是处理恐慌并生成您所看到的确切消息的函数。
条目 10 仍然不是您的代码,但可能也很有趣:恐慌是在 Vec<T>
的 index()
函数中触发的,当您使用 []
操作员。最后,条目 11 显示了定义的函数 you。但是您可能已经注意到此条目缺少文件位置...上一节介绍了如何解决该问题。
堆栈跟踪有什么用? (tl;博士)
- 如果您还没有激活调试符号(例如,只需在调试模式下编译)。
- 忽略堆栈跟踪顶部
std
和core
中的所有函数。 - 查看你定义的第一个函数,在你的文件中找到相应的位置并修复错误。
- 如果您还没有,请将所有
camelCase
函数和方法名称更改为snake_case
以遵循社区范围的风格指南。