Skip to content

Commit

Permalink
Merge pull request #698 from philipc/dwp
Browse files Browse the repository at this point in the history
DWP improvements
  • Loading branch information
philipc authored Mar 14, 2024
2 parents d8361e8 + 33fe60c commit 1130ac1
Show file tree
Hide file tree
Showing 14 changed files with 537 additions and 231 deletions.
4 changes: 2 additions & 2 deletions crates/examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ default = ["read", "std", "fallible-iterator"]

[[bin]]
name = "simple"
required-features = ["read"]
required-features = ["read", "std"]

[[bin]]
name = "simple_line"
required-features = ["read"]
required-features = ["read", "std"]

[[bin]]
name = "dwarfdump"
Expand Down
138 changes: 98 additions & 40 deletions crates/examples/src/bin/simple.rs
Original file line number Diff line number Diff line change
@@ -1,44 +1,82 @@
//! 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};
use std::{borrow, env, error, 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();

fn dump_file(object: &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()) {
Some(ref section) => Ok(section
.uncompressed_data()
.unwrap_or(borrow::Cow::Borrowed(&[][..]))),
None => Ok(borrow::Cow::Borrowed(&[][..])),
}
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
};

// Load all of the sections.
let dwarf_cow = gimli::Dwarf::load(&load_section)?;
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,
dwp_object: Option<&object::File>,
endian: gimli::RunTimeEndian,
) -> Result<(), Box<dyn error::Error>> {
// Load a section and return as `Cow<[u8]>`.
fn load_section<'a>(
object: &'a object::File,
name: &str,
) -> Result<borrow::Cow<'a, [u8]>, Box<dyn error::Error>> {
Ok(match object.section_by_name(name) {
Some(section) => section.uncompressed_data()?,
None => borrow::Cow::Borrowed(&[]),
})
}

// 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);
let borrow_section = |section| gimli::EndianSlice::new(borrow::Cow::as_ref(section), endian);

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

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

// Iterate over the compilation units.
let mut iter = dwarf.units();
Expand All @@ -48,19 +86,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
32 changes: 15 additions & 17 deletions crates/examples/src/bin/simple_line.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! A simple example of parsing `.debug_line`.
use object::{Object, ObjectSection};
use std::{borrow, env, fs, path};
use std::{borrow, env, error, fs, path};

fn main() {
for path in env::args().skip(1) {
Expand All @@ -17,28 +17,26 @@ fn main() {
}
}

fn dump_file(object: &object::File, endian: gimli::RunTimeEndian) -> Result<(), gimli::Error> {
fn dump_file(
object: &object::File,
endian: gimli::RunTimeEndian,
) -> Result<(), Box<dyn error::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()) {
Some(ref section) => Ok(section
.uncompressed_data()
.unwrap_or(borrow::Cow::Borrowed(&[][..]))),
None => Ok(borrow::Cow::Borrowed(&[][..])),
}
let load_section = |id: gimli::SectionId| -> Result<borrow::Cow<[u8]>, Box<dyn error::Error>> {
Ok(match object.section_by_name(id.name()) {
Some(section) => section.uncompressed_data()?,
None => borrow::Cow::Borrowed(&[]),
})
};

// Load all of the sections.
let dwarf_cow = gimli::Dwarf::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);
let borrow_section = |section| gimli::EndianSlice::new(borrow::Cow::as_ref(section), endian);

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

// Create `EndianSlice`s for all of the sections.
let dwarf = dwarf_cow.borrow(&borrow_section);
let dwarf = dwarf_sections.borrow(borrow_section);

// Iterate over the compilation units.
let mut iter = dwarf.units();
Expand Down
12 changes: 1 addition & 11 deletions src/read/abbrev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,7 @@ impl<T> DebugAbbrev<T> {
///
/// This is useful when `R` implements `Reader` but `T` does not.
///
/// ## Example Usage
///
/// ```rust,no_run
/// # let load_section = || unimplemented!();
/// // Read the DWARF section into a `Vec` with whatever object loader you're using.
/// let owned_section: gimli::DebugAbbrev<Vec<u8>> = load_section();
/// // Create a reference to the DWARF section.
/// let section = owned_section.borrow(|section| {
/// gimli::EndianSlice::new(&section, gimli::LittleEndian)
/// });
/// ```
/// Used by `DwarfSections::borrow`.
pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugAbbrev<R>
where
F: FnMut(&'a T) -> R,
Expand Down
12 changes: 1 addition & 11 deletions src/read/addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,7 @@ impl<T> DebugAddr<T> {
///
/// This is useful when `R` implements `Reader` but `T` does not.
///
/// ## Example Usage
///
/// ```rust,no_run
/// # let load_section = || unimplemented!();
/// // Read the DWARF section into a `Vec` with whatever object loader you're using.
/// let owned_section: gimli::DebugAddr<Vec<u8>> = load_section();
/// // Create a reference to the DWARF section.
/// let section = owned_section.borrow(|section| {
/// gimli::EndianSlice::new(&section, gimli::LittleEndian)
/// });
/// ```
/// Used by `DwarfSections::borrow`.
pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugAddr<R>
where
F: FnMut(&'a T) -> R,
Expand Down
12 changes: 1 addition & 11 deletions src/read/aranges.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,7 @@ impl<T> DebugAranges<T> {
///
/// This is useful when `R` implements `Reader` but `T` does not.
///
/// ## Example Usage
///
/// ```rust,no_run
/// # let load_section = || unimplemented!();
/// // Read the DWARF section into a `Vec` with whatever object loader you're using.
/// let owned_section: gimli::DebugAranges<Vec<u8>> = load_section();
/// // Create a reference to the DWARF section.
/// let section = owned_section.borrow(|section| {
/// gimli::EndianSlice::new(&section, gimli::LittleEndian)
/// });
/// ```
/// Used by `DwarfSections::borrow`.
pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugAranges<R>
where
F: FnMut(&'a T) -> R,
Expand Down
Loading

0 comments on commit 1130ac1

Please sign in to comment.