Compared to DWARF debug info, the PDB debug info are always externalized from the original binary. Nevertheless, the original binary keeps the path of the PDB file in the attribute lief.PE.CodeViewPDB.filename
/ LIEF::PE::CodeViewPDB::filename()
.
Based on this fact, lief.Binary.debug_info
or LIEF::Binary::debug_info()
tries to instantiate a lief.pdb.DebugInfo
or a LIEF::pdb::DebugInfo
based on this file path. If it fails, it returns a nullptr/None.
One can also instantiate a lief.pdb.DebugInfo
/LIEF::pdb::DebugInfo
using LIEF::pdb::load()
or lief.pdb.load()
:
import lief
pe = lief.PE.parse("some.exe")
if debug_info := pe.debug_info:
assert isinstance(debug_info, lief.pdb.DebugInfo)
print(f"PDB Debug handler: {debug_info}")
# Or you can load the PDB directly:
pdb: lief.pdb.DebugInfo = lief.pdb.load("some.pdb")
std::unique_ptr<LIEF::PE::Binary> pe = LIEF::PE::Parser::parse("some.exe");
if (const LIEF::DebugInfo* info = pe->debug_info()) {
assert(LIEF::pdb::DebugInfo::classof(info) && "Wrong DebugInfo type");
const auto& pdb = static_cast<const LIEF::pdb::DebugInfo&>(*info);
}
// Or loading directly the pdb file
std::unique_ptr<LIEF::pdb::DebugInfo> pdb = LIEF::pdb::load("some.pdb");
let pe = lief::pe::Binary::parse("some.exe");
if let Some(lief::DebugInfo::Pdb(pdb)) = pe.debug_info() {
// PDB debug info
}
let pdb = lief::pdb::load("some.pdb");
At this point, the PDB instance (lief.pdb.DebugInfo
/LIEF::pdb::DebugInfo
) can be used to explore the PDB debug info:
print("arg={}, guid={}", pdb.age, pdb.guid)
for sym in pdb.public_symbols:
print("name={}, section={}, RVA={}",
sym.name, sym.section_name, sym.RVA)
for ty in pdb.types:
if isinstance(ty, lief.pdb.types.Class):
print("Class[name]={}", ty.name)
for cu in pdb.compilation_units:
print("module={}", cu.module_name)
for src in cu.sources:
print(" - {}", src)
for func in cu.functions:
print("name={}, section={}, RVA={}, code_size={}",
func.name, func.section_name, func.RVA, func.code_size)
log(LEVEL::INFO, "age={}, guid={}", std::to_string(pdb->age()), pdb->guid());
for (std::unique_ptr<LIEF::pdb::PublicSymbol> symbol : pdb->public_symbols()) {
log(LEVEL::INFO, "name={}, section={}, RVA={}",
symbol->name(), symbol->section_name(), symbol->RVA());
}
for (std::unique_ptr<LIEF::pdb::Type> ty : pdb->types()) {
if (LIEF::pdb::types::Class::classof(ty.get())) {
auto* clazz = ty->as<LIEF::pdb::types::Class>();
log(LEVEL::INFO, "Class[name]={}", clazz->name());
}
}
for (std::unique_ptr<LIEF::pdb::CompilationUnit> CU : pdb->compilation_units()) {
log(LEVEL::INFO, "module={}", CU->module_name());
for (const std::string& src : CU->sources()) {
log(LEVEL::INFO, " - {}", src);
}
for (std::unique_ptr<LIEF::pdb::Function> func : CU->functions()) {
log(LEVEL::INFO, "name={}, section={}, RVA={}, code size={}",
func->name(), func->section_name(), func->RVA(), func->code_size());
}
}
let pdb = lief::pdb::load(&path).unwrap_or_else(|| {
process::exit(1);
});
println!("age={}, guid={}", pdb.age(), pdb.guid());
for symbol in pdb.public_symbols() {
println!("name={}, section={}, RVA={}",
symbol.name(), symbol.section_name().unwrap_or("".to_string()),
symbol.rva());
}
for ty in pdb.types() {
if let lief::pdb::Type::Class(clazz) = ty {
println!("Class[name]={}", clazz.name());
}
}
for cu in pdb.compilation_units() {
println!("module={}", cu.module_name());
for src in cu.sources() {
println!(" - {}", src);
}
for func in cu.functions() {
println!("name={}, section={}, RVA={}, code_size={}",
func.name(), func.section_name(), func.rva(), func.code_size()
);
}
}
You can find the documentation of the API for the different languages here:
Rust API: https://lief-rs.s3.fr-par.scw.cloud/doc/latest/lief/index.html