A modern Rust debugger library

Headcrab: September 2020 progress report

We are working towards creating a modular, composable, and modern debugger library for Rust, and this month we want to highlight some of the exciting changes that were made possible thanks to our supporters and contributors.

Imgui-based GUI example for Headcrab by @bjorn3
Inline source view by @blitzerr

GUI example

In pull request #114, @bjorn3 has implemented a Dear ImGui-based graphical interface for Headcrab. It demonstrates how Headcrab functionality can be used to visualize the state of a running program. The demo shows backtrace and a source view, and it can be expanded to display more contextual information.

One of the goals of Headcrab is providing tools for domain-specific debuggers and data visualization. The Headcrab core is not opinionated about how the user interface should be presented: it can be a native GUI (like in this case), a command line application, or a browser page that communicates with the debugger through its API.

Code injection

Pull request #114 demonstrates how Cranelift can be used for code injection. This allows to intercept and replace functions in runtime and it has many useful applications. For example, it can be used to run code snippets in the debugger command line, or for dynamic tracing to record information about a debuggee process.

Currently, this implementation injects the Cranelift IR code, but with the help of rustc_codegen_cranelift it can be expanded to code written in Rust. However, this will require a lot more work.

Starting program: tests/testees/hello
Stopped(Pid(10787), SIGTRAP)

> inject examples/inject_hello_world.clif
run function: 0x00007ffff7fca030 stack: 0x00007ffff7fc8ff8
Hello World from injected code!
Stopped(Pid(10787), SIGTRAP) at 0x00007ffff7fca001

> injectlib libhello_dylib.so
run function: 0x00007ffff7fc7008 stack: 0x00007ffff7fc5ff8
orig rip: 0000555555559295
Hello World from dylib!
Stopped(Pid(10787), SIGTRAP) at 0x00007ffff7fc7001

> cont
Hello, world!

Exited(Pid(10787), 0)

Command line improvements

In pull request #106, @bjorn3 added highlighting and completion for the REPL example:

This was enhanced further by @blitzerr in PR #107, which added inline source view for the code. Now it works similarly to LLDB:

(headcrab) exec tests/testees/hello
Starting program: tests/testees/hello
Stopped(Pid(75698), SIGTRAP)

(headcrab) cont
Stopped(Pid(75698), SIGTRAP)
0000555555559295 core::core_arch::x86::sse2::_mm_pause /rust/src/stdarch/crates/core_arch/src/x86/sse2.rs:25
    4 #[inline(never)]
    5 fn breakpoint() {
    6     // This will be patched by the debugger to be a breakpoint
>   7     unsafe { core::arch::x86_64::_mm_pause(); }
    8 }
   10 #[inline(never)]

Breakpoint support on Linux

In pull request #108, @Arthamys implemented functions that allow to set user breakpoints, which is a cornerstone feature of any debugger. This pull request also expands the command line example and allows setting breakpoints given a memory address or a function name.


We always need help, so if you’d like to join, we have a Zulip chat where we coordinate the development. You can help in a lot of ways: ideas, developer experience, design, documentation, and code. We also welcome first-time contributors and we would be happy to mentor you!

You can also support our work financially by contributing to our OpenCollective.


This month’s contributors were:

Project sponsors

We thank our sponsors, Embark and Khonsu Labs for supporting our project.

OpenCollective backers for this month:

Thank you for your support!

Financial transparency

We have spent €173.57 in August, which have been paid out to individual contributors (@bjorn3, @JJendryka, @nbaksalyar).

At the end of this month, our total remaining balance is $207.34.


For future updates, please subscribe to the RSS feed or to our email newsletter: