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