1 // Allow clippy lints when building without clippy.
2 #![allow(unknown_lints)]
3 
4 use fallible_iterator::FallibleIterator;
5 use gimli::{Section, UnitHeader, UnitOffset, UnitSectionOffset, UnitType, UnwindSection};
6 use object::{Object, ObjectSection, ObjectSymbol};
7 use regex::bytes::Regex;
8 use std::borrow::{Borrow, Cow};
9 use std::cmp::min;
10 use std::collections::HashMap;
11 use std::env;
12 use std::fmt::{self, Debug};
13 use std::fs;
14 use std::io;
15 use std::io::{BufWriter, Write};
16 use std::iter::Iterator;
17 use std::mem;
18 use std::process;
19 use std::result;
20 use std::sync::{Condvar, Mutex};
21 use typed_arena::Arena;
22 
23 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
24 pub enum Error {
25     GimliError(gimli::Error),
26     ObjectError(object::read::Error),
27     IoError,
28 }
29 
30 impl fmt::Display for Error {
31     #[inline]
fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error>32     fn fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
33         Debug::fmt(self, f)
34     }
35 }
36 
writeln_error<W: Write, R: Reader>( w: &mut W, dwarf: &gimli::Dwarf<R>, err: Error, msg: &str, ) -> io::Result<()>37 fn writeln_error<W: Write, R: Reader>(
38     w: &mut W,
39     dwarf: &gimli::Dwarf<R>,
40     err: Error,
41     msg: &str,
42 ) -> io::Result<()> {
43     writeln!(
44         w,
45         "{}: {}",
46         msg,
47         match err {
48             Error::GimliError(err) => dwarf.format_error(err),
49             Error::ObjectError(err) =>
50                 format!("{}:{:?}", "An object error occurred while reading", err),
51             Error::IoError => "An I/O error occurred while writing.".to_string(),
52         }
53     )
54 }
55 
56 impl From<gimli::Error> for Error {
from(err: gimli::Error) -> Self57     fn from(err: gimli::Error) -> Self {
58         Error::GimliError(err)
59     }
60 }
61 
62 impl From<io::Error> for Error {
from(_: io::Error) -> Self63     fn from(_: io::Error) -> Self {
64         Error::IoError
65     }
66 }
67 
68 impl From<object::read::Error> for Error {
from(err: object::read::Error) -> Self69     fn from(err: object::read::Error) -> Self {
70         Error::ObjectError(err)
71     }
72 }
73 
74 pub type Result<T> = result::Result<T, Error>;
75 
parallel_output<II, F>(max_workers: usize, iter: II, f: F) -> Result<()> where F: Sync + Fn(II::Item, &mut Vec<u8>) -> Result<()>, II: IntoIterator, II::IntoIter: Send,76 fn parallel_output<II, F>(max_workers: usize, iter: II, f: F) -> Result<()>
77 where
78     F: Sync + Fn(II::Item, &mut Vec<u8>) -> Result<()>,
79     II: IntoIterator,
80     II::IntoIter: Send,
81 {
82     struct ParallelOutputState<I: Iterator> {
83         iterator: I,
84         current_worker: usize,
85         result: Result<()>,
86     }
87 
88     let state = Mutex::new(ParallelOutputState {
89         iterator: iter.into_iter().fuse(),
90         current_worker: 0,
91         result: Ok(()),
92     });
93     let workers = min(max_workers, num_cpus::get());
94     let mut condvars = Vec::new();
95     for _ in 0..workers {
96         condvars.push(Condvar::new());
97     }
98     {
99         let state_ref = &state;
100         let f_ref = &f;
101         let condvars_ref = &condvars;
102         crossbeam::scope(|scope| {
103             for i in 0..workers {
104                 scope.spawn(move |_| {
105                     let mut v = Vec::new();
106                     let mut lock = state_ref.lock().unwrap();
107                     while lock.current_worker != i {
108                         lock = condvars_ref[i].wait(lock).unwrap();
109                     }
110                     loop {
111                         let item = if lock.result.is_ok() {
112                             lock.iterator.next()
113                         } else {
114                             None
115                         };
116                         lock.current_worker = (i + 1) % workers;
117                         condvars_ref[lock.current_worker].notify_one();
118                         mem::drop(lock);
119 
120                         let ret = if let Some(item) = item {
121                             v.clear();
122                             f_ref(item, &mut v)
123                         } else {
124                             return;
125                         };
126 
127                         lock = state_ref.lock().unwrap();
128                         while lock.current_worker != i {
129                             lock = condvars_ref[i].wait(lock).unwrap();
130                         }
131                         if lock.result.is_ok() {
132                             let out = io::stdout();
133                             let ret2 = out.lock().write_all(&v);
134                             if ret.is_err() {
135                                 lock.result = ret;
136                             } else {
137                                 lock.result = ret2.map_err(Error::from);
138                             }
139                         }
140                     }
141                 });
142             }
143         })
144         .unwrap();
145     }
146     state.into_inner().unwrap().result
147 }
148 
149 trait Reader: gimli::Reader<Offset = usize> + Send + Sync {}
150 
151 impl<'input, Endian> Reader for gimli::EndianSlice<'input, Endian> where
152     Endian: gimli::Endianity + Send + Sync
153 {
154 }
155 
156 type RelocationMap = HashMap<usize, object::Relocation>;
157 
add_relocations( relocations: &mut RelocationMap, file: &object::File, section: &object::Section, )158 fn add_relocations(
159     relocations: &mut RelocationMap,
160     file: &object::File,
161     section: &object::Section,
162 ) {
163     for (offset64, mut relocation) in section.relocations() {
164         let offset = offset64 as usize;
165         if offset as u64 != offset64 {
166             continue;
167         }
168         let offset = offset as usize;
169         match relocation.kind() {
170             object::RelocationKind::Absolute => {
171                 match relocation.target() {
172                     object::RelocationTarget::Symbol(symbol_idx) => {
173                         match file.symbol_by_index(symbol_idx) {
174                             Ok(symbol) => {
175                                 let addend =
176                                     symbol.address().wrapping_add(relocation.addend() as u64);
177                                 relocation.set_addend(addend as i64);
178                             }
179                             Err(_) => {
180                                 println!(
181                                     "Relocation with invalid symbol for section {} at offset 0x{:08x}",
182                                     section.name().unwrap(),
183                                     offset
184                                 );
185                             }
186                         }
187                     }
188                     object::RelocationTarget::Section(_section_idx) => {}
189                 }
190                 if relocations.insert(offset, relocation).is_some() {
191                     println!(
192                         "Multiple relocations for section {} at offset 0x{:08x}",
193                         section.name().unwrap(),
194                         offset
195                     );
196                 }
197             }
198             _ => {
199                 println!(
200                     "Unsupported relocation for section {} at offset 0x{:08x}",
201                     section.name().unwrap(),
202                     offset
203                 );
204             }
205         }
206     }
207 }
208 
209 /// Apply relocations to addresses and offsets during parsing,
210 /// instead of requiring the data to be fully relocated prior
211 /// to parsing.
212 ///
213 /// Pros
214 /// - allows readonly buffers, we don't need to implement writing of values back to buffers
215 /// - potentially allows us to handle addresses and offsets differently
216 /// - potentially allows us to add metadata from the relocation (eg symbol names)
217 /// Cons
218 /// - maybe incomplete
219 #[derive(Debug, Clone)]
220 struct Relocate<'a, R: gimli::Reader<Offset = usize>> {
221     relocations: &'a RelocationMap,
222     section: R,
223     reader: R,
224 }
225 
226 impl<'a, R: gimli::Reader<Offset = usize>> Relocate<'a, R> {
relocate(&self, offset: usize, value: u64) -> u64227     fn relocate(&self, offset: usize, value: u64) -> u64 {
228         if let Some(relocation) = self.relocations.get(&offset) {
229             match relocation.kind() {
230                 object::RelocationKind::Absolute => {
231                     if relocation.has_implicit_addend() {
232                         // Use the explicit addend too, because it may have the symbol value.
233                         return value.wrapping_add(relocation.addend() as u64);
234                     } else {
235                         return relocation.addend() as u64;
236                     }
237                 }
238                 _ => {}
239             }
240         };
241         value
242     }
243 }
244 
245 impl<'a, R: gimli::Reader<Offset = usize>> gimli::Reader for Relocate<'a, R> {
246     type Endian = R::Endian;
247     type Offset = R::Offset;
248 
read_address(&mut self, address_size: u8) -> gimli::Result<u64>249     fn read_address(&mut self, address_size: u8) -> gimli::Result<u64> {
250         let offset = self.reader.offset_from(&self.section);
251         let value = self.reader.read_address(address_size)?;
252         Ok(self.relocate(offset, value))
253     }
254 
read_length(&mut self, format: gimli::Format) -> gimli::Result<usize>255     fn read_length(&mut self, format: gimli::Format) -> gimli::Result<usize> {
256         let offset = self.reader.offset_from(&self.section);
257         let value = self.reader.read_length(format)?;
258         <usize as gimli::ReaderOffset>::from_u64(self.relocate(offset, value as u64))
259     }
260 
read_offset(&mut self, format: gimli::Format) -> gimli::Result<usize>261     fn read_offset(&mut self, format: gimli::Format) -> gimli::Result<usize> {
262         let offset = self.reader.offset_from(&self.section);
263         let value = self.reader.read_offset(format)?;
264         <usize as gimli::ReaderOffset>::from_u64(self.relocate(offset, value as u64))
265     }
266 
read_sized_offset(&mut self, size: u8) -> gimli::Result<usize>267     fn read_sized_offset(&mut self, size: u8) -> gimli::Result<usize> {
268         let offset = self.reader.offset_from(&self.section);
269         let value = self.reader.read_sized_offset(size)?;
270         <usize as gimli::ReaderOffset>::from_u64(self.relocate(offset, value as u64))
271     }
272 
273     #[inline]
split(&mut self, len: Self::Offset) -> gimli::Result<Self>274     fn split(&mut self, len: Self::Offset) -> gimli::Result<Self> {
275         let mut other = self.clone();
276         other.reader.truncate(len)?;
277         self.reader.skip(len)?;
278         Ok(other)
279     }
280 
281     // All remaining methods simply delegate to `self.reader`.
282 
283     #[inline]
endian(&self) -> Self::Endian284     fn endian(&self) -> Self::Endian {
285         self.reader.endian()
286     }
287 
288     #[inline]
len(&self) -> Self::Offset289     fn len(&self) -> Self::Offset {
290         self.reader.len()
291     }
292 
293     #[inline]
empty(&mut self)294     fn empty(&mut self) {
295         self.reader.empty()
296     }
297 
298     #[inline]
truncate(&mut self, len: Self::Offset) -> gimli::Result<()>299     fn truncate(&mut self, len: Self::Offset) -> gimli::Result<()> {
300         self.reader.truncate(len)
301     }
302 
303     #[inline]
offset_from(&self, base: &Self) -> Self::Offset304     fn offset_from(&self, base: &Self) -> Self::Offset {
305         self.reader.offset_from(&base.reader)
306     }
307 
308     #[inline]
offset_id(&self) -> gimli::ReaderOffsetId309     fn offset_id(&self) -> gimli::ReaderOffsetId {
310         self.reader.offset_id()
311     }
312 
313     #[inline]
lookup_offset_id(&self, id: gimli::ReaderOffsetId) -> Option<Self::Offset>314     fn lookup_offset_id(&self, id: gimli::ReaderOffsetId) -> Option<Self::Offset> {
315         self.reader.lookup_offset_id(id)
316     }
317 
318     #[inline]
find(&self, byte: u8) -> gimli::Result<Self::Offset>319     fn find(&self, byte: u8) -> gimli::Result<Self::Offset> {
320         self.reader.find(byte)
321     }
322 
323     #[inline]
skip(&mut self, len: Self::Offset) -> gimli::Result<()>324     fn skip(&mut self, len: Self::Offset) -> gimli::Result<()> {
325         self.reader.skip(len)
326     }
327 
328     #[inline]
to_slice(&self) -> gimli::Result<Cow<[u8]>>329     fn to_slice(&self) -> gimli::Result<Cow<[u8]>> {
330         self.reader.to_slice()
331     }
332 
333     #[inline]
to_string(&self) -> gimli::Result<Cow<str>>334     fn to_string(&self) -> gimli::Result<Cow<str>> {
335         self.reader.to_string()
336     }
337 
338     #[inline]
to_string_lossy(&self) -> gimli::Result<Cow<str>>339     fn to_string_lossy(&self) -> gimli::Result<Cow<str>> {
340         self.reader.to_string_lossy()
341     }
342 
343     #[inline]
read_slice(&mut self, buf: &mut [u8]) -> gimli::Result<()>344     fn read_slice(&mut self, buf: &mut [u8]) -> gimli::Result<()> {
345         self.reader.read_slice(buf)
346     }
347 }
348 
349 impl<'a, R: Reader> Reader for Relocate<'a, R> {}
350 
351 #[derive(Default)]
352 struct Flags {
353     eh_frame: bool,
354     goff: bool,
355     info: bool,
356     line: bool,
357     pubnames: bool,
358     pubtypes: bool,
359     aranges: bool,
360     dwo: bool,
361     raw: bool,
362     match_units: Option<Regex>,
363 }
364 
365 impl Flags {
section_name(&self, id: gimli::SectionId) -> Option<&'static str>366     fn section_name(&self, id: gimli::SectionId) -> Option<&'static str> {
367         if self.dwo {
368             id.dwo_name()
369         } else {
370             Some(id.name())
371         }
372     }
373 }
374 
print_usage(opts: &getopts::Options) -> !375 fn print_usage(opts: &getopts::Options) -> ! {
376     let brief = format!("Usage: {} <options> <file>", env::args().next().unwrap());
377     write!(&mut io::stderr(), "{}", opts.usage(&brief)).ok();
378     process::exit(1);
379 }
380 
main()381 fn main() {
382     let mut opts = getopts::Options::new();
383     opts.optflag(
384         "",
385         "eh-frame",
386         "print .eh-frame exception handling frame information",
387     );
388     opts.optflag("G", "", "show global die offsets");
389     opts.optflag("i", "", "print .debug_info and .debug_types sections");
390     opts.optflag("l", "", "print .debug_line section");
391     opts.optflag("p", "", "print .debug_pubnames section");
392     opts.optflag("r", "", "print .debug_aranges section");
393     opts.optflag("y", "", "print .debug_pubtypes section");
394     opts.optflag(
395         "",
396         "dwo",
397         "print the .dwo versions of the selected sections",
398     );
399     opts.optflag("", "raw", "print raw data values");
400     opts.optopt(
401         "u",
402         "match-units",
403         "print compilation units whose output matches a regex",
404         "REGEX",
405     );
406 
407     let matches = match opts.parse(env::args().skip(1)) {
408         Ok(m) => m,
409         Err(e) => {
410             writeln!(&mut io::stderr(), "{:?}\n", e).ok();
411             print_usage(&opts);
412         }
413     };
414     if matches.free.is_empty() {
415         print_usage(&opts);
416     }
417 
418     let mut all = true;
419     let mut flags = Flags::default();
420     if matches.opt_present("eh-frame") {
421         flags.eh_frame = true;
422         all = false;
423     }
424     if matches.opt_present("G") {
425         flags.goff = true;
426     }
427     if matches.opt_present("i") {
428         flags.info = true;
429         all = false;
430     }
431     if matches.opt_present("l") {
432         flags.line = true;
433         all = false;
434     }
435     if matches.opt_present("p") {
436         flags.pubnames = true;
437         all = false;
438     }
439     if matches.opt_present("y") {
440         flags.pubtypes = true;
441         all = false;
442     }
443     if matches.opt_present("r") {
444         flags.aranges = true;
445         all = false;
446     }
447     if matches.opt_present("dwo") {
448         flags.dwo = true;
449     }
450     if matches.opt_present("raw") {
451         flags.raw = true;
452     }
453     if all {
454         // .eh_frame is excluded even when printing all information.
455         // cosmetic flags like -G must be set explicitly too.
456         flags.info = true;
457         flags.line = true;
458         flags.pubnames = true;
459         flags.pubtypes = true;
460         flags.aranges = true;
461     }
462     flags.match_units = if let Some(r) = matches.opt_str("u") {
463         match Regex::new(&r) {
464             Ok(r) => Some(r),
465             Err(e) => {
466                 println!("Invalid regular expression {}: {}", r, e);
467                 process::exit(1);
468             }
469         }
470     } else {
471         None
472     };
473 
474     for file_path in &matches.free {
475         if matches.free.len() != 1 {
476             println!("{}", file_path);
477             println!();
478         }
479 
480         let file = match fs::File::open(&file_path) {
481             Ok(file) => file,
482             Err(err) => {
483                 println!("Failed to open file '{}': {}", file_path, err);
484                 continue;
485             }
486         };
487         let file = match unsafe { memmap::Mmap::map(&file) } {
488             Ok(mmap) => mmap,
489             Err(err) => {
490                 println!("Failed to map file '{}': {}", file_path, err);
491                 continue;
492             }
493         };
494         let file = match object::File::parse(&*file) {
495             Ok(file) => file,
496             Err(err) => {
497                 println!("Failed to parse file '{}': {}", file_path, err);
498                 continue;
499             }
500         };
501 
502         let endian = if file.is_little_endian() {
503             gimli::RunTimeEndian::Little
504         } else {
505             gimli::RunTimeEndian::Big
506         };
507         let ret = dump_file(&file, endian, &flags);
508         match ret {
509             Ok(_) => (),
510             Err(err) => println!("Failed to dump '{}': {}", file_path, err,),
511         }
512     }
513 }
514 
dump_file<Endian>(file: &object::File, endian: Endian, flags: &Flags) -> Result<()> where Endian: gimli::Endianity + Send + Sync,515 fn dump_file<Endian>(file: &object::File, endian: Endian, flags: &Flags) -> Result<()>
516 where
517     Endian: gimli::Endianity + Send + Sync,
518 {
519     let arena = (Arena::new(), Arena::new());
520 
521     let mut load_section = |id: gimli::SectionId| -> Result<_> {
522         let mut relocations = RelocationMap::default();
523         let name = flags.section_name(id);
524         let data = match name.and_then(|name| file.section_by_name(&name)) {
525             Some(ref section) => {
526                 // DWO sections never have relocations, so don't bother.
527                 if !flags.dwo {
528                     add_relocations(&mut relocations, file, section);
529                 }
530                 section.uncompressed_data()?
531             }
532             // Use a non-zero capacity so that `ReaderOffsetId`s are unique.
533             None => Cow::Owned(Vec::with_capacity(1)),
534         };
535         let data_ref = (*arena.0.alloc(data)).borrow();
536         let reader = gimli::EndianSlice::new(data_ref, endian);
537         let section = reader;
538         let relocations = (*arena.1.alloc(relocations)).borrow();
539         Ok(Relocate {
540             relocations,
541             section,
542             reader,
543         })
544     };
545 
546     let no_relocations = (*arena.1.alloc(RelocationMap::default())).borrow();
547     let no_reader = Relocate {
548         relocations: no_relocations,
549         section: Default::default(),
550         reader: Default::default(),
551     };
552 
553     let mut dwarf = gimli::Dwarf::load(&mut load_section, |_| Ok(no_reader.clone())).unwrap();
554     if flags.dwo {
555         dwarf.file_type = gimli::DwarfFileType::Dwo;
556     }
557 
558     let out = io::stdout();
559     if flags.eh_frame {
560         // TODO: this might be better based on the file format.
561         let address_size = file
562             .architecture()
563             .address_size()
564             .map(|w| w.bytes())
565             .unwrap_or(mem::size_of::<usize>() as u8);
566 
567         fn register_name_none(_: gimli::Register) -> Option<&'static str> {
568             None
569         }
570         let arch_register_name = match file.architecture() {
571             object::Architecture::Arm | object::Architecture::Aarch64 => gimli::Arm::register_name,
572             object::Architecture::I386 => gimli::X86::register_name,
573             object::Architecture::X86_64 => gimli::X86_64::register_name,
574             _ => register_name_none,
575         };
576         let register_name = |register| match arch_register_name(register) {
577             Some(name) => Cow::Borrowed(name),
578             None => Cow::Owned(format!("{}", register.0)),
579         };
580 
581         let mut eh_frame = gimli::EhFrame::load(&mut load_section).unwrap();
582         eh_frame.set_address_size(address_size);
583         let mut bases = gimli::BaseAddresses::default();
584         if let Some(section) = file.section_by_name(".eh_frame_hdr") {
585             bases = bases.set_eh_frame_hdr(section.address());
586         }
587         if let Some(section) = file.section_by_name(".eh_frame") {
588             bases = bases.set_eh_frame(section.address());
589         }
590         if let Some(section) = file.section_by_name(".text") {
591             bases = bases.set_text(section.address());
592         }
593         if let Some(section) = file.section_by_name(".got") {
594             bases = bases.set_got(section.address());
595         }
596         dump_eh_frame(
597             &mut BufWriter::new(out.lock()),
598             &eh_frame,
599             &bases,
600             &register_name,
601         )?;
602     }
603     if flags.info {
604         dump_info(&dwarf, flags)?;
605         dump_types(&mut BufWriter::new(out.lock()), &dwarf, flags)?;
606         writeln!(&mut out.lock())?;
607     }
608     let w = &mut BufWriter::new(out.lock());
609     if flags.line {
610         dump_line(w, &dwarf)?;
611     }
612     if flags.pubnames {
613         let debug_pubnames = &gimli::Section::load(&mut load_section).unwrap();
614         dump_pubnames(w, debug_pubnames, &dwarf.debug_info)?;
615     }
616     if flags.aranges {
617         let debug_aranges = &gimli::Section::load(&mut load_section).unwrap();
618         dump_aranges(w, debug_aranges, &dwarf.debug_info)?;
619     }
620     if flags.pubtypes {
621         let debug_pubtypes = &gimli::Section::load(&mut load_section).unwrap();
622         dump_pubtypes(w, debug_pubtypes, &dwarf.debug_info)?;
623     }
624     Ok(())
625 }
626 
dump_eh_frame<R: Reader, W: Write>( w: &mut W, eh_frame: &gimli::EhFrame<R>, bases: &gimli::BaseAddresses, register_name: &dyn Fn(gimli::Register) -> Cow<'static, str>, ) -> Result<()>627 fn dump_eh_frame<R: Reader, W: Write>(
628     w: &mut W,
629     eh_frame: &gimli::EhFrame<R>,
630     bases: &gimli::BaseAddresses,
631     register_name: &dyn Fn(gimli::Register) -> Cow<'static, str>,
632 ) -> Result<()> {
633     // TODO: Print "__eh_frame" here on macOS, and more generally use the
634     // section that we're actually looking at, which is what the canonical
635     // dwarfdump does.
636     writeln!(
637         w,
638         "Exception handling frame information for section .eh_frame"
639     )?;
640 
641     let mut cies = HashMap::new();
642 
643     let mut entries = eh_frame.entries(bases);
644     loop {
645         match entries.next()? {
646             None => return Ok(()),
647             Some(gimli::CieOrFde::Cie(cie)) => {
648                 writeln!(w)?;
649                 writeln!(w, "{:#010x}: CIE", cie.offset())?;
650                 writeln!(w, "        length: {:#010x}", cie.entry_len())?;
651                 // TODO: CIE_id
652                 writeln!(w, "       version: {:#04x}", cie.version())?;
653                 // TODO: augmentation
654                 writeln!(w, "    code_align: {}", cie.code_alignment_factor())?;
655                 writeln!(w, "    data_align: {}", cie.data_alignment_factor())?;
656                 writeln!(w, "   ra_register: {:#x}", cie.return_address_register().0)?;
657                 if let Some(encoding) = cie.lsda_encoding() {
658                     writeln!(w, " lsda_encoding: {:#02x}", encoding.0)?;
659                 }
660                 if let Some((encoding, personality)) = cie.personality_with_encoding() {
661                     write!(w, "   personality: {:#02x} ", encoding.0)?;
662                     dump_pointer(w, personality)?;
663                     writeln!(w)?;
664                 }
665                 if let Some(encoding) = cie.fde_address_encoding() {
666                     writeln!(w, "  fde_encoding: {:#02x}", encoding.0)?;
667                 }
668                 dump_cfi_instructions(w, cie.instructions(eh_frame, bases), true, register_name)?;
669                 writeln!(w)?;
670             }
671             Some(gimli::CieOrFde::Fde(partial)) => {
672                 let mut offset = None;
673                 let fde = partial.parse(|_, bases, o| {
674                     offset = Some(o);
675                     cies.entry(o)
676                         .or_insert_with(|| eh_frame.cie_from_offset(bases, o))
677                         .clone()
678                 })?;
679 
680                 writeln!(w)?;
681                 writeln!(w, "{:#010x}: FDE", fde.offset())?;
682                 writeln!(w, "        length: {:#010x}", fde.entry_len())?;
683                 writeln!(w, "   CIE_pointer: {:#010x}", offset.unwrap().0)?;
684                 // TODO: symbolicate the start address like the canonical dwarfdump does.
685                 writeln!(w, "    start_addr: {:#018x}", fde.initial_address())?;
686                 writeln!(
687                     w,
688                     "    range_size: {:#018x} (end_addr = {:#018x})",
689                     fde.len(),
690                     fde.initial_address() + fde.len()
691                 )?;
692                 if let Some(lsda) = fde.lsda() {
693                     write!(w, "          lsda: ")?;
694                     dump_pointer(w, lsda)?;
695                     writeln!(w)?;
696                 }
697                 dump_cfi_instructions(w, fde.instructions(eh_frame, bases), false, register_name)?;
698                 writeln!(w)?;
699             }
700         }
701     }
702 }
703 
dump_pointer<W: Write>(w: &mut W, p: gimli::Pointer) -> Result<()>704 fn dump_pointer<W: Write>(w: &mut W, p: gimli::Pointer) -> Result<()> {
705     match p {
706         gimli::Pointer::Direct(p) => {
707             write!(w, "{:#018x}", p)?;
708         }
709         gimli::Pointer::Indirect(p) => {
710             write!(w, "({:#018x})", p)?;
711         }
712     }
713     Ok(())
714 }
715 
716 #[allow(clippy::unneeded_field_pattern)]
dump_cfi_instructions<R: Reader, W: Write>( w: &mut W, mut insns: gimli::CallFrameInstructionIter<R>, is_initial: bool, register_name: &dyn Fn(gimli::Register) -> Cow<'static, str>, ) -> Result<()>717 fn dump_cfi_instructions<R: Reader, W: Write>(
718     w: &mut W,
719     mut insns: gimli::CallFrameInstructionIter<R>,
720     is_initial: bool,
721     register_name: &dyn Fn(gimli::Register) -> Cow<'static, str>,
722 ) -> Result<()> {
723     use gimli::CallFrameInstruction::*;
724 
725     // TODO: we need to actually evaluate these instructions as we iterate them
726     // so we can print the initialized state for CIEs, and each unwind row's
727     // registers for FDEs.
728     //
729     // TODO: We should print DWARF expressions for the CFI instructions that
730     // embed DWARF expressions within themselves.
731 
732     if !is_initial {
733         writeln!(w, "  Instructions:")?;
734     }
735 
736     loop {
737         match insns.next() {
738             Err(e) => {
739                 writeln!(w, "Failed to decode CFI instruction: {}", e)?;
740                 return Ok(());
741             }
742             Ok(None) => {
743                 if is_initial {
744                     writeln!(w, "  Instructions: Init State:")?;
745                 }
746                 return Ok(());
747             }
748             Ok(Some(op)) => match op {
749                 SetLoc { address } => {
750                     writeln!(w, "                DW_CFA_set_loc ({:#x})", address)?;
751                 }
752                 AdvanceLoc { delta } => {
753                     writeln!(w, "                DW_CFA_advance_loc ({})", delta)?;
754                 }
755                 DefCfa { register, offset } => {
756                     writeln!(
757                         w,
758                         "                DW_CFA_def_cfa ({}, {})",
759                         register_name(register),
760                         offset
761                     )?;
762                 }
763                 DefCfaSf {
764                     register,
765                     factored_offset,
766                 } => {
767                     writeln!(
768                         w,
769                         "                DW_CFA_def_cfa_sf ({}, {})",
770                         register_name(register),
771                         factored_offset
772                     )?;
773                 }
774                 DefCfaRegister { register } => {
775                     writeln!(
776                         w,
777                         "                DW_CFA_def_cfa_register ({})",
778                         register_name(register)
779                     )?;
780                 }
781                 DefCfaOffset { offset } => {
782                     writeln!(w, "                DW_CFA_def_cfa_offset ({})", offset)?;
783                 }
784                 DefCfaOffsetSf { factored_offset } => {
785                     writeln!(
786                         w,
787                         "                DW_CFA_def_cfa_offset_sf ({})",
788                         factored_offset
789                     )?;
790                 }
791                 DefCfaExpression { expression: _ } => {
792                     writeln!(w, "                DW_CFA_def_cfa_expression (...)")?;
793                 }
794                 Undefined { register } => {
795                     writeln!(
796                         w,
797                         "                DW_CFA_undefined ({})",
798                         register_name(register)
799                     )?;
800                 }
801                 SameValue { register } => {
802                     writeln!(
803                         w,
804                         "                DW_CFA_same_value ({})",
805                         register_name(register)
806                     )?;
807                 }
808                 Offset {
809                     register,
810                     factored_offset,
811                 } => {
812                     writeln!(
813                         w,
814                         "                DW_CFA_offset ({}, {})",
815                         register_name(register),
816                         factored_offset
817                     )?;
818                 }
819                 OffsetExtendedSf {
820                     register,
821                     factored_offset,
822                 } => {
823                     writeln!(
824                         w,
825                         "                DW_CFA_offset_extended_sf ({}, {})",
826                         register_name(register),
827                         factored_offset
828                     )?;
829                 }
830                 ValOffset {
831                     register,
832                     factored_offset,
833                 } => {
834                     writeln!(
835                         w,
836                         "                DW_CFA_val_offset ({}, {})",
837                         register_name(register),
838                         factored_offset
839                     )?;
840                 }
841                 ValOffsetSf {
842                     register,
843                     factored_offset,
844                 } => {
845                     writeln!(
846                         w,
847                         "                DW_CFA_val_offset_sf ({}, {})",
848                         register_name(register),
849                         factored_offset
850                     )?;
851                 }
852                 Register {
853                     dest_register,
854                     src_register,
855                 } => {
856                     writeln!(
857                         w,
858                         "                DW_CFA_register ({}, {})",
859                         register_name(dest_register),
860                         register_name(src_register)
861                     )?;
862                 }
863                 Expression {
864                     register,
865                     expression: _,
866                 } => {
867                     writeln!(
868                         w,
869                         "                DW_CFA_expression ({}, ...)",
870                         register_name(register)
871                     )?;
872                 }
873                 ValExpression {
874                     register,
875                     expression: _,
876                 } => {
877                     writeln!(
878                         w,
879                         "                DW_CFA_val_expression ({}, ...)",
880                         register_name(register)
881                     )?;
882                 }
883                 Restore { register } => {
884                     writeln!(
885                         w,
886                         "                DW_CFA_restore ({})",
887                         register_name(register)
888                     )?;
889                 }
890                 RememberState => {
891                     writeln!(w, "                DW_CFA_remember_state")?;
892                 }
893                 RestoreState => {
894                     writeln!(w, "                DW_CFA_restore_state")?;
895                 }
896                 ArgsSize { size } => {
897                     writeln!(w, "                DW_CFA_GNU_args_size ({})", size)?;
898                 }
899                 Nop => {
900                     writeln!(w, "                DW_CFA_nop")?;
901                 }
902             },
903         }
904     }
905 }
906 
dump_info<R: Reader>(dwarf: &gimli::Dwarf<R>, flags: &Flags) -> Result<()> where R::Endian: Send + Sync,907 fn dump_info<R: Reader>(dwarf: &gimli::Dwarf<R>, flags: &Flags) -> Result<()>
908 where
909     R::Endian: Send + Sync,
910 {
911     let out = io::stdout();
912     writeln!(&mut BufWriter::new(out.lock()), "\n.debug_info")?;
913 
914     let units = match dwarf.units().collect::<Vec<_>>() {
915         Ok(units) => units,
916         Err(err) => {
917             writeln_error(
918                 &mut BufWriter::new(out.lock()),
919                 dwarf,
920                 Error::GimliError(err),
921                 "Failed to read unit headers",
922             )?;
923             return Ok(());
924         }
925     };
926     let process_unit = |header: UnitHeader<R>, buf: &mut Vec<u8>| -> Result<()> {
927         writeln!(
928             buf,
929             "\nUNIT<header overall offset = 0x{:08x}>:",
930             header.offset().as_debug_info_offset().unwrap().0,
931         )?;
932 
933         match header.type_() {
934             UnitType::Compilation | UnitType::Partial => (),
935             UnitType::Type {
936                 type_signature,
937                 type_offset,
938             }
939             | UnitType::SplitType {
940                 type_signature,
941                 type_offset,
942             } => {
943                 write!(buf, "  signature        = ")?;
944                 dump_type_signature(buf, type_signature)?;
945                 writeln!(buf)?;
946                 writeln!(buf, "  typeoffset       = 0x{:08x}", type_offset.0,)?;
947             }
948             UnitType::Skeleton(dwo_id) | UnitType::SplitCompilation(dwo_id) => {
949                 write!(buf, "  dwo_id           = ")?;
950                 writeln!(buf, "0x{:016x}", dwo_id.0)?;
951             }
952         }
953 
954         let unit = match dwarf.unit(header) {
955             Ok(unit) => unit,
956             Err(err) => {
957                 writeln_error(buf, dwarf, err.into(), "Failed to parse unit root entry")?;
958                 return Ok(());
959             }
960         };
961 
962         let entries_result = dump_entries(buf, unit, dwarf, flags);
963         if let Err(err) = entries_result {
964             writeln_error(buf, dwarf, err, "Failed to dump entries")?;
965         }
966         if !flags
967             .match_units
968             .as_ref()
969             .map(|r| r.is_match(&buf))
970             .unwrap_or(true)
971         {
972             buf.clear();
973         }
974         Ok(())
975     };
976     // Don't use more than 16 cores even if available. No point in soaking hundreds
977     // of cores if you happen to have them.
978     parallel_output(16, units, process_unit)
979 }
980 
dump_types<R: Reader, W: Write>( w: &mut W, dwarf: &gimli::Dwarf<R>, flags: &Flags, ) -> Result<()>981 fn dump_types<R: Reader, W: Write>(
982     w: &mut W,
983     dwarf: &gimli::Dwarf<R>,
984     flags: &Flags,
985 ) -> Result<()> {
986     writeln!(w, "\n.debug_types")?;
987 
988     let mut iter = dwarf.type_units();
989     while let Some(header) = iter.next()? {
990         writeln!(
991             w,
992             "\nUNIT<header overall offset = 0x{:08x}>:",
993             header.offset().as_debug_types_offset().unwrap().0,
994         )?;
995         write!(w, "  signature        = ")?;
996         let (type_signature, type_offset) = match header.type_() {
997             UnitType::Type {
998                 type_signature,
999                 type_offset,
1000             } => (type_signature, type_offset),
1001             _ => unreachable!(), // No other units allowed in .debug_types.
1002         };
1003         dump_type_signature(w, type_signature)?;
1004         writeln!(w)?;
1005         writeln!(w, "  typeoffset       = 0x{:08x}", type_offset.0,)?;
1006 
1007         let unit = match dwarf.unit(header) {
1008             Ok(unit) => unit,
1009             Err(err) => {
1010                 writeln_error(w, dwarf, err.into(), "Failed to parse type unit root entry")?;
1011                 continue;
1012             }
1013         };
1014         let entries_result = dump_entries(w, unit, dwarf, flags);
1015         if let Err(err) = entries_result {
1016             writeln_error(w, dwarf, err, "Failed to dump entries")?;
1017         }
1018     }
1019     Ok(())
1020 }
1021 
spaces(buf: &mut String, len: usize) -> &str1022 fn spaces(buf: &mut String, len: usize) -> &str {
1023     while buf.len() < len {
1024         buf.push(' ');
1025     }
1026     &buf[..len]
1027 }
1028 
1029 // " GOFF=0x{:08x}" adds exactly 16 spaces.
1030 const GOFF_SPACES: usize = 16;
1031 
write_offset<R: Reader, W: Write>( w: &mut W, unit: &gimli::Unit<R>, offset: gimli::UnitOffset<R::Offset>, flags: &Flags, ) -> Result<()>1032 fn write_offset<R: Reader, W: Write>(
1033     w: &mut W,
1034     unit: &gimli::Unit<R>,
1035     offset: gimli::UnitOffset<R::Offset>,
1036     flags: &Flags,
1037 ) -> Result<()> {
1038     write!(w, "<0x{:08x}", offset.0)?;
1039     if flags.goff {
1040         let goff = match offset.to_unit_section_offset(unit) {
1041             UnitSectionOffset::DebugInfoOffset(o) => o.0,
1042             UnitSectionOffset::DebugTypesOffset(o) => o.0,
1043         };
1044         write!(w, " GOFF=0x{:08x}", goff)?;
1045     }
1046     write!(w, ">")?;
1047     Ok(())
1048 }
1049 
dump_entries<R: Reader, W: Write>( w: &mut W, unit: gimli::Unit<R>, dwarf: &gimli::Dwarf<R>, flags: &Flags, ) -> Result<()>1050 fn dump_entries<R: Reader, W: Write>(
1051     w: &mut W,
1052     unit: gimli::Unit<R>,
1053     dwarf: &gimli::Dwarf<R>,
1054     flags: &Flags,
1055 ) -> Result<()> {
1056     let mut spaces_buf = String::new();
1057 
1058     let mut depth = 0;
1059     let mut entries = unit.entries();
1060     while let Some((delta_depth, entry)) = entries.next_dfs()? {
1061         depth += delta_depth;
1062         assert!(depth >= 0);
1063         let mut indent = depth as usize * 2 + 2;
1064         write!(w, "<{}{}>", if depth < 10 { " " } else { "" }, depth)?;
1065         write_offset(w, &unit, entry.offset(), flags)?;
1066         writeln!(w, "{}{}", spaces(&mut spaces_buf, indent), entry.tag())?;
1067 
1068         indent += 18;
1069         if flags.goff {
1070             indent += GOFF_SPACES;
1071         }
1072 
1073         let mut attrs = entry.attrs();
1074         while let Some(attr) = attrs.next()? {
1075             w.write_all(spaces(&mut spaces_buf, indent).as_bytes())?;
1076             if let Some(n) = attr.name().static_string() {
1077                 let right_padding = 27 - std::cmp::min(27, n.len());
1078                 write!(w, "{}{} ", n, spaces(&mut spaces_buf, right_padding))?;
1079             } else {
1080                 write!(w, "{:27} ", attr.name())?;
1081             }
1082             if flags.raw {
1083                 writeln!(w, "{:?}", attr.raw_value())?;
1084             } else {
1085                 match dump_attr_value(w, &attr, &unit, dwarf) {
1086                     Ok(_) => (),
1087                     Err(err) => writeln_error(w, dwarf, err, "Failed to dump attribute value")?,
1088                 };
1089             }
1090         }
1091     }
1092     Ok(())
1093 }
1094 
dump_attr_value<R: Reader, W: Write>( w: &mut W, attr: &gimli::Attribute<R>, unit: &gimli::Unit<R>, dwarf: &gimli::Dwarf<R>, ) -> Result<()>1095 fn dump_attr_value<R: Reader, W: Write>(
1096     w: &mut W,
1097     attr: &gimli::Attribute<R>,
1098     unit: &gimli::Unit<R>,
1099     dwarf: &gimli::Dwarf<R>,
1100 ) -> Result<()> {
1101     let value = attr.value();
1102     match value {
1103         gimli::AttributeValue::Addr(address) => {
1104             writeln!(w, "0x{:08x}", address)?;
1105         }
1106         gimli::AttributeValue::Block(data) => {
1107             for byte in data.to_slice()?.iter() {
1108                 write!(w, "{:02x}", byte)?;
1109             }
1110             writeln!(w)?;
1111         }
1112         gimli::AttributeValue::Data1(_)
1113         | gimli::AttributeValue::Data2(_)
1114         | gimli::AttributeValue::Data4(_)
1115         | gimli::AttributeValue::Data8(_) => {
1116             if let (Some(udata), Some(sdata)) = (attr.udata_value(), attr.sdata_value()) {
1117                 if sdata >= 0 {
1118                     writeln!(w, "{}", udata)?;
1119                 } else {
1120                     writeln!(w, "{} ({})", udata, sdata)?;
1121                 }
1122             } else {
1123                 writeln!(w, "{:?}", value)?;
1124             }
1125         }
1126         gimli::AttributeValue::Sdata(data) => {
1127             match attr.name() {
1128                 gimli::DW_AT_data_member_location => {
1129                     writeln!(w, "{}", data)?;
1130                 }
1131                 _ => {
1132                     if data >= 0 {
1133                         writeln!(w, "0x{:08x}", data)?;
1134                     } else {
1135                         writeln!(w, "0x{:08x} ({})", data, data)?;
1136                     }
1137                 }
1138             };
1139         }
1140         gimli::AttributeValue::Udata(data) => {
1141             match attr.name() {
1142                 gimli::DW_AT_high_pc => {
1143                     writeln!(w, "<offset-from-lowpc>{}", data)?;
1144                 }
1145                 gimli::DW_AT_data_member_location => {
1146                     if let Some(sdata) = attr.sdata_value() {
1147                         // This is a DW_FORM_data* value.
1148                         // libdwarf-dwarfdump displays this as signed too.
1149                         if sdata >= 0 {
1150                             writeln!(w, "{}", data)?;
1151                         } else {
1152                             writeln!(w, "{} ({})", data, sdata)?;
1153                         }
1154                     } else {
1155                         writeln!(w, "{}", data)?;
1156                     }
1157                 }
1158                 gimli::DW_AT_lower_bound | gimli::DW_AT_upper_bound => {
1159                     writeln!(w, "{}", data)?;
1160                 }
1161                 _ => {
1162                     writeln!(w, "0x{:08x}", data)?;
1163                 }
1164             };
1165         }
1166         gimli::AttributeValue::Exprloc(ref data) => {
1167             if let gimli::AttributeValue::Exprloc(_) = attr.raw_value() {
1168                 write!(w, "len 0x{:04x}: ", data.0.len())?;
1169                 for byte in data.0.to_slice()?.iter() {
1170                     write!(w, "{:02x}", byte)?;
1171                 }
1172                 write!(w, ": ")?;
1173             }
1174             dump_exprloc(w, unit.encoding(), data)?;
1175             writeln!(w)?;
1176         }
1177         gimli::AttributeValue::Flag(true) => {
1178             writeln!(w, "yes")?;
1179         }
1180         gimli::AttributeValue::Flag(false) => {
1181             writeln!(w, "no")?;
1182         }
1183         gimli::AttributeValue::SecOffset(offset) => {
1184             writeln!(w, "0x{:08x}", offset)?;
1185         }
1186         gimli::AttributeValue::DebugAddrBase(base) => {
1187             writeln!(w, "<.debug_addr+0x{:08x}>", base.0)?;
1188         }
1189         gimli::AttributeValue::DebugAddrIndex(index) => {
1190             write!(w, "(indirect address, index {:#x}): ", index.0)?;
1191             let address = dwarf.address(unit, index)?;
1192             writeln!(w, "0x{:08x}", address)?;
1193         }
1194         gimli::AttributeValue::UnitRef(offset) => {
1195             write!(w, "0x{:08x}", offset.0)?;
1196             match offset.to_unit_section_offset(unit) {
1197                 UnitSectionOffset::DebugInfoOffset(goff) => {
1198                     write!(w, "<.debug_info+0x{:08x}>", goff.0)?;
1199                 }
1200                 UnitSectionOffset::DebugTypesOffset(goff) => {
1201                     write!(w, "<.debug_types+0x{:08x}>", goff.0)?;
1202                 }
1203             }
1204             writeln!(w)?;
1205         }
1206         gimli::AttributeValue::DebugInfoRef(offset) => {
1207             writeln!(w, "<.debug_info+0x{:08x}>", offset.0)?;
1208         }
1209         gimli::AttributeValue::DebugInfoRefSup(offset) => {
1210             writeln!(w, "<.debug_info(sup)+0x{:08x}>", offset.0)?;
1211         }
1212         gimli::AttributeValue::DebugLineRef(offset) => {
1213             writeln!(w, "<.debug_line+0x{:08x}>", offset.0)?;
1214         }
1215         gimli::AttributeValue::LocationListsRef(offset) => {
1216             dump_loc_list(w, offset, unit, dwarf)?;
1217         }
1218         gimli::AttributeValue::DebugLocListsBase(base) => {
1219             writeln!(w, "<.debug_loclists+0x{:08x}>", base.0)?;
1220         }
1221         gimli::AttributeValue::DebugLocListsIndex(index) => {
1222             write!(w, "(indirect location list, index {:#x}): ", index.0)?;
1223             let offset = dwarf.locations_offset(unit, index)?;
1224             dump_loc_list(w, offset, unit, dwarf)?;
1225         }
1226         gimli::AttributeValue::DebugMacinfoRef(offset) => {
1227             writeln!(w, "<.debug_macinfo+0x{:08x}>", offset.0)?;
1228         }
1229         gimli::AttributeValue::DebugMacroRef(offset) => {
1230             writeln!(w, "<.debug_macro+0x{:08x}>", offset.0)?;
1231         }
1232         gimli::AttributeValue::RangeListsRef(offset) => {
1233             dump_range_list(w, offset, unit, dwarf)?;
1234         }
1235         gimli::AttributeValue::DebugRngListsBase(base) => {
1236             writeln!(w, "<.debug_rnglists+0x{:08x}>", base.0)?;
1237         }
1238         gimli::AttributeValue::DebugRngListsIndex(index) => {
1239             write!(w, "(indirect range list, index {:#x}): ", index.0)?;
1240             let offset = dwarf.ranges_offset(unit, index)?;
1241             dump_range_list(w, offset, unit, dwarf)?;
1242         }
1243         gimli::AttributeValue::DebugTypesRef(signature) => {
1244             dump_type_signature(w, signature)?;
1245             writeln!(w, " <type signature>")?;
1246         }
1247         gimli::AttributeValue::DebugStrRef(offset) => {
1248             if let Ok(s) = dwarf.debug_str.get_str(offset) {
1249                 writeln!(w, "{}", s.to_string_lossy()?)?;
1250             } else {
1251                 writeln!(w, "<.debug_str+0x{:08x}>", offset.0)?;
1252             }
1253         }
1254         gimli::AttributeValue::DebugStrRefSup(offset) => {
1255             writeln!(w, "<.debug_str(sup)+0x{:08x}>", offset.0)?;
1256         }
1257         gimli::AttributeValue::DebugStrOffsetsBase(base) => {
1258             writeln!(w, "<.debug_str_offsets+0x{:08x}>", base.0)?;
1259         }
1260         gimli::AttributeValue::DebugStrOffsetsIndex(index) => {
1261             write!(w, "(indirect string, index {:#x}): ", index.0)?;
1262             let offset = dwarf.debug_str_offsets.get_str_offset(
1263                 unit.encoding().format,
1264                 unit.str_offsets_base,
1265                 index,
1266             )?;
1267             if let Ok(s) = dwarf.debug_str.get_str(offset) {
1268                 writeln!(w, "{}", s.to_string_lossy()?)?;
1269             } else {
1270                 writeln!(w, "<.debug_str+0x{:08x}>", offset.0)?;
1271             }
1272         }
1273         gimli::AttributeValue::DebugLineStrRef(offset) => {
1274             if let Ok(s) = dwarf.debug_line_str.get_str(offset) {
1275                 writeln!(w, "{}", s.to_string_lossy()?)?;
1276             } else {
1277                 writeln!(w, "<.debug_line_str=0x{:08x}>", offset.0)?;
1278             }
1279         }
1280         gimli::AttributeValue::String(s) => {
1281             writeln!(w, "{}", s.to_string_lossy()?)?;
1282         }
1283         gimli::AttributeValue::Encoding(value) => {
1284             writeln!(w, "{}", value)?;
1285         }
1286         gimli::AttributeValue::DecimalSign(value) => {
1287             writeln!(w, "{}", value)?;
1288         }
1289         gimli::AttributeValue::Endianity(value) => {
1290             writeln!(w, "{}", value)?;
1291         }
1292         gimli::AttributeValue::Accessibility(value) => {
1293             writeln!(w, "{}", value)?;
1294         }
1295         gimli::AttributeValue::Visibility(value) => {
1296             writeln!(w, "{}", value)?;
1297         }
1298         gimli::AttributeValue::Virtuality(value) => {
1299             writeln!(w, "{}", value)?;
1300         }
1301         gimli::AttributeValue::Language(value) => {
1302             writeln!(w, "{}", value)?;
1303         }
1304         gimli::AttributeValue::AddressClass(value) => {
1305             writeln!(w, "{}", value)?;
1306         }
1307         gimli::AttributeValue::IdentifierCase(value) => {
1308             writeln!(w, "{}", value)?;
1309         }
1310         gimli::AttributeValue::CallingConvention(value) => {
1311             writeln!(w, "{}", value)?;
1312         }
1313         gimli::AttributeValue::Inline(value) => {
1314             writeln!(w, "{}", value)?;
1315         }
1316         gimli::AttributeValue::Ordering(value) => {
1317             writeln!(w, "{}", value)?;
1318         }
1319         gimli::AttributeValue::FileIndex(value) => {
1320             write!(w, "0x{:08x}", value)?;
1321             dump_file_index(w, value, unit, dwarf)?;
1322             writeln!(w)?;
1323         }
1324         gimli::AttributeValue::DwoId(value) => {
1325             writeln!(w, "0x{:016x}", value.0)?;
1326         }
1327     }
1328 
1329     Ok(())
1330 }
1331 
dump_type_signature<W: Write>(w: &mut W, signature: gimli::DebugTypeSignature) -> Result<()>1332 fn dump_type_signature<W: Write>(w: &mut W, signature: gimli::DebugTypeSignature) -> Result<()> {
1333     write!(w, "0x{:016x}", signature.0)?;
1334     Ok(())
1335 }
1336 
dump_file_index<R: Reader, W: Write>( w: &mut W, file: u64, unit: &gimli::Unit<R>, dwarf: &gimli::Dwarf<R>, ) -> Result<()>1337 fn dump_file_index<R: Reader, W: Write>(
1338     w: &mut W,
1339     file: u64,
1340     unit: &gimli::Unit<R>,
1341     dwarf: &gimli::Dwarf<R>,
1342 ) -> Result<()> {
1343     if file == 0 {
1344         return Ok(());
1345     }
1346     let header = match unit.line_program {
1347         Some(ref program) => program.header(),
1348         None => return Ok(()),
1349     };
1350     let file = match header.file(file) {
1351         Some(header) => header,
1352         None => {
1353             writeln!(w, "Unable to get header for file {}", file)?;
1354             return Ok(());
1355         }
1356     };
1357     write!(w, " ")?;
1358     if let Some(directory) = file.directory(header) {
1359         let directory = dwarf.attr_string(unit, directory)?;
1360         let directory = directory.to_string_lossy()?;
1361         if !directory.starts_with('/') {
1362             if let Some(ref comp_dir) = unit.comp_dir {
1363                 write!(w, "{}/", comp_dir.to_string_lossy()?,)?;
1364             }
1365         }
1366         write!(w, "{}/", directory)?;
1367     }
1368     write!(
1369         w,
1370         "{}",
1371         dwarf
1372             .attr_string(unit, file.path_name())?
1373             .to_string_lossy()?
1374     )?;
1375     Ok(())
1376 }
1377 
dump_exprloc<R: Reader, W: Write>( w: &mut W, encoding: gimli::Encoding, data: &gimli::Expression<R>, ) -> Result<()>1378 fn dump_exprloc<R: Reader, W: Write>(
1379     w: &mut W,
1380     encoding: gimli::Encoding,
1381     data: &gimli::Expression<R>,
1382 ) -> Result<()> {
1383     let mut pc = data.0.clone();
1384     let mut space = false;
1385     while pc.len() != 0 {
1386         let mut op_pc = pc.clone();
1387         let dwop = gimli::DwOp(op_pc.read_u8()?);
1388         match gimli::Operation::parse(&mut pc, encoding) {
1389             Ok(op) => {
1390                 if space {
1391                     write!(w, " ")?;
1392                 } else {
1393                     space = true;
1394                 }
1395                 dump_op(w, encoding, dwop, op)?;
1396             }
1397             Err(gimli::Error::InvalidExpression(op)) => {
1398                 writeln!(w, "WARNING: unsupported operation 0x{:02x}", op.0)?;
1399                 return Ok(());
1400             }
1401             Err(gimli::Error::UnsupportedRegister(register)) => {
1402                 writeln!(w, "WARNING: unsupported register {}", register)?;
1403                 return Ok(());
1404             }
1405             Err(gimli::Error::UnexpectedEof(_)) => {
1406                 writeln!(w, "WARNING: truncated or malformed expression")?;
1407                 return Ok(());
1408             }
1409             Err(e) => {
1410                 writeln!(w, "WARNING: unexpected operation parse error: {}", e)?;
1411                 return Ok(());
1412             }
1413         }
1414     }
1415     Ok(())
1416 }
1417 
dump_op<R: Reader, W: Write>( w: &mut W, encoding: gimli::Encoding, dwop: gimli::DwOp, op: gimli::Operation<R>, ) -> Result<()>1418 fn dump_op<R: Reader, W: Write>(
1419     w: &mut W,
1420     encoding: gimli::Encoding,
1421     dwop: gimli::DwOp,
1422     op: gimli::Operation<R>,
1423 ) -> Result<()> {
1424     write!(w, "{}", dwop)?;
1425     match op {
1426         gimli::Operation::Deref {
1427             base_type, size, ..
1428         } => {
1429             if dwop == gimli::DW_OP_deref_size || dwop == gimli::DW_OP_xderef_size {
1430                 write!(w, " {}", size)?;
1431             }
1432             if base_type != UnitOffset(0) {
1433                 write!(w, " type 0x{:08x}", base_type.0)?;
1434             }
1435         }
1436         gimli::Operation::Pick { index } => {
1437             if dwop == gimli::DW_OP_pick {
1438                 write!(w, " {}", index)?;
1439             }
1440         }
1441         gimli::Operation::PlusConstant { value } => {
1442             write!(w, " {}", value as i64)?;
1443         }
1444         gimli::Operation::Bra { target } => {
1445             write!(w, " {}", target)?;
1446         }
1447         gimli::Operation::Skip { target } => {
1448             write!(w, " {}", target)?;
1449         }
1450         gimli::Operation::SignedConstant { value } => match dwop {
1451             gimli::DW_OP_const1s
1452             | gimli::DW_OP_const2s
1453             | gimli::DW_OP_const4s
1454             | gimli::DW_OP_const8s
1455             | gimli::DW_OP_consts => {
1456                 write!(w, " {}", value)?;
1457             }
1458             _ => {}
1459         },
1460         gimli::Operation::UnsignedConstant { value } => match dwop {
1461             gimli::DW_OP_const1u
1462             | gimli::DW_OP_const2u
1463             | gimli::DW_OP_const4u
1464             | gimli::DW_OP_const8u
1465             | gimli::DW_OP_constu => {
1466                 write!(w, " {}", value)?;
1467             }
1468             _ => {
1469                 // These have the value encoded in the operation, eg DW_OP_lit0.
1470             }
1471         },
1472         gimli::Operation::Register { register } => {
1473             if dwop == gimli::DW_OP_regx {
1474                 write!(w, " {}", register.0)?;
1475             }
1476         }
1477         gimli::Operation::RegisterOffset {
1478             register,
1479             offset,
1480             base_type,
1481         } => {
1482             if dwop >= gimli::DW_OP_breg0 && dwop <= gimli::DW_OP_breg31 {
1483                 write!(w, "{:+}", offset)?;
1484             } else {
1485                 write!(w, " {}", register.0)?;
1486                 if offset != 0 {
1487                     write!(w, "{:+}", offset)?;
1488                 }
1489                 if base_type != UnitOffset(0) {
1490                     write!(w, " type 0x{:08x}", base_type.0)?;
1491                 }
1492             }
1493         }
1494         gimli::Operation::FrameOffset { offset } => {
1495             write!(w, " {}", offset)?;
1496         }
1497         gimli::Operation::Call { offset } => match offset {
1498             gimli::DieReference::UnitRef(gimli::UnitOffset(offset)) => {
1499                 write!(w, " 0x{:08x}", offset)?;
1500             }
1501             gimli::DieReference::DebugInfoRef(gimli::DebugInfoOffset(offset)) => {
1502                 write!(w, " 0x{:08x}", offset)?;
1503             }
1504         },
1505         gimli::Operation::Piece {
1506             size_in_bits,
1507             bit_offset: None,
1508         } => {
1509             write!(w, " {}", size_in_bits / 8)?;
1510         }
1511         gimli::Operation::Piece {
1512             size_in_bits,
1513             bit_offset: Some(bit_offset),
1514         } => {
1515             write!(w, " 0x{:08x} offset 0x{:08x}", size_in_bits, bit_offset)?;
1516         }
1517         gimli::Operation::ImplicitValue { data } => {
1518             let data = data.to_slice()?;
1519             write!(w, " 0x{:08x} contents 0x", data.len())?;
1520             for byte in data.iter() {
1521                 write!(w, "{:02x}", byte)?;
1522             }
1523         }
1524         gimli::Operation::ImplicitPointer { value, byte_offset } => {
1525             write!(w, " 0x{:08x} {}", value.0, byte_offset)?;
1526         }
1527         gimli::Operation::EntryValue { expression } => {
1528             write!(w, "(")?;
1529             dump_exprloc(w, encoding, &gimli::Expression(expression))?;
1530             write!(w, ")")?;
1531         }
1532         gimli::Operation::ParameterRef { offset } => {
1533             write!(w, " 0x{:08x}", offset.0)?;
1534         }
1535         gimli::Operation::Address { address } => {
1536             write!(w, " 0x{:08x}", address)?;
1537         }
1538         gimli::Operation::AddressIndex { index } => {
1539             write!(w, " 0x{:08x}", index.0)?;
1540         }
1541         gimli::Operation::ConstantIndex { index } => {
1542             write!(w, " 0x{:08x}", index.0)?;
1543         }
1544         gimli::Operation::TypedLiteral { base_type, value } => {
1545             write!(w, " type 0x{:08x} contents 0x", base_type.0)?;
1546             for byte in value.to_slice()?.iter() {
1547                 write!(w, "{:02x}", byte)?;
1548             }
1549         }
1550         gimli::Operation::Convert { base_type } => {
1551             write!(w, " type 0x{:08x}", base_type.0)?;
1552         }
1553         gimli::Operation::Reinterpret { base_type } => {
1554             write!(w, " type 0x{:08x}", base_type.0)?;
1555         }
1556         gimli::Operation::Drop
1557         | gimli::Operation::Swap
1558         | gimli::Operation::Rot
1559         | gimli::Operation::Abs
1560         | gimli::Operation::And
1561         | gimli::Operation::Div
1562         | gimli::Operation::Minus
1563         | gimli::Operation::Mod
1564         | gimli::Operation::Mul
1565         | gimli::Operation::Neg
1566         | gimli::Operation::Not
1567         | gimli::Operation::Or
1568         | gimli::Operation::Plus
1569         | gimli::Operation::Shl
1570         | gimli::Operation::Shr
1571         | gimli::Operation::Shra
1572         | gimli::Operation::Xor
1573         | gimli::Operation::Eq
1574         | gimli::Operation::Ge
1575         | gimli::Operation::Gt
1576         | gimli::Operation::Le
1577         | gimli::Operation::Lt
1578         | gimli::Operation::Ne
1579         | gimli::Operation::Nop
1580         | gimli::Operation::PushObjectAddress
1581         | gimli::Operation::TLS
1582         | gimli::Operation::CallFrameCFA
1583         | gimli::Operation::StackValue => {}
1584     };
1585     Ok(())
1586 }
1587 
dump_loc_list<R: Reader, W: Write>( w: &mut W, offset: gimli::LocationListsOffset<R::Offset>, unit: &gimli::Unit<R>, dwarf: &gimli::Dwarf<R>, ) -> Result<()>1588 fn dump_loc_list<R: Reader, W: Write>(
1589     w: &mut W,
1590     offset: gimli::LocationListsOffset<R::Offset>,
1591     unit: &gimli::Unit<R>,
1592     dwarf: &gimli::Dwarf<R>,
1593 ) -> Result<()> {
1594     let raw_locations = dwarf.locations.raw_locations(offset, unit.encoding())?;
1595     let raw_locations: Vec<_> = raw_locations.collect()?;
1596     let mut locations = dwarf.locations(unit, offset)?;
1597     writeln!(
1598         w,
1599         "<loclist at {}+0x{:08x} with {} entries>",
1600         if unit.encoding().version < 5 {
1601             ".debug_loc"
1602         } else {
1603             ".debug_loclists"
1604         },
1605         offset.0,
1606         raw_locations.len()
1607     )?;
1608     for (i, raw) in raw_locations.iter().enumerate() {
1609         write!(w, "\t\t\t[{:2}]", i)?;
1610         match *raw {
1611             gimli::RawLocListEntry::BaseAddress { addr } => {
1612                 writeln!(w, "<new base address 0x{:08x}>", addr)?;
1613             }
1614             gimli::RawLocListEntry::BaseAddressx { addr } => {
1615                 let addr_val = dwarf.address(unit, addr)?;
1616                 writeln!(w, "<new base addressx [{}]0x{:08x}>", addr.0, addr_val)?;
1617             }
1618             gimli::RawLocListEntry::StartxEndx {
1619                 begin,
1620                 end,
1621                 ref data,
1622             } => {
1623                 let begin_val = dwarf.address(unit, begin)?;
1624                 let end_val = dwarf.address(unit, end)?;
1625                 let location = locations.next()?.unwrap();
1626                 write!(
1627                     w,
1628                     "<startx-endx \
1629                      low-off: [{}]0x{:08x} addr 0x{:08x} \
1630                      high-off: [{}]0x{:08x} addr 0x{:08x}>",
1631                     begin.0, begin_val, location.range.begin, end.0, end_val, location.range.end
1632                 )?;
1633                 dump_exprloc(w, unit.encoding(), data)?;
1634                 writeln!(w)?;
1635             }
1636             gimli::RawLocListEntry::StartxLength {
1637                 begin,
1638                 length,
1639                 ref data,
1640             } => {
1641                 let begin_val = dwarf.address(unit, begin)?;
1642                 let location = locations.next()?.unwrap();
1643                 write!(
1644                     w,
1645                     "<start-length \
1646                      low-off: [{}]0x{:08x} addr 0x{:08x} \
1647                      high-off: 0x{:08x} addr 0x{:08x}>",
1648                     begin.0, begin_val, location.range.begin, length, location.range.end
1649                 )?;
1650                 dump_exprloc(w, unit.encoding(), data)?;
1651                 writeln!(w)?;
1652             }
1653             gimli::RawLocListEntry::AddressOrOffsetPair {
1654                 begin,
1655                 end,
1656                 ref data,
1657             }
1658             | gimli::RawLocListEntry::OffsetPair {
1659                 begin,
1660                 end,
1661                 ref data,
1662             } => {
1663                 let location = locations.next()?.unwrap();
1664                 write!(
1665                     w,
1666                     "<offset pair \
1667                      low-off: 0x{:08x} addr 0x{:08x} \
1668                      high-off: 0x{:08x} addr 0x{:08x}>",
1669                     begin, location.range.begin, end, location.range.end
1670                 )?;
1671                 dump_exprloc(w, unit.encoding(), data)?;
1672                 writeln!(w)?;
1673             }
1674             gimli::RawLocListEntry::DefaultLocation { ref data } => {
1675                 write!(w, "<default location>")?;
1676                 dump_exprloc(w, unit.encoding(), data)?;
1677                 writeln!(w)?;
1678             }
1679             gimli::RawLocListEntry::StartEnd {
1680                 begin,
1681                 end,
1682                 ref data,
1683             } => {
1684                 let location = locations.next()?.unwrap();
1685                 write!(
1686                     w,
1687                     "<start-end \
1688                      low-off: 0x{:08x} addr 0x{:08x} \
1689                      high-off: 0x{:08x} addr 0x{:08x}>",
1690                     begin, location.range.begin, end, location.range.end
1691                 )?;
1692                 dump_exprloc(w, unit.encoding(), data)?;
1693                 writeln!(w)?;
1694             }
1695             gimli::RawLocListEntry::StartLength {
1696                 begin,
1697                 length,
1698                 ref data,
1699             } => {
1700                 let location = locations.next()?.unwrap();
1701                 write!(
1702                     w,
1703                     "<start-length \
1704                      low-off: 0x{:08x} addr 0x{:08x} \
1705                      high-off: 0x{:08x} addr 0x{:08x}>",
1706                     begin, location.range.begin, length, location.range.end
1707                 )?;
1708                 dump_exprloc(w, unit.encoding(), data)?;
1709                 writeln!(w)?;
1710             }
1711         };
1712     }
1713     Ok(())
1714 }
1715 
dump_range_list<R: Reader, W: Write>( w: &mut W, offset: gimli::RangeListsOffset<R::Offset>, unit: &gimli::Unit<R>, dwarf: &gimli::Dwarf<R>, ) -> Result<()>1716 fn dump_range_list<R: Reader, W: Write>(
1717     w: &mut W,
1718     offset: gimli::RangeListsOffset<R::Offset>,
1719     unit: &gimli::Unit<R>,
1720     dwarf: &gimli::Dwarf<R>,
1721 ) -> Result<()> {
1722     let raw_ranges = dwarf.ranges.raw_ranges(offset, unit.encoding())?;
1723     let raw_ranges: Vec<_> = raw_ranges.collect()?;
1724     let mut ranges = dwarf.ranges(unit, offset)?;
1725     writeln!(
1726         w,
1727         "<rnglist at {}+0x{:08x} with {} entries>",
1728         if unit.encoding().version < 5 {
1729             ".debug_ranges"
1730         } else {
1731             ".debug_rnglists"
1732         },
1733         offset.0,
1734         raw_ranges.len()
1735     )?;
1736     for (i, raw) in raw_ranges.iter().enumerate() {
1737         write!(w, "\t\t\t[{:2}] ", i)?;
1738         match *raw {
1739             gimli::RawRngListEntry::AddressOrOffsetPair { begin, end } => {
1740                 let range = ranges.next()?.unwrap();
1741                 writeln!(
1742                     w,
1743                     "<address pair \
1744                      low-off: 0x{:08x} addr 0x{:08x} \
1745                      high-off: 0x{:08x} addr 0x{:08x}>",
1746                     begin, range.begin, end, range.end
1747                 )?;
1748             }
1749             gimli::RawRngListEntry::BaseAddress { addr } => {
1750                 writeln!(w, "<new base address 0x{:08x}>", addr)?;
1751             }
1752             gimli::RawRngListEntry::BaseAddressx { addr } => {
1753                 let addr_val = dwarf.address(unit, addr)?;
1754                 writeln!(w, "<new base addressx [{}]0x{:08x}>", addr.0, addr_val)?;
1755             }
1756             gimli::RawRngListEntry::StartxEndx { begin, end } => {
1757                 let begin_val = dwarf.address(unit, begin)?;
1758                 let end_val = dwarf.address(unit, end)?;
1759                 let range = if begin_val == end_val {
1760                     gimli::Range {
1761                         begin: begin_val,
1762                         end: end_val,
1763                     }
1764                 } else {
1765                     ranges.next()?.unwrap()
1766                 };
1767                 writeln!(
1768                     w,
1769                     "<startx-endx \
1770                      low-off: [{}]0x{:08x} addr 0x{:08x} \
1771                      high-off: [{}]0x{:08x} addr 0x{:08x}>",
1772                     begin.0, begin_val, range.begin, end.0, end_val, range.end
1773                 )?;
1774             }
1775             gimli::RawRngListEntry::StartxLength { begin, length } => {
1776                 let begin_val = dwarf.address(unit, begin)?;
1777                 let range = ranges.next()?.unwrap();
1778                 writeln!(
1779                     w,
1780                     "<startx-length \
1781                      low-off: [{}]0x{:08x} addr 0x{:08x} \
1782                      high-off: 0x{:08x} addr 0x{:08x}>",
1783                     begin.0, begin_val, range.begin, length, range.end
1784                 )?;
1785             }
1786             gimli::RawRngListEntry::OffsetPair { begin, end } => {
1787                 let range = ranges.next()?.unwrap();
1788                 writeln!(
1789                     w,
1790                     "<offset pair \
1791                      low-off: 0x{:08x} addr 0x{:08x} \
1792                      high-off: 0x{:08x} addr 0x{:08x}>",
1793                     begin, range.begin, end, range.end
1794                 )?;
1795             }
1796             gimli::RawRngListEntry::StartEnd { begin, end } => {
1797                 let range = if begin == end {
1798                     gimli::Range { begin, end }
1799                 } else {
1800                     ranges.next()?.unwrap()
1801                 };
1802                 writeln!(
1803                     w,
1804                     "<start-end \
1805                      low-off: 0x{:08x} addr 0x{:08x} \
1806                      high-off: 0x{:08x} addr 0x{:08x}>",
1807                     begin, range.begin, end, range.end
1808                 )?;
1809             }
1810             gimli::RawRngListEntry::StartLength { begin, length } => {
1811                 let range = ranges.next()?.unwrap();
1812                 writeln!(
1813                     w,
1814                     "<start-length \
1815                      low-off: 0x{:08x} addr 0x{:08x} \
1816                      high-off: 0x{:08x} addr 0x{:08x}>",
1817                     begin, range.begin, length, range.end
1818                 )?;
1819             }
1820         };
1821     }
1822     Ok(())
1823 }
1824 
dump_line<R: Reader, W: Write>(w: &mut W, dwarf: &gimli::Dwarf<R>) -> Result<()>1825 fn dump_line<R: Reader, W: Write>(w: &mut W, dwarf: &gimli::Dwarf<R>) -> Result<()> {
1826     let mut iter = dwarf.units();
1827     while let Some(header) = iter.next()? {
1828         writeln!(
1829             w,
1830             "\n.debug_line: line number info for unit at .debug_info offset 0x{:08x}",
1831             header.offset().as_debug_info_offset().unwrap().0
1832         )?;
1833         let unit = match dwarf.unit(header) {
1834             Ok(unit) => unit,
1835             Err(err) => {
1836                 writeln_error(
1837                     w,
1838                     dwarf,
1839                     err.into(),
1840                     "Failed to parse unit root entry for dump_line",
1841                 )?;
1842                 continue;
1843             }
1844         };
1845         match dump_line_program(w, &unit, dwarf) {
1846             Ok(_) => (),
1847             Err(Error::IoError) => return Err(Error::IoError),
1848             Err(err) => writeln_error(w, dwarf, err, "Failed to dump line program")?,
1849         }
1850     }
1851     Ok(())
1852 }
1853 
dump_line_program<R: Reader, W: Write>( w: &mut W, unit: &gimli::Unit<R>, dwarf: &gimli::Dwarf<R>, ) -> Result<()>1854 fn dump_line_program<R: Reader, W: Write>(
1855     w: &mut W,
1856     unit: &gimli::Unit<R>,
1857     dwarf: &gimli::Dwarf<R>,
1858 ) -> Result<()> {
1859     if let Some(program) = unit.line_program.clone() {
1860         {
1861             let header = program.header();
1862             writeln!(w)?;
1863             writeln!(
1864                 w,
1865                 "Offset:                             0x{:x}",
1866                 header.offset().0
1867             )?;
1868             writeln!(
1869                 w,
1870                 "Length:                             {}",
1871                 header.unit_length()
1872             )?;
1873             writeln!(
1874                 w,
1875                 "DWARF version:                      {}",
1876                 header.version()
1877             )?;
1878             writeln!(
1879                 w,
1880                 "Address size:                       {}",
1881                 header.address_size()
1882             )?;
1883             writeln!(
1884                 w,
1885                 "Prologue length:                    {}",
1886                 header.header_length()
1887             )?;
1888             writeln!(
1889                 w,
1890                 "Minimum instruction length:         {}",
1891                 header.minimum_instruction_length()
1892             )?;
1893             writeln!(
1894                 w,
1895                 "Maximum operations per instruction: {}",
1896                 header.maximum_operations_per_instruction()
1897             )?;
1898             writeln!(
1899                 w,
1900                 "Default is_stmt:                    {}",
1901                 header.default_is_stmt()
1902             )?;
1903             writeln!(
1904                 w,
1905                 "Line base:                          {}",
1906                 header.line_base()
1907             )?;
1908             writeln!(
1909                 w,
1910                 "Line range:                         {}",
1911                 header.line_range()
1912             )?;
1913             writeln!(
1914                 w,
1915                 "Opcode base:                        {}",
1916                 header.opcode_base()
1917             )?;
1918 
1919             writeln!(w)?;
1920             writeln!(w, "Opcodes:")?;
1921             for (i, length) in header
1922                 .standard_opcode_lengths()
1923                 .to_slice()?
1924                 .iter()
1925                 .enumerate()
1926             {
1927                 writeln!(w, "  Opcode {} has {} args", i + 1, length)?;
1928             }
1929 
1930             let base = if header.version() >= 5 { 0 } else { 1 };
1931             writeln!(w)?;
1932             writeln!(w, "The Directory Table:")?;
1933             for (i, dir) in header.include_directories().iter().enumerate() {
1934                 writeln!(
1935                     w,
1936                     "  {} {}",
1937                     base + i,
1938                     dwarf.attr_string(unit, dir.clone())?.to_string_lossy()?
1939                 )?;
1940             }
1941 
1942             writeln!(w)?;
1943             writeln!(w, "The File Name Table")?;
1944             write!(w, "  Entry\tDir\tTime\tSize")?;
1945             if header.file_has_md5() {
1946                 write!(w, "\tMD5\t\t\t\t")?;
1947             }
1948             writeln!(w, "\tName")?;
1949             for (i, file) in header.file_names().iter().enumerate() {
1950                 write!(
1951                     w,
1952                     "  {}\t{}\t{}\t{}",
1953                     base + i,
1954                     file.directory_index(),
1955                     file.timestamp(),
1956                     file.size(),
1957                 )?;
1958                 if header.file_has_md5() {
1959                     let md5 = file.md5();
1960                     write!(w, "\t")?;
1961                     for i in 0..16 {
1962                         write!(w, "{:02X}", md5[i])?;
1963                     }
1964                 }
1965                 writeln!(
1966                     w,
1967                     "\t{}",
1968                     dwarf
1969                         .attr_string(unit, file.path_name())?
1970                         .to_string_lossy()?
1971                 )?;
1972             }
1973 
1974             writeln!(w)?;
1975             writeln!(w, "Line Number Instructions:")?;
1976             let mut instructions = header.instructions();
1977             while let Some(instruction) = instructions.next_instruction(header)? {
1978                 writeln!(w, "  {}", instruction)?;
1979             }
1980 
1981             writeln!(w)?;
1982             writeln!(w, "Line Number Rows:")?;
1983             writeln!(w, "<pc>        [lno,col]")?;
1984         }
1985         let mut rows = program.rows();
1986         let mut file_index = 0;
1987         while let Some((header, row)) = rows.next_row()? {
1988             let line = row.line().unwrap_or(0);
1989             let column = match row.column() {
1990                 gimli::ColumnType::Column(column) => column,
1991                 gimli::ColumnType::LeftEdge => 0,
1992             };
1993             write!(w, "0x{:08x}  [{:4},{:2}]", row.address(), line, column)?;
1994             if row.is_stmt() {
1995                 write!(w, " NS")?;
1996             }
1997             if row.basic_block() {
1998                 write!(w, " BB")?;
1999             }
2000             if row.end_sequence() {
2001                 write!(w, " ET")?;
2002             }
2003             if row.prologue_end() {
2004                 write!(w, " PE")?;
2005             }
2006             if row.epilogue_begin() {
2007                 write!(w, " EB")?;
2008             }
2009             if row.isa() != 0 {
2010                 write!(w, " IS={}", row.isa())?;
2011             }
2012             if row.discriminator() != 0 {
2013                 write!(w, " DI={}", row.discriminator())?;
2014             }
2015             if file_index != row.file_index() {
2016                 file_index = row.file_index();
2017                 if let Some(file) = row.file(header) {
2018                     if let Some(directory) = file.directory(header) {
2019                         write!(
2020                             w,
2021                             " uri: \"{}/{}\"",
2022                             dwarf.attr_string(unit, directory)?.to_string_lossy()?,
2023                             dwarf
2024                                 .attr_string(unit, file.path_name())?
2025                                 .to_string_lossy()?
2026                         )?;
2027                     } else {
2028                         write!(
2029                             w,
2030                             " uri: \"{}\"",
2031                             dwarf
2032                                 .attr_string(unit, file.path_name())?
2033                                 .to_string_lossy()?
2034                         )?;
2035                     }
2036                 }
2037             }
2038             writeln!(w)?;
2039         }
2040     }
2041     Ok(())
2042 }
2043 
dump_pubnames<R: Reader, W: Write>( w: &mut W, debug_pubnames: &gimli::DebugPubNames<R>, debug_info: &gimli::DebugInfo<R>, ) -> Result<()>2044 fn dump_pubnames<R: Reader, W: Write>(
2045     w: &mut W,
2046     debug_pubnames: &gimli::DebugPubNames<R>,
2047     debug_info: &gimli::DebugInfo<R>,
2048 ) -> Result<()> {
2049     writeln!(w, "\n.debug_pubnames")?;
2050 
2051     let mut cu_offset;
2052     let mut cu_die_offset = gimli::DebugInfoOffset(0);
2053     let mut prev_cu_offset = None;
2054     let mut pubnames = debug_pubnames.items();
2055     while let Some(pubname) = pubnames.next()? {
2056         cu_offset = pubname.unit_header_offset();
2057         if Some(cu_offset) != prev_cu_offset {
2058             let cu = debug_info.header_from_offset(cu_offset)?;
2059             cu_die_offset = gimli::DebugInfoOffset(cu_offset.0 + cu.header_size());
2060             prev_cu_offset = Some(cu_offset);
2061         }
2062         let die_in_cu = pubname.die_offset();
2063         let die_in_sect = cu_offset.0 + die_in_cu.0;
2064         writeln!(w,
2065             "global die-in-sect 0x{:08x}, cu-in-sect 0x{:08x}, die-in-cu 0x{:08x}, cu-header-in-sect 0x{:08x} '{}'",
2066             die_in_sect,
2067             cu_die_offset.0,
2068             die_in_cu.0,
2069             cu_offset.0,
2070             pubname.name().to_string_lossy()?
2071         )?;
2072     }
2073     Ok(())
2074 }
2075 
dump_pubtypes<R: Reader, W: Write>( w: &mut W, debug_pubtypes: &gimli::DebugPubTypes<R>, debug_info: &gimli::DebugInfo<R>, ) -> Result<()>2076 fn dump_pubtypes<R: Reader, W: Write>(
2077     w: &mut W,
2078     debug_pubtypes: &gimli::DebugPubTypes<R>,
2079     debug_info: &gimli::DebugInfo<R>,
2080 ) -> Result<()> {
2081     writeln!(w, "\n.debug_pubtypes")?;
2082 
2083     let mut cu_offset;
2084     let mut cu_die_offset = gimli::DebugInfoOffset(0);
2085     let mut prev_cu_offset = None;
2086     let mut pubtypes = debug_pubtypes.items();
2087     while let Some(pubtype) = pubtypes.next()? {
2088         cu_offset = pubtype.unit_header_offset();
2089         if Some(cu_offset) != prev_cu_offset {
2090             let cu = debug_info.header_from_offset(cu_offset)?;
2091             cu_die_offset = gimli::DebugInfoOffset(cu_offset.0 + cu.header_size());
2092             prev_cu_offset = Some(cu_offset);
2093         }
2094         let die_in_cu = pubtype.die_offset();
2095         let die_in_sect = cu_offset.0 + die_in_cu.0;
2096         writeln!(w,
2097             "pubtype die-in-sect 0x{:08x}, cu-in-sect 0x{:08x}, die-in-cu 0x{:08x}, cu-header-in-sect 0x{:08x} '{}'",
2098             die_in_sect,
2099             cu_die_offset.0,
2100             die_in_cu.0,
2101             cu_offset.0,
2102             pubtype.name().to_string_lossy()?
2103         )?;
2104     }
2105     Ok(())
2106 }
2107 
dump_aranges<R: Reader, W: Write>( w: &mut W, debug_aranges: &gimli::DebugAranges<R>, debug_info: &gimli::DebugInfo<R>, ) -> Result<()>2108 fn dump_aranges<R: Reader, W: Write>(
2109     w: &mut W,
2110     debug_aranges: &gimli::DebugAranges<R>,
2111     debug_info: &gimli::DebugInfo<R>,
2112 ) -> Result<()> {
2113     writeln!(w, "\n.debug_aranges")?;
2114 
2115     let mut cu_die_offset = gimli::DebugInfoOffset(0);
2116     let mut prev_cu_offset = None;
2117     let mut aranges = debug_aranges.items();
2118     while let Some(arange) = aranges.next()? {
2119         let cu_offset = arange.debug_info_offset();
2120         if Some(cu_offset) != prev_cu_offset {
2121             let cu = debug_info.header_from_offset(cu_offset)?;
2122             cu_die_offset = gimli::DebugInfoOffset(cu_offset.0 + cu.header_size());
2123             prev_cu_offset = Some(cu_offset);
2124         }
2125         if let Some(segment) = arange.segment() {
2126             write!(
2127                 w,
2128                 "arange starts at seg,off 0x{:08x},0x{:08x}, ",
2129                 segment,
2130                 arange.address()
2131             )?;
2132         } else {
2133             write!(w, "arange starts at 0x{:08x}, ", arange.address())?;
2134         }
2135         writeln!(
2136             w,
2137             "length of 0x{:08x}, cu_die_offset = 0x{:08x}",
2138             arange.length(),
2139             cu_die_offset.0
2140         )?;
2141     }
2142     Ok(())
2143 }
2144