DWARF debug info can be embedded in the binary itself (default behavior for ELF) or externalized in a dedicated file.
import lief
elf = lief.ELF.parse("/bin/with_debug")
if debug_info := elf.debug_info:
assert isinstance(debug_info, lief.dwarf.DebugInfo)
print(f"DWARF Debug handler: {debug_info}")
auto elf = LIEF::ELF::Parser::parse("/bin/with_debug");
if (const LIEF::DebugInfo* info = elf->debug_info()) {
assert(LIEF::dwarf::DebugInfo::classof(info) && "Wrong debug type");
const auto& dwarf_dbg = static_cast<const LIEF::dwarf::DebugInfo&>(*info);
}
let elf = lief::elf::Binary::parse("/bin/ls");
if let Some(lief::DebugInfo::Dwarf(dwarf)) = elf.debug_info() {
// DWARF debug info
}
import lief
dbg: lief.dwarf.DebugInfo = lief.dwarf.load("/bin/with_debug")
dbg: lief.dwarf.DebugInfo = lief.dwarf.load("external_dwarf")
dbg: lief.dwarf.DebugInfo = lief.dwarf.load("debug.dwo")
auto dbg = LIEF::dwarf::load("/bin/with_debug");
auto dbg = LIEF::dwarf::load("external_dwarf");
auto dbg = LIEF::dwarf::load("debug.dwo");
let dbg = lief::dwarf::load("/bin/with_debug");
let dbg = lief::dwarf::load("external_dwarf");
let dbg = lief::dwarf::load("debug.dwo");
import lief
dbg: lief.dwarf.DebugInfo = ...
for compilation_unit in dbg.compilation_units:
print(compilation_unit.producer)
for func in compilation_unit.functions:
print(func.name, func.linkage_name, func.address)
for var in compilation_unit.variables:
print(var.name, var.address)
for ty in compilation_unit.types:
print(ty.name, ty.size)
dbg.find_function("_ZNSi4peekEv")
dbg.find_function("std::basic_istream<char, std::char_traits<char> >::peek()")
dbg.find_function(0x137a70)
dbg.find_variable("_ZNSt12out_of_rangeC1EPKc")
dbg.find_variable("std::out_of_range::out_of_range(char const*)")
dbg.find_variable(0x2773a0)
dbg.find_type("my_type_t")
for (std::unique_ptr<LIEF::dwarf::CompilationUnit> CU : dbg->compilation_units()) {
log(LEVEL::INFO, "Producer: {}", CU->producer());
for (std::unique_ptr<LIEF::dwarf::Function> func : CU->functions()) {
log(LEVEL::INFO, "name={}, linkage={}, address={}",
func->name(), func->linkage_name(), func->address().value_or(0));
}
for (std::unique_ptr<LIEF::dwarf::Variable> var : CU->variables()) {
log(LEVEL::INFO, "name={}, address={}", var->name(), var->address().value_or(0));
}
for (std::unique_ptr<LIEF::dwarf::Type> ty : CU->types()) {
log(LEVEL::INFO, "name={}, size={}", ty->name().value_or(""), std::to_string(ty->size().value_or(0)));
}
}
dbg->find_function("_ZNSi4peekEv");
dbg->find_function("std::basic_istream<char, std::char_traits<char> >::peek()");
dbg->find_function(0x137a70);
dbg->find_variable("_ZNSt12out_of_rangeC1EPKc");
dbg->find_function("std::out_of_range::out_of_range(char const*)");
dbg->find_function(0x2773a0);
let dbg = lief::dwarf::load(&path).unwrap_or_else(|| {
process::exit(1);
});
for cu in dbg.compilation_units() {
println!("Producer: {}", cu.producer());
for func in cu.functions() {
println!("name={}, linkage={}, address={}",
func.name(), func.linkage_name(),
func.address().unwrap_or(0)
);
}
for var in cu.variables() {
println!("name={}, address={}", var.name(), var.address().unwrap_or(0));
}
for ty in cu.types() {
println!("name={}, size={}", ty.name().unwrap_or("".to_string()), ty.size().unwrap_or(0));
}
}
dbg.function_by_name("_ZNSi4peekEv");
dbg.function_by_name("std::basic_istream<char, std::char_traits<char> >::peek()");
dbg.function_by_addr(0x137a70);
dbg.variable_by_name("_ZNSt12out_of_rangeC1EPKc");
dbg.variable_by_name("std::out_of_range::out_of_range(char const*)");
dbg.variable_by_addr(0x137a70);
Editing Existing DWARF
Currently, LIEF does not support modifying an existing DWARF file
import lief
pe = lief.PE.parse("demo.exe")
editor: lief.dwarf.Editor = lief.dwarf.Editor.from_binary(pe)
std::unique_ptr<LIEF::PE::Binary> pe = LIEF::PE::Parser::parse("demo.exe");
std::unique_ptr<LIEF::dwarf::Editor> editor =
LIEF::dwarf::Editor::from_binary(*pe);
let mut bin = lief::pe::Binary::parse(&path).unwrap();
let editor = lief::dwarf::Editor::from_binary(&mut bin);
unit: lief.dwarf.editor.CompilationUnit = editor.create_compilation_unit()
unit.set_producer("LIEF")
func: lief.dwarf.editor.Function = unit.create_function("hello")
func.set_address(0x123)
func.set_return_type(
unit.create_structure("my_struct_t").pointer_to()
)
var: lief.dwarf.editor.Variable = func.create_stack_variable("local_var")
var.set_stack_offset(8)
editor.write("/tmp/out.debug")
std::unique_ptr<LIEF::dwarf::editor::CompilationUnit>
unit = editor->create_compilation_unit();
unit->set_producer("LIEF");
std::unique_ptr<LIEF::dwarf::editor::Function>
func = unit->create_function("hello");
func->set_address(0x123);
func->set_return_type(
*unit->create_structure("my_struct_t")->pointer_to()
);
std::unique_ptr<LIEF::dwarf::editor::Variable> var =
func->create_stack_variable("local_var");
var->set_stack_offset(8);
editor->write("/tmp/out.debug");
let mut unit = editor.create_compile_unit().unwrap();
unit.set_producer("LIEF");
let mut func = unit.create_function("hello").unwrap();
func.set_address(0x123);
func.set_return_type(
&unit.create_structure("my_struct_t").pointer_to()
);
let mut var = func.create_stack_variable("local_var");
var.set_stack_offset(8);
editor.write("/tmp/out.debug");
BinaryNinja & Ghidra
This feature is provided as a plugin for: BinaryNinja and Ghidra
You can find the documentation of the API for the different languages here:
Rust API: lief::dwarf