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