]>
Commit | Line | Data |
---|---|---|
f035d41b XL |
1 | //! A simple example of parsing `.debug_line`. |
2 | ||
3 | use object::{Object, ObjectSection}; | |
4 | use std::{borrow, env, fs, path}; | |
5 | ||
6 | fn main() { | |
7 | for path in env::args().skip(1) { | |
8 | let file = fs::File::open(&path).unwrap(); | |
9 | let mmap = unsafe { memmap::Mmap::map(&file).unwrap() }; | |
10 | let object = object::File::parse(&*mmap).unwrap(); | |
11 | let endian = if object.is_little_endian() { | |
12 | gimli::RunTimeEndian::Little | |
13 | } else { | |
14 | gimli::RunTimeEndian::Big | |
15 | }; | |
16 | dump_file(&object, endian).unwrap(); | |
17 | } | |
18 | } | |
19 | ||
20 | fn dump_file(object: &object::File, endian: gimli::RunTimeEndian) -> Result<(), gimli::Error> { | |
21 | // Load a section and return as `Cow<[u8]>`. | |
22 | let load_section = |id: gimli::SectionId| -> Result<borrow::Cow<[u8]>, gimli::Error> { | |
23 | match object.section_by_name(id.name()) { | |
24 | Some(ref section) => Ok(section | |
25 | .uncompressed_data() | |
26 | .unwrap_or(borrow::Cow::Borrowed(&[][..]))), | |
27 | None => Ok(borrow::Cow::Borrowed(&[][..])), | |
28 | } | |
29 | }; | |
30 | // Load a supplementary section. We don't have a supplementary object file, | |
31 | // so always return an empty slice. | |
32 | let load_section_sup = |_| Ok(borrow::Cow::Borrowed(&[][..])); | |
33 | ||
34 | // Load all of the sections. | |
35 | let dwarf_cow = gimli::Dwarf::load(&load_section, &load_section_sup)?; | |
36 | ||
37 | // Borrow a `Cow<[u8]>` to create an `EndianSlice`. | |
38 | let borrow_section: &dyn for<'a> Fn( | |
39 | &'a borrow::Cow<[u8]>, | |
40 | ) -> gimli::EndianSlice<'a, gimli::RunTimeEndian> = | |
41 | &|section| gimli::EndianSlice::new(&*section, endian); | |
42 | ||
43 | // Create `EndianSlice`s for all of the sections. | |
44 | let dwarf = dwarf_cow.borrow(&borrow_section); | |
45 | ||
46 | // Iterate over the compilation units. | |
47 | let mut iter = dwarf.units(); | |
48 | while let Some(header) = iter.next()? { | |
49 | println!( | |
50 | "Line number info for unit at <.debug_info+0x{:x}>", | |
fc512014 | 51 | header.offset().as_debug_info_offset().unwrap().0 |
f035d41b XL |
52 | ); |
53 | let unit = dwarf.unit(header)?; | |
54 | ||
55 | // Get the line program for the compilation unit. | |
56 | if let Some(program) = unit.line_program.clone() { | |
57 | let comp_dir = if let Some(ref dir) = unit.comp_dir { | |
58 | path::PathBuf::from(dir.to_string_lossy().into_owned()) | |
59 | } else { | |
60 | path::PathBuf::new() | |
61 | }; | |
62 | ||
63 | // Iterate over the line program rows. | |
64 | let mut rows = program.rows(); | |
65 | while let Some((header, row)) = rows.next_row()? { | |
66 | if row.end_sequence() { | |
67 | // End of sequence indicates a possible gap in addresses. | |
68 | println!("{:x} end-sequence", row.address()); | |
69 | } else { | |
70 | // Determine the path. Real applications should cache this for performance. | |
71 | let mut path = path::PathBuf::new(); | |
72 | if let Some(file) = row.file(header) { | |
73 | path = comp_dir.clone(); | |
74 | if let Some(dir) = file.directory(header) { | |
75 | path.push(dwarf.attr_string(&unit, dir)?.to_string_lossy().as_ref()); | |
76 | } | |
77 | path.push( | |
78 | dwarf | |
79 | .attr_string(&unit, file.path_name())? | |
80 | .to_string_lossy() | |
81 | .as_ref(), | |
82 | ); | |
83 | } | |
84 | ||
85 | // Determine line/column. DWARF line/column is never 0, so we use that | |
86 | // but other applications may want to display this differently. | |
87 | let line = row.line().unwrap_or(0); | |
88 | let column = match row.column() { | |
89 | gimli::ColumnType::LeftEdge => 0, | |
90 | gimli::ColumnType::Column(x) => x, | |
91 | }; | |
92 | ||
93 | println!("{:x} {}:{}:{}", row.address(), path.display(), line, column); | |
94 | } | |
95 | } | |
96 | } | |
97 | } | |
98 | Ok(()) | |
99 | } |