diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:57:31 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:57:31 +0000 |
commit | dc0db358abe19481e475e10c32149b53370f1a1c (patch) | |
tree | ab8ce99c4b255ce46f99ef402c27916055b899ee /vendor/gimli/examples | |
parent | Releasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff) | |
download | rustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip |
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/gimli/examples')
-rw-r--r-- | vendor/gimli/examples/dwarf-validate.rs | 267 | ||||
-rw-r--r-- | vendor/gimli/examples/dwarfdump.rs | 2369 | ||||
-rw-r--r-- | vendor/gimli/examples/simple.rs | 67 | ||||
-rw-r--r-- | vendor/gimli/examples/simple_line.rs | 106 |
4 files changed, 0 insertions, 2809 deletions
diff --git a/vendor/gimli/examples/dwarf-validate.rs b/vendor/gimli/examples/dwarf-validate.rs deleted file mode 100644 index 54d8f3a1d..000000000 --- a/vendor/gimli/examples/dwarf-validate.rs +++ /dev/null @@ -1,267 +0,0 @@ -// Allow clippy lints when building without clippy. -#![allow(unknown_lints)] - -use gimli::{AttributeValue, UnitHeader}; -use object::{Object, ObjectSection}; -use rayon::prelude::*; -use std::borrow::{Borrow, Cow}; -use std::env; -use std::fs; -use std::io::{self, BufWriter, Write}; -use std::iter::Iterator; -use std::path::{Path, PathBuf}; -use std::process; -use std::sync::Mutex; -use typed_arena::Arena; - -trait Reader: gimli::Reader<Offset = usize> + Send + Sync { - type SyncSendEndian: gimli::Endianity + Send + Sync; -} - -impl<'input, Endian> Reader for gimli::EndianSlice<'input, Endian> -where - Endian: gimli::Endianity + Send + Sync, -{ - type SyncSendEndian = Endian; -} - -struct ErrorWriter<W: Write + Send> { - inner: Mutex<(W, usize)>, - path: PathBuf, -} - -impl<W: Write + Send> ErrorWriter<W> { - #[allow(clippy::needless_pass_by_value)] - fn error(&self, s: String) { - let mut lock = self.inner.lock().unwrap(); - writeln!(&mut lock.0, "DWARF error in {}: {}", self.path.display(), s).unwrap(); - lock.1 += 1; - } -} - -fn main() { - let mut w = BufWriter::new(io::stdout()); - let mut errors = 0; - for arg in env::args_os().skip(1) { - let path = Path::new(&arg); - let file = match fs::File::open(&path) { - Ok(file) => file, - Err(err) => { - eprintln!("Failed to open file '{}': {}", path.display(), err); - errors += 1; - continue; - } - }; - let file = match unsafe { memmap2::Mmap::map(&file) } { - Ok(mmap) => mmap, - Err(err) => { - eprintln!("Failed to map file '{}': {}", path.display(), &err); - errors += 1; - continue; - } - }; - let file = match object::File::parse(&*file) { - Ok(file) => file, - Err(err) => { - eprintln!("Failed to parse file '{}': {}", path.display(), err); - errors += 1; - continue; - } - }; - - let endian = if file.is_little_endian() { - gimli::RunTimeEndian::Little - } else { - gimli::RunTimeEndian::Big - }; - let mut error_writer = ErrorWriter { - inner: Mutex::new((&mut w, 0)), - path: path.to_owned(), - }; - validate_file(&mut error_writer, &file, endian); - errors += error_writer.inner.into_inner().unwrap().1; - } - // Flush any errors. - drop(w); - if errors > 0 { - process::exit(1); - } -} - -fn validate_file<W, Endian>(w: &mut ErrorWriter<W>, file: &object::File, endian: Endian) -where - W: Write + Send, - Endian: gimli::Endianity + Send + Sync, -{ - let arena = Arena::new(); - - fn load_section<'a, 'file, 'input, S, Endian>( - arena: &'a Arena<Cow<'file, [u8]>>, - file: &'file object::File<'input>, - endian: Endian, - ) -> S - where - S: gimli::Section<gimli::EndianSlice<'a, Endian>>, - Endian: gimli::Endianity + Send + Sync, - 'file: 'input, - 'a: 'file, - { - let data = match file.section_by_name(S::section_name()) { - Some(ref section) => section - .uncompressed_data() - .unwrap_or(Cow::Borrowed(&[][..])), - None => Cow::Borrowed(&[][..]), - }; - let data_ref = (*arena.alloc(data)).borrow(); - S::from(gimli::EndianSlice::new(data_ref, endian)) - } - - // Variables representing sections of the file. The type of each is inferred from its use in the - // validate_info function below. - let debug_abbrev = &load_section(&arena, file, endian); - let debug_info = &load_section(&arena, file, endian); - - validate_info(w, debug_info, debug_abbrev); -} - -struct UnitSummary { - // True if we successfully parsed all the DIEs and attributes in the compilation unit - internally_valid: bool, - offset: gimli::DebugInfoOffset, - die_offsets: Vec<gimli::UnitOffset>, - global_die_references: Vec<(gimli::UnitOffset, gimli::DebugInfoOffset)>, -} - -fn validate_info<W, R>( - w: &mut ErrorWriter<W>, - debug_info: &gimli::DebugInfo<R>, - debug_abbrev: &gimli::DebugAbbrev<R>, -) where - W: Write + Send, - R: Reader, -{ - let mut units = Vec::new(); - let mut units_iter = debug_info.units(); - let mut last_offset = 0; - loop { - let u = match units_iter.next() { - Err(err) => { - w.error(format!( - "Can't read unit header at offset {:#x}, stopping reading units: {}", - last_offset, err - )); - break; - } - Ok(None) => break, - Ok(Some(u)) => u, - }; - last_offset = u.offset().as_debug_info_offset().unwrap().0 + u.length_including_self(); - units.push(u); - } - let process_unit = |unit: UnitHeader<R>| -> UnitSummary { - let unit_offset = unit.offset().as_debug_info_offset().unwrap(); - let mut ret = UnitSummary { - internally_valid: false, - offset: unit_offset, - die_offsets: Vec::new(), - global_die_references: Vec::new(), - }; - let abbrevs = match unit.abbreviations(debug_abbrev) { - Ok(abbrevs) => abbrevs, - Err(err) => { - w.error(format!( - "Invalid abbrevs for unit {:#x}: {}", - unit_offset.0, &err - )); - return ret; - } - }; - let mut entries = unit.entries(&abbrevs); - let mut unit_refs = Vec::new(); - loop { - let (_, entry) = match entries.next_dfs() { - Err(err) => { - w.error(format!( - "Invalid DIE for unit {:#x}: {}", - unit_offset.0, &err - )); - return ret; - } - Ok(None) => break, - Ok(Some(entry)) => entry, - }; - ret.die_offsets.push(entry.offset()); - - let mut attrs = entry.attrs(); - loop { - let attr = match attrs.next() { - Err(err) => { - w.error(format!( - "Invalid attribute for unit {:#x} at DIE {:#x}: {}", - unit_offset.0, - entry.offset().0, - &err - )); - return ret; - } - Ok(None) => break, - Ok(Some(attr)) => attr, - }; - match attr.value() { - AttributeValue::UnitRef(offset) => { - unit_refs.push((entry.offset(), offset)); - } - AttributeValue::DebugInfoRef(offset) => { - ret.global_die_references.push((entry.offset(), offset)); - } - _ => (), - } - } - } - ret.internally_valid = true; - ret.die_offsets.shrink_to_fit(); - ret.global_die_references.shrink_to_fit(); - - // Check intra-unit references - for (from, to) in unit_refs { - if ret.die_offsets.binary_search(&to).is_err() { - w.error(format!( - "Invalid intra-unit reference in unit {:#x} from DIE {:#x} to {:#x}", - unit_offset.0, from.0, to.0 - )); - } - } - - ret - }; - let processed_units = units.into_par_iter().map(process_unit).collect::<Vec<_>>(); - - let check_unit = |summary: &UnitSummary| { - if !summary.internally_valid { - return; - } - for &(from, to) in summary.global_die_references.iter() { - let u = match processed_units.binary_search_by_key(&to, |v| v.offset) { - Ok(i) => &processed_units[i], - Err(i) => { - if i > 0 { - &processed_units[i - 1] - } else { - w.error(format!("Invalid cross-unit reference in unit {:#x} from DIE {:#x} to global DIE {:#x}: no unit found", - summary.offset.0, from.0, to.0)); - continue; - } - } - }; - if !u.internally_valid { - continue; - } - let to_offset = gimli::UnitOffset(to.0 - u.offset.0); - if u.die_offsets.binary_search(&to_offset).is_err() { - w.error(format!("Invalid cross-unit reference in unit {:#x} from DIE {:#x} to global DIE {:#x}: unit at {:#x} contains no DIE {:#x}", - summary.offset.0, from.0, to.0, u.offset.0, to_offset.0)); - } - } - }; - processed_units.par_iter().for_each(check_unit); -} diff --git a/vendor/gimli/examples/dwarfdump.rs b/vendor/gimli/examples/dwarfdump.rs deleted file mode 100644 index a11f298f8..000000000 --- a/vendor/gimli/examples/dwarfdump.rs +++ /dev/null @@ -1,2369 +0,0 @@ -// Allow clippy lints when building without clippy. -#![allow(unknown_lints)] - -use fallible_iterator::FallibleIterator; -use gimli::{Section, UnitHeader, UnitOffset, UnitSectionOffset, UnitType, UnwindSection}; -use object::{Object, ObjectSection, ObjectSymbol}; -use regex::bytes::Regex; -use std::borrow::{Borrow, Cow}; -use std::cmp::min; -use std::collections::HashMap; -use std::env; -use std::fmt::{self, Debug}; -use std::fs; -use std::io; -use std::io::{BufWriter, Write}; -use std::iter::Iterator; -use std::mem; -use std::process; -use std::result; -use std::sync::{Condvar, Mutex}; -use typed_arena::Arena; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Error { - GimliError(gimli::Error), - ObjectError(object::read::Error), - IoError, -} - -impl fmt::Display for Error { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> { - Debug::fmt(self, f) - } -} - -fn writeln_error<W: Write, R: Reader>( - w: &mut W, - dwarf: &gimli::Dwarf<R>, - err: Error, - msg: &str, -) -> io::Result<()> { - writeln!( - w, - "{}: {}", - msg, - match err { - Error::GimliError(err) => dwarf.format_error(err), - Error::ObjectError(err) => - format!("{}:{:?}", "An object error occurred while reading", err), - Error::IoError => "An I/O error occurred while writing.".to_string(), - } - ) -} - -impl From<gimli::Error> for Error { - fn from(err: gimli::Error) -> Self { - Error::GimliError(err) - } -} - -impl From<io::Error> for Error { - fn from(_: io::Error) -> Self { - Error::IoError - } -} - -impl From<object::read::Error> for Error { - fn from(err: object::read::Error) -> Self { - Error::ObjectError(err) - } -} - -pub type Result<T> = result::Result<T, Error>; - -fn parallel_output<W, II, F>(w: &mut W, max_workers: usize, iter: II, f: F) -> Result<()> -where - W: Write + Send, - F: Sync + Fn(II::Item, &mut Vec<u8>) -> Result<()>, - II: IntoIterator, - II::IntoIter: Send, -{ - struct ParallelOutputState<I, W> { - iterator: I, - current_worker: usize, - result: Result<()>, - w: W, - } - - let state = Mutex::new(ParallelOutputState { - iterator: iter.into_iter().fuse(), - current_worker: 0, - result: Ok(()), - w, - }); - let workers = min(max_workers, num_cpus::get()); - let mut condvars = Vec::new(); - for _ in 0..workers { - condvars.push(Condvar::new()); - } - { - let state_ref = &state; - let f_ref = &f; - let condvars_ref = &condvars; - crossbeam::scope(|scope| { - for i in 0..workers { - scope.spawn(move |_| { - let mut v = Vec::new(); - let mut lock = state_ref.lock().unwrap(); - while lock.current_worker != i { - lock = condvars_ref[i].wait(lock).unwrap(); - } - loop { - let item = if lock.result.is_ok() { - lock.iterator.next() - } else { - None - }; - lock.current_worker = (i + 1) % workers; - condvars_ref[lock.current_worker].notify_one(); - mem::drop(lock); - - let ret = if let Some(item) = item { - v.clear(); - f_ref(item, &mut v) - } else { - return; - }; - - lock = state_ref.lock().unwrap(); - while lock.current_worker != i { - lock = condvars_ref[i].wait(lock).unwrap(); - } - if lock.result.is_ok() { - let ret2 = lock.w.write_all(&v); - if ret.is_err() { - lock.result = ret; - } else { - lock.result = ret2.map_err(Error::from); - } - } - } - }); - } - }) - .unwrap(); - } - state.into_inner().unwrap().result -} - -trait Reader: gimli::Reader<Offset = usize> + Send + Sync {} - -impl<'input, Endian> Reader for gimli::EndianSlice<'input, Endian> where - Endian: gimli::Endianity + Send + Sync -{ -} - -type RelocationMap = HashMap<usize, object::Relocation>; - -fn add_relocations( - relocations: &mut RelocationMap, - file: &object::File, - section: &object::Section, -) { - for (offset64, mut relocation) in section.relocations() { - let offset = offset64 as usize; - if offset as u64 != offset64 { - continue; - } - let offset = offset as usize; - match relocation.kind() { - object::RelocationKind::Absolute => { - match relocation.target() { - object::RelocationTarget::Symbol(symbol_idx) => { - match file.symbol_by_index(symbol_idx) { - Ok(symbol) => { - let addend = - symbol.address().wrapping_add(relocation.addend() as u64); - relocation.set_addend(addend as i64); - } - Err(_) => { - eprintln!( - "Relocation with invalid symbol for section {} at offset 0x{:08x}", - section.name().unwrap(), - offset - ); - } - } - } - _ => {} - } - if relocations.insert(offset, relocation).is_some() { - eprintln!( - "Multiple relocations for section {} at offset 0x{:08x}", - section.name().unwrap(), - offset - ); - } - } - _ => { - eprintln!( - "Unsupported relocation for section {} at offset 0x{:08x}", - section.name().unwrap(), - offset - ); - } - } - } -} - -/// Apply relocations to addresses and offsets during parsing, -/// instead of requiring the data to be fully relocated prior -/// to parsing. -/// -/// Pros -/// - allows readonly buffers, we don't need to implement writing of values back to buffers -/// - potentially allows us to handle addresses and offsets differently -/// - potentially allows us to add metadata from the relocation (eg symbol names) -/// Cons -/// - maybe incomplete -#[derive(Debug, Clone)] -struct Relocate<'a, R: gimli::Reader<Offset = usize>> { - relocations: &'a RelocationMap, - section: R, - reader: R, -} - -impl<'a, R: gimli::Reader<Offset = usize>> Relocate<'a, R> { - fn relocate(&self, offset: usize, value: u64) -> u64 { - if let Some(relocation) = self.relocations.get(&offset) { - match relocation.kind() { - object::RelocationKind::Absolute => { - if relocation.has_implicit_addend() { - // Use the explicit addend too, because it may have the symbol value. - return value.wrapping_add(relocation.addend() as u64); - } else { - return relocation.addend() as u64; - } - } - _ => {} - } - }; - value - } -} - -impl<'a, R: gimli::Reader<Offset = usize>> gimli::Reader for Relocate<'a, R> { - type Endian = R::Endian; - type Offset = R::Offset; - - fn read_address(&mut self, address_size: u8) -> gimli::Result<u64> { - let offset = self.reader.offset_from(&self.section); - let value = self.reader.read_address(address_size)?; - Ok(self.relocate(offset, value)) - } - - fn read_length(&mut self, format: gimli::Format) -> gimli::Result<usize> { - let offset = self.reader.offset_from(&self.section); - let value = self.reader.read_length(format)?; - <usize as gimli::ReaderOffset>::from_u64(self.relocate(offset, value as u64)) - } - - fn read_offset(&mut self, format: gimli::Format) -> gimli::Result<usize> { - let offset = self.reader.offset_from(&self.section); - let value = self.reader.read_offset(format)?; - <usize as gimli::ReaderOffset>::from_u64(self.relocate(offset, value as u64)) - } - - fn read_sized_offset(&mut self, size: u8) -> gimli::Result<usize> { - let offset = self.reader.offset_from(&self.section); - let value = self.reader.read_sized_offset(size)?; - <usize as gimli::ReaderOffset>::from_u64(self.relocate(offset, value as u64)) - } - - #[inline] - fn split(&mut self, len: Self::Offset) -> gimli::Result<Self> { - let mut other = self.clone(); - other.reader.truncate(len)?; - self.reader.skip(len)?; - Ok(other) - } - - // All remaining methods simply delegate to `self.reader`. - - #[inline] - fn endian(&self) -> Self::Endian { - self.reader.endian() - } - - #[inline] - fn len(&self) -> Self::Offset { - self.reader.len() - } - - #[inline] - fn empty(&mut self) { - self.reader.empty() - } - - #[inline] - fn truncate(&mut self, len: Self::Offset) -> gimli::Result<()> { - self.reader.truncate(len) - } - - #[inline] - fn offset_from(&self, base: &Self) -> Self::Offset { - self.reader.offset_from(&base.reader) - } - - #[inline] - fn offset_id(&self) -> gimli::ReaderOffsetId { - self.reader.offset_id() - } - - #[inline] - fn lookup_offset_id(&self, id: gimli::ReaderOffsetId) -> Option<Self::Offset> { - self.reader.lookup_offset_id(id) - } - - #[inline] - fn find(&self, byte: u8) -> gimli::Result<Self::Offset> { - self.reader.find(byte) - } - - #[inline] - fn skip(&mut self, len: Self::Offset) -> gimli::Result<()> { - self.reader.skip(len) - } - - #[inline] - fn to_slice(&self) -> gimli::Result<Cow<[u8]>> { - self.reader.to_slice() - } - - #[inline] - fn to_string(&self) -> gimli::Result<Cow<str>> { - self.reader.to_string() - } - - #[inline] - fn to_string_lossy(&self) -> gimli::Result<Cow<str>> { - self.reader.to_string_lossy() - } - - #[inline] - fn read_slice(&mut self, buf: &mut [u8]) -> gimli::Result<()> { - self.reader.read_slice(buf) - } -} - -impl<'a, R: Reader> Reader for Relocate<'a, R> {} - -#[derive(Default)] -struct Flags<'a> { - eh_frame: bool, - goff: bool, - info: bool, - line: bool, - pubnames: bool, - pubtypes: bool, - aranges: bool, - dwo: bool, - dwp: bool, - dwo_parent: Option<object::File<'a>>, - sup: Option<object::File<'a>>, - raw: bool, - match_units: Option<Regex>, -} - -fn print_usage(opts: &getopts::Options) -> ! { - let brief = format!("Usage: {} <options> <file>", env::args().next().unwrap()); - write!(&mut io::stderr(), "{}", opts.usage(&brief)).ok(); - process::exit(1); -} - -fn main() { - let mut opts = getopts::Options::new(); - opts.optflag( - "", - "eh-frame", - "print .eh-frame exception handling frame information", - ); - opts.optflag("G", "", "show global die offsets"); - opts.optflag("i", "", "print .debug_info and .debug_types sections"); - opts.optflag("l", "", "print .debug_line section"); - opts.optflag("p", "", "print .debug_pubnames section"); - opts.optflag("r", "", "print .debug_aranges section"); - opts.optflag("y", "", "print .debug_pubtypes section"); - opts.optflag( - "", - "dwo", - "print the .dwo versions of the selected sections", - ); - opts.optflag( - "", - "dwp", - "print the .dwp versions of the selected sections", - ); - opts.optopt( - "", - "dwo-parent", - "use the specified file as the parent of the dwo or dwp (e.g. for .debug_addr)", - "library path", - ); - opts.optflag("", "raw", "print raw data values"); - opts.optopt( - "u", - "match-units", - "print compilation units whose output matches a regex", - "REGEX", - ); - opts.optopt("", "sup", "path to supplementary object file", "PATH"); - - let matches = match opts.parse(env::args().skip(1)) { - Ok(m) => m, - Err(e) => { - writeln!(&mut io::stderr(), "{:?}\n", e).ok(); - print_usage(&opts); - } - }; - if matches.free.is_empty() { - print_usage(&opts); - } - - let mut all = true; - let mut flags = Flags::default(); - if matches.opt_present("eh-frame") { - flags.eh_frame = true; - all = false; - } - if matches.opt_present("G") { - flags.goff = true; - } - if matches.opt_present("i") { - flags.info = true; - all = false; - } - if matches.opt_present("l") { - flags.line = true; - all = false; - } - if matches.opt_present("p") { - flags.pubnames = true; - all = false; - } - if matches.opt_present("y") { - flags.pubtypes = true; - all = false; - } - if matches.opt_present("r") { - flags.aranges = true; - all = false; - } - if matches.opt_present("dwo") { - flags.dwo = true; - } - if matches.opt_present("dwp") { - flags.dwp = true; - } - if matches.opt_present("raw") { - flags.raw = true; - } - if all { - // .eh_frame is excluded even when printing all information. - // cosmetic flags like -G must be set explicitly too. - flags.info = true; - flags.line = true; - flags.pubnames = true; - flags.pubtypes = true; - flags.aranges = true; - } - flags.match_units = if let Some(r) = matches.opt_str("u") { - match Regex::new(&r) { - Ok(r) => Some(r), - Err(e) => { - eprintln!("Invalid regular expression {}: {}", r, e); - process::exit(1); - } - } - } else { - None - }; - - let arena_mmap = Arena::new(); - let load_file = |path| { - let file = match fs::File::open(&path) { - Ok(file) => file, - Err(err) => { - eprintln!("Failed to open file '{}': {}", path, err); - process::exit(1); - } - }; - let mmap = match unsafe { memmap2::Mmap::map(&file) } { - Ok(mmap) => mmap, - Err(err) => { - eprintln!("Failed to map file '{}': {}", path, err); - process::exit(1); - } - }; - let mmap_ref = (*arena_mmap.alloc(mmap)).borrow(); - match object::File::parse(&**mmap_ref) { - Ok(file) => Some(file), - Err(err) => { - eprintln!("Failed to parse file '{}': {}", path, err); - process::exit(1); - } - } - }; - - flags.sup = matches.opt_str("sup").and_then(load_file); - flags.dwo_parent = matches.opt_str("dwo-parent").and_then(load_file); - if flags.dwo_parent.is_some() && !flags.dwo && !flags.dwp { - eprintln!("--dwo-parent also requires --dwo or --dwp"); - process::exit(1); - } - if flags.dwo_parent.is_none() && flags.dwp { - eprintln!("--dwp also requires --dwo-parent"); - process::exit(1); - } - - for file_path in &matches.free { - if matches.free.len() != 1 { - println!("{}", file_path); - println!(); - } - - let file = match fs::File::open(&file_path) { - Ok(file) => file, - Err(err) => { - eprintln!("Failed to open file '{}': {}", file_path, err); - continue; - } - }; - let file = match unsafe { memmap2::Mmap::map(&file) } { - Ok(mmap) => mmap, - Err(err) => { - eprintln!("Failed to map file '{}': {}", file_path, err); - continue; - } - }; - let file = match object::File::parse(&*file) { - Ok(file) => file, - Err(err) => { - eprintln!("Failed to parse file '{}': {}", file_path, err); - continue; - } - }; - - let endian = if file.is_little_endian() { - gimli::RunTimeEndian::Little - } else { - gimli::RunTimeEndian::Big - }; - let ret = dump_file(&file, endian, &flags); - match ret { - Ok(_) => (), - Err(err) => eprintln!("Failed to dump '{}': {}", file_path, err,), - } - } -} - -fn empty_file_section<'input, 'arena, Endian: gimli::Endianity>( - endian: Endian, - arena_relocations: &'arena Arena<RelocationMap>, -) -> Relocate<'arena, gimli::EndianSlice<'arena, Endian>> { - let reader = gimli::EndianSlice::new(&[], endian); - let section = reader; - let relocations = RelocationMap::default(); - let relocations = (*arena_relocations.alloc(relocations)).borrow(); - Relocate { - relocations, - section, - reader, - } -} - -fn load_file_section<'input, 'arena, Endian: gimli::Endianity>( - id: gimli::SectionId, - file: &object::File<'input>, - endian: Endian, - is_dwo: bool, - arena_data: &'arena Arena<Cow<'input, [u8]>>, - arena_relocations: &'arena Arena<RelocationMap>, -) -> Result<Relocate<'arena, gimli::EndianSlice<'arena, Endian>>> { - let mut relocations = RelocationMap::default(); - let name = if is_dwo { - id.dwo_name() - } else if file.format() == object::BinaryFormat::Xcoff { - id.xcoff_name() - } else { - Some(id.name()) - }; - - let data = match name.and_then(|name| file.section_by_name(&name)) { - Some(ref section) => { - // DWO sections never have relocations, so don't bother. - if !is_dwo { - add_relocations(&mut relocations, file, section); - } - section.uncompressed_data()? - } - // Use a non-zero capacity so that `ReaderOffsetId`s are unique. - None => Cow::Owned(Vec::with_capacity(1)), - }; - let data_ref = (*arena_data.alloc(data)).borrow(); - let reader = gimli::EndianSlice::new(data_ref, endian); - let section = reader; - let relocations = (*arena_relocations.alloc(relocations)).borrow(); - Ok(Relocate { - relocations, - section, - reader, - }) -} - -fn dump_file<Endian>(file: &object::File, endian: Endian, flags: &Flags) -> Result<()> -where - Endian: gimli::Endianity + Send + Sync, -{ - let arena_data = Arena::new(); - let arena_relocations = Arena::new(); - - let dwo_parent = if let Some(dwo_parent_file) = flags.dwo_parent.as_ref() { - let mut load_dwo_parent_section = |id: gimli::SectionId| -> Result<_> { - load_file_section( - id, - dwo_parent_file, - endian, - false, - &arena_data, - &arena_relocations, - ) - }; - Some(gimli::Dwarf::load(&mut load_dwo_parent_section)?) - } else { - None - }; - let dwo_parent = dwo_parent.as_ref(); - - let dwo_parent_units = if let Some(dwo_parent) = dwo_parent { - Some( - match dwo_parent - .units() - .map(|unit_header| dwo_parent.unit(unit_header)) - .filter_map(|unit| Ok(unit.dwo_id.map(|dwo_id| (dwo_id, unit)))) - .collect() - { - Ok(units) => units, - Err(err) => { - eprintln!("Failed to process --dwo-parent units: {}", err); - return Ok(()); - } - }, - ) - } else { - None - }; - let dwo_parent_units = dwo_parent_units.as_ref(); - - let mut load_section = |id: gimli::SectionId| -> Result<_> { - load_file_section( - id, - file, - endian, - flags.dwo || flags.dwp, - &arena_data, - &arena_relocations, - ) - }; - - let w = &mut BufWriter::new(io::stdout()); - if flags.dwp { - let empty = empty_file_section(endian, &arena_relocations); - let dwp = gimli::DwarfPackage::load(&mut load_section, empty)?; - dump_dwp(w, &dwp, dwo_parent.unwrap(), dwo_parent_units, flags)?; - w.flush()?; - return Ok(()); - } - - let mut dwarf = gimli::Dwarf::load(&mut load_section)?; - if flags.dwo { - if let Some(dwo_parent) = dwo_parent { - dwarf.make_dwo(&dwo_parent); - } else { - dwarf.file_type = gimli::DwarfFileType::Dwo; - } - } - - if let Some(sup_file) = flags.sup.as_ref() { - let mut load_sup_section = |id: gimli::SectionId| -> Result<_> { - // Note: we really only need the `.debug_str` section, - // but for now we load them all. - load_file_section(id, sup_file, endian, false, &arena_data, &arena_relocations) - }; - dwarf.load_sup(&mut load_sup_section)?; - } - - if flags.eh_frame { - let eh_frame = gimli::EhFrame::load(&mut load_section).unwrap(); - dump_eh_frame(w, file, eh_frame)?; - } - if flags.info { - dump_info(w, &dwarf, dwo_parent_units, flags)?; - dump_types(w, &dwarf, dwo_parent_units, flags)?; - } - if flags.line { - dump_line(w, &dwarf)?; - } - if flags.pubnames { - let debug_pubnames = &gimli::Section::load(&mut load_section).unwrap(); - dump_pubnames(w, debug_pubnames, &dwarf.debug_info)?; - } - if flags.aranges { - let debug_aranges = &gimli::Section::load(&mut load_section).unwrap(); - dump_aranges(w, debug_aranges)?; - } - if flags.pubtypes { - let debug_pubtypes = &gimli::Section::load(&mut load_section).unwrap(); - dump_pubtypes(w, debug_pubtypes, &dwarf.debug_info)?; - } - w.flush()?; - Ok(()) -} - -fn dump_eh_frame<R: Reader, W: Write>( - w: &mut W, - file: &object::File, - mut eh_frame: gimli::EhFrame<R>, -) -> Result<()> { - // TODO: this might be better based on the file format. - let address_size = file - .architecture() - .address_size() - .map(|w| w.bytes()) - .unwrap_or(mem::size_of::<usize>() as u8); - eh_frame.set_address_size(address_size); - - fn register_name_none(_: gimli::Register) -> Option<&'static str> { - None - } - let arch_register_name = match file.architecture() { - object::Architecture::Arm | object::Architecture::Aarch64 => gimli::Arm::register_name, - object::Architecture::I386 => gimli::X86::register_name, - object::Architecture::X86_64 => gimli::X86_64::register_name, - _ => register_name_none, - }; - let register_name = &|register| match arch_register_name(register) { - Some(name) => Cow::Borrowed(name), - None => Cow::Owned(format!("{}", register.0)), - }; - - let mut bases = gimli::BaseAddresses::default(); - if let Some(section) = file.section_by_name(".eh_frame_hdr") { - bases = bases.set_eh_frame_hdr(section.address()); - } - if let Some(section) = file.section_by_name(".eh_frame") { - bases = bases.set_eh_frame(section.address()); - } - if let Some(section) = file.section_by_name(".text") { - bases = bases.set_text(section.address()); - } - if let Some(section) = file.section_by_name(".got") { - bases = bases.set_got(section.address()); - } - - // TODO: Print "__eh_frame" here on macOS, and more generally use the - // section that we're actually looking at, which is what the canonical - // dwarfdump does. - writeln!( - w, - "Exception handling frame information for section .eh_frame" - )?; - - let mut cies = HashMap::new(); - - let mut entries = eh_frame.entries(&bases); - loop { - match entries.next()? { - None => return Ok(()), - Some(gimli::CieOrFde::Cie(cie)) => { - writeln!(w)?; - writeln!(w, "{:#010x}: CIE", cie.offset())?; - writeln!(w, " length: {:#010x}", cie.entry_len())?; - // TODO: CIE_id - writeln!(w, " version: {:#04x}", cie.version())?; - // TODO: augmentation - writeln!(w, " code_align: {}", cie.code_alignment_factor())?; - writeln!(w, " data_align: {}", cie.data_alignment_factor())?; - writeln!( - w, - " ra_register: {}", - register_name(cie.return_address_register()) - )?; - if let Some(encoding) = cie.lsda_encoding() { - writeln!( - w, - " lsda_encoding: {}/{}", - encoding.application(), - encoding.format() - )?; - } - if let Some((encoding, personality)) = cie.personality_with_encoding() { - write!( - w, - " personality: {}/{} ", - encoding.application(), - encoding.format() - )?; - dump_pointer(w, personality)?; - writeln!(w)?; - } - if let Some(encoding) = cie.fde_address_encoding() { - writeln!( - w, - " fde_encoding: {}/{}", - encoding.application(), - encoding.format() - )?; - } - let instructions = cie.instructions(&eh_frame, &bases); - dump_cfi_instructions(w, instructions, true, register_name)?; - writeln!(w)?; - } - Some(gimli::CieOrFde::Fde(partial)) => { - let mut offset = None; - let fde = partial.parse(|_, bases, o| { - offset = Some(o); - cies.entry(o) - .or_insert_with(|| eh_frame.cie_from_offset(bases, o)) - .clone() - })?; - - writeln!(w)?; - writeln!(w, "{:#010x}: FDE", fde.offset())?; - writeln!(w, " length: {:#010x}", fde.entry_len())?; - writeln!(w, " CIE_pointer: {:#010x}", offset.unwrap().0)?; - // TODO: symbolicate the start address like the canonical dwarfdump does. - writeln!(w, " start_addr: {:#018x}", fde.initial_address())?; - writeln!( - w, - " range_size: {:#018x} (end_addr = {:#018x})", - fde.len(), - fde.initial_address() + fde.len() - )?; - if let Some(lsda) = fde.lsda() { - write!(w, " lsda: ")?; - dump_pointer(w, lsda)?; - writeln!(w)?; - } - let instructions = fde.instructions(&eh_frame, &bases); - dump_cfi_instructions(w, instructions, false, register_name)?; - writeln!(w)?; - } - } - } -} - -fn dump_pointer<W: Write>(w: &mut W, p: gimli::Pointer) -> Result<()> { - match p { - gimli::Pointer::Direct(p) => { - write!(w, "{:#018x}", p)?; - } - gimli::Pointer::Indirect(p) => { - write!(w, "({:#018x})", p)?; - } - } - Ok(()) -} - -#[allow(clippy::unneeded_field_pattern)] -fn dump_cfi_instructions<R: Reader, W: Write>( - w: &mut W, - mut insns: gimli::CallFrameInstructionIter<R>, - is_initial: bool, - register_name: &dyn Fn(gimli::Register) -> Cow<'static, str>, -) -> Result<()> { - use gimli::CallFrameInstruction::*; - - // TODO: we need to actually evaluate these instructions as we iterate them - // so we can print the initialized state for CIEs, and each unwind row's - // registers for FDEs. - // - // TODO: We should print DWARF expressions for the CFI instructions that - // embed DWARF expressions within themselves. - - if !is_initial { - writeln!(w, " Instructions:")?; - } - - loop { - match insns.next() { - Err(e) => { - writeln!(w, "Failed to decode CFI instruction: {}", e)?; - return Ok(()); - } - Ok(None) => { - if is_initial { - writeln!(w, " Instructions: Init State:")?; - } - return Ok(()); - } - Ok(Some(op)) => match op { - SetLoc { address } => { - writeln!(w, " DW_CFA_set_loc ({:#x})", address)?; - } - AdvanceLoc { delta } => { - writeln!(w, " DW_CFA_advance_loc ({})", delta)?; - } - DefCfa { register, offset } => { - writeln!( - w, - " DW_CFA_def_cfa ({}, {})", - register_name(register), - offset - )?; - } - DefCfaSf { - register, - factored_offset, - } => { - writeln!( - w, - " DW_CFA_def_cfa_sf ({}, {})", - register_name(register), - factored_offset - )?; - } - DefCfaRegister { register } => { - writeln!( - w, - " DW_CFA_def_cfa_register ({})", - register_name(register) - )?; - } - DefCfaOffset { offset } => { - writeln!(w, " DW_CFA_def_cfa_offset ({})", offset)?; - } - DefCfaOffsetSf { factored_offset } => { - writeln!( - w, - " DW_CFA_def_cfa_offset_sf ({})", - factored_offset - )?; - } - DefCfaExpression { expression: _ } => { - writeln!(w, " DW_CFA_def_cfa_expression (...)")?; - } - Undefined { register } => { - writeln!( - w, - " DW_CFA_undefined ({})", - register_name(register) - )?; - } - SameValue { register } => { - writeln!( - w, - " DW_CFA_same_value ({})", - register_name(register) - )?; - } - Offset { - register, - factored_offset, - } => { - writeln!( - w, - " DW_CFA_offset ({}, {})", - register_name(register), - factored_offset - )?; - } - OffsetExtendedSf { - register, - factored_offset, - } => { - writeln!( - w, - " DW_CFA_offset_extended_sf ({}, {})", - register_name(register), - factored_offset - )?; - } - ValOffset { - register, - factored_offset, - } => { - writeln!( - w, - " DW_CFA_val_offset ({}, {})", - register_name(register), - factored_offset - )?; - } - ValOffsetSf { - register, - factored_offset, - } => { - writeln!( - w, - " DW_CFA_val_offset_sf ({}, {})", - register_name(register), - factored_offset - )?; - } - Register { - dest_register, - src_register, - } => { - writeln!( - w, - " DW_CFA_register ({}, {})", - register_name(dest_register), - register_name(src_register) - )?; - } - Expression { - register, - expression: _, - } => { - writeln!( - w, - " DW_CFA_expression ({}, ...)", - register_name(register) - )?; - } - ValExpression { - register, - expression: _, - } => { - writeln!( - w, - " DW_CFA_val_expression ({}, ...)", - register_name(register) - )?; - } - Restore { register } => { - writeln!( - w, - " DW_CFA_restore ({})", - register_name(register) - )?; - } - RememberState => { - writeln!(w, " DW_CFA_remember_state")?; - } - RestoreState => { - writeln!(w, " DW_CFA_restore_state")?; - } - ArgsSize { size } => { - writeln!(w, " DW_CFA_GNU_args_size ({})", size)?; - } - Nop => { - writeln!(w, " DW_CFA_nop")?; - } - }, - } - } -} - -fn dump_dwp<R: Reader, W: Write + Send>( - w: &mut W, - dwp: &gimli::DwarfPackage<R>, - dwo_parent: &gimli::Dwarf<R>, - dwo_parent_units: Option<&HashMap<gimli::DwoId, gimli::Unit<R>>>, - flags: &Flags, -) -> Result<()> -where - R::Endian: Send + Sync, -{ - if dwp.cu_index.unit_count() != 0 { - writeln!( - w, - "\n.debug_cu_index: version = {}, sections = {}, units = {}, slots = {}", - dwp.cu_index.version(), - dwp.cu_index.section_count(), - dwp.cu_index.unit_count(), - dwp.cu_index.slot_count(), - )?; - for i in 1..=dwp.cu_index.unit_count() { - writeln!(w, "\nCU index {}", i)?; - dump_dwp_sections( - w, - &dwp, - dwo_parent, - dwo_parent_units, - flags, - dwp.cu_index.sections(i)?, - )?; - } - } - - if dwp.tu_index.unit_count() != 0 { - writeln!( - w, - "\n.debug_tu_index: version = {}, sections = {}, units = {}, slots = {}", - dwp.tu_index.version(), - dwp.tu_index.section_count(), - dwp.tu_index.unit_count(), - dwp.tu_index.slot_count(), - )?; - for i in 1..=dwp.tu_index.unit_count() { - writeln!(w, "\nTU index {}", i)?; - dump_dwp_sections( - w, - &dwp, - dwo_parent, - dwo_parent_units, - flags, - dwp.tu_index.sections(i)?, - )?; - } - } - - Ok(()) -} - -fn dump_dwp_sections<R: Reader, W: Write + Send>( - w: &mut W, - dwp: &gimli::DwarfPackage<R>, - dwo_parent: &gimli::Dwarf<R>, - dwo_parent_units: Option<&HashMap<gimli::DwoId, gimli::Unit<R>>>, - flags: &Flags, - sections: gimli::UnitIndexSectionIterator<R>, -) -> Result<()> -where - R::Endian: Send + Sync, -{ - for section in sections.clone() { - writeln!( - w, - " {}: offset = 0x{:x}, size = 0x{:x}", - section.section.dwo_name().unwrap(), - section.offset, - section.size - )?; - } - let dwarf = dwp.sections(sections, dwo_parent)?; - if flags.info { - dump_info(w, &dwarf, dwo_parent_units, flags)?; - dump_types(w, &dwarf, dwo_parent_units, flags)?; - } - if flags.line { - dump_line(w, &dwarf)?; - } - Ok(()) -} - -fn dump_info<R: Reader, W: Write + Send>( - w: &mut W, - dwarf: &gimli::Dwarf<R>, - dwo_parent_units: Option<&HashMap<gimli::DwoId, gimli::Unit<R>>>, - flags: &Flags, -) -> Result<()> -where - R::Endian: Send + Sync, -{ - writeln!(w, "\n.debug_info")?; - - let units = match dwarf.units().collect::<Vec<_>>() { - Ok(units) => units, - Err(err) => { - writeln_error( - w, - dwarf, - Error::GimliError(err), - "Failed to read unit headers", - )?; - return Ok(()); - } - }; - let process_unit = |header: UnitHeader<R>, buf: &mut Vec<u8>| -> Result<()> { - dump_unit(buf, header, dwarf, dwo_parent_units, flags)?; - if !flags - .match_units - .as_ref() - .map(|r| r.is_match(&buf)) - .unwrap_or(true) - { - buf.clear(); - } - Ok(()) - }; - // Don't use more than 16 cores even if available. No point in soaking hundreds - // of cores if you happen to have them. - parallel_output(w, 16, units, process_unit) -} - -fn dump_types<R: Reader, W: Write>( - w: &mut W, - dwarf: &gimli::Dwarf<R>, - dwo_parent_units: Option<&HashMap<gimli::DwoId, gimli::Unit<R>>>, - flags: &Flags, -) -> Result<()> { - writeln!(w, "\n.debug_types")?; - - let mut iter = dwarf.type_units(); - while let Some(header) = iter.next()? { - dump_unit(w, header, dwarf, dwo_parent_units, flags)?; - } - Ok(()) -} - -fn dump_unit<R: Reader, W: Write>( - w: &mut W, - header: UnitHeader<R>, - dwarf: &gimli::Dwarf<R>, - dwo_parent_units: Option<&HashMap<gimli::DwoId, gimli::Unit<R>>>, - flags: &Flags, -) -> Result<()> { - write!(w, "\nUNIT<")?; - match header.offset() { - UnitSectionOffset::DebugInfoOffset(o) => { - write!(w, ".debug_info+0x{:08x}", o.0)?; - } - UnitSectionOffset::DebugTypesOffset(o) => { - write!(w, ".debug_types+0x{:08x}", o.0)?; - } - } - writeln!(w, ">: length = 0x{:x}, format = {:?}, version = {}, address_size = {}, abbrev_offset = 0x{:x}", - header.unit_length(), - header.format(), - header.version(), - header.address_size(), - header.debug_abbrev_offset().0, - )?; - - match header.type_() { - UnitType::Compilation | UnitType::Partial => (), - UnitType::Type { - type_signature, - type_offset, - } - | UnitType::SplitType { - type_signature, - type_offset, - } => { - write!(w, " signature = ")?; - dump_type_signature(w, type_signature)?; - writeln!(w)?; - writeln!(w, " type_offset = 0x{:x}", type_offset.0,)?; - } - UnitType::Skeleton(dwo_id) | UnitType::SplitCompilation(dwo_id) => { - write!(w, " dwo_id = ")?; - writeln!(w, "0x{:016x}", dwo_id.0)?; - } - } - - let mut unit = match dwarf.unit(header) { - Ok(unit) => unit, - Err(err) => { - writeln_error(w, dwarf, err.into(), "Failed to parse unit root entry")?; - return Ok(()); - } - }; - - if let Some(dwo_parent_units) = dwo_parent_units { - if let Some(dwo_id) = unit.dwo_id { - if let Some(parent_unit) = dwo_parent_units.get(&dwo_id) { - unit.copy_relocated_attributes(parent_unit); - } - } - } - - let entries_result = dump_entries(w, unit, dwarf, flags); - if let Err(err) = entries_result { - writeln_error(w, dwarf, err, "Failed to dump entries")?; - } - Ok(()) -} - -fn spaces(buf: &mut String, len: usize) -> &str { - while buf.len() < len { - buf.push(' '); - } - &buf[..len] -} - -// " GOFF=0x{:08x}" adds exactly 16 spaces. -const GOFF_SPACES: usize = 16; - -fn write_offset<R: Reader, W: Write>( - w: &mut W, - unit: &gimli::Unit<R>, - offset: gimli::UnitOffset<R::Offset>, - flags: &Flags, -) -> Result<()> { - write!(w, "<0x{:08x}", offset.0)?; - if flags.goff { - let goff = match offset.to_unit_section_offset(unit) { - UnitSectionOffset::DebugInfoOffset(o) => o.0, - UnitSectionOffset::DebugTypesOffset(o) => o.0, - }; - write!(w, " GOFF=0x{:08x}", goff)?; - } - write!(w, ">")?; - Ok(()) -} - -fn dump_entries<R: Reader, W: Write>( - w: &mut W, - unit: gimli::Unit<R>, - dwarf: &gimli::Dwarf<R>, - flags: &Flags, -) -> Result<()> { - let mut spaces_buf = String::new(); - - let mut entries = unit.entries_raw(None)?; - while !entries.is_empty() { - let offset = entries.next_offset(); - let depth = entries.next_depth(); - let abbrev = entries.read_abbreviation()?; - - let mut indent = if depth >= 0 { - depth as usize * 2 + 2 - } else { - 2 - }; - write!(w, "<{}{}>", if depth < 10 { " " } else { "" }, depth)?; - write_offset(w, &unit, offset, flags)?; - writeln!( - w, - "{}{}", - spaces(&mut spaces_buf, indent), - abbrev.map(|x| x.tag()).unwrap_or(gimli::DW_TAG_null) - )?; - - indent += 18; - if flags.goff { - indent += GOFF_SPACES; - } - - for spec in abbrev.map(|x| x.attributes()).unwrap_or(&[]) { - let attr = entries.read_attribute(*spec)?; - w.write_all(spaces(&mut spaces_buf, indent).as_bytes())?; - if let Some(n) = attr.name().static_string() { - let right_padding = 27 - std::cmp::min(27, n.len()); - write!(w, "{}{} ", n, spaces(&mut spaces_buf, right_padding))?; - } else { - write!(w, "{:27} ", attr.name())?; - } - if flags.raw { - writeln!(w, "{:?}", attr.raw_value())?; - } else { - match dump_attr_value(w, &attr, &unit, dwarf) { - Ok(_) => (), - Err(err) => writeln_error(w, dwarf, err, "Failed to dump attribute value")?, - }; - } - } - } - Ok(()) -} - -fn dump_attr_value<R: Reader, W: Write>( - w: &mut W, - attr: &gimli::Attribute<R>, - unit: &gimli::Unit<R>, - dwarf: &gimli::Dwarf<R>, -) -> Result<()> { - let value = attr.value(); - match value { - gimli::AttributeValue::Addr(address) => { - writeln!(w, "0x{:08x}", address)?; - } - gimli::AttributeValue::Block(data) => { - for byte in data.to_slice()?.iter() { - write!(w, "{:02x}", byte)?; - } - writeln!(w)?; - } - gimli::AttributeValue::Data1(_) - | gimli::AttributeValue::Data2(_) - | gimli::AttributeValue::Data4(_) - | gimli::AttributeValue::Data8(_) => { - if let (Some(udata), Some(sdata)) = (attr.udata_value(), attr.sdata_value()) { - if sdata >= 0 { - writeln!(w, "{}", udata)?; - } else { - writeln!(w, "{} ({})", udata, sdata)?; - } - } else { - writeln!(w, "{:?}", value)?; - } - } - gimli::AttributeValue::Sdata(data) => { - match attr.name() { - gimli::DW_AT_data_member_location => { - writeln!(w, "{}", data)?; - } - _ => { - if data >= 0 { - writeln!(w, "0x{:08x}", data)?; - } else { - writeln!(w, "0x{:08x} ({})", data, data)?; - } - } - }; - } - gimli::AttributeValue::Udata(data) => { - match attr.name() { - gimli::DW_AT_high_pc => { - writeln!(w, "<offset-from-lowpc>{}", data)?; - } - gimli::DW_AT_data_member_location => { - if let Some(sdata) = attr.sdata_value() { - // This is a DW_FORM_data* value. - // libdwarf-dwarfdump displays this as signed too. - if sdata >= 0 { - writeln!(w, "{}", data)?; - } else { - writeln!(w, "{} ({})", data, sdata)?; - } - } else { - writeln!(w, "{}", data)?; - } - } - gimli::DW_AT_lower_bound | gimli::DW_AT_upper_bound => { - writeln!(w, "{}", data)?; - } - _ => { - writeln!(w, "0x{:08x}", data)?; - } - }; - } - gimli::AttributeValue::Exprloc(ref data) => { - if let gimli::AttributeValue::Exprloc(_) = attr.raw_value() { - write!(w, "len 0x{:04x}: ", data.0.len())?; - for byte in data.0.to_slice()?.iter() { - write!(w, "{:02x}", byte)?; - } - write!(w, ": ")?; - } - dump_exprloc(w, unit.encoding(), data)?; - writeln!(w)?; - } - gimli::AttributeValue::Flag(true) => { - writeln!(w, "yes")?; - } - gimli::AttributeValue::Flag(false) => { - writeln!(w, "no")?; - } - gimli::AttributeValue::SecOffset(offset) => { - writeln!(w, "0x{:08x}", offset)?; - } - gimli::AttributeValue::DebugAddrBase(base) => { - writeln!(w, "<.debug_addr+0x{:08x}>", base.0)?; - } - gimli::AttributeValue::DebugAddrIndex(index) => { - write!(w, "(indirect address, index {:#x}): ", index.0)?; - let address = dwarf.address(unit, index)?; - writeln!(w, "0x{:08x}", address)?; - } - gimli::AttributeValue::UnitRef(offset) => { - write!(w, "0x{:08x}", offset.0)?; - match offset.to_unit_section_offset(unit) { - UnitSectionOffset::DebugInfoOffset(goff) => { - write!(w, "<.debug_info+0x{:08x}>", goff.0)?; - } - UnitSectionOffset::DebugTypesOffset(goff) => { - write!(w, "<.debug_types+0x{:08x}>", goff.0)?; - } - } - writeln!(w)?; - } - gimli::AttributeValue::DebugInfoRef(offset) => { - writeln!(w, "<.debug_info+0x{:08x}>", offset.0)?; - } - gimli::AttributeValue::DebugInfoRefSup(offset) => { - writeln!(w, "<.debug_info(sup)+0x{:08x}>", offset.0)?; - } - gimli::AttributeValue::DebugLineRef(offset) => { - writeln!(w, "<.debug_line+0x{:08x}>", offset.0)?; - } - gimli::AttributeValue::LocationListsRef(offset) => { - dump_loc_list(w, offset, unit, dwarf)?; - } - gimli::AttributeValue::DebugLocListsBase(base) => { - writeln!(w, "<.debug_loclists+0x{:08x}>", base.0)?; - } - gimli::AttributeValue::DebugLocListsIndex(index) => { - write!(w, "(indirect location list, index {:#x}): ", index.0)?; - let offset = dwarf.locations_offset(unit, index)?; - dump_loc_list(w, offset, unit, dwarf)?; - } - gimli::AttributeValue::DebugMacinfoRef(offset) => { - writeln!(w, "<.debug_macinfo+0x{:08x}>", offset.0)?; - } - gimli::AttributeValue::DebugMacroRef(offset) => { - writeln!(w, "<.debug_macro+0x{:08x}>", offset.0)?; - } - gimli::AttributeValue::RangeListsRef(offset) => { - let offset = dwarf.ranges_offset_from_raw(unit, offset); - dump_range_list(w, offset, unit, dwarf)?; - } - gimli::AttributeValue::DebugRngListsBase(base) => { - writeln!(w, "<.debug_rnglists+0x{:08x}>", base.0)?; - } - gimli::AttributeValue::DebugRngListsIndex(index) => { - write!(w, "(indirect range list, index {:#x}): ", index.0)?; - let offset = dwarf.ranges_offset(unit, index)?; - dump_range_list(w, offset, unit, dwarf)?; - } - gimli::AttributeValue::DebugTypesRef(signature) => { - dump_type_signature(w, signature)?; - writeln!(w, " <type signature>")?; - } - gimli::AttributeValue::DebugStrRef(offset) => { - if let Ok(s) = dwarf.debug_str.get_str(offset) { - writeln!(w, "{}", s.to_string_lossy()?)?; - } else { - writeln!(w, "<.debug_str+0x{:08x}>", offset.0)?; - } - } - gimli::AttributeValue::DebugStrRefSup(offset) => { - if let Some(s) = dwarf - .sup() - .and_then(|sup| sup.debug_str.get_str(offset).ok()) - { - writeln!(w, "{}", s.to_string_lossy()?)?; - } else { - writeln!(w, "<.debug_str(sup)+0x{:08x}>", offset.0)?; - } - } - gimli::AttributeValue::DebugStrOffsetsBase(base) => { - writeln!(w, "<.debug_str_offsets+0x{:08x}>", base.0)?; - } - gimli::AttributeValue::DebugStrOffsetsIndex(index) => { - write!(w, "(indirect string, index {:#x}): ", index.0)?; - let offset = dwarf.debug_str_offsets.get_str_offset( - unit.encoding().format, - unit.str_offsets_base, - index, - )?; - if let Ok(s) = dwarf.debug_str.get_str(offset) { - writeln!(w, "{}", s.to_string_lossy()?)?; - } else { - writeln!(w, "<.debug_str+0x{:08x}>", offset.0)?; - } - } - gimli::AttributeValue::DebugLineStrRef(offset) => { - if let Ok(s) = dwarf.debug_line_str.get_str(offset) { - writeln!(w, "{}", s.to_string_lossy()?)?; - } else { - writeln!(w, "<.debug_line_str=0x{:08x}>", offset.0)?; - } - } - gimli::AttributeValue::String(s) => { - writeln!(w, "{}", s.to_string_lossy()?)?; - } - gimli::AttributeValue::Encoding(value) => { - writeln!(w, "{}", value)?; - } - gimli::AttributeValue::DecimalSign(value) => { - writeln!(w, "{}", value)?; - } - gimli::AttributeValue::Endianity(value) => { - writeln!(w, "{}", value)?; - } - gimli::AttributeValue::Accessibility(value) => { - writeln!(w, "{}", value)?; - } - gimli::AttributeValue::Visibility(value) => { - writeln!(w, "{}", value)?; - } - gimli::AttributeValue::Virtuality(value) => { - writeln!(w, "{}", value)?; - } - gimli::AttributeValue::Language(value) => { - writeln!(w, "{}", value)?; - } - gimli::AttributeValue::AddressClass(value) => { - writeln!(w, "{}", value)?; - } - gimli::AttributeValue::IdentifierCase(value) => { - writeln!(w, "{}", value)?; - } - gimli::AttributeValue::CallingConvention(value) => { - writeln!(w, "{}", value)?; - } - gimli::AttributeValue::Inline(value) => { - writeln!(w, "{}", value)?; - } - gimli::AttributeValue::Ordering(value) => { - writeln!(w, "{}", value)?; - } - gimli::AttributeValue::FileIndex(value) => { - write!(w, "0x{:08x}", value)?; - dump_file_index(w, value, unit, dwarf)?; - writeln!(w)?; - } - gimli::AttributeValue::DwoId(value) => { - writeln!(w, "0x{:016x}", value.0)?; - } - } - - Ok(()) -} - -fn dump_type_signature<W: Write>(w: &mut W, signature: gimli::DebugTypeSignature) -> Result<()> { - write!(w, "0x{:016x}", signature.0)?; - Ok(()) -} - -fn dump_file_index<R: Reader, W: Write>( - w: &mut W, - file_index: u64, - unit: &gimli::Unit<R>, - dwarf: &gimli::Dwarf<R>, -) -> Result<()> { - if file_index == 0 && unit.header.version() <= 4 { - return Ok(()); - } - let header = match unit.line_program { - Some(ref program) => program.header(), - None => return Ok(()), - }; - let file = match header.file(file_index) { - Some(file) => file, - None => { - writeln!(w, "Unable to get header for file {}", file_index)?; - return Ok(()); - } - }; - write!(w, " ")?; - if let Some(directory) = file.directory(header) { - let directory = dwarf.attr_string(unit, directory)?; - let directory = directory.to_string_lossy()?; - if file.directory_index() != 0 && !directory.starts_with('/') { - if let Some(ref comp_dir) = unit.comp_dir { - write!(w, "{}/", comp_dir.to_string_lossy()?,)?; - } - } - write!(w, "{}/", directory)?; - } - write!( - w, - "{}", - dwarf - .attr_string(unit, file.path_name())? - .to_string_lossy()? - )?; - Ok(()) -} - -fn dump_exprloc<R: Reader, W: Write>( - w: &mut W, - encoding: gimli::Encoding, - data: &gimli::Expression<R>, -) -> Result<()> { - let mut pc = data.0.clone(); - let mut space = false; - while pc.len() != 0 { - let pc_clone = pc.clone(); - match gimli::Operation::parse(&mut pc, encoding) { - Ok(op) => { - if space { - write!(w, " ")?; - } else { - space = true; - } - dump_op(w, encoding, pc_clone, op)?; - } - Err(gimli::Error::InvalidExpression(op)) => { - writeln!(w, "WARNING: unsupported operation 0x{:02x}", op.0)?; - return Ok(()); - } - Err(gimli::Error::UnsupportedRegister(register)) => { - writeln!(w, "WARNING: unsupported register {}", register)?; - return Ok(()); - } - Err(gimli::Error::UnexpectedEof(_)) => { - writeln!(w, "WARNING: truncated or malformed expression")?; - return Ok(()); - } - Err(e) => { - writeln!(w, "WARNING: unexpected operation parse error: {}", e)?; - return Ok(()); - } - } - } - Ok(()) -} - -fn dump_op<R: Reader, W: Write>( - w: &mut W, - encoding: gimli::Encoding, - mut pc: R, - op: gimli::Operation<R>, -) -> Result<()> { - let dwop = gimli::DwOp(pc.read_u8()?); - write!(w, "{}", dwop)?; - match op { - gimli::Operation::Deref { - base_type, size, .. - } => { - if dwop == gimli::DW_OP_deref_size || dwop == gimli::DW_OP_xderef_size { - write!(w, " {}", size)?; - } - if base_type != UnitOffset(0) { - write!(w, " type 0x{:08x}", base_type.0)?; - } - } - gimli::Operation::Pick { index } => { - if dwop == gimli::DW_OP_pick { - write!(w, " {}", index)?; - } - } - gimli::Operation::PlusConstant { value } => { - write!(w, " {}", value as i64)?; - } - gimli::Operation::Bra { target } => { - write!(w, " {}", target)?; - } - gimli::Operation::Skip { target } => { - write!(w, " {}", target)?; - } - gimli::Operation::SignedConstant { value } => match dwop { - gimli::DW_OP_const1s - | gimli::DW_OP_const2s - | gimli::DW_OP_const4s - | gimli::DW_OP_const8s - | gimli::DW_OP_consts => { - write!(w, " {}", value)?; - } - _ => {} - }, - gimli::Operation::UnsignedConstant { value } => match dwop { - gimli::DW_OP_const1u - | gimli::DW_OP_const2u - | gimli::DW_OP_const4u - | gimli::DW_OP_const8u - | gimli::DW_OP_constu => { - write!(w, " {}", value)?; - } - _ => { - // These have the value encoded in the operation, eg DW_OP_lit0. - } - }, - gimli::Operation::Register { register } => { - if dwop == gimli::DW_OP_regx { - write!(w, " {}", register.0)?; - } - } - gimli::Operation::RegisterOffset { - register, - offset, - base_type, - } => { - if dwop >= gimli::DW_OP_breg0 && dwop <= gimli::DW_OP_breg31 { - write!(w, "{:+}", offset)?; - } else { - write!(w, " {}", register.0)?; - if offset != 0 { - write!(w, "{:+}", offset)?; - } - if base_type != UnitOffset(0) { - write!(w, " type 0x{:08x}", base_type.0)?; - } - } - } - gimli::Operation::FrameOffset { offset } => { - write!(w, " {}", offset)?; - } - gimli::Operation::Call { offset } => match offset { - gimli::DieReference::UnitRef(gimli::UnitOffset(offset)) => { - write!(w, " 0x{:08x}", offset)?; - } - gimli::DieReference::DebugInfoRef(gimli::DebugInfoOffset(offset)) => { - write!(w, " 0x{:08x}", offset)?; - } - }, - gimli::Operation::Piece { - size_in_bits, - bit_offset: None, - } => { - write!(w, " {}", size_in_bits / 8)?; - } - gimli::Operation::Piece { - size_in_bits, - bit_offset: Some(bit_offset), - } => { - write!(w, " 0x{:08x} offset 0x{:08x}", size_in_bits, bit_offset)?; - } - gimli::Operation::ImplicitValue { data } => { - let data = data.to_slice()?; - write!(w, " 0x{:08x} contents 0x", data.len())?; - for byte in data.iter() { - write!(w, "{:02x}", byte)?; - } - } - gimli::Operation::ImplicitPointer { value, byte_offset } => { - write!(w, " 0x{:08x} {}", value.0, byte_offset)?; - } - gimli::Operation::EntryValue { expression } => { - write!(w, "(")?; - dump_exprloc(w, encoding, &gimli::Expression(expression))?; - write!(w, ")")?; - } - gimli::Operation::ParameterRef { offset } => { - write!(w, " 0x{:08x}", offset.0)?; - } - gimli::Operation::Address { address } => { - write!(w, " 0x{:08x}", address)?; - } - gimli::Operation::AddressIndex { index } => { - write!(w, " 0x{:08x}", index.0)?; - } - gimli::Operation::ConstantIndex { index } => { - write!(w, " 0x{:08x}", index.0)?; - } - gimli::Operation::TypedLiteral { base_type, value } => { - write!(w, " type 0x{:08x} contents 0x", base_type.0)?; - for byte in value.to_slice()?.iter() { - write!(w, "{:02x}", byte)?; - } - } - gimli::Operation::Convert { base_type } => { - write!(w, " type 0x{:08x}", base_type.0)?; - } - gimli::Operation::Reinterpret { base_type } => { - write!(w, " type 0x{:08x}", base_type.0)?; - } - gimli::Operation::WasmLocal { index } - | gimli::Operation::WasmGlobal { index } - | gimli::Operation::WasmStack { index } => { - let wasmop = pc.read_u8()?; - write!(w, " 0x{:x} 0x{:x}", wasmop, index)?; - } - gimli::Operation::Drop - | gimli::Operation::Swap - | gimli::Operation::Rot - | gimli::Operation::Abs - | gimli::Operation::And - | gimli::Operation::Div - | gimli::Operation::Minus - | gimli::Operation::Mod - | gimli::Operation::Mul - | gimli::Operation::Neg - | gimli::Operation::Not - | gimli::Operation::Or - | gimli::Operation::Plus - | gimli::Operation::Shl - | gimli::Operation::Shr - | gimli::Operation::Shra - | gimli::Operation::Xor - | gimli::Operation::Eq - | gimli::Operation::Ge - | gimli::Operation::Gt - | gimli::Operation::Le - | gimli::Operation::Lt - | gimli::Operation::Ne - | gimli::Operation::Nop - | gimli::Operation::PushObjectAddress - | gimli::Operation::TLS - | gimli::Operation::CallFrameCFA - | gimli::Operation::StackValue => {} - }; - Ok(()) -} - -fn dump_range<W: Write>(w: &mut W, range: Option<gimli::Range>) -> Result<()> { - if let Some(range) = range { - write!(w, " [0x{:08x}, 0x{:08x}]", range.begin, range.end)?; - } else { - write!(w, " [ignored]")?; - } - Ok(()) -} - -fn dump_loc_list<R: Reader, W: Write>( - w: &mut W, - offset: gimli::LocationListsOffset<R::Offset>, - unit: &gimli::Unit<R>, - dwarf: &gimli::Dwarf<R>, -) -> Result<()> { - let mut locations = dwarf.locations(unit, offset)?; - writeln!( - w, - "<loclist at {}+0x{:08x}>", - if unit.encoding().version < 5 { - ".debug_loc" - } else { - ".debug_loclists" - }, - offset.0, - )?; - let mut i = 0; - while let Some(raw) = locations.next_raw()? { - write!(w, "\t\t\t[{:2}]", i)?; - i += 1; - let range = locations - .convert_raw(raw.clone())? - .map(|location| location.range); - match raw { - gimli::RawLocListEntry::BaseAddress { addr } => { - writeln!(w, "<base-address 0x{:08x}>", addr)?; - } - gimli::RawLocListEntry::BaseAddressx { addr } => { - let addr_val = dwarf.address(unit, addr)?; - writeln!(w, "<base-addressx [{}]0x{:08x}>", addr.0, addr_val)?; - } - gimli::RawLocListEntry::StartxEndx { - begin, - end, - ref data, - } => { - let begin_val = dwarf.address(unit, begin)?; - let end_val = dwarf.address(unit, end)?; - write!( - w, - "<startx-endx [{}]0x{:08x}, [{}]0x{:08x}>", - begin.0, begin_val, end.0, end_val, - )?; - dump_range(w, range)?; - dump_exprloc(w, unit.encoding(), data)?; - writeln!(w)?; - } - gimli::RawLocListEntry::StartxLength { - begin, - length, - ref data, - } => { - let begin_val = dwarf.address(unit, begin)?; - write!( - w, - "<startx-length [{}]0x{:08x}, 0x{:08x}>", - begin.0, begin_val, length, - )?; - dump_range(w, range)?; - dump_exprloc(w, unit.encoding(), data)?; - writeln!(w)?; - } - gimli::RawLocListEntry::AddressOrOffsetPair { - begin, - end, - ref data, - } - | gimli::RawLocListEntry::OffsetPair { - begin, - end, - ref data, - } => { - write!(w, "<offset-pair 0x{:08x}, 0x{:08x}>", begin, end)?; - dump_range(w, range)?; - dump_exprloc(w, unit.encoding(), data)?; - writeln!(w)?; - } - gimli::RawLocListEntry::DefaultLocation { ref data } => { - write!(w, "<default location>")?; - dump_exprloc(w, unit.encoding(), data)?; - writeln!(w)?; - } - gimli::RawLocListEntry::StartEnd { - begin, - end, - ref data, - } => { - write!(w, "<start-end 0x{:08x}, 0x{:08x}>", begin, end)?; - dump_range(w, range)?; - dump_exprloc(w, unit.encoding(), data)?; - writeln!(w)?; - } - gimli::RawLocListEntry::StartLength { - begin, - length, - ref data, - } => { - write!(w, "<start-length 0x{:08x}, 0x{:08x}>", begin, length)?; - dump_range(w, range)?; - dump_exprloc(w, unit.encoding(), data)?; - writeln!(w)?; - } - }; - } - Ok(()) -} - -fn dump_range_list<R: Reader, W: Write>( - w: &mut W, - offset: gimli::RangeListsOffset<R::Offset>, - unit: &gimli::Unit<R>, - dwarf: &gimli::Dwarf<R>, -) -> Result<()> { - let mut ranges = dwarf.ranges(unit, offset)?; - writeln!( - w, - "<rnglist at {}+0x{:08x}>", - if unit.encoding().version < 5 { - ".debug_ranges" - } else { - ".debug_rnglists" - }, - offset.0, - )?; - let mut i = 0; - while let Some(raw) = ranges.next_raw()? { - write!(w, "\t\t\t[{:2}] ", i)?; - i += 1; - let range = ranges.convert_raw(raw.clone())?; - match raw { - gimli::RawRngListEntry::BaseAddress { addr } => { - writeln!(w, "<new base address 0x{:08x}>", addr)?; - } - gimli::RawRngListEntry::BaseAddressx { addr } => { - let addr_val = dwarf.address(unit, addr)?; - writeln!(w, "<new base addressx [{}]0x{:08x}>", addr.0, addr_val)?; - } - gimli::RawRngListEntry::StartxEndx { begin, end } => { - let begin_val = dwarf.address(unit, begin)?; - let end_val = dwarf.address(unit, end)?; - write!( - w, - "<startx-endx [{}]0x{:08x}, [{}]0x{:08x}>", - begin.0, begin_val, end.0, end_val, - )?; - dump_range(w, range)?; - writeln!(w)?; - } - gimli::RawRngListEntry::StartxLength { begin, length } => { - let begin_val = dwarf.address(unit, begin)?; - write!( - w, - "<startx-length [{}]0x{:08x}, 0x{:08x}>", - begin.0, begin_val, length, - )?; - dump_range(w, range)?; - writeln!(w)?; - } - gimli::RawRngListEntry::AddressOrOffsetPair { begin, end } - | gimli::RawRngListEntry::OffsetPair { begin, end } => { - write!(w, "<offset-pair 0x{:08x}, 0x{:08x}>", begin, end)?; - dump_range(w, range)?; - writeln!(w)?; - } - gimli::RawRngListEntry::StartEnd { begin, end } => { - write!(w, "<start-end 0x{:08x}, 0x{:08x}>", begin, end)?; - dump_range(w, range)?; - writeln!(w)?; - } - gimli::RawRngListEntry::StartLength { begin, length } => { - write!(w, "<start-length 0x{:08x}, 0x{:08x}>", begin, length)?; - dump_range(w, range)?; - writeln!(w)?; - } - }; - } - Ok(()) -} - -fn dump_line<R: Reader, W: Write>(w: &mut W, dwarf: &gimli::Dwarf<R>) -> Result<()> { - let mut iter = dwarf.units(); - while let Some(header) = iter.next()? { - writeln!( - w, - "\n.debug_line: line number info for unit at .debug_info offset 0x{:08x}", - header.offset().as_debug_info_offset().unwrap().0 - )?; - let unit = match dwarf.unit(header) { - Ok(unit) => unit, - Err(err) => { - writeln_error( - w, - dwarf, - err.into(), - "Failed to parse unit root entry for dump_line", - )?; - continue; - } - }; - match dump_line_program(w, &unit, dwarf) { - Ok(_) => (), - Err(Error::IoError) => return Err(Error::IoError), - Err(err) => writeln_error(w, dwarf, err, "Failed to dump line program")?, - } - } - Ok(()) -} - -fn dump_line_program<R: Reader, W: Write>( - w: &mut W, - unit: &gimli::Unit<R>, - dwarf: &gimli::Dwarf<R>, -) -> Result<()> { - if let Some(program) = unit.line_program.clone() { - { - let header = program.header(); - writeln!(w)?; - writeln!( - w, - "Offset: 0x{:x}", - header.offset().0 - )?; - writeln!( - w, - "Length: {}", - header.unit_length() - )?; - writeln!( - w, - "DWARF version: {}", - header.version() - )?; - writeln!( - w, - "Address size: {}", - header.address_size() - )?; - writeln!( - w, - "Prologue length: {}", - header.header_length() - )?; - writeln!( - w, - "Minimum instruction length: {}", - header.minimum_instruction_length() - )?; - writeln!( - w, - "Maximum operations per instruction: {}", - header.maximum_operations_per_instruction() - )?; - writeln!( - w, - "Default is_stmt: {}", - header.default_is_stmt() - )?; - writeln!( - w, - "Line base: {}", - header.line_base() - )?; - writeln!( - w, - "Line range: {}", - header.line_range() - )?; - writeln!( - w, - "Opcode base: {}", - header.opcode_base() - )?; - - writeln!(w)?; - writeln!(w, "Opcodes:")?; - for (i, length) in header - .standard_opcode_lengths() - .to_slice()? - .iter() - .enumerate() - { - writeln!(w, " Opcode {} has {} args", i + 1, length)?; - } - - let base = if header.version() >= 5 { 0 } else { 1 }; - writeln!(w)?; - writeln!(w, "The Directory Table:")?; - for (i, dir) in header.include_directories().iter().enumerate() { - writeln!( - w, - " {} {}", - base + i, - dwarf.attr_string(unit, dir.clone())?.to_string_lossy()? - )?; - } - - writeln!(w)?; - writeln!(w, "The File Name Table")?; - write!(w, " Entry\tDir\tTime\tSize")?; - if header.file_has_md5() { - write!(w, "\tMD5\t\t\t\t")?; - } - writeln!(w, "\tName")?; - for (i, file) in header.file_names().iter().enumerate() { - write!( - w, - " {}\t{}\t{}\t{}", - base + i, - file.directory_index(), - file.timestamp(), - file.size(), - )?; - if header.file_has_md5() { - let md5 = file.md5(); - write!(w, "\t")?; - for i in 0..16 { - write!(w, "{:02X}", md5[i])?; - } - } - writeln!( - w, - "\t{}", - dwarf - .attr_string(unit, file.path_name())? - .to_string_lossy()? - )?; - } - - writeln!(w)?; - writeln!(w, "Line Number Instructions:")?; - let mut instructions = header.instructions(); - while let Some(instruction) = instructions.next_instruction(header)? { - writeln!(w, " {}", instruction)?; - } - - writeln!(w)?; - writeln!(w, "Line Number Rows:")?; - writeln!(w, "<pc> [lno,col]")?; - } - let mut rows = program.rows(); - let mut file_index = std::u64::MAX; - while let Some((header, row)) = rows.next_row()? { - let line = match row.line() { - Some(line) => line.get(), - None => 0, - }; - let column = match row.column() { - gimli::ColumnType::Column(column) => column.get(), - gimli::ColumnType::LeftEdge => 0, - }; - write!(w, "0x{:08x} [{:4},{:2}]", row.address(), line, column)?; - if row.is_stmt() { - write!(w, " NS")?; - } - if row.basic_block() { - write!(w, " BB")?; - } - if row.end_sequence() { - write!(w, " ET")?; - } - if row.prologue_end() { - write!(w, " PE")?; - } - if row.epilogue_begin() { - write!(w, " EB")?; - } - if row.isa() != 0 { - write!(w, " IS={}", row.isa())?; - } - if row.discriminator() != 0 { - write!(w, " DI={}", row.discriminator())?; - } - if file_index != row.file_index() { - file_index = row.file_index(); - if let Some(file) = row.file(header) { - if let Some(directory) = file.directory(header) { - write!( - w, - " uri: \"{}/{}\"", - dwarf.attr_string(unit, directory)?.to_string_lossy()?, - dwarf - .attr_string(unit, file.path_name())? - .to_string_lossy()? - )?; - } else { - write!( - w, - " uri: \"{}\"", - dwarf - .attr_string(unit, file.path_name())? - .to_string_lossy()? - )?; - } - } - } - writeln!(w)?; - } - } - Ok(()) -} - -fn dump_pubnames<R: Reader, W: Write>( - w: &mut W, - debug_pubnames: &gimli::DebugPubNames<R>, - debug_info: &gimli::DebugInfo<R>, -) -> Result<()> { - writeln!(w, "\n.debug_pubnames")?; - - let mut cu_offset; - let mut cu_die_offset = gimli::DebugInfoOffset(0); - let mut prev_cu_offset = None; - let mut pubnames = debug_pubnames.items(); - while let Some(pubname) = pubnames.next()? { - cu_offset = pubname.unit_header_offset(); - if Some(cu_offset) != prev_cu_offset { - let cu = debug_info.header_from_offset(cu_offset)?; - cu_die_offset = gimli::DebugInfoOffset(cu_offset.0 + cu.header_size()); - prev_cu_offset = Some(cu_offset); - } - let die_in_cu = pubname.die_offset(); - let die_in_sect = cu_offset.0 + die_in_cu.0; - writeln!(w, - "global die-in-sect 0x{:08x}, cu-in-sect 0x{:08x}, die-in-cu 0x{:08x}, cu-header-in-sect 0x{:08x} '{}'", - die_in_sect, - cu_die_offset.0, - die_in_cu.0, - cu_offset.0, - pubname.name().to_string_lossy()? - )?; - } - Ok(()) -} - -fn dump_pubtypes<R: Reader, W: Write>( - w: &mut W, - debug_pubtypes: &gimli::DebugPubTypes<R>, - debug_info: &gimli::DebugInfo<R>, -) -> Result<()> { - writeln!(w, "\n.debug_pubtypes")?; - - let mut cu_offset; - let mut cu_die_offset = gimli::DebugInfoOffset(0); - let mut prev_cu_offset = None; - let mut pubtypes = debug_pubtypes.items(); - while let Some(pubtype) = pubtypes.next()? { - cu_offset = pubtype.unit_header_offset(); - if Some(cu_offset) != prev_cu_offset { - let cu = debug_info.header_from_offset(cu_offset)?; - cu_die_offset = gimli::DebugInfoOffset(cu_offset.0 + cu.header_size()); - prev_cu_offset = Some(cu_offset); - } - let die_in_cu = pubtype.die_offset(); - let die_in_sect = cu_offset.0 + die_in_cu.0; - writeln!(w, - "pubtype die-in-sect 0x{:08x}, cu-in-sect 0x{:08x}, die-in-cu 0x{:08x}, cu-header-in-sect 0x{:08x} '{}'", - die_in_sect, - cu_die_offset.0, - die_in_cu.0, - cu_offset.0, - pubtype.name().to_string_lossy()? - )?; - } - Ok(()) -} - -fn dump_aranges<R: Reader, W: Write>( - w: &mut W, - debug_aranges: &gimli::DebugAranges<R>, -) -> Result<()> { - writeln!(w, "\n.debug_aranges")?; - - let mut headers = debug_aranges.headers(); - while let Some(header) = headers.next()? { - writeln!( - w, - "Address Range Header: length = 0x{:08x}, version = 0x{:04x}, cu_offset = 0x{:08x}, addr_size = 0x{:02x}, seg_size = 0x{:02x}", - header.length(), - header.encoding().version, - header.debug_info_offset().0, - header.encoding().address_size, - header.segment_size(), - )?; - let mut aranges = header.entries(); - while let Some(arange) = aranges.next()? { - let range = arange.range(); - if let Some(segment) = arange.segment() { - writeln!( - w, - "[0x{:016x}, 0x{:016x}) segment 0x{:x}", - range.begin, range.end, segment - )?; - } else { - writeln!(w, "[0x{:016x}, 0x{:016x})", range.begin, range.end)?; - } - } - } - Ok(()) -} diff --git a/vendor/gimli/examples/simple.rs b/vendor/gimli/examples/simple.rs deleted file mode 100644 index 7c958d45c..000000000 --- a/vendor/gimli/examples/simple.rs +++ /dev/null @@ -1,67 +0,0 @@ -//! A simple example of parsing `.debug_info`. - -use object::{Object, ObjectSection}; -use std::{borrow, env, fs}; - -fn main() { - for path in env::args().skip(1) { - let file = fs::File::open(&path).unwrap(); - let mmap = unsafe { memmap2::Mmap::map(&file).unwrap() }; - let object = object::File::parse(&*mmap).unwrap(); - let endian = if object.is_little_endian() { - gimli::RunTimeEndian::Little - } else { - gimli::RunTimeEndian::Big - }; - dump_file(&object, endian).unwrap(); - } -} - -fn dump_file(object: &object::File, endian: gimli::RunTimeEndian) -> Result<(), gimli::Error> { - // Load a section and return as `Cow<[u8]>`. - let load_section = |id: gimli::SectionId| -> Result<borrow::Cow<[u8]>, gimli::Error> { - match object.section_by_name(id.name()) { - Some(ref section) => Ok(section - .uncompressed_data() - .unwrap_or(borrow::Cow::Borrowed(&[][..]))), - None => Ok(borrow::Cow::Borrowed(&[][..])), - } - }; - - // Load all of the sections. - let dwarf_cow = gimli::Dwarf::load(&load_section)?; - - // Borrow a `Cow<[u8]>` to create an `EndianSlice`. - let borrow_section: &dyn for<'a> Fn( - &'a borrow::Cow<[u8]>, - ) -> gimli::EndianSlice<'a, gimli::RunTimeEndian> = - &|section| gimli::EndianSlice::new(&*section, endian); - - // Create `EndianSlice`s for all of the sections. - let dwarf = dwarf_cow.borrow(&borrow_section); - - // Iterate over the compilation units. - let mut iter = dwarf.units(); - while let Some(header) = iter.next()? { - println!( - "Unit at <.debug_info+0x{:x}>", - header.offset().as_debug_info_offset().unwrap().0 - ); - let unit = dwarf.unit(header)?; - - // Iterate over the Debugging Information Entries (DIEs) in the unit. - let mut depth = 0; - let mut entries = unit.entries(); - while let Some((delta_depth, entry)) = entries.next_dfs()? { - depth += delta_depth; - println!("<{}><{:x}> {}", depth, entry.offset().0, entry.tag()); - - // Iterate over the attributes in the DIE. - let mut attrs = entry.attrs(); - while let Some(attr) = attrs.next()? { - println!(" {}: {:?}", attr.name(), attr.value()); - } - } - } - Ok(()) -} diff --git a/vendor/gimli/examples/simple_line.rs b/vendor/gimli/examples/simple_line.rs deleted file mode 100644 index 87b224cda..000000000 --- a/vendor/gimli/examples/simple_line.rs +++ /dev/null @@ -1,106 +0,0 @@ -//! A simple example of parsing `.debug_line`. - -use object::{Object, ObjectSection}; -use std::{borrow, env, fs, path}; - -fn main() { - for path in env::args().skip(1) { - let file = fs::File::open(&path).unwrap(); - let mmap = unsafe { memmap2::Mmap::map(&file).unwrap() }; - let object = object::File::parse(&*mmap).unwrap(); - let endian = if object.is_little_endian() { - gimli::RunTimeEndian::Little - } else { - gimli::RunTimeEndian::Big - }; - dump_file(&object, endian).unwrap(); - } -} - -fn dump_file(object: &object::File, endian: gimli::RunTimeEndian) -> Result<(), gimli::Error> { - // Load a section and return as `Cow<[u8]>`. - let load_section = |id: gimli::SectionId| -> Result<borrow::Cow<[u8]>, gimli::Error> { - match object.section_by_name(id.name()) { - Some(ref section) => Ok(section - .uncompressed_data() - .unwrap_or(borrow::Cow::Borrowed(&[][..]))), - None => Ok(borrow::Cow::Borrowed(&[][..])), - } - }; - - // Load all of the sections. - let dwarf_cow = gimli::Dwarf::load(&load_section)?; - - // Borrow a `Cow<[u8]>` to create an `EndianSlice`. - let borrow_section: &dyn for<'a> Fn( - &'a borrow::Cow<[u8]>, - ) -> gimli::EndianSlice<'a, gimli::RunTimeEndian> = - &|section| gimli::EndianSlice::new(&*section, endian); - - // Create `EndianSlice`s for all of the sections. - let dwarf = dwarf_cow.borrow(&borrow_section); - - // Iterate over the compilation units. - let mut iter = dwarf.units(); - while let Some(header) = iter.next()? { - println!( - "Line number info for unit at <.debug_info+0x{:x}>", - header.offset().as_debug_info_offset().unwrap().0 - ); - let unit = dwarf.unit(header)?; - - // Get the line program for the compilation unit. - if let Some(program) = unit.line_program.clone() { - let comp_dir = if let Some(ref dir) = unit.comp_dir { - path::PathBuf::from(dir.to_string_lossy().into_owned()) - } else { - path::PathBuf::new() - }; - - // Iterate over the line program rows. - let mut rows = program.rows(); - while let Some((header, row)) = rows.next_row()? { - if row.end_sequence() { - // End of sequence indicates a possible gap in addresses. - println!("{:x} end-sequence", row.address()); - } else { - // Determine the path. Real applications should cache this for performance. - let mut path = path::PathBuf::new(); - if let Some(file) = row.file(header) { - path = comp_dir.clone(); - - // The directory index 0 is defined to correspond to the compilation unit directory. - if file.directory_index() != 0 { - if let Some(dir) = file.directory(header) { - path.push( - dwarf.attr_string(&unit, dir)?.to_string_lossy().as_ref(), - ); - } - } - - path.push( - dwarf - .attr_string(&unit, file.path_name())? - .to_string_lossy() - .as_ref(), - ); - } - - // Determine line/column. DWARF line/column is never 0, so we use that - // but other applications may want to display this differently. - let line = match row.line() { - Some(line) => line.get(), - None => 0, - }; - let column = match row.column() { - gimli::ColumnType::LeftEdge => 0, - gimli::ColumnType::Column(column) => column.get(), - }; - - println!("{:x} {}:{}:{}", row.address(), path.display(), line, column); - } - } - } - } - Ok(()) -} |