DWARF

DWARF debug info can be embedded in the binary itself (default behavior for ELF) or externalized in a dedicated file.

If the DWARF debug info are embedded in the binary itself, one can use the attribute: lief.Binary.debug_info or LIEF::Binary::debug_info() to access an instance of lief.dwarf.DebugInfo or LIEF::dwarf::DebugInfo:

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}")

On the other hand, we can also use the function: LIEF::dwarf::load() or lief.dwarf.load() to load a DWARF file regardless whether it is embedded or not:

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")

At this point, one can use all the API exposed in lief.dwarf.DebugInfo or LIEF::dwarf::DebugInfo on the instantiated debug info:

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")

You can find the documentation of the API for the different languages here:

Python API

C++ API

Rust API: https://lief-rs.s3.fr-par.scw.cloud/doc/latest/lief/index.html