]> git.proxmox.com Git - rustc.git/blame - vendor/gimli-0.26.2/examples/dwarfdump.rs
New upstream version 1.72.1+dfsg1
[rustc.git] / vendor / gimli-0.26.2 / examples / dwarfdump.rs
CommitLineData
9ffffee4
FG
1// Allow clippy lints when building without clippy.
2#![allow(unknown_lints)]
3
4use fallible_iterator::FallibleIterator;
5use gimli::{Section, UnitHeader, UnitOffset, UnitSectionOffset, UnitType, UnwindSection};
6use object::{Object, ObjectSection, ObjectSymbol};
7use regex::bytes::Regex;
8use std::borrow::{Borrow, Cow};
9use std::cmp::min;
10use std::collections::HashMap;
11use std::env;
12use std::fmt::{self, Debug};
13use std::fs;
14use std::io;
15use std::io::{BufWriter, Write};
16use std::iter::Iterator;
17use std::mem;
18use std::process;
19use std::result;
20use std::sync::{Condvar, Mutex};
21use typed_arena::Arena;
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub enum Error {
25 GimliError(gimli::Error),
26 ObjectError(object::read::Error),
27 IoError,
28}
29
30impl fmt::Display for Error {
31 #[inline]
32 fn fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
33 Debug::fmt(self, f)
34 }
35}
36
37fn 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
56impl From<gimli::Error> for Error {
57 fn from(err: gimli::Error) -> Self {
58 Error::GimliError(err)
59 }
60}
61
62impl From<io::Error> for Error {
63 fn from(_: io::Error) -> Self {
64 Error::IoError
65 }
66}
67
68impl From<object::read::Error> for Error {
69 fn from(err: object::read::Error) -> Self {
70 Error::ObjectError(err)
71 }
72}
73
74pub type Result<T> = result::Result<T, Error>;
75
76fn parallel_output<W, II, F>(w: &mut W, max_workers: usize, iter: II, f: F) -> Result<()>
77where
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
151trait Reader: gimli::Reader<Offset = usize> + Send + Sync {}
152
153impl<'input, Endian> Reader for gimli::EndianSlice<'input, Endian> where
154 Endian: gimli::Endianity + Send + Sync
155{
156}
157
158type RelocationMap = HashMap<usize, object::Relocation>;
159
160fn 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)]
222struct Relocate<'a, R: gimli::Reader<Offset = usize>> {
223 relocations: &'a RelocationMap,
224 section: R,
225 reader: R,
226}
227
228impl<'a, R: gimli::Reader<Offset = usize>> Relocate<'a, R> {
229 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
247impl<'a, R: gimli::Reader<Offset = usize>> gimli::Reader for Relocate<'a, R> {
248 type Endian = R::Endian;
249 type Offset = R::Offset;
250
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
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
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
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]
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]
286 fn endian(&self) -> Self::Endian {
287 self.reader.endian()
288 }
289
290 #[inline]
291 fn len(&self) -> Self::Offset {
292 self.reader.len()
293 }
294
295 #[inline]
296 fn empty(&mut self) {
297 self.reader.empty()
298 }
299
300 #[inline]
301 fn truncate(&mut self, len: Self::Offset) -> gimli::Result<()> {
302 self.reader.truncate(len)
303 }
304
305 #[inline]
306 fn offset_from(&self, base: &Self) -> Self::Offset {
307 self.reader.offset_from(&base.reader)
308 }
309
310 #[inline]
311 fn offset_id(&self) -> gimli::ReaderOffsetId {
312 self.reader.offset_id()
313 }
314
315 #[inline]
316 fn lookup_offset_id(&self, id: gimli::ReaderOffsetId) -> Option<Self::Offset> {
317 self.reader.lookup_offset_id(id)
318 }
319
320 #[inline]
321 fn find(&self, byte: u8) -> gimli::Result<Self::Offset> {
322 self.reader.find(byte)
323 }
324
325 #[inline]
326 fn skip(&mut self, len: Self::Offset) -> gimli::Result<()> {
327 self.reader.skip(len)
328 }
329
330 #[inline]
331 fn to_slice(&self) -> gimli::Result<Cow<[u8]>> {
332 self.reader.to_slice()
333 }
334
335 #[inline]
336 fn to_string(&self) -> gimli::Result<Cow<str>> {
337 self.reader.to_string()
338 }
339
340 #[inline]
341 fn to_string_lossy(&self) -> gimli::Result<Cow<str>> {
342 self.reader.to_string_lossy()
343 }
344
345 #[inline]
346 fn read_slice(&mut self, buf: &mut [u8]) -> gimli::Result<()> {
347 self.reader.read_slice(buf)
348 }
349}
350
351impl<'a, R: Reader> Reader for Relocate<'a, R> {}
352
353#[derive(Default)]
354struct 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
370fn 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
376fn 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 { memmap2::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 { memmap2::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
562fn 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
577fn 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
614fn dump_file<Endian>(file: &object::File, endian: Endian, flags: &Flags) -> Result<()>
615where
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
725fn 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!(
790 w,
791 " ra_register: {}",
792 register_name(cie.return_address_register())
793 )?;
794 if let Some(encoding) = cie.lsda_encoding() {
795 writeln!(
796 w,
797 " lsda_encoding: {}/{}",
798 encoding.application(),
799 encoding.format()
800 )?;
801 }
802 if let Some((encoding, personality)) = cie.personality_with_encoding() {
803 write!(
804 w,
805 " personality: {}/{} ",
806 encoding.application(),
807 encoding.format()
808 )?;
809 dump_pointer(w, personality)?;
810 writeln!(w)?;
811 }
812 if let Some(encoding) = cie.fde_address_encoding() {
813 writeln!(
814 w,
815 " fde_encoding: {}/{}",
816 encoding.application(),
817 encoding.format()
818 )?;
819 }
820 let instructions = cie.instructions(&eh_frame, &bases);
821 dump_cfi_instructions(w, instructions, true, register_name)?;
822 writeln!(w)?;
823 }
824 Some(gimli::CieOrFde::Fde(partial)) => {
825 let mut offset = None;
826 let fde = partial.parse(|_, bases, o| {
827 offset = Some(o);
828 cies.entry(o)
829 .or_insert_with(|| eh_frame.cie_from_offset(bases, o))
830 .clone()
831 })?;
832
833 writeln!(w)?;
834 writeln!(w, "{:#010x}: FDE", fde.offset())?;
835 writeln!(w, " length: {:#010x}", fde.entry_len())?;
836 writeln!(w, " CIE_pointer: {:#010x}", offset.unwrap().0)?;
837 // TODO: symbolicate the start address like the canonical dwarfdump does.
838 writeln!(w, " start_addr: {:#018x}", fde.initial_address())?;
839 writeln!(
840 w,
841 " range_size: {:#018x} (end_addr = {:#018x})",
842 fde.len(),
843 fde.initial_address() + fde.len()
844 )?;
845 if let Some(lsda) = fde.lsda() {
846 write!(w, " lsda: ")?;
847 dump_pointer(w, lsda)?;
848 writeln!(w)?;
849 }
850 let instructions = fde.instructions(&eh_frame, &bases);
851 dump_cfi_instructions(w, instructions, false, register_name)?;
852 writeln!(w)?;
853 }
854 }
855 }
856}
857
858fn dump_pointer<W: Write>(w: &mut W, p: gimli::Pointer) -> Result<()> {
859 match p {
860 gimli::Pointer::Direct(p) => {
861 write!(w, "{:#018x}", p)?;
862 }
863 gimli::Pointer::Indirect(p) => {
864 write!(w, "({:#018x})", p)?;
865 }
866 }
867 Ok(())
868}
869
870#[allow(clippy::unneeded_field_pattern)]
871fn dump_cfi_instructions<R: Reader, W: Write>(
872 w: &mut W,
873 mut insns: gimli::CallFrameInstructionIter<R>,
874 is_initial: bool,
875 register_name: &dyn Fn(gimli::Register) -> Cow<'static, str>,
876) -> Result<()> {
877 use gimli::CallFrameInstruction::*;
878
879 // TODO: we need to actually evaluate these instructions as we iterate them
880 // so we can print the initialized state for CIEs, and each unwind row's
881 // registers for FDEs.
882 //
883 // TODO: We should print DWARF expressions for the CFI instructions that
884 // embed DWARF expressions within themselves.
885
886 if !is_initial {
887 writeln!(w, " Instructions:")?;
888 }
889
890 loop {
891 match insns.next() {
892 Err(e) => {
893 writeln!(w, "Failed to decode CFI instruction: {}", e)?;
894 return Ok(());
895 }
896 Ok(None) => {
897 if is_initial {
898 writeln!(w, " Instructions: Init State:")?;
899 }
900 return Ok(());
901 }
902 Ok(Some(op)) => match op {
903 SetLoc { address } => {
904 writeln!(w, " DW_CFA_set_loc ({:#x})", address)?;
905 }
906 AdvanceLoc { delta } => {
907 writeln!(w, " DW_CFA_advance_loc ({})", delta)?;
908 }
909 DefCfa { register, offset } => {
910 writeln!(
911 w,
912 " DW_CFA_def_cfa ({}, {})",
913 register_name(register),
914 offset
915 )?;
916 }
917 DefCfaSf {
918 register,
919 factored_offset,
920 } => {
921 writeln!(
922 w,
923 " DW_CFA_def_cfa_sf ({}, {})",
924 register_name(register),
925 factored_offset
926 )?;
927 }
928 DefCfaRegister { register } => {
929 writeln!(
930 w,
931 " DW_CFA_def_cfa_register ({})",
932 register_name(register)
933 )?;
934 }
935 DefCfaOffset { offset } => {
936 writeln!(w, " DW_CFA_def_cfa_offset ({})", offset)?;
937 }
938 DefCfaOffsetSf { factored_offset } => {
939 writeln!(
940 w,
941 " DW_CFA_def_cfa_offset_sf ({})",
942 factored_offset
943 )?;
944 }
945 DefCfaExpression { expression: _ } => {
946 writeln!(w, " DW_CFA_def_cfa_expression (...)")?;
947 }
948 Undefined { register } => {
949 writeln!(
950 w,
951 " DW_CFA_undefined ({})",
952 register_name(register)
953 )?;
954 }
955 SameValue { register } => {
956 writeln!(
957 w,
958 " DW_CFA_same_value ({})",
959 register_name(register)
960 )?;
961 }
962 Offset {
963 register,
964 factored_offset,
965 } => {
966 writeln!(
967 w,
968 " DW_CFA_offset ({}, {})",
969 register_name(register),
970 factored_offset
971 )?;
972 }
973 OffsetExtendedSf {
974 register,
975 factored_offset,
976 } => {
977 writeln!(
978 w,
979 " DW_CFA_offset_extended_sf ({}, {})",
980 register_name(register),
981 factored_offset
982 )?;
983 }
984 ValOffset {
985 register,
986 factored_offset,
987 } => {
988 writeln!(
989 w,
990 " DW_CFA_val_offset ({}, {})",
991 register_name(register),
992 factored_offset
993 )?;
994 }
995 ValOffsetSf {
996 register,
997 factored_offset,
998 } => {
999 writeln!(
1000 w,
1001 " DW_CFA_val_offset_sf ({}, {})",
1002 register_name(register),
1003 factored_offset
1004 )?;
1005 }
1006 Register {
1007 dest_register,
1008 src_register,
1009 } => {
1010 writeln!(
1011 w,
1012 " DW_CFA_register ({}, {})",
1013 register_name(dest_register),
1014 register_name(src_register)
1015 )?;
1016 }
1017 Expression {
1018 register,
1019 expression: _,
1020 } => {
1021 writeln!(
1022 w,
1023 " DW_CFA_expression ({}, ...)",
1024 register_name(register)
1025 )?;
1026 }
1027 ValExpression {
1028 register,
1029 expression: _,
1030 } => {
1031 writeln!(
1032 w,
1033 " DW_CFA_val_expression ({}, ...)",
1034 register_name(register)
1035 )?;
1036 }
1037 Restore { register } => {
1038 writeln!(
1039 w,
1040 " DW_CFA_restore ({})",
1041 register_name(register)
1042 )?;
1043 }
1044 RememberState => {
1045 writeln!(w, " DW_CFA_remember_state")?;
1046 }
1047 RestoreState => {
1048 writeln!(w, " DW_CFA_restore_state")?;
1049 }
1050 ArgsSize { size } => {
1051 writeln!(w, " DW_CFA_GNU_args_size ({})", size)?;
1052 }
1053 Nop => {
1054 writeln!(w, " DW_CFA_nop")?;
1055 }
1056 },
1057 }
1058 }
1059}
1060
1061fn dump_dwp<R: Reader, W: Write + Send>(
1062 w: &mut W,
1063 dwp: &gimli::DwarfPackage<R>,
1064 dwo_parent: &gimli::Dwarf<R>,
1065 dwo_parent_units: Option<&HashMap<gimli::DwoId, gimli::Unit<R>>>,
1066 flags: &Flags,
1067) -> Result<()>
1068where
1069 R::Endian: Send + Sync,
1070{
1071 if dwp.cu_index.unit_count() != 0 {
1072 writeln!(
1073 w,
1074 "\n.debug_cu_index: version = {}, sections = {}, units = {}, slots = {}",
1075 dwp.cu_index.version(),
1076 dwp.cu_index.section_count(),
1077 dwp.cu_index.unit_count(),
1078 dwp.cu_index.slot_count(),
1079 )?;
1080 for i in 1..=dwp.cu_index.unit_count() {
1081 writeln!(w, "\nCU index {}", i)?;
1082 dump_dwp_sections(
1083 w,
1084 &dwp,
1085 dwo_parent,
1086 dwo_parent_units,
1087 flags,
1088 dwp.cu_index.sections(i)?,
1089 )?;
1090 }
1091 }
1092
1093 if dwp.tu_index.unit_count() != 0 {
1094 writeln!(
1095 w,
1096 "\n.debug_tu_index: version = {}, sections = {}, units = {}, slots = {}",
1097 dwp.tu_index.version(),
1098 dwp.tu_index.section_count(),
1099 dwp.tu_index.unit_count(),
1100 dwp.tu_index.slot_count(),
1101 )?;
1102 for i in 1..=dwp.tu_index.unit_count() {
1103 writeln!(w, "\nTU index {}", i)?;
1104 dump_dwp_sections(
1105 w,
1106 &dwp,
1107 dwo_parent,
1108 dwo_parent_units,
1109 flags,
1110 dwp.tu_index.sections(i)?,
1111 )?;
1112 }
1113 }
1114
1115 Ok(())
1116}
1117
1118fn dump_dwp_sections<R: Reader, W: Write + Send>(
1119 w: &mut W,
1120 dwp: &gimli::DwarfPackage<R>,
1121 dwo_parent: &gimli::Dwarf<R>,
1122 dwo_parent_units: Option<&HashMap<gimli::DwoId, gimli::Unit<R>>>,
1123 flags: &Flags,
1124 sections: gimli::UnitIndexSectionIterator<R>,
1125) -> Result<()>
1126where
1127 R::Endian: Send + Sync,
1128{
1129 for section in sections.clone() {
1130 writeln!(
1131 w,
1132 " {}: offset = 0x{:x}, size = 0x{:x}",
1133 section.section.dwo_name().unwrap(),
1134 section.offset,
1135 section.size
1136 )?;
1137 }
1138 let dwarf = dwp.sections(sections, dwo_parent)?;
1139 if flags.info {
1140 dump_info(w, &dwarf, dwo_parent_units, flags)?;
1141 dump_types(w, &dwarf, dwo_parent_units, flags)?;
1142 }
1143 if flags.line {
1144 dump_line(w, &dwarf)?;
1145 }
1146 Ok(())
1147}
1148
1149fn dump_info<R: Reader, W: Write + Send>(
1150 w: &mut W,
1151 dwarf: &gimli::Dwarf<R>,
1152 dwo_parent_units: Option<&HashMap<gimli::DwoId, gimli::Unit<R>>>,
1153 flags: &Flags,
1154) -> Result<()>
1155where
1156 R::Endian: Send + Sync,
1157{
1158 writeln!(w, "\n.debug_info")?;
1159
1160 let units = match dwarf.units().collect::<Vec<_>>() {
1161 Ok(units) => units,
1162 Err(err) => {
1163 writeln_error(
1164 w,
1165 dwarf,
1166 Error::GimliError(err),
1167 "Failed to read unit headers",
1168 )?;
1169 return Ok(());
1170 }
1171 };
1172 let process_unit = |header: UnitHeader<R>, buf: &mut Vec<u8>| -> Result<()> {
1173 dump_unit(buf, header, dwarf, dwo_parent_units, flags)?;
1174 if !flags
1175 .match_units
1176 .as_ref()
1177 .map(|r| r.is_match(&buf))
1178 .unwrap_or(true)
1179 {
1180 buf.clear();
1181 }
1182 Ok(())
1183 };
1184 // Don't use more than 16 cores even if available. No point in soaking hundreds
1185 // of cores if you happen to have them.
1186 parallel_output(w, 16, units, process_unit)
1187}
1188
1189fn dump_types<R: Reader, W: Write>(
1190 w: &mut W,
1191 dwarf: &gimli::Dwarf<R>,
1192 dwo_parent_units: Option<&HashMap<gimli::DwoId, gimli::Unit<R>>>,
1193 flags: &Flags,
1194) -> Result<()> {
1195 writeln!(w, "\n.debug_types")?;
1196
1197 let mut iter = dwarf.type_units();
1198 while let Some(header) = iter.next()? {
1199 dump_unit(w, header, dwarf, dwo_parent_units, flags)?;
1200 }
1201 Ok(())
1202}
1203
1204fn dump_unit<R: Reader, W: Write>(
1205 w: &mut W,
1206 header: UnitHeader<R>,
1207 dwarf: &gimli::Dwarf<R>,
1208 dwo_parent_units: Option<&HashMap<gimli::DwoId, gimli::Unit<R>>>,
1209 flags: &Flags,
1210) -> Result<()> {
1211 write!(w, "\nUNIT<")?;
1212 match header.offset() {
1213 UnitSectionOffset::DebugInfoOffset(o) => {
1214 write!(w, ".debug_info+0x{:08x}", o.0)?;
1215 }
1216 UnitSectionOffset::DebugTypesOffset(o) => {
1217 write!(w, ".debug_types+0x{:08x}", o.0)?;
1218 }
1219 }
1220 writeln!(w, ">: length = 0x{:x}, format = {:?}, version = {}, address_size = {}, abbrev_offset = 0x{:x}",
1221 header.unit_length(),
1222 header.format(),
1223 header.version(),
1224 header.address_size(),
1225 header.debug_abbrev_offset().0,
1226 )?;
1227
1228 match header.type_() {
1229 UnitType::Compilation | UnitType::Partial => (),
1230 UnitType::Type {
1231 type_signature,
1232 type_offset,
1233 }
1234 | UnitType::SplitType {
1235 type_signature,
1236 type_offset,
1237 } => {
1238 write!(w, " signature = ")?;
1239 dump_type_signature(w, type_signature)?;
1240 writeln!(w)?;
1241 writeln!(w, " type_offset = 0x{:x}", type_offset.0,)?;
1242 }
1243 UnitType::Skeleton(dwo_id) | UnitType::SplitCompilation(dwo_id) => {
1244 write!(w, " dwo_id = ")?;
1245 writeln!(w, "0x{:016x}", dwo_id.0)?;
1246 }
1247 }
1248
1249 let mut unit = match dwarf.unit(header) {
1250 Ok(unit) => unit,
1251 Err(err) => {
1252 writeln_error(w, dwarf, err.into(), "Failed to parse unit root entry")?;
1253 return Ok(());
1254 }
1255 };
1256
1257 if let Some(dwo_parent_units) = dwo_parent_units {
1258 if let Some(dwo_id) = unit.dwo_id {
1259 if let Some(parent_unit) = dwo_parent_units.get(&dwo_id) {
1260 unit.copy_relocated_attributes(parent_unit);
1261 }
1262 }
1263 }
1264
1265 let entries_result = dump_entries(w, unit, dwarf, flags);
1266 if let Err(err) = entries_result {
1267 writeln_error(w, dwarf, err, "Failed to dump entries")?;
1268 }
1269 Ok(())
1270}
1271
1272fn spaces(buf: &mut String, len: usize) -> &str {
1273 while buf.len() < len {
1274 buf.push(' ');
1275 }
1276 &buf[..len]
1277}
1278
1279// " GOFF=0x{:08x}" adds exactly 16 spaces.
1280const GOFF_SPACES: usize = 16;
1281
1282fn write_offset<R: Reader, W: Write>(
1283 w: &mut W,
1284 unit: &gimli::Unit<R>,
1285 offset: gimli::UnitOffset<R::Offset>,
1286 flags: &Flags,
1287) -> Result<()> {
1288 write!(w, "<0x{:08x}", offset.0)?;
1289 if flags.goff {
1290 let goff = match offset.to_unit_section_offset(unit) {
1291 UnitSectionOffset::DebugInfoOffset(o) => o.0,
1292 UnitSectionOffset::DebugTypesOffset(o) => o.0,
1293 };
1294 write!(w, " GOFF=0x{:08x}", goff)?;
1295 }
1296 write!(w, ">")?;
1297 Ok(())
1298}
1299
1300fn dump_entries<R: Reader, W: Write>(
1301 w: &mut W,
1302 unit: gimli::Unit<R>,
1303 dwarf: &gimli::Dwarf<R>,
1304 flags: &Flags,
1305) -> Result<()> {
1306 let mut spaces_buf = String::new();
1307
1308 let mut entries = unit.entries_raw(None)?;
1309 while !entries.is_empty() {
1310 let offset = entries.next_offset();
1311 let depth = entries.next_depth();
1312 let abbrev = entries.read_abbreviation()?;
1313
1314 let mut indent = if depth >= 0 {
1315 depth as usize * 2 + 2
1316 } else {
1317 2
1318 };
1319 write!(w, "<{}{}>", if depth < 10 { " " } else { "" }, depth)?;
1320 write_offset(w, &unit, offset, flags)?;
1321 writeln!(
1322 w,
1323 "{}{}",
1324 spaces(&mut spaces_buf, indent),
1325 abbrev.map(|x| x.tag()).unwrap_or(gimli::DW_TAG_null)
1326 )?;
1327
1328 indent += 18;
1329 if flags.goff {
1330 indent += GOFF_SPACES;
1331 }
1332
1333 for spec in abbrev.map(|x| x.attributes()).unwrap_or(&[]) {
1334 let attr = entries.read_attribute(*spec)?;
1335 w.write_all(spaces(&mut spaces_buf, indent).as_bytes())?;
1336 if let Some(n) = attr.name().static_string() {
1337 let right_padding = 27 - std::cmp::min(27, n.len());
1338 write!(w, "{}{} ", n, spaces(&mut spaces_buf, right_padding))?;
1339 } else {
1340 write!(w, "{:27} ", attr.name())?;
1341 }
1342 if flags.raw {
1343 writeln!(w, "{:?}", attr.raw_value())?;
1344 } else {
1345 match dump_attr_value(w, &attr, &unit, dwarf) {
1346 Ok(_) => (),
1347 Err(err) => writeln_error(w, dwarf, err, "Failed to dump attribute value")?,
1348 };
1349 }
1350 }
1351 }
1352 Ok(())
1353}
1354
1355fn dump_attr_value<R: Reader, W: Write>(
1356 w: &mut W,
1357 attr: &gimli::Attribute<R>,
1358 unit: &gimli::Unit<R>,
1359 dwarf: &gimli::Dwarf<R>,
1360) -> Result<()> {
1361 let value = attr.value();
1362 match value {
1363 gimli::AttributeValue::Addr(address) => {
1364 writeln!(w, "0x{:08x}", address)?;
1365 }
1366 gimli::AttributeValue::Block(data) => {
1367 for byte in data.to_slice()?.iter() {
1368 write!(w, "{:02x}", byte)?;
1369 }
1370 writeln!(w)?;
1371 }
1372 gimli::AttributeValue::Data1(_)
1373 | gimli::AttributeValue::Data2(_)
1374 | gimli::AttributeValue::Data4(_)
1375 | gimli::AttributeValue::Data8(_) => {
1376 if let (Some(udata), Some(sdata)) = (attr.udata_value(), attr.sdata_value()) {
1377 if sdata >= 0 {
1378 writeln!(w, "{}", udata)?;
1379 } else {
1380 writeln!(w, "{} ({})", udata, sdata)?;
1381 }
1382 } else {
1383 writeln!(w, "{:?}", value)?;
1384 }
1385 }
1386 gimli::AttributeValue::Sdata(data) => {
1387 match attr.name() {
1388 gimli::DW_AT_data_member_location => {
1389 writeln!(w, "{}", data)?;
1390 }
1391 _ => {
1392 if data >= 0 {
1393 writeln!(w, "0x{:08x}", data)?;
1394 } else {
1395 writeln!(w, "0x{:08x} ({})", data, data)?;
1396 }
1397 }
1398 };
1399 }
1400 gimli::AttributeValue::Udata(data) => {
1401 match attr.name() {
1402 gimli::DW_AT_high_pc => {
1403 writeln!(w, "<offset-from-lowpc>{}", data)?;
1404 }
1405 gimli::DW_AT_data_member_location => {
1406 if let Some(sdata) = attr.sdata_value() {
1407 // This is a DW_FORM_data* value.
1408 // libdwarf-dwarfdump displays this as signed too.
1409 if sdata >= 0 {
1410 writeln!(w, "{}", data)?;
1411 } else {
1412 writeln!(w, "{} ({})", data, sdata)?;
1413 }
1414 } else {
1415 writeln!(w, "{}", data)?;
1416 }
1417 }
1418 gimli::DW_AT_lower_bound | gimli::DW_AT_upper_bound => {
1419 writeln!(w, "{}", data)?;
1420 }
1421 _ => {
1422 writeln!(w, "0x{:08x}", data)?;
1423 }
1424 };
1425 }
1426 gimli::AttributeValue::Exprloc(ref data) => {
1427 if let gimli::AttributeValue::Exprloc(_) = attr.raw_value() {
1428 write!(w, "len 0x{:04x}: ", data.0.len())?;
1429 for byte in data.0.to_slice()?.iter() {
1430 write!(w, "{:02x}", byte)?;
1431 }
1432 write!(w, ": ")?;
1433 }
1434 dump_exprloc(w, unit.encoding(), data)?;
1435 writeln!(w)?;
1436 }
1437 gimli::AttributeValue::Flag(true) => {
1438 writeln!(w, "yes")?;
1439 }
1440 gimli::AttributeValue::Flag(false) => {
1441 writeln!(w, "no")?;
1442 }
1443 gimli::AttributeValue::SecOffset(offset) => {
1444 writeln!(w, "0x{:08x}", offset)?;
1445 }
1446 gimli::AttributeValue::DebugAddrBase(base) => {
1447 writeln!(w, "<.debug_addr+0x{:08x}>", base.0)?;
1448 }
1449 gimli::AttributeValue::DebugAddrIndex(index) => {
1450 write!(w, "(indirect address, index {:#x}): ", index.0)?;
1451 let address = dwarf.address(unit, index)?;
1452 writeln!(w, "0x{:08x}", address)?;
1453 }
1454 gimli::AttributeValue::UnitRef(offset) => {
1455 write!(w, "0x{:08x}", offset.0)?;
1456 match offset.to_unit_section_offset(unit) {
1457 UnitSectionOffset::DebugInfoOffset(goff) => {
1458 write!(w, "<.debug_info+0x{:08x}>", goff.0)?;
1459 }
1460 UnitSectionOffset::DebugTypesOffset(goff) => {
1461 write!(w, "<.debug_types+0x{:08x}>", goff.0)?;
1462 }
1463 }
1464 writeln!(w)?;
1465 }
1466 gimli::AttributeValue::DebugInfoRef(offset) => {
1467 writeln!(w, "<.debug_info+0x{:08x}>", offset.0)?;
1468 }
1469 gimli::AttributeValue::DebugInfoRefSup(offset) => {
1470 writeln!(w, "<.debug_info(sup)+0x{:08x}>", offset.0)?;
1471 }
1472 gimli::AttributeValue::DebugLineRef(offset) => {
1473 writeln!(w, "<.debug_line+0x{:08x}>", offset.0)?;
1474 }
1475 gimli::AttributeValue::LocationListsRef(offset) => {
1476 dump_loc_list(w, offset, unit, dwarf)?;
1477 }
1478 gimli::AttributeValue::DebugLocListsBase(base) => {
1479 writeln!(w, "<.debug_loclists+0x{:08x}>", base.0)?;
1480 }
1481 gimli::AttributeValue::DebugLocListsIndex(index) => {
1482 write!(w, "(indirect location list, index {:#x}): ", index.0)?;
1483 let offset = dwarf.locations_offset(unit, index)?;
1484 dump_loc_list(w, offset, unit, dwarf)?;
1485 }
1486 gimli::AttributeValue::DebugMacinfoRef(offset) => {
1487 writeln!(w, "<.debug_macinfo+0x{:08x}>", offset.0)?;
1488 }
1489 gimli::AttributeValue::DebugMacroRef(offset) => {
1490 writeln!(w, "<.debug_macro+0x{:08x}>", offset.0)?;
1491 }
1492 gimli::AttributeValue::RangeListsRef(offset) => {
1493 let offset = dwarf.ranges_offset_from_raw(unit, offset);
1494 dump_range_list(w, offset, unit, dwarf)?;
1495 }
1496 gimli::AttributeValue::DebugRngListsBase(base) => {
1497 writeln!(w, "<.debug_rnglists+0x{:08x}>", base.0)?;
1498 }
1499 gimli::AttributeValue::DebugRngListsIndex(index) => {
1500 write!(w, "(indirect range list, index {:#x}): ", index.0)?;
1501 let offset = dwarf.ranges_offset(unit, index)?;
1502 dump_range_list(w, offset, unit, dwarf)?;
1503 }
1504 gimli::AttributeValue::DebugTypesRef(signature) => {
1505 dump_type_signature(w, signature)?;
1506 writeln!(w, " <type signature>")?;
1507 }
1508 gimli::AttributeValue::DebugStrRef(offset) => {
1509 if let Ok(s) = dwarf.debug_str.get_str(offset) {
1510 writeln!(w, "{}", s.to_string_lossy()?)?;
1511 } else {
1512 writeln!(w, "<.debug_str+0x{:08x}>", offset.0)?;
1513 }
1514 }
1515 gimli::AttributeValue::DebugStrRefSup(offset) => {
1516 if let Some(s) = dwarf
1517 .sup()
1518 .and_then(|sup| sup.debug_str.get_str(offset).ok())
1519 {
1520 writeln!(w, "{}", s.to_string_lossy()?)?;
1521 } else {
1522 writeln!(w, "<.debug_str(sup)+0x{:08x}>", offset.0)?;
1523 }
1524 }
1525 gimli::AttributeValue::DebugStrOffsetsBase(base) => {
1526 writeln!(w, "<.debug_str_offsets+0x{:08x}>", base.0)?;
1527 }
1528 gimli::AttributeValue::DebugStrOffsetsIndex(index) => {
1529 write!(w, "(indirect string, index {:#x}): ", index.0)?;
1530 let offset = dwarf.debug_str_offsets.get_str_offset(
1531 unit.encoding().format,
1532 unit.str_offsets_base,
1533 index,
1534 )?;
1535 if let Ok(s) = dwarf.debug_str.get_str(offset) {
1536 writeln!(w, "{}", s.to_string_lossy()?)?;
1537 } else {
1538 writeln!(w, "<.debug_str+0x{:08x}>", offset.0)?;
1539 }
1540 }
1541 gimli::AttributeValue::DebugLineStrRef(offset) => {
1542 if let Ok(s) = dwarf.debug_line_str.get_str(offset) {
1543 writeln!(w, "{}", s.to_string_lossy()?)?;
1544 } else {
1545 writeln!(w, "<.debug_line_str=0x{:08x}>", offset.0)?;
1546 }
1547 }
1548 gimli::AttributeValue::String(s) => {
1549 writeln!(w, "{}", s.to_string_lossy()?)?;
1550 }
1551 gimli::AttributeValue::Encoding(value) => {
1552 writeln!(w, "{}", value)?;
1553 }
1554 gimli::AttributeValue::DecimalSign(value) => {
1555 writeln!(w, "{}", value)?;
1556 }
1557 gimli::AttributeValue::Endianity(value) => {
1558 writeln!(w, "{}", value)?;
1559 }
1560 gimli::AttributeValue::Accessibility(value) => {
1561 writeln!(w, "{}", value)?;
1562 }
1563 gimli::AttributeValue::Visibility(value) => {
1564 writeln!(w, "{}", value)?;
1565 }
1566 gimli::AttributeValue::Virtuality(value) => {
1567 writeln!(w, "{}", value)?;
1568 }
1569 gimli::AttributeValue::Language(value) => {
1570 writeln!(w, "{}", value)?;
1571 }
1572 gimli::AttributeValue::AddressClass(value) => {
1573 writeln!(w, "{}", value)?;
1574 }
1575 gimli::AttributeValue::IdentifierCase(value) => {
1576 writeln!(w, "{}", value)?;
1577 }
1578 gimli::AttributeValue::CallingConvention(value) => {
1579 writeln!(w, "{}", value)?;
1580 }
1581 gimli::AttributeValue::Inline(value) => {
1582 writeln!(w, "{}", value)?;
1583 }
1584 gimli::AttributeValue::Ordering(value) => {
1585 writeln!(w, "{}", value)?;
1586 }
1587 gimli::AttributeValue::FileIndex(value) => {
1588 write!(w, "0x{:08x}", value)?;
1589 dump_file_index(w, value, unit, dwarf)?;
1590 writeln!(w)?;
1591 }
1592 gimli::AttributeValue::DwoId(value) => {
1593 writeln!(w, "0x{:016x}", value.0)?;
1594 }
1595 }
1596
1597 Ok(())
1598}
1599
1600fn dump_type_signature<W: Write>(w: &mut W, signature: gimli::DebugTypeSignature) -> Result<()> {
1601 write!(w, "0x{:016x}", signature.0)?;
1602 Ok(())
1603}
1604
1605fn dump_file_index<R: Reader, W: Write>(
1606 w: &mut W,
1607 file_index: u64,
1608 unit: &gimli::Unit<R>,
1609 dwarf: &gimli::Dwarf<R>,
1610) -> Result<()> {
1611 if file_index == 0 && unit.header.version() <= 4 {
1612 return Ok(());
1613 }
1614 let header = match unit.line_program {
1615 Some(ref program) => program.header(),
1616 None => return Ok(()),
1617 };
1618 let file = match header.file(file_index) {
1619 Some(file) => file,
1620 None => {
1621 writeln!(w, "Unable to get header for file {}", file_index)?;
1622 return Ok(());
1623 }
1624 };
1625 write!(w, " ")?;
1626 if let Some(directory) = file.directory(header) {
1627 let directory = dwarf.attr_string(unit, directory)?;
1628 let directory = directory.to_string_lossy()?;
1629 if file.directory_index() != 0 && !directory.starts_with('/') {
1630 if let Some(ref comp_dir) = unit.comp_dir {
1631 write!(w, "{}/", comp_dir.to_string_lossy()?,)?;
1632 }
1633 }
1634 write!(w, "{}/", directory)?;
1635 }
1636 write!(
1637 w,
1638 "{}",
1639 dwarf
1640 .attr_string(unit, file.path_name())?
1641 .to_string_lossy()?
1642 )?;
1643 Ok(())
1644}
1645
1646fn dump_exprloc<R: Reader, W: Write>(
1647 w: &mut W,
1648 encoding: gimli::Encoding,
1649 data: &gimli::Expression<R>,
1650) -> Result<()> {
1651 let mut pc = data.0.clone();
1652 let mut space = false;
1653 while pc.len() != 0 {
1654 let pc_clone = pc.clone();
1655 match gimli::Operation::parse(&mut pc, encoding) {
1656 Ok(op) => {
1657 if space {
1658 write!(w, " ")?;
1659 } else {
1660 space = true;
1661 }
1662 dump_op(w, encoding, pc_clone, op)?;
1663 }
1664 Err(gimli::Error::InvalidExpression(op)) => {
1665 writeln!(w, "WARNING: unsupported operation 0x{:02x}", op.0)?;
1666 return Ok(());
1667 }
1668 Err(gimli::Error::UnsupportedRegister(register)) => {
1669 writeln!(w, "WARNING: unsupported register {}", register)?;
1670 return Ok(());
1671 }
1672 Err(gimli::Error::UnexpectedEof(_)) => {
1673 writeln!(w, "WARNING: truncated or malformed expression")?;
1674 return Ok(());
1675 }
1676 Err(e) => {
1677 writeln!(w, "WARNING: unexpected operation parse error: {}", e)?;
1678 return Ok(());
1679 }
1680 }
1681 }
1682 Ok(())
1683}
1684
1685fn dump_op<R: Reader, W: Write>(
1686 w: &mut W,
1687 encoding: gimli::Encoding,
1688 mut pc: R,
1689 op: gimli::Operation<R>,
1690) -> Result<()> {
1691 let dwop = gimli::DwOp(pc.read_u8()?);
1692 write!(w, "{}", dwop)?;
1693 match op {
1694 gimli::Operation::Deref {
1695 base_type, size, ..
1696 } => {
1697 if dwop == gimli::DW_OP_deref_size || dwop == gimli::DW_OP_xderef_size {
1698 write!(w, " {}", size)?;
1699 }
1700 if base_type != UnitOffset(0) {
1701 write!(w, " type 0x{:08x}", base_type.0)?;
1702 }
1703 }
1704 gimli::Operation::Pick { index } => {
1705 if dwop == gimli::DW_OP_pick {
1706 write!(w, " {}", index)?;
1707 }
1708 }
1709 gimli::Operation::PlusConstant { value } => {
1710 write!(w, " {}", value as i64)?;
1711 }
1712 gimli::Operation::Bra { target } => {
1713 write!(w, " {}", target)?;
1714 }
1715 gimli::Operation::Skip { target } => {
1716 write!(w, " {}", target)?;
1717 }
1718 gimli::Operation::SignedConstant { value } => match dwop {
1719 gimli::DW_OP_const1s
1720 | gimli::DW_OP_const2s
1721 | gimli::DW_OP_const4s
1722 | gimli::DW_OP_const8s
1723 | gimli::DW_OP_consts => {
1724 write!(w, " {}", value)?;
1725 }
1726 _ => {}
1727 },
1728 gimli::Operation::UnsignedConstant { value } => match dwop {
1729 gimli::DW_OP_const1u
1730 | gimli::DW_OP_const2u
1731 | gimli::DW_OP_const4u
1732 | gimli::DW_OP_const8u
1733 | gimli::DW_OP_constu => {
1734 write!(w, " {}", value)?;
1735 }
1736 _ => {
1737 // These have the value encoded in the operation, eg DW_OP_lit0.
1738 }
1739 },
1740 gimli::Operation::Register { register } => {
1741 if dwop == gimli::DW_OP_regx {
1742 write!(w, " {}", register.0)?;
1743 }
1744 }
1745 gimli::Operation::RegisterOffset {
1746 register,
1747 offset,
1748 base_type,
1749 } => {
1750 if dwop >= gimli::DW_OP_breg0 && dwop <= gimli::DW_OP_breg31 {
1751 write!(w, "{:+}", offset)?;
1752 } else {
1753 write!(w, " {}", register.0)?;
1754 if offset != 0 {
1755 write!(w, "{:+}", offset)?;
1756 }
1757 if base_type != UnitOffset(0) {
1758 write!(w, " type 0x{:08x}", base_type.0)?;
1759 }
1760 }
1761 }
1762 gimli::Operation::FrameOffset { offset } => {
1763 write!(w, " {}", offset)?;
1764 }
1765 gimli::Operation::Call { offset } => match offset {
1766 gimli::DieReference::UnitRef(gimli::UnitOffset(offset)) => {
1767 write!(w, " 0x{:08x}", offset)?;
1768 }
1769 gimli::DieReference::DebugInfoRef(gimli::DebugInfoOffset(offset)) => {
1770 write!(w, " 0x{:08x}", offset)?;
1771 }
1772 },
1773 gimli::Operation::Piece {
1774 size_in_bits,
1775 bit_offset: None,
1776 } => {
1777 write!(w, " {}", size_in_bits / 8)?;
1778 }
1779 gimli::Operation::Piece {
1780 size_in_bits,
1781 bit_offset: Some(bit_offset),
1782 } => {
1783 write!(w, " 0x{:08x} offset 0x{:08x}", size_in_bits, bit_offset)?;
1784 }
1785 gimli::Operation::ImplicitValue { data } => {
1786 let data = data.to_slice()?;
1787 write!(w, " 0x{:08x} contents 0x", data.len())?;
1788 for byte in data.iter() {
1789 write!(w, "{:02x}", byte)?;
1790 }
1791 }
1792 gimli::Operation::ImplicitPointer { value, byte_offset } => {
1793 write!(w, " 0x{:08x} {}", value.0, byte_offset)?;
1794 }
1795 gimli::Operation::EntryValue { expression } => {
1796 write!(w, "(")?;
1797 dump_exprloc(w, encoding, &gimli::Expression(expression))?;
1798 write!(w, ")")?;
1799 }
1800 gimli::Operation::ParameterRef { offset } => {
1801 write!(w, " 0x{:08x}", offset.0)?;
1802 }
1803 gimli::Operation::Address { address } => {
1804 write!(w, " 0x{:08x}", address)?;
1805 }
1806 gimli::Operation::AddressIndex { index } => {
1807 write!(w, " 0x{:08x}", index.0)?;
1808 }
1809 gimli::Operation::ConstantIndex { index } => {
1810 write!(w, " 0x{:08x}", index.0)?;
1811 }
1812 gimli::Operation::TypedLiteral { base_type, value } => {
1813 write!(w, " type 0x{:08x} contents 0x", base_type.0)?;
1814 for byte in value.to_slice()?.iter() {
1815 write!(w, "{:02x}", byte)?;
1816 }
1817 }
1818 gimli::Operation::Convert { base_type } => {
1819 write!(w, " type 0x{:08x}", base_type.0)?;
1820 }
1821 gimli::Operation::Reinterpret { base_type } => {
1822 write!(w, " type 0x{:08x}", base_type.0)?;
1823 }
1824 gimli::Operation::WasmLocal { index }
1825 | gimli::Operation::WasmGlobal { index }
1826 | gimli::Operation::WasmStack { index } => {
1827 let wasmop = pc.read_u8()?;
1828 write!(w, " 0x{:x} 0x{:x}", wasmop, index)?;
1829 }
1830 gimli::Operation::Drop
1831 | gimli::Operation::Swap
1832 | gimli::Operation::Rot
1833 | gimli::Operation::Abs
1834 | gimli::Operation::And
1835 | gimli::Operation::Div
1836 | gimli::Operation::Minus
1837 | gimli::Operation::Mod
1838 | gimli::Operation::Mul
1839 | gimli::Operation::Neg
1840 | gimli::Operation::Not
1841 | gimli::Operation::Or
1842 | gimli::Operation::Plus
1843 | gimli::Operation::Shl
1844 | gimli::Operation::Shr
1845 | gimli::Operation::Shra
1846 | gimli::Operation::Xor
1847 | gimli::Operation::Eq
1848 | gimli::Operation::Ge
1849 | gimli::Operation::Gt
1850 | gimli::Operation::Le
1851 | gimli::Operation::Lt
1852 | gimli::Operation::Ne
1853 | gimli::Operation::Nop
1854 | gimli::Operation::PushObjectAddress
1855 | gimli::Operation::TLS
1856 | gimli::Operation::CallFrameCFA
1857 | gimli::Operation::StackValue => {}
1858 };
1859 Ok(())
1860}
1861
1862fn dump_loc_list<R: Reader, W: Write>(
1863 w: &mut W,
1864 offset: gimli::LocationListsOffset<R::Offset>,
1865 unit: &gimli::Unit<R>,
1866 dwarf: &gimli::Dwarf<R>,
1867) -> Result<()> {
1868 let raw_locations = dwarf.raw_locations(unit, offset)?;
1869 let raw_locations: Vec<_> = raw_locations.collect()?;
1870 let mut locations = dwarf.locations(unit, offset)?;
1871 writeln!(
1872 w,
1873 "<loclist at {}+0x{:08x} with {} entries>",
1874 if unit.encoding().version < 5 {
1875 ".debug_loc"
1876 } else {
1877 ".debug_loclists"
1878 },
1879 offset.0,
1880 raw_locations.len()
1881 )?;
1882 for (i, raw) in raw_locations.iter().enumerate() {
1883 write!(w, "\t\t\t[{:2}]", i)?;
1884 match *raw {
1885 gimli::RawLocListEntry::BaseAddress { addr } => {
1886 writeln!(w, "<new base address 0x{:08x}>", addr)?;
1887 }
1888 gimli::RawLocListEntry::BaseAddressx { addr } => {
1889 let addr_val = dwarf.address(unit, addr)?;
1890 writeln!(w, "<new base addressx [{}]0x{:08x}>", addr.0, addr_val)?;
1891 }
1892 gimli::RawLocListEntry::StartxEndx {
1893 begin,
1894 end,
1895 ref data,
1896 } => {
1897 let begin_val = dwarf.address(unit, begin)?;
1898 let end_val = dwarf.address(unit, end)?;
1899 let location = locations.next()?.unwrap();
1900 write!(
1901 w,
1902 "<startx-endx \
1903 low-off: [{}]0x{:08x} addr 0x{:08x} \
1904 high-off: [{}]0x{:08x} addr 0x{:08x}>",
1905 begin.0, begin_val, location.range.begin, end.0, end_val, location.range.end
1906 )?;
1907 dump_exprloc(w, unit.encoding(), data)?;
1908 writeln!(w)?;
1909 }
1910 gimli::RawLocListEntry::StartxLength {
1911 begin,
1912 length,
1913 ref data,
1914 } => {
1915 let begin_val = dwarf.address(unit, begin)?;
1916 let location = locations.next()?.unwrap();
1917 write!(
1918 w,
1919 "<start-length \
1920 low-off: [{}]0x{:08x} addr 0x{:08x} \
1921 high-off: 0x{:08x} addr 0x{:08x}>",
1922 begin.0, begin_val, location.range.begin, length, location.range.end
1923 )?;
1924 dump_exprloc(w, unit.encoding(), data)?;
1925 writeln!(w)?;
1926 }
1927 gimli::RawLocListEntry::AddressOrOffsetPair {
1928 begin,
1929 end,
1930 ref data,
1931 }
1932 | gimli::RawLocListEntry::OffsetPair {
1933 begin,
1934 end,
1935 ref data,
1936 } => {
1937 let location = locations.next()?.unwrap();
1938 write!(
1939 w,
1940 "<offset pair \
1941 low-off: 0x{:08x} addr 0x{:08x} \
1942 high-off: 0x{:08x} addr 0x{:08x}>",
1943 begin, location.range.begin, end, location.range.end
1944 )?;
1945 dump_exprloc(w, unit.encoding(), data)?;
1946 writeln!(w)?;
1947 }
1948 gimli::RawLocListEntry::DefaultLocation { ref data } => {
1949 write!(w, "<default location>")?;
1950 dump_exprloc(w, unit.encoding(), data)?;
1951 writeln!(w)?;
1952 }
1953 gimli::RawLocListEntry::StartEnd {
1954 begin,
1955 end,
1956 ref data,
1957 } => {
1958 let location = locations.next()?.unwrap();
1959 write!(
1960 w,
1961 "<start-end \
1962 low-off: 0x{:08x} addr 0x{:08x} \
1963 high-off: 0x{:08x} addr 0x{:08x}>",
1964 begin, location.range.begin, end, location.range.end
1965 )?;
1966 dump_exprloc(w, unit.encoding(), data)?;
1967 writeln!(w)?;
1968 }
1969 gimli::RawLocListEntry::StartLength {
1970 begin,
1971 length,
1972 ref data,
1973 } => {
1974 let location = locations.next()?.unwrap();
1975 write!(
1976 w,
1977 "<start-length \
1978 low-off: 0x{:08x} addr 0x{:08x} \
1979 high-off: 0x{:08x} addr 0x{:08x}>",
1980 begin, location.range.begin, length, location.range.end
1981 )?;
1982 dump_exprloc(w, unit.encoding(), data)?;
1983 writeln!(w)?;
1984 }
1985 };
1986 }
1987 Ok(())
1988}
1989
1990fn dump_range_list<R: Reader, W: Write>(
1991 w: &mut W,
1992 offset: gimli::RangeListsOffset<R::Offset>,
1993 unit: &gimli::Unit<R>,
1994 dwarf: &gimli::Dwarf<R>,
1995) -> Result<()> {
1996 let raw_ranges = dwarf.raw_ranges(unit, offset)?;
1997 let raw_ranges: Vec<_> = raw_ranges.collect()?;
1998 let mut ranges = dwarf.ranges(unit, offset)?;
1999 writeln!(
2000 w,
2001 "<rnglist at {}+0x{:08x} with {} entries>",
2002 if unit.encoding().version < 5 {
2003 ".debug_ranges"
2004 } else {
2005 ".debug_rnglists"
2006 },
2007 offset.0,
2008 raw_ranges.len()
2009 )?;
2010 for (i, raw) in raw_ranges.iter().enumerate() {
2011 write!(w, "\t\t\t[{:2}] ", i)?;
2012 match *raw {
2013 gimli::RawRngListEntry::AddressOrOffsetPair { begin, end } => {
2014 let range = ranges.next()?.unwrap();
2015 writeln!(
2016 w,
2017 "<address pair \
2018 low-off: 0x{:08x} addr 0x{:08x} \
2019 high-off: 0x{:08x} addr 0x{:08x}>",
2020 begin, range.begin, end, range.end
2021 )?;
2022 }
2023 gimli::RawRngListEntry::BaseAddress { addr } => {
2024 writeln!(w, "<new base address 0x{:08x}>", addr)?;
2025 }
2026 gimli::RawRngListEntry::BaseAddressx { addr } => {
2027 let addr_val = dwarf.address(unit, addr)?;
2028 writeln!(w, "<new base addressx [{}]0x{:08x}>", addr.0, addr_val)?;
2029 }
2030 gimli::RawRngListEntry::StartxEndx { begin, end } => {
2031 let begin_val = dwarf.address(unit, begin)?;
2032 let end_val = dwarf.address(unit, end)?;
2033 let range = if begin_val == end_val {
2034 gimli::Range {
2035 begin: begin_val,
2036 end: end_val,
2037 }
2038 } else {
2039 ranges.next()?.unwrap()
2040 };
2041 writeln!(
2042 w,
2043 "<startx-endx \
2044 low-off: [{}]0x{:08x} addr 0x{:08x} \
2045 high-off: [{}]0x{:08x} addr 0x{:08x}>",
2046 begin.0, begin_val, range.begin, end.0, end_val, range.end
2047 )?;
2048 }
2049 gimli::RawRngListEntry::StartxLength { begin, length } => {
2050 let begin_val = dwarf.address(unit, begin)?;
2051 let range = ranges.next()?.unwrap();
2052 writeln!(
2053 w,
2054 "<startx-length \
2055 low-off: [{}]0x{:08x} addr 0x{:08x} \
2056 high-off: 0x{:08x} addr 0x{:08x}>",
2057 begin.0, begin_val, range.begin, length, range.end
2058 )?;
2059 }
2060 gimli::RawRngListEntry::OffsetPair { begin, end } => {
2061 let range = ranges.next()?.unwrap();
2062 writeln!(
2063 w,
2064 "<offset pair \
2065 low-off: 0x{:08x} addr 0x{:08x} \
2066 high-off: 0x{:08x} addr 0x{:08x}>",
2067 begin, range.begin, end, range.end
2068 )?;
2069 }
2070 gimli::RawRngListEntry::StartEnd { begin, end } => {
2071 let range = if begin == end {
2072 gimli::Range { begin, end }
2073 } else {
2074 ranges.next()?.unwrap()
2075 };
2076 writeln!(
2077 w,
2078 "<start-end \
2079 low-off: 0x{:08x} addr 0x{:08x} \
2080 high-off: 0x{:08x} addr 0x{:08x}>",
2081 begin, range.begin, end, range.end
2082 )?;
2083 }
2084 gimli::RawRngListEntry::StartLength { begin, length } => {
2085 let range = ranges.next()?.unwrap();
2086 writeln!(
2087 w,
2088 "<start-length \
2089 low-off: 0x{:08x} addr 0x{:08x} \
2090 high-off: 0x{:08x} addr 0x{:08x}>",
2091 begin, range.begin, length, range.end
2092 )?;
2093 }
2094 };
2095 }
2096 Ok(())
2097}
2098
2099fn dump_line<R: Reader, W: Write>(w: &mut W, dwarf: &gimli::Dwarf<R>) -> Result<()> {
2100 let mut iter = dwarf.units();
2101 while let Some(header) = iter.next()? {
2102 writeln!(
2103 w,
2104 "\n.debug_line: line number info for unit at .debug_info offset 0x{:08x}",
2105 header.offset().as_debug_info_offset().unwrap().0
2106 )?;
2107 let unit = match dwarf.unit(header) {
2108 Ok(unit) => unit,
2109 Err(err) => {
2110 writeln_error(
2111 w,
2112 dwarf,
2113 err.into(),
2114 "Failed to parse unit root entry for dump_line",
2115 )?;
2116 continue;
2117 }
2118 };
2119 match dump_line_program(w, &unit, dwarf) {
2120 Ok(_) => (),
2121 Err(Error::IoError) => return Err(Error::IoError),
2122 Err(err) => writeln_error(w, dwarf, err, "Failed to dump line program")?,
2123 }
2124 }
2125 Ok(())
2126}
2127
2128fn dump_line_program<R: Reader, W: Write>(
2129 w: &mut W,
2130 unit: &gimli::Unit<R>,
2131 dwarf: &gimli::Dwarf<R>,
2132) -> Result<()> {
2133 if let Some(program) = unit.line_program.clone() {
2134 {
2135 let header = program.header();
2136 writeln!(w)?;
2137 writeln!(
2138 w,
2139 "Offset: 0x{:x}",
2140 header.offset().0
2141 )?;
2142 writeln!(
2143 w,
2144 "Length: {}",
2145 header.unit_length()
2146 )?;
2147 writeln!(
2148 w,
2149 "DWARF version: {}",
2150 header.version()
2151 )?;
2152 writeln!(
2153 w,
2154 "Address size: {}",
2155 header.address_size()
2156 )?;
2157 writeln!(
2158 w,
2159 "Prologue length: {}",
2160 header.header_length()
2161 )?;
2162 writeln!(
2163 w,
2164 "Minimum instruction length: {}",
2165 header.minimum_instruction_length()
2166 )?;
2167 writeln!(
2168 w,
2169 "Maximum operations per instruction: {}",
2170 header.maximum_operations_per_instruction()
2171 )?;
2172 writeln!(
2173 w,
2174 "Default is_stmt: {}",
2175 header.default_is_stmt()
2176 )?;
2177 writeln!(
2178 w,
2179 "Line base: {}",
2180 header.line_base()
2181 )?;
2182 writeln!(
2183 w,
2184 "Line range: {}",
2185 header.line_range()
2186 )?;
2187 writeln!(
2188 w,
2189 "Opcode base: {}",
2190 header.opcode_base()
2191 )?;
2192
2193 writeln!(w)?;
2194 writeln!(w, "Opcodes:")?;
2195 for (i, length) in header
2196 .standard_opcode_lengths()
2197 .to_slice()?
2198 .iter()
2199 .enumerate()
2200 {
2201 writeln!(w, " Opcode {} has {} args", i + 1, length)?;
2202 }
2203
2204 let base = if header.version() >= 5 { 0 } else { 1 };
2205 writeln!(w)?;
2206 writeln!(w, "The Directory Table:")?;
2207 for (i, dir) in header.include_directories().iter().enumerate() {
2208 writeln!(
2209 w,
2210 " {} {}",
2211 base + i,
2212 dwarf.attr_string(unit, dir.clone())?.to_string_lossy()?
2213 )?;
2214 }
2215
2216 writeln!(w)?;
2217 writeln!(w, "The File Name Table")?;
2218 write!(w, " Entry\tDir\tTime\tSize")?;
2219 if header.file_has_md5() {
2220 write!(w, "\tMD5\t\t\t\t")?;
2221 }
2222 writeln!(w, "\tName")?;
2223 for (i, file) in header.file_names().iter().enumerate() {
2224 write!(
2225 w,
2226 " {}\t{}\t{}\t{}",
2227 base + i,
2228 file.directory_index(),
2229 file.timestamp(),
2230 file.size(),
2231 )?;
2232 if header.file_has_md5() {
2233 let md5 = file.md5();
2234 write!(w, "\t")?;
2235 for i in 0..16 {
2236 write!(w, "{:02X}", md5[i])?;
2237 }
2238 }
2239 writeln!(
2240 w,
2241 "\t{}",
2242 dwarf
2243 .attr_string(unit, file.path_name())?
2244 .to_string_lossy()?
2245 )?;
2246 }
2247
2248 writeln!(w)?;
2249 writeln!(w, "Line Number Instructions:")?;
2250 let mut instructions = header.instructions();
2251 while let Some(instruction) = instructions.next_instruction(header)? {
2252 writeln!(w, " {}", instruction)?;
2253 }
2254
2255 writeln!(w)?;
2256 writeln!(w, "Line Number Rows:")?;
2257 writeln!(w, "<pc> [lno,col]")?;
2258 }
2259 let mut rows = program.rows();
2260 let mut file_index = std::u64::MAX;
2261 while let Some((header, row)) = rows.next_row()? {
2262 let line = match row.line() {
2263 Some(line) => line.get(),
2264 None => 0,
2265 };
2266 let column = match row.column() {
2267 gimli::ColumnType::Column(column) => column.get(),
2268 gimli::ColumnType::LeftEdge => 0,
2269 };
2270 write!(w, "0x{:08x} [{:4},{:2}]", row.address(), line, column)?;
2271 if row.is_stmt() {
2272 write!(w, " NS")?;
2273 }
2274 if row.basic_block() {
2275 write!(w, " BB")?;
2276 }
2277 if row.end_sequence() {
2278 write!(w, " ET")?;
2279 }
2280 if row.prologue_end() {
2281 write!(w, " PE")?;
2282 }
2283 if row.epilogue_begin() {
2284 write!(w, " EB")?;
2285 }
2286 if row.isa() != 0 {
2287 write!(w, " IS={}", row.isa())?;
2288 }
2289 if row.discriminator() != 0 {
2290 write!(w, " DI={}", row.discriminator())?;
2291 }
2292 if file_index != row.file_index() {
2293 file_index = row.file_index();
2294 if let Some(file) = row.file(header) {
2295 if let Some(directory) = file.directory(header) {
2296 write!(
2297 w,
2298 " uri: \"{}/{}\"",
2299 dwarf.attr_string(unit, directory)?.to_string_lossy()?,
2300 dwarf
2301 .attr_string(unit, file.path_name())?
2302 .to_string_lossy()?
2303 )?;
2304 } else {
2305 write!(
2306 w,
2307 " uri: \"{}\"",
2308 dwarf
2309 .attr_string(unit, file.path_name())?
2310 .to_string_lossy()?
2311 )?;
2312 }
2313 }
2314 }
2315 writeln!(w)?;
2316 }
2317 }
2318 Ok(())
2319}
2320
2321fn dump_pubnames<R: Reader, W: Write>(
2322 w: &mut W,
2323 debug_pubnames: &gimli::DebugPubNames<R>,
2324 debug_info: &gimli::DebugInfo<R>,
2325) -> Result<()> {
2326 writeln!(w, "\n.debug_pubnames")?;
2327
2328 let mut cu_offset;
2329 let mut cu_die_offset = gimli::DebugInfoOffset(0);
2330 let mut prev_cu_offset = None;
2331 let mut pubnames = debug_pubnames.items();
2332 while let Some(pubname) = pubnames.next()? {
2333 cu_offset = pubname.unit_header_offset();
2334 if Some(cu_offset) != prev_cu_offset {
2335 let cu = debug_info.header_from_offset(cu_offset)?;
2336 cu_die_offset = gimli::DebugInfoOffset(cu_offset.0 + cu.header_size());
2337 prev_cu_offset = Some(cu_offset);
2338 }
2339 let die_in_cu = pubname.die_offset();
2340 let die_in_sect = cu_offset.0 + die_in_cu.0;
2341 writeln!(w,
2342 "global die-in-sect 0x{:08x}, cu-in-sect 0x{:08x}, die-in-cu 0x{:08x}, cu-header-in-sect 0x{:08x} '{}'",
2343 die_in_sect,
2344 cu_die_offset.0,
2345 die_in_cu.0,
2346 cu_offset.0,
2347 pubname.name().to_string_lossy()?
2348 )?;
2349 }
2350 Ok(())
2351}
2352
2353fn dump_pubtypes<R: Reader, W: Write>(
2354 w: &mut W,
2355 debug_pubtypes: &gimli::DebugPubTypes<R>,
2356 debug_info: &gimli::DebugInfo<R>,
2357) -> Result<()> {
2358 writeln!(w, "\n.debug_pubtypes")?;
2359
2360 let mut cu_offset;
2361 let mut cu_die_offset = gimli::DebugInfoOffset(0);
2362 let mut prev_cu_offset = None;
2363 let mut pubtypes = debug_pubtypes.items();
2364 while let Some(pubtype) = pubtypes.next()? {
2365 cu_offset = pubtype.unit_header_offset();
2366 if Some(cu_offset) != prev_cu_offset {
2367 let cu = debug_info.header_from_offset(cu_offset)?;
2368 cu_die_offset = gimli::DebugInfoOffset(cu_offset.0 + cu.header_size());
2369 prev_cu_offset = Some(cu_offset);
2370 }
2371 let die_in_cu = pubtype.die_offset();
2372 let die_in_sect = cu_offset.0 + die_in_cu.0;
2373 writeln!(w,
2374 "pubtype die-in-sect 0x{:08x}, cu-in-sect 0x{:08x}, die-in-cu 0x{:08x}, cu-header-in-sect 0x{:08x} '{}'",
2375 die_in_sect,
2376 cu_die_offset.0,
2377 die_in_cu.0,
2378 cu_offset.0,
2379 pubtype.name().to_string_lossy()?
2380 )?;
2381 }
2382 Ok(())
2383}
2384
2385fn dump_aranges<R: Reader, W: Write>(
2386 w: &mut W,
2387 debug_aranges: &gimli::DebugAranges<R>,
2388) -> Result<()> {
2389 writeln!(w, "\n.debug_aranges")?;
2390
2391 let mut headers = debug_aranges.headers();
2392 while let Some(header) = headers.next()? {
2393 writeln!(
2394 w,
2395 "Address Range Header: length = 0x{:08x}, version = 0x{:04x}, cu_offset = 0x{:08x}, addr_size = 0x{:02x}, seg_size = 0x{:02x}",
2396 header.length(),
2397 header.encoding().version,
2398 header.debug_info_offset().0,
2399 header.encoding().address_size,
2400 header.segment_size(),
2401 )?;
2402 let mut aranges = header.entries();
2403 while let Some(arange) = aranges.next()? {
2404 let range = arange.range();
2405 if let Some(segment) = arange.segment() {
2406 writeln!(
2407 w,
2408 "[0x{:016x}, 0x{:016x}) segment 0x{:x}",
2409 range.begin, range.end, segment
2410 )?;
2411 } else {
2412 writeln!(w, "[0x{:016x}, 0x{:016x})", range.begin, range.end)?;
2413 }
2414 }
2415 }
2416 Ok(())
2417}