-
Notifications
You must be signed in to change notification settings - Fork 108
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #460 from philipc/line-example
Add simple_line example
- Loading branch information
Showing
3 changed files
with
102 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
//! A simple example of parsing `.debug_line`. | ||
|
||
use object::Object; | ||
use std::{borrow, env, fs, path}; | ||
|
||
fn main() { | ||
for path in env::args().skip(1) { | ||
let file = fs::File::open(&path).unwrap(); | ||
let mmap = unsafe { memmap::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(); | ||
} | ||
} | ||
|
||
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> { | ||
Ok(object | ||
.section_data_by_name(id.name()) | ||
.unwrap_or(borrow::Cow::Borrowed(&[][..]))) | ||
}; | ||
// Load a supplementary section. We don't have a supplementary object file, | ||
// so always return an empty slice. | ||
let load_section_sup = |_| Ok(borrow::Cow::Borrowed(&[][..])); | ||
|
||
// Load all of the sections. | ||
let dwarf_cow = gimli::Dwarf::load(&load_section, &load_section_sup)?; | ||
|
||
// 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); | ||
|
||
// Create `EndianSlice`s for all of the sections. | ||
let dwarf = dwarf_cow.borrow(&borrow_section); | ||
|
||
// Iterate over the compilation units. | ||
let mut iter = dwarf.units(); | ||
while let Some(header) = iter.next()? { | ||
println!( | ||
"Line number info for unit at <.debug_info+0x{:x}>", | ||
header.offset().0 | ||
); | ||
let unit = dwarf.unit(header)?; | ||
|
||
// Get the line program for the compilation unit. | ||
if let Some(program) = unit.line_program.clone() { | ||
let comp_dir = if let Some(ref dir) = unit.comp_dir { | ||
path::PathBuf::from(dir.to_string_lossy().into_owned()) | ||
} else { | ||
path::PathBuf::new() | ||
}; | ||
|
||
// Iterate over the line program rows. | ||
let mut rows = program.rows(); | ||
while let Some((header, row)) = rows.next_row()? { | ||
if row.end_sequence() { | ||
// End of sequence indicates a possible gap in addresses. | ||
println!("{:x} end-sequence", row.address()); | ||
} else { | ||
// Determine the path. Real applications should cache this for performance. | ||
let mut path = path::PathBuf::new(); | ||
if let Some(file) = row.file(header) { | ||
path = comp_dir.clone(); | ||
if let Some(dir) = file.directory(header) { | ||
path.push(dwarf.attr_string(&unit, dir)?.to_string_lossy().as_ref()); | ||
} | ||
path.push( | ||
dwarf | ||
.attr_string(&unit, file.path_name())? | ||
.to_string_lossy() | ||
.as_ref(), | ||
); | ||
} | ||
|
||
// Determine line/column. DWARF line/column is never 0, so we use that | ||
// but other applications may want to display this differently. | ||
let line = row.line().unwrap_or(0); | ||
let column = match row.column() { | ||
gimli::ColumnType::LeftEdge => 0, | ||
gimli::ColumnType::Column(x) => x, | ||
}; | ||
|
||
println!("{:x} {}:{}:{}", row.address(), path.display(), line, column); | ||
} | ||
} | ||
} | ||
} | ||
Ok(()) | ||
} |