5个版本
0.1.4 | 2023年5月7日 |
---|---|
0.1.3 | 2022年9月25日 |
0.1.2 | 2021年9月8日 |
0.1.1 | 2021年6月11日 |
0.1.0 | 2021年5月12日 |
#322 在 嵌入式开发
230KB
5K SLoC
mini-backtrace
此crate为no_std
和嵌入式程序提供回溯支持。
这是通过编译具有特定标志的LLVM的libunwind来实现的,以移除所有操作系统依赖,包括libc和任何内存分配。
使用方法
设置
使用此crate有两个前提条件
-
即使将unwinding设置为中止,也要将unwind表构建到二进制文件中。这可以通过使用
-C force-unwind-tables
标志来完成。 -
需要由链接器定义几个
__eh_frame_*
符号,以便libunwind可以定位unwind表。这可以通过包含eh_frame.ld
链接器脚本片段来完成。
这两个都可以通过设置RUSTFLAGS
来实现。
export RUSTFLAGS="-Cforce-unwind-tables -Clink-arg=-Wl,eh_frame.ld"
请注意,默认情况下,这些标志也适用于构建依赖项和proc宏。在调用cargo时显式指定目标可以解决此问题。
# Applies RUSTFLAGS to everything
cargo build
# Doesn't apply RUSTFLAGS to build dependencies and proc macros
cargo build --target x86_64-unknown-linux-gnu
捕获回溯
将mini-backtrace
crate作为依赖项添加到您的程序中
[dependencies]
mini-backtrace = "0.1"
您可以使用返回指令指针地址的Backtrace
类型来捕获回溯,该类型作为ArrayVec
返回一个帧列表。
use mini_backtrace::Backtrace;
// Capture up to 16 frames. This is returned using an ArrayVec that doesn't
// perform any dynamic memory allocation.
let bt = Backtrace::<16>::capture();
println!("Backtrace:");
for frame in bt.frames {
println!(" {:#x}", frame);
}
if bt.frames_omitted {
println!(" ... <frames omitted>");
}
这将输出
Backtrace:
0x5587058c3eb1
0x5587058c3cdb
0x5587058c491e
0x5587058c38b1
0x5587058daf1a
0x5587058c3890
0x5587058c414c
位置无关代码
如果您的代码在与其他链接地址不同的地址上执行,则需要修复帧指针地址以相对于模块基本地址。这可以通过以下函数来完成
fn adjust_for_pic(ip: usize) -> usize {
extern "C" {
// Symbol defined by the linker
static __executable_start: [u8; 0];
}
let base = unsafe { __executable_start.as_ptr() as usize };
ip - base
}
在处理完成后,输出应如下所示
Backtrace:
0x8eb1
0x8cdb
0x999e
0x88b1
0x1ffba
0x8890
0x91cc
请查看examples/backtrace.rs
以获取完整示例。
请注意,adjust_for_pic
仅应针对位置无关的二进制文件调用。静态链接的二进制文件应发出未调整的地址,以便正确解析回溯。
解析回溯
可以通过使用来自LLVM或binutils的addr2line
工具以及使用rustfilt来去混淆Rust符号名称,将Backtrace
生成的地址转换为人类可读的函数名称、文件名和行号。
在终端中简单地运行 addr2line -fipe /path/to/binary | rustfilt
,然后将回溯中的地址粘贴进去。
$ llvm-addr2line -fipe target/x86_64-unknown-linux-gnu/debug/examples/backtrace | rustfilt
0x8ed1
0x8ea6
0x8e96
0x8cdb
0x99be
0x88b1
0x1ffda
0x8890
0x91ec
backtrace::bar at /home/amanieu/code/mini-backtrace/examples/backtrace.rs:15
backtrace::foo at /home/amanieu/code/mini-backtrace/examples/backtrace.rs:10
backtrace::main at /home/amanieu/code/mini-backtrace/examples/backtrace.rs:5
core::ops::function::FnOnce::call_once at /home/amanieu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:227
std::sys_common::backtrace::__rust_begin_short_backtrace at /home/amanieu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys_common/backtrace.rs:128
std::rt::lang_start::{{closure}} at /home/amanieu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:49
std::panicking::try at /rustc/676ee14729462585b969bbc52f32c307403f4126/library/std/src/panicking.rs:344
(inlined by) std::panic::catch_unwind at /rustc/676ee14729462585b969bbc52f32c307403f4126/library/std/src/panic.rs:431
(inlined by) std::rt::lang_start_internal at /rustc/676ee14729462585b969bbc52f32c307403f4126/library/std/src/rt.rs:34
std::rt::lang_start at /home/amanieu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:48
main at ??:0
来自信号/中断处理器的回溯
此crate使用的libunwind回溯器通常无法回溯过信号处理程序或中断处理程序帧。相反,您可以使用Backtrace::capture_from_context
并传入异常发生时的寄存器状态。在信号处理程序中,这可以通过uc_mcontext
字段获得。
目前仅实现于
- AArch64
- RISC-V (RV32 & RV64)
变更日志
许可证
根据您的要求,许可协议可以是以下之一:
- Apache许可证,版本2.0(LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT许可证(LICENSE-MIT 或 http://opensource.org/licenses/MIT)
任选其一。
贡献
除非您明确表示,否则根据Apache-2.0许可证定义的,任何有意提交以包含在作品中的贡献,都应按上述方式双许可,不附加任何额外的条款或条件。
依赖
~0–2.8MB
~44K SLoC