Crate firedbg_rust_debugger

Source
Expand description

§FireDBG Debugger Engine for Rust

Based on lldb.

This library is semver exempt. The version number is intended to track rustc’s version.

§Debugger Config

Configuration can be set via the FIREDBG_RUST_CONFIG environment variable. e.g. FIREDBG_RUST_CONFIG=MAX_ARRAY_SIZE=100;DONT_TRACE_ALLOCATION

KeyTypeDescription
MAX_ARRAY_SIZEusizeMaximum number of items in array, string and other containers
RECURSIVE_DEREF_LIMITusizeRecursive limit; i.e. this limits the depth of a binary tree
KEEP_HASH_ORDERboolIf set, don’t sort hash maps by hash key
DONT_TRACE_ALLOCATIONboolIf set, don’t trace heap allocations

§Instruction Set

Currently supports x64 (aka amd64) and arm64 (aka aarch64). There are quite some assembly parsing and register fiddling catered to each platform. There are some assumptions to pointers being 8 bytes in the codebase. It requires considerable effort to support a new architecture, but we are open to commercial collaboration.

§Operating Systems

There is no OS specific code for now. lldb is used on both Linux and macOS. But on macOS we’d connect to the host’s lldb-server. If we decided to support Windows natively, we’d need to make a Windows backend.

The debugger binary must be compiled for the same platform as the target binary. In addition, we assume they both use the same rustc (not necessarily exactly the same, but ABI compatible with each other).

§Standard Library Types

We intend to build-in all handling of standard library types. For HashMap, frozen-hashbrown is used. In the future, we want to open scripting interface (maybe via rhai) to handle vendor library types (e.g. DateTime, Decimal), in a similar sense to Natvis.

§Binary Value Format

The format for serializing Rust values can be best understood by reading SourceReader::read_values() in reader.rs. It should be pretty straight-forward, the only tricky part is ReaderContext which is for resolving memory references.

§Return Value Capture

This is highly architecture specific. We try to capture the return value at the moment the function returns, i.e. at the ret instruction. Not everything is on the stack, sometimes the return value will be passed through registers.

According to Rust’s ABI convention, it means if the return value is:

  1. One or two primitives, each no bigger than 64 bits. This includes (i64, i64) and struct { a: i64, b: i64 }.

  2. One i128 / u128; will be split into rax / rdx

  3. One or two f32 / f64; will be put in xmm0 / xmm1

  4. Option<T> and Result<T, E>; where T & E is no bigger than 64 bits

    The enum discriminant is in rax, where:

    TypeTE
    OptionSome = 1None = 0
    ResultOk = 0Err = 1

    and the T / E will be in rdx.

Unfortunately it is much more complicated than the above summary. Right now the implementation is all mess, and completely based on heuristics. If we got the chance to do this properly, may be we can generate rust code and inspect the assembly (systematically). Say our return type is (T, F):

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

If we disassemble the binary, we should see:

extractor:
call probe
mov ..
call black_box

So between probe and black_box, there would be some memory fiddling, which would end up writing the full struct onto the stack, where the address will then be stored in rax / x0.

There should be better ways to do this, if you have an idea please open a discussion thread!

§Heap allocation

Right now it is still a WIP. We can trace all Box, Rc, Arc allocations now, so that we are able to extract the content of Box<dyn T>. The TODO is to trace deallocations and output the information to a dedicated event stream.

Modules§

typename
version

Structs§

Addr
Memory Address. Assumed to be 8 bytes.
ArgumentList
A wrapper type only for implementing Display.
Breakpoint
Breakpoint
Bytes
Blob of Bytes. Right now it is backed by a Vec<u8>.
DebuggerInfo
Debugger Info
EventStream
Event Stream
FireDbgForRust
Our magic pass phrase.
LineColumn
Line number of column of a symbol.
ProgExitInfo
Program Exit Info
Reader
Stream Reader
SourceFile
Source File
UnionType
Aka Rust’s complex enums, e.g. Result, Option.

Enums§

ArrayType
Type of Array
BreakpointType
Reason to set this breakpoint
Event
Debugger Event
InfoMessage
Information of the debugger run.
PValue
Primitive Value
RValue
A representation of Rust Value
Reason
Reason a breakpoint is hit.
RefAddr
Reference Address
RefCountedType
Reference-counted Smart Pointers
RefType
Reference Type
StringType
Type of String
VariableCapture
Option for capturing variables.

Constants§

BREAKPOINT_STREAM
CORE_REF_CELL
EVENT_STREAM
FILE_STREAM
FIRE_DBG_FOR_RUST
INFO_STREAM
STD_HASH_MAP
STD_HASH_SET
STD_HASH_STATE
STD_MUTEX
STD_RWLOCK