Skip to content

Commit

Permalink
Update simple example to handle DWP files
Browse files Browse the repository at this point in the history
  • Loading branch information
philipc committed Mar 14, 2024
1 parent e6e90c9 commit 5e4ce05
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 29 deletions.
121 changes: 92 additions & 29 deletions crates/examples/src/bin/simple.rs
Original file line number Diff line number Diff line change
@@ -1,45 +1,88 @@
//! A simple example of parsing `.debug_info`.
//!
//! This example demonstrates how to parse the `.debug_info` section of a
//! DWARF object file and iterate over the compilation units and their DIEs.
//! It also demonstrates how to find the DWO unit for each CU in a DWP file.
//!
//! Most of the complexity is due to loading the sections from the object
//! file and DWP file, which is not something that is provided by gimli itself.
use object::{Object, ObjectSection};
use std::{borrow, env, fs};

fn main() {
for path in env::args().skip(1) {
let file = fs::File::open(&path).unwrap();
let mmap = unsafe { memmap2::Mmap::map(&file).unwrap() };
let object = object::File::parse(&*mmap).unwrap();
let endian = if object.is_little_endian() {
gimli::RunTimeEndian::Little
} else {
gimli::RunTimeEndian::Big
};
dump_file(&object, endian).unwrap();
let mut args = env::args();
if args.len() != 2 && args.len() != 3 {
println!("Usage: {} <file> [dwp]", args.next().unwrap());
return;
}
args.next().unwrap();
let path = args.next().unwrap();
let dwp_path = args.next();

let file = fs::File::open(path).unwrap();
let mmap = unsafe { memmap2::Mmap::map(&file).unwrap() };
let object = object::File::parse(&*mmap).unwrap();
let endian = if object.is_little_endian() {
gimli::RunTimeEndian::Little
} else {
gimli::RunTimeEndian::Big
};

if let Some(dwp_path) = dwp_path {
let dwp_file = fs::File::open(dwp_path).unwrap();
let dwp_mmap = unsafe { memmap2::Mmap::map(&dwp_file).unwrap() };
let dwp_object = object::File::parse(&*dwp_mmap).unwrap();
assert_eq!(dwp_object.is_little_endian(), object.is_little_endian());

dump_file(&object, Some(&dwp_object), endian).unwrap();
} else {
dump_file(&object, None, endian).unwrap();
}
}

fn dump_file(object: &object::File, endian: gimli::RunTimeEndian) -> Result<(), gimli::Error> {
fn dump_file(
object: &object::File,
dwp_object: Option<&object::File>,
endian: gimli::RunTimeEndian,
) -> Result<(), gimli::Error> {
// Load a section and return as `Cow<[u8]>`.
let load_section = |id: gimli::SectionId| -> Result<borrow::Cow<[u8]>, gimli::Error> {
match object.section_by_name(id.name()) {
fn load_section<'a>(
object: &'a object::File,
name: &str,
) -> Result<borrow::Cow<'a, [u8]>, gimli::Error> {
match object.section_by_name(name) {
Some(ref section) => Ok(section
.uncompressed_data()
.unwrap_or(borrow::Cow::Borrowed(&[][..]))),
None => Ok(borrow::Cow::Borrowed(&[][..])),
}
};

// Load all of the sections.
let dwarf_cow = gimli::DwarfSections::load(&load_section)?;
}

// Borrow a `Cow<[u8]>` to create an `EndianSlice`.
let borrow_section: &dyn for<'a> Fn(
&'a borrow::Cow<[u8]>,
) -> gimli::EndianSlice<'a, gimli::RunTimeEndian> =
&|section| gimli::EndianSlice::new(section, endian);

// Load all of the sections.
let dwarf_sections = gimli::DwarfSections::load(|id| load_section(object, id.name()))?;
let dwp_sections = if let Some(dwp_object) = dwp_object {
Some(gimli::DwarfPackageSections::load(|id| {
load_section(dwp_object, id.dwo_name().unwrap())
})?)
} else {
None
};

// Create `EndianSlice`s for all of the sections.
// Alternatively, we could have used `Dwarf::load` with an owned type such as `EndianRcSlice`.
let dwarf = dwarf_cow.borrow(&borrow_section);
let dwarf = dwarf_sections.borrow(&borrow_section);
let dwp = if let Some(dwp_sections) = &dwp_sections {
Some(dwp_sections.borrow(&borrow_section, gimli::EndianSlice::new(&[][..], endian))?)
} else {
None
};

// Iterate over the compilation units.
let mut iter = dwarf.units();
Expand All @@ -49,19 +92,39 @@ fn dump_file(object: &object::File, endian: gimli::RunTimeEndian) -> Result<(),
header.offset().as_debug_info_offset().unwrap().0
);
let unit = dwarf.unit(header)?;
dump_unit(&unit)?;

// Check for a DWO unit.
let Some(dwp) = &dwp else { continue };
let Some(dwo_id) = unit.dwo_id else { continue };
println!("DWO Unit ID {:x}", dwo_id.0);
let Some(dwo) = dwp.find_cu(dwo_id, &dwarf)? else {
continue;
};
let Some(header) = dwo.units().next()? else {
continue;
};
let unit = dwo.unit(header)?;
dump_unit(&unit)?;
}

Ok(())
}

// Iterate over the Debugging Information Entries (DIEs) in the unit.
let mut depth = 0;
let mut entries = unit.entries();
while let Some((delta_depth, entry)) = entries.next_dfs()? {
depth += delta_depth;
println!("<{}><{:x}> {}", depth, entry.offset().0, entry.tag());
fn dump_unit(
unit: &gimli::Unit<gimli::EndianSlice<gimli::RunTimeEndian>>,
) -> Result<(), gimli::Error> {
// Iterate over the Debugging Information Entries (DIEs) in the unit.
let mut depth = 0;
let mut entries = unit.entries();
while let Some((delta_depth, entry)) = entries.next_dfs()? {
depth += delta_depth;
println!("<{}><{:x}> {}", depth, entry.offset().0, entry.tag());

// Iterate over the attributes in the DIE.
let mut attrs = entry.attrs();
while let Some(attr) = attrs.next()? {
println!(" {}: {:?}", attr.name(), attr.value());
}
// Iterate over the attributes in the DIE.
let mut attrs = entry.attrs();
while let Some(attr) = attrs.next()? {
println!(" {}: {:?}", attr.name(), attr.value());
}
}
Ok(())
Expand Down
16 changes: 16 additions & 0 deletions src/read/dwarf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,22 @@ impl<R: Reader> DwarfPackage<R> {

/// Find the compilation unit with the given DWO identifier and return its section
/// contributions.
///
/// ## Example Usage
///
/// ```rust,no_run
/// # fn example<R: gimli::Reader>(
/// # dwarf: &gimli::Dwarf<R>,
/// # dwp: &gimli::DwarfPackage<R>,
/// # dwo_id: gimli::DwoId,
/// # ) -> Result<(), gimli::Error> {
/// if let Some(dwo) = dwp.find_cu(dwo_id, dwarf)? {
/// let dwo_header = dwo.units().next()?.expect("DWO should have one unit");
/// let dwo_unit = dwo.unit(dwo_header)?;
/// // Do something with `dwo_unit`.
/// }
/// # unreachable!()
/// # }
pub fn find_cu(&self, id: DwoId, parent: &Dwarf<R>) -> Result<Option<Dwarf<R>>> {
let row = match self.cu_index.find(id.0) {
Some(row) => row,
Expand Down

0 comments on commit 5e4ce05

Please sign in to comment.