Thanks for all the replies! @fitzgen (he/him) @Adel Prokurov I finally made it by using object and gimli for writing an in-memory ELF object with DWARF, and LLDB's JIT interface now recognizes my generated code. It's lucky that these two are all bundled in the Cranelift related crates. Some notable steps to make this happen:
cranelift-jit crate to expose the function size, which seems impossible to get in the original crate. This serves as the size of the .text section.object::write to write the ELF object, leave the .text section data blank. Add a symbol to this section with the generated function name, e.g. b"jit_main"..set_section_data.object::read to read it again.Then the hard part: do the manual relocations (have to be unsafe):
.text section, set sh_addr with the code address, and sh_sizewith the size.sh_addr to the bytes.as_ptr() + sh_off, so those 0x0 addresses are now the actual ones in virtual memory.Because I notice that object::write and object::build only accepts a Cow to write (I'm afraid it copies) the data, but since we already have a portion of in-memory generated code, we only need to set the right address and size.
wasmtime-jit-debug crate.And now settting breakpoints should work, but stacktraces and unwinding might not work properly, I'm still doing my experimentation on this.
Anqur has marked this topic as resolved.
For backtraces/unwinding you could take inspiration from https://github.com/rust-lang/rustc_codegen_cranelift/blob/9d292ca475cf182d404f5c1f4b6eaf07ac8bfb21/src/debuginfo/unwind.rs#L265-L312
Although I think that only works for backtraces generated by your executable itself, not for debuggers. For debuggers I suspect you need to include the .eh_frame section in the debuginfo ELF file you register with the debugger.
Last updated: Dec 06 2025 at 06:05 UTC