2个稳定版本

1.74.1 2023年12月11日
1.74.0 2023年12月8日

#217 in 调试


firedbg-stream-indexer 中使用

MIT/Apache

435KB
11K SLoC

FireDBG调试引擎(用于Rust)

基于 lldb.

此库免于semver版本控制。版本号旨在跟踪rustc的版本。

调试器配置

可以通过环境变量FIREDBG_RUST_CONFIG来设置配置。例如:FIREDBG_RUST_CONFIG=MAX_ARRAY_SIZE=100;DONT_TRACE_ALLOCATION

类型 描述
MAX_ARRAY_SIZE usize 数组、字符串和其他容器中的最大项目数
RECURSIVE_DEREF_LIMIT usize 递归限制;即限制二叉树的深度
KEEP_HASH_ORDER bool 如果设置,不要按哈希键排序哈希表
DONT_TRACE_ALLOCATION bool 如果设置,不要跟踪堆分配

指令集

目前支持x64(即amd64)和arm64(即aarch64)。为每个平台提供了大量的汇编解析和寄存器操作。代码库中对指针是8字节有一些假设。支持新的架构需要相当大的努力,但我们愿意进行商业合作。

操作系统

目前没有特定于操作系统的代码。在Linux和macOS上使用lldb。但在macOS上,我们将连接到主机的lldb-server。如果我们决定原生支持Windows,我们需要创建一个Windows后端。

必须为与目标二进制文件相同的平台编译debugger二进制文件。此外,我们假设它们都使用相同的rustc(不一定是完全相同的,但应与彼此兼容)。

标准库类型

我们打算内置所有标准库类型的处理。对于 HashMap,使用的是 frozen-hashbrown。未来,我们希望开放脚本接口(可能通过 rhai)来处理供应商库类型(例如 DateTimeDecimal),类似于 Natvis 的方式。

二进制值格式

序列化 Rust 值的格式可以通过阅读 SourceReader::read_values() 来最好地理解,它在 reader.rs 中。这应该是相当直接的,唯一棘手的部分是 ReaderContext,它是用于解析内存引用的。

返回值捕获

这非常依赖于架构。我们试图在函数返回时捕获返回值,即在 ret 指令处。并非所有内容都在栈上,有时返回值将通过寄存器传递。

根据 Rust 的 ABI 规范,这意味着如果返回值是

  1. 一个或两个原语,每个都不大于 64 位。这包括 (i64, i64)struct { a: i64, b: i64 }

  2. 一个 i128 / u128;将被拆分为 rax / rdx

  3. 一个或两个 f32 / f64;将放在 xmm0 / xmm1

  4. Option<T>Result<T, E>;其中 T & E 不大于 64 位

    枚举区分符在 rax 中,其中

    类型 T E
    Option Some = 1 None = 0
    Result Ok = 0 Err = 1

    并且 T / E 将在 rdx 中。

不幸的是,这比 上面的摘要 要复杂得多。目前实现非常混乱,完全基于启发式方法。如果我们有机会正确地做这件事,也许我们可以生成 Rust 代码并检查汇编(系统性地)。假设我们的返回类型是 (T, F)

fn probe() -> (T, F) { todo!() }
fn extractor() {
    let res = probe();
    std::hint::black_box(&res);
}

如果我们反汇编二进制文件,我们应该看到

extractor:
call probe
mov ..
call black_box

所以在 probeblack_box 之间,会有一些内存操作,最终将整个结构体写入栈中,然后地址将存储在 rax / x0 中。

应该有更好的方法来做这件事,如果你有想法,请开一个讨论线程!

堆分配

目前仍处于工作状态。我们现在可以跟踪所有 BoxRcArc 分配,因此我们可以提取 Box<dyn T> 的内容。待办事项是跟踪释放并输出信息到专用事件流。

依赖关系

~11–25MB
~337K SLoC