debugr

a native debugger that lives in your browser — built in Rust, UI in Vue

Attach to a running process (or launch one, or open its core dump) and watch it: image buffers render as actual images while the program runs, container internals decode to their real values, and every number on screen is a live watch — re-resolved from the variable's name on every read, so nothing goes stale.

see your data, not your bytes

A render buffer is a picture, so show the picture

Attached to a running C++ path tracer. An image watch on s_Instance.m_LayerStack[0].m_Renderer.m_ImageData pulls the framebuffer out of the live process and renders it — an 820×614 viewport streaming at 10 Hz, next to the variable tree that produced it. No instrumentation in the target, no snapshot button: the pixels are read straight out of its memory.

A live path-traced viewport rendered from an attached process, beside the variable tree

follow the pointer to the real thing

Drill through smart pointers to the object that's actually there

That buffer lives four hops deep — a std::vector<std::shared_ptr<Layer>>, a unique_ptr<Renderer>, another shared_ptr. debugr decodes libstdc++ containers with use counts, and follows a shared_ptr<Layer> to the real MainLayer behind it — vtable-resolved, print object done automatically — so the path lands on the derived fields instead of a base-class stub.

A layer object drilled down live: renderer, camera, viewport dimensions, sky color as a vec3

the whole watch story on one screen

Compose the workbench from widgets

Every panel — source, disassembly, charts, images, symbol tables — is a widget on a grid surface you arrange yourself. Right-click a number and chart it while the process runs; right-click a buffer and pin it as an image. Open as many as you like, tab multiple surfaces, and put one on each monitor: two browser windows share one session.

A dashboard with a live frame-time chart beside the streaming viewport image

write, don't just read

Double-click a value and set it

A watch is not read-only. Double-click a value to edit it: g_pixels[2] = 0xdeadbeef resolves through the same pointer path, encodes per the DWARF type, size-checks it, and pokes the live process — the next read shows the change. Leaves only; a type mismatch or an out-of-bounds index fails loudly without touching memory.

teach it your types

Container knowledge is a sandboxed WASM plugin

The libstdc++ decoding ships in-tree for speed, but it's just the built-in of a plugin interface. A data-model plugin makes a container iterable, a handle dereferenceable, an element addressable — always returning real addresses and types, never pre-rendered text. That one invariant is why traversal, image watches, and the write path all compose on top of a type debugr has never seen — the CV north star: your proprietary image buffers, first-class.

// what a value IS, structurally — addresses, never rendered text
interface data-model {
    summarize: func(value: value-info) -> option<string>;
    children:  func(value: value-info) -> option<child-set>;
    deref:     func(value: value-info) -> option<target>;
}
// child-set = sequence{addr, count, elem-type} | named{(name, addr, type)…}

tracepoints — debugging without stopping

The trajectory of a moving value, charted live

A tracepoint is a breakpoint that doesn't stop: each hit captures the values you asked for and streams them over a WebSocket while the process runs at full speed. The XY view draws the captured path, and the ledger says exactly what you got — captured · hits · dropped, never a silent gap. One click records the unthrottled stream to compressed parquet and loads it back for replay.

one place for the whole binary

Static analysis, tiled and coherent

Symbols, types, globals, namespaces, and a section-size treemap — the ELF/DWARF explorer, as widgets on one surface. Every name is a demangled entity with the same right-click menu wherever it appears: a function goes to source or takes a breakpoint, a global becomes a watch, an address opens in hex. If you can read it, you can act on it.

The Explore surface: symbols, types, globals, namespaces, and a section-size treemap as tiled widgets

under the hood

Also in the box