diff options
Diffstat (limited to 'vendor/backtrace/src/symbolize')
19 files changed, 0 insertions, 3213 deletions
diff --git a/vendor/backtrace/src/symbolize/dbghelp.rs b/vendor/backtrace/src/symbolize/dbghelp.rs deleted file mode 100644 index 181dba7..0000000 --- a/vendor/backtrace/src/symbolize/dbghelp.rs +++ /dev/null @@ -1,218 +0,0 @@ -//! Symbolication strategy using `dbghelp.dll` on Windows, only used for MSVC -//! -//! This symbolication strategy, like with backtraces, uses dynamically loaded -//! information from `dbghelp.dll`. (see `src/dbghelp.rs` for info about why -//! it's dynamically loaded). -//! -//! This API selects its resolution strategy based on the frame provided or the -//! information we have at hand. If a frame from `StackWalkEx` is given to us -//! then we use similar APIs to generate correct information about inlined -//! functions. Otherwise if all we have is an address or an older stack frame -//! from `StackWalk64` we use the older APIs for symbolication. -//! -//! There's a good deal of support in this module, but a good chunk of it is -//! converting back and forth between Windows types and Rust types. For example -//! symbols come to us as wide strings which we then convert to utf-8 strings if -//! we can. - -#![allow(bad_style)] - -use super::super::{backtrace::StackFrame, dbghelp, windows::*}; -use super::{BytesOrWideString, ResolveWhat, SymbolName}; -use core::char; -use core::ffi::c_void; -use core::marker; -use core::mem; -use core::slice; - -// Store an OsString on std so we can provide the symbol name and filename. -pub struct Symbol<'a> { - name: *const [u8], - addr: *mut c_void, - line: Option<u32>, - filename: Option<*const [u16]>, - #[cfg(feature = "std")] - _filename_cache: Option<::std::ffi::OsString>, - #[cfg(not(feature = "std"))] - _filename_cache: (), - _marker: marker::PhantomData<&'a i32>, -} - -impl Symbol<'_> { - pub fn name(&self) -> Option<SymbolName<'_>> { - Some(SymbolName::new(unsafe { &*self.name })) - } - - pub fn addr(&self) -> Option<*mut c_void> { - Some(self.addr as *mut _) - } - - pub fn filename_raw(&self) -> Option<BytesOrWideString<'_>> { - self.filename - .map(|slice| unsafe { BytesOrWideString::Wide(&*slice) }) - } - - pub fn colno(&self) -> Option<u32> { - None - } - - pub fn lineno(&self) -> Option<u32> { - self.line - } - - #[cfg(feature = "std")] - pub fn filename(&self) -> Option<&::std::path::Path> { - use std::path::Path; - - self._filename_cache.as_ref().map(Path::new) - } -} - -#[repr(C, align(8))] -struct Aligned8<T>(T); - -pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol)) { - // Ensure this process's symbols are initialized - let dbghelp = match dbghelp::init() { - Ok(dbghelp) => dbghelp, - Err(()) => return, // oh well... - }; - - match what { - ResolveWhat::Address(_) => resolve_without_inline(&dbghelp, what.address_or_ip(), cb), - ResolveWhat::Frame(frame) => match &frame.inner.stack_frame { - StackFrame::New(frame) => resolve_with_inline(&dbghelp, frame, cb), - StackFrame::Old(_) => resolve_without_inline(&dbghelp, frame.ip(), cb), - }, - } -} - -unsafe fn resolve_with_inline( - dbghelp: &dbghelp::Init, - frame: &STACKFRAME_EX, - cb: &mut dyn FnMut(&super::Symbol), -) { - do_resolve( - |info| { - dbghelp.SymFromInlineContextW()( - GetCurrentProcess(), - super::adjust_ip(frame.AddrPC.Offset as *mut _) as u64, - frame.InlineFrameContext, - &mut 0, - info, - ) - }, - |line| { - dbghelp.SymGetLineFromInlineContextW()( - GetCurrentProcess(), - super::adjust_ip(frame.AddrPC.Offset as *mut _) as u64, - frame.InlineFrameContext, - 0, - &mut 0, - line, - ) - }, - cb, - ) -} - -unsafe fn resolve_without_inline( - dbghelp: &dbghelp::Init, - addr: *mut c_void, - cb: &mut dyn FnMut(&super::Symbol), -) { - do_resolve( - |info| dbghelp.SymFromAddrW()(GetCurrentProcess(), addr as DWORD64, &mut 0, info), - |line| dbghelp.SymGetLineFromAddrW64()(GetCurrentProcess(), addr as DWORD64, &mut 0, line), - cb, - ) -} - -unsafe fn do_resolve( - sym_from_addr: impl FnOnce(*mut SYMBOL_INFOW) -> BOOL, - get_line_from_addr: impl FnOnce(&mut IMAGEHLP_LINEW64) -> BOOL, - cb: &mut dyn FnMut(&super::Symbol), -) { - const SIZE: usize = 2 * MAX_SYM_NAME + mem::size_of::<SYMBOL_INFOW>(); - let mut data = Aligned8([0u8; SIZE]); - let data = &mut data.0; - let info = &mut *(data.as_mut_ptr() as *mut SYMBOL_INFOW); - info.MaxNameLen = MAX_SYM_NAME as ULONG; - // the struct size in C. the value is different to - // `size_of::<SYMBOL_INFOW>() - MAX_SYM_NAME + 1` (== 81) - // due to struct alignment. - info.SizeOfStruct = 88; - - if sym_from_addr(info) != TRUE { - return; - } - - // If the symbol name is greater than MaxNameLen, SymFromAddrW will - // give a buffer of (MaxNameLen - 1) characters and set NameLen to - // the real value. - let name_len = ::core::cmp::min(info.NameLen as usize, info.MaxNameLen as usize - 1); - let name_ptr = info.Name.as_ptr() as *const u16; - let name = slice::from_raw_parts(name_ptr, name_len); - - // Reencode the utf-16 symbol to utf-8 so we can use `SymbolName::new` like - // all other platforms - let mut name_len = 0; - let mut name_buffer = [0; 256]; - { - let mut remaining = &mut name_buffer[..]; - for c in char::decode_utf16(name.iter().cloned()) { - let c = c.unwrap_or(char::REPLACEMENT_CHARACTER); - let len = c.len_utf8(); - if len < remaining.len() { - c.encode_utf8(remaining); - let tmp = remaining; - remaining = &mut tmp[len..]; - name_len += len; - } else { - break; - } - } - } - let name = &name_buffer[..name_len] as *const [u8]; - - let mut line = mem::zeroed::<IMAGEHLP_LINEW64>(); - line.SizeOfStruct = mem::size_of::<IMAGEHLP_LINEW64>() as DWORD; - - let mut filename = None; - let mut lineno = None; - if get_line_from_addr(&mut line) == TRUE { - lineno = Some(line.LineNumber as u32); - - let base = line.FileName; - let mut len = 0; - while *base.offset(len) != 0 { - len += 1; - } - - let len = len as usize; - - filename = Some(slice::from_raw_parts(base, len) as *const [u16]); - } - - cb(&super::Symbol { - inner: Symbol { - name, - addr: info.Address as *mut _, - line: lineno, - filename, - _filename_cache: cache(filename), - _marker: marker::PhantomData, - }, - }) -} - -#[cfg(feature = "std")] -unsafe fn cache(filename: Option<*const [u16]>) -> Option<::std::ffi::OsString> { - use std::os::windows::ffi::OsStringExt; - filename.map(|f| ::std::ffi::OsString::from_wide(&*f)) -} - -#[cfg(not(feature = "std"))] -unsafe fn cache(_filename: Option<*const [u16]>) {} - -pub unsafe fn clear_symbol_cache() {} diff --git a/vendor/backtrace/src/symbolize/gimli.rs b/vendor/backtrace/src/symbolize/gimli.rs deleted file mode 100644 index 7f1c6a5..0000000 --- a/vendor/backtrace/src/symbolize/gimli.rs +++ /dev/null @@ -1,511 +0,0 @@ -//! Support for symbolication using the `gimli` crate on crates.io -//! -//! This is the default symbolication implementation for Rust. - -use self::gimli::read::EndianSlice; -use self::gimli::NativeEndian as Endian; -use self::mmap::Mmap; -use self::stash::Stash; -use super::BytesOrWideString; -use super::ResolveWhat; -use super::SymbolName; -use addr2line::gimli; -use core::convert::TryInto; -use core::mem; -use core::u32; -use libc::c_void; -use mystd::ffi::OsString; -use mystd::fs::File; -use mystd::path::Path; -use mystd::prelude::v1::*; - -#[cfg(backtrace_in_libstd)] -mod mystd { - pub use crate::*; -} -#[cfg(not(backtrace_in_libstd))] -extern crate std as mystd; - -cfg_if::cfg_if! { - if #[cfg(windows)] { - #[path = "gimli/mmap_windows.rs"] - mod mmap; - } else if #[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "openbsd", - target_os = "solaris", - target_os = "illumos", - ))] { - #[path = "gimli/mmap_unix.rs"] - mod mmap; - } else { - #[path = "gimli/mmap_fake.rs"] - mod mmap; - } -} - -mod stash; - -const MAPPINGS_CACHE_SIZE: usize = 4; - -struct Mapping { - // 'static lifetime is a lie to hack around lack of support for self-referential structs. - cx: Context<'static>, - _map: Mmap, - stash: Stash, -} - -enum Either<A, B> { - #[allow(dead_code)] - A(A), - B(B), -} - -impl Mapping { - /// Creates a `Mapping` by ensuring that the `data` specified is used to - /// create a `Context` and it can only borrow from that or the `Stash` of - /// decompressed sections or auxiliary data. - fn mk<F>(data: Mmap, mk: F) -> Option<Mapping> - where - F: for<'a> FnOnce(&'a [u8], &'a Stash) -> Option<Context<'a>>, - { - Mapping::mk_or_other(data, move |data, stash| { - let cx = mk(data, stash)?; - Some(Either::B(cx)) - }) - } - - /// Creates a `Mapping` from `data`, or if the closure decides to, returns a - /// different mapping. - fn mk_or_other<F>(data: Mmap, mk: F) -> Option<Mapping> - where - F: for<'a> FnOnce(&'a [u8], &'a Stash) -> Option<Either<Mapping, Context<'a>>>, - { - let stash = Stash::new(); - let cx = match mk(&data, &stash)? { - Either::A(mapping) => return Some(mapping), - Either::B(cx) => cx, - }; - Some(Mapping { - // Convert to 'static lifetimes since the symbols should - // only borrow `map` and `stash` and we're preserving them below. - cx: unsafe { core::mem::transmute::<Context<'_>, Context<'static>>(cx) }, - _map: data, - stash: stash, - }) - } -} - -struct Context<'a> { - dwarf: addr2line::Context<EndianSlice<'a, Endian>>, - object: Object<'a>, - package: Option<gimli::DwarfPackage<EndianSlice<'a, Endian>>>, -} - -impl<'data> Context<'data> { - fn new( - stash: &'data Stash, - object: Object<'data>, - sup: Option<Object<'data>>, - dwp: Option<Object<'data>>, - ) -> Option<Context<'data>> { - let mut sections = gimli::Dwarf::load(|id| -> Result<_, ()> { - let data = object.section(stash, id.name()).unwrap_or(&[]); - Ok(EndianSlice::new(data, Endian)) - }) - .ok()?; - - if let Some(sup) = sup { - sections - .load_sup(|id| -> Result<_, ()> { - let data = sup.section(stash, id.name()).unwrap_or(&[]); - Ok(EndianSlice::new(data, Endian)) - }) - .ok()?; - } - let dwarf = addr2line::Context::from_dwarf(sections).ok()?; - - let mut package = None; - if let Some(dwp) = dwp { - package = Some( - gimli::DwarfPackage::load( - |id| -> Result<_, gimli::Error> { - let data = id - .dwo_name() - .and_then(|name| dwp.section(stash, name)) - .unwrap_or(&[]); - Ok(EndianSlice::new(data, Endian)) - }, - EndianSlice::new(&[], Endian), - ) - .ok()?, - ); - } - - Some(Context { - dwarf, - object, - package, - }) - } - - fn find_frames( - &'_ self, - stash: &'data Stash, - probe: u64, - ) -> gimli::Result<addr2line::FrameIter<'_, EndianSlice<'data, Endian>>> { - use addr2line::{LookupContinuation, LookupResult}; - - let mut l = self.dwarf.find_frames(probe); - loop { - let (load, continuation) = match l { - LookupResult::Output(output) => break output, - LookupResult::Load { load, continuation } => (load, continuation), - }; - - l = continuation.resume(handle_split_dwarf(self.package.as_ref(), stash, load)); - } - } -} - -fn mmap(path: &Path) -> Option<Mmap> { - let file = File::open(path).ok()?; - let len = file.metadata().ok()?.len().try_into().ok()?; - unsafe { Mmap::map(&file, len) } -} - -cfg_if::cfg_if! { - if #[cfg(windows)] { - mod coff; - use self::coff::{handle_split_dwarf, Object}; - } else if #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - ))] { - mod macho; - use self::macho::{handle_split_dwarf, Object}; - } else { - mod elf; - use self::elf::{handle_split_dwarf, Object}; - } -} - -cfg_if::cfg_if! { - if #[cfg(windows)] { - mod libs_windows; - use libs_windows::native_libraries; - } else if #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - ))] { - mod libs_macos; - use libs_macos::native_libraries; - } else if #[cfg(target_os = "illumos")] { - mod libs_illumos; - use libs_illumos::native_libraries; - } else if #[cfg(all( - any( - target_os = "linux", - target_os = "fuchsia", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - all(target_os = "android", feature = "dl_iterate_phdr"), - ), - not(target_env = "uclibc"), - ))] { - mod libs_dl_iterate_phdr; - use libs_dl_iterate_phdr::native_libraries; - #[path = "gimli/parse_running_mmaps_unix.rs"] - mod parse_running_mmaps; - } else if #[cfg(target_env = "libnx")] { - mod libs_libnx; - use libs_libnx::native_libraries; - } else if #[cfg(target_os = "haiku")] { - mod libs_haiku; - use libs_haiku::native_libraries; - } else { - // Everything else should doesn't know how to load native libraries. - fn native_libraries() -> Vec<Library> { - Vec::new() - } - } -} - -#[derive(Default)] -struct Cache { - /// All known shared libraries that have been loaded. - libraries: Vec<Library>, - - /// Mappings cache where we retain parsed dwarf information. - /// - /// This list has a fixed capacity for its entire lifetime which never - /// increases. The `usize` element of each pair is an index into `libraries` - /// above where `usize::max_value()` represents the current executable. The - /// `Mapping` is corresponding parsed dwarf information. - /// - /// Note that this is basically an LRU cache and we'll be shifting things - /// around in here as we symbolize addresses. - mappings: Vec<(usize, Mapping)>, -} - -struct Library { - name: OsString, - /// Segments of this library loaded into memory, and where they're loaded. - segments: Vec<LibrarySegment>, - /// The "bias" of this library, typically where it's loaded into memory. - /// This value is added to each segment's stated address to get the actual - /// virtual memory address that the segment is loaded into. Additionally - /// this bias is subtracted from real virtual memory addresses to index into - /// debuginfo and the symbol table. - bias: usize, -} - -struct LibrarySegment { - /// The stated address of this segment in the object file. This is not - /// actually where the segment is loaded, but rather this address plus the - /// containing library's `bias` is where to find it. - stated_virtual_memory_address: usize, - /// The size of this segment in memory. - len: usize, -} - -// unsafe because this is required to be externally synchronized -pub unsafe fn clear_symbol_cache() { - Cache::with_global(|cache| cache.mappings.clear()); -} - -impl Cache { - fn new() -> Cache { - Cache { - mappings: Vec::with_capacity(MAPPINGS_CACHE_SIZE), - libraries: native_libraries(), - } - } - - // unsafe because this is required to be externally synchronized - unsafe fn with_global(f: impl FnOnce(&mut Self)) { - // A very small, very simple LRU cache for debug info mappings. - // - // The hit rate should be very high, since the typical stack doesn't cross - // between many shared libraries. - // - // The `addr2line::Context` structures are pretty expensive to create. Its - // cost is expected to be amortized by subsequent `locate` queries, which - // leverage the structures built when constructing `addr2line::Context`s to - // get nice speedups. If we didn't have this cache, that amortization would - // never happen, and symbolicating backtraces would be ssssllllooooowwww. - static mut MAPPINGS_CACHE: Option<Cache> = None; - - f(MAPPINGS_CACHE.get_or_insert_with(|| Cache::new())) - } - - fn avma_to_svma(&self, addr: *const u8) -> Option<(usize, *const u8)> { - self.libraries - .iter() - .enumerate() - .filter_map(|(i, lib)| { - // First up, test if this `lib` has any segment containing the - // `addr` (handling relocation). If this check passes then we - // can continue below and actually translate the address. - // - // Note that we're using `wrapping_add` here to avoid overflow - // checks. It's been seen in the wild that the SVMA + bias - // computation overflows. It seems a bit odd that would happen - // but there's not a huge amount we can do about it other than - // probably just ignore those segments since they're likely - // pointing off into space. This originally came up in - // rust-lang/backtrace-rs#329. - if !lib.segments.iter().any(|s| { - let svma = s.stated_virtual_memory_address; - let start = svma.wrapping_add(lib.bias); - let end = start.wrapping_add(s.len); - let address = addr as usize; - start <= address && address < end - }) { - return None; - } - - // Now that we know `lib` contains `addr`, we can offset with - // the bias to find the stated virtual memory address. - let svma = (addr as usize).wrapping_sub(lib.bias); - Some((i, svma as *const u8)) - }) - .next() - } - - fn mapping_for_lib<'a>(&'a mut self, lib: usize) -> Option<(&'a mut Context<'a>, &'a Stash)> { - let idx = self.mappings.iter().position(|(idx, _)| *idx == lib); - - // Invariant: after this conditional completes without early returning - // from an error, the cache entry for this path is at index 0. - - if let Some(idx) = idx { - // When the mapping is already in the cache, move it to the front. - if idx != 0 { - let entry = self.mappings.remove(idx); - self.mappings.insert(0, entry); - } - } else { - // When the mapping is not in the cache, create a new mapping, - // insert it into the front of the cache, and evict the oldest cache - // entry if necessary. - let name = &self.libraries[lib].name; - let mapping = Mapping::new(name.as_ref())?; - - if self.mappings.len() == MAPPINGS_CACHE_SIZE { - self.mappings.pop(); - } - - self.mappings.insert(0, (lib, mapping)); - } - - let mapping = &mut self.mappings[0].1; - let cx: &'a mut Context<'static> = &mut mapping.cx; - let stash: &'a Stash = &mapping.stash; - // don't leak the `'static` lifetime, make sure it's scoped to just - // ourselves - Some(( - unsafe { mem::transmute::<&'a mut Context<'static>, &'a mut Context<'a>>(cx) }, - stash, - )) - } -} - -pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol)) { - let addr = what.address_or_ip(); - let mut call = |sym: Symbol<'_>| { - // Extend the lifetime of `sym` to `'static` since we are unfortunately - // required to here, but it's only ever going out as a reference so no - // reference to it should be persisted beyond this frame anyway. - let sym = mem::transmute::<Symbol<'_>, Symbol<'static>>(sym); - (cb)(&super::Symbol { inner: sym }); - }; - - Cache::with_global(|cache| { - let (lib, addr) = match cache.avma_to_svma(addr as *const u8) { - Some(pair) => pair, - None => return, - }; - - // Finally, get a cached mapping or create a new mapping for this file, and - // evaluate the DWARF info to find the file/line/name for this address. - let (cx, stash) = match cache.mapping_for_lib(lib) { - Some((cx, stash)) => (cx, stash), - None => return, - }; - let mut any_frames = false; - if let Ok(mut frames) = cx.find_frames(stash, addr as u64) { - while let Ok(Some(frame)) = frames.next() { - any_frames = true; - let name = match frame.function { - Some(f) => Some(f.name.slice()), - None => cx.object.search_symtab(addr as u64), - }; - call(Symbol::Frame { - addr: addr as *mut c_void, - location: frame.location, - name, - }); - } - } - if !any_frames { - if let Some((object_cx, object_addr)) = cx.object.search_object_map(addr as u64) { - if let Ok(mut frames) = object_cx.find_frames(stash, object_addr) { - while let Ok(Some(frame)) = frames.next() { - any_frames = true; - call(Symbol::Frame { - addr: addr as *mut c_void, - location: frame.location, - name: frame.function.map(|f| f.name.slice()), - }); - } - } - } - } - if !any_frames { - if let Some(name) = cx.object.search_symtab(addr as u64) { - call(Symbol::Symtab { - addr: addr as *mut c_void, - name, - }); - } - } - }); -} - -pub enum Symbol<'a> { - /// We were able to locate frame information for this symbol, and - /// `addr2line`'s frame internally has all the nitty gritty details. - Frame { - addr: *mut c_void, - location: Option<addr2line::Location<'a>>, - name: Option<&'a [u8]>, - }, - /// Couldn't find debug information, but we found it in the symbol table of - /// the elf executable. - Symtab { addr: *mut c_void, name: &'a [u8] }, -} - -impl Symbol<'_> { - pub fn name(&self) -> Option<SymbolName<'_>> { - match self { - Symbol::Frame { name, .. } => { - let name = name.as_ref()?; - Some(SymbolName::new(name)) - } - Symbol::Symtab { name, .. } => Some(SymbolName::new(name)), - } - } - - pub fn addr(&self) -> Option<*mut c_void> { - match self { - Symbol::Frame { addr, .. } => Some(*addr), - Symbol::Symtab { .. } => None, - } - } - - pub fn filename_raw(&self) -> Option<BytesOrWideString<'_>> { - match self { - Symbol::Frame { location, .. } => { - let file = location.as_ref()?.file?; - Some(BytesOrWideString::Bytes(file.as_bytes())) - } - Symbol::Symtab { .. } => None, - } - } - - pub fn filename(&self) -> Option<&Path> { - match self { - Symbol::Frame { location, .. } => { - let file = location.as_ref()?.file?; - Some(Path::new(file)) - } - Symbol::Symtab { .. } => None, - } - } - - pub fn lineno(&self) -> Option<u32> { - match self { - Symbol::Frame { location, .. } => location.as_ref()?.line, - Symbol::Symtab { .. } => None, - } - } - - pub fn colno(&self) -> Option<u32> { - match self { - Symbol::Frame { location, .. } => location.as_ref()?.column, - Symbol::Symtab { .. } => None, - } - } -} diff --git a/vendor/backtrace/src/symbolize/gimli/coff.rs b/vendor/backtrace/src/symbolize/gimli/coff.rs deleted file mode 100644 index 759c827..0000000 --- a/vendor/backtrace/src/symbolize/gimli/coff.rs +++ /dev/null @@ -1,118 +0,0 @@ -use super::{gimli, Context, Endian, EndianSlice, Mapping, Path, Stash, Vec}; -use alloc::sync::Arc; -use core::convert::TryFrom; -use object::pe::{ImageDosHeader, ImageSymbol}; -use object::read::coff::ImageSymbol as _; -use object::read::pe::{ImageNtHeaders, ImageOptionalHeader, SectionTable}; -use object::read::StringTable; -use object::LittleEndian as LE; - -#[cfg(target_pointer_width = "32")] -type Pe = object::pe::ImageNtHeaders32; -#[cfg(target_pointer_width = "64")] -type Pe = object::pe::ImageNtHeaders64; - -impl Mapping { - pub fn new(path: &Path) -> Option<Mapping> { - let map = super::mmap(path)?; - Mapping::mk(map, |data, stash| { - Context::new(stash, Object::parse(data)?, None, None) - }) - } -} - -pub struct Object<'a> { - data: &'a [u8], - sections: SectionTable<'a>, - symbols: Vec<(usize, &'a ImageSymbol)>, - strings: StringTable<'a>, -} - -pub fn get_image_base(data: &[u8]) -> Option<usize> { - let dos_header = ImageDosHeader::parse(data).ok()?; - let mut offset = dos_header.nt_headers_offset().into(); - let (nt_headers, _) = Pe::parse(data, &mut offset).ok()?; - usize::try_from(nt_headers.optional_header().image_base()).ok() -} - -impl<'a> Object<'a> { - fn parse(data: &'a [u8]) -> Option<Object<'a>> { - let dos_header = ImageDosHeader::parse(data).ok()?; - let mut offset = dos_header.nt_headers_offset().into(); - let (nt_headers, _) = Pe::parse(data, &mut offset).ok()?; - let sections = nt_headers.sections(data, offset).ok()?; - let symtab = nt_headers.symbols(data).ok()?; - let strings = symtab.strings(); - let image_base = usize::try_from(nt_headers.optional_header().image_base()).ok()?; - - // Collect all the symbols into a local vector which is sorted - // by address and contains enough data to learn about the symbol - // name. Note that we only look at function symbols and also - // note that the sections are 1-indexed because the zero section - // is special (apparently). - let mut symbols = Vec::new(); - let mut i = 0; - let len = symtab.len(); - while i < len { - let sym = symtab.symbol(i).ok()?; - i += 1 + sym.number_of_aux_symbols as usize; - let section_number = sym.section_number.get(LE); - if sym.derived_type() != object::pe::IMAGE_SYM_DTYPE_FUNCTION || section_number == 0 { - continue; - } - let addr = usize::try_from(sym.value.get(LE)).ok()?; - let section = sections - .section(usize::try_from(section_number).ok()?) - .ok()?; - let va = usize::try_from(section.virtual_address.get(LE)).ok()?; - symbols.push((addr + va + image_base, sym)); - } - symbols.sort_unstable_by_key(|x| x.0); - Some(Object { - data, - sections, - strings, - symbols, - }) - } - - pub fn section(&self, _: &Stash, name: &str) -> Option<&'a [u8]> { - Some( - self.sections - .section_by_name(self.strings, name.as_bytes())? - .1 - .pe_data(self.data) - .ok()?, - ) - } - - pub fn search_symtab<'b>(&'b self, addr: u64) -> Option<&'b [u8]> { - // Note that unlike other formats COFF doesn't embed the size of - // each symbol. As a last ditch effort search for the *closest* - // symbol to a particular address and return that one. This gets - // really wonky once symbols start getting removed because the - // symbols returned here can be totally incorrect, but we have - // no idea of knowing how to detect that. - let addr = usize::try_from(addr).ok()?; - let i = match self.symbols.binary_search_by_key(&addr, |p| p.0) { - Ok(i) => i, - // typically `addr` isn't in the array, but `i` is where - // we'd insert it, so the previous position must be the - // greatest less than `addr` - Err(i) => i.checked_sub(1)?, - }; - self.symbols[i].1.name(self.strings).ok() - } - - pub(super) fn search_object_map(&self, _addr: u64) -> Option<(&Context<'_>, u64)> { - None - } -} - -pub(super) fn handle_split_dwarf<'data>( - _package: Option<&gimli::DwarfPackage<EndianSlice<'data, Endian>>>, - _stash: &'data Stash, - _load: addr2line::SplitDwarfLoad<EndianSlice<'data, Endian>>, -) -> Option<Arc<gimli::Dwarf<EndianSlice<'data, Endian>>>> { - None -} diff --git a/vendor/backtrace/src/symbolize/gimli/elf.rs b/vendor/backtrace/src/symbolize/gimli/elf.rs deleted file mode 100644 index b0eec07..0000000 --- a/vendor/backtrace/src/symbolize/gimli/elf.rs +++ /dev/null @@ -1,495 +0,0 @@ -use super::mystd::ffi::{OsStr, OsString}; -use super::mystd::fs; -use super::mystd::os::unix::ffi::{OsStrExt, OsStringExt}; -use super::mystd::path::{Path, PathBuf}; -use super::Either; -use super::{gimli, Context, Endian, EndianSlice, Mapping, Stash, Vec}; -use alloc::sync::Arc; -use core::convert::{TryFrom, TryInto}; -use core::str; -use object::elf::{ELFCOMPRESS_ZLIB, ELF_NOTE_GNU, NT_GNU_BUILD_ID, SHF_COMPRESSED}; -use object::read::elf::{CompressionHeader, FileHeader, SectionHeader, SectionTable, Sym}; -use object::read::StringTable; -use object::{BigEndian, Bytes, NativeEndian}; - -#[cfg(target_pointer_width = "32")] -type Elf = object::elf::FileHeader32<NativeEndian>; -#[cfg(target_pointer_width = "64")] -type Elf = object::elf::FileHeader64<NativeEndian>; - -impl Mapping { - pub fn new(path: &Path) -> Option<Mapping> { - let map = super::mmap(path)?; - Mapping::mk_or_other(map, |map, stash| { - let object = Object::parse(&map)?; - - // Try to locate an external debug file using the build ID. - if let Some(path_debug) = object.build_id().and_then(locate_build_id) { - if let Some(mapping) = Mapping::new_debug(path, path_debug, None) { - return Some(Either::A(mapping)); - } - } - - // Try to locate an external debug file using the GNU debug link section. - if let Some((path_debug, crc)) = object.gnu_debuglink_path(path) { - if let Some(mapping) = Mapping::new_debug(path, path_debug, Some(crc)) { - return Some(Either::A(mapping)); - } - } - - let dwp = Mapping::load_dwarf_package(path, stash); - - Context::new(stash, object, None, dwp).map(Either::B) - }) - } - - /// Load debuginfo from an external debug file. - fn new_debug(original_path: &Path, path: PathBuf, crc: Option<u32>) -> Option<Mapping> { - let map = super::mmap(&path)?; - Mapping::mk(map, |map, stash| { - let object = Object::parse(&map)?; - - if let Some(_crc) = crc { - // TODO: check crc - } - - // Try to locate a supplementary object file. - let mut sup = None; - if let Some((path_sup, build_id_sup)) = object.gnu_debugaltlink_path(&path) { - if let Some(map_sup) = super::mmap(&path_sup) { - let map_sup = stash.cache_mmap(map_sup); - if let Some(sup_) = Object::parse(map_sup) { - if sup_.build_id() == Some(build_id_sup) { - sup = Some(sup_); - } - } - } - } - - let dwp = Mapping::load_dwarf_package(original_path, stash); - - Context::new(stash, object, sup, dwp) - }) - } - - /// Try to locate a DWARF package file. - fn load_dwarf_package<'data>(path: &Path, stash: &'data Stash) -> Option<Object<'data>> { - let mut path_dwp = path.to_path_buf(); - let dwp_extension = path - .extension() - .map(|previous_extension| { - let mut previous_extension = previous_extension.to_os_string(); - previous_extension.push(".dwp"); - previous_extension - }) - .unwrap_or_else(|| "dwp".into()); - path_dwp.set_extension(dwp_extension); - if let Some(map_dwp) = super::mmap(&path_dwp) { - let map_dwp = stash.cache_mmap(map_dwp); - if let Some(dwp_) = Object::parse(map_dwp) { - return Some(dwp_); - } - } - - None - } -} - -struct ParsedSym { - address: u64, - size: u64, - name: u32, -} - -pub struct Object<'a> { - /// Zero-sized type representing the native endianness. - /// - /// We could use a literal instead, but this helps ensure correctness. - endian: NativeEndian, - /// The entire file data. - data: &'a [u8], - sections: SectionTable<'a, Elf>, - strings: StringTable<'a>, - /// List of pre-parsed and sorted symbols by base address. - syms: Vec<ParsedSym>, -} - -impl<'a> Object<'a> { - fn parse(data: &'a [u8]) -> Option<Object<'a>> { - let elf = Elf::parse(data).ok()?; - let endian = elf.endian().ok()?; - let sections = elf.sections(endian, data).ok()?; - let mut syms = sections - .symbols(endian, data, object::elf::SHT_SYMTAB) - .ok()?; - if syms.is_empty() { - syms = sections - .symbols(endian, data, object::elf::SHT_DYNSYM) - .ok()?; - } - let strings = syms.strings(); - - let mut syms = syms - .iter() - // Only look at function/object symbols. This mirrors what - // libbacktrace does and in general we're only symbolicating - // function addresses in theory. Object symbols correspond - // to data, and maybe someone's crazy enough to have a - // function go into static data? - .filter(|sym| { - let st_type = sym.st_type(); - st_type == object::elf::STT_FUNC || st_type == object::elf::STT_OBJECT - }) - // skip anything that's in an undefined section header, - // since it means it's an imported function and we're only - // symbolicating with locally defined functions. - .filter(|sym| sym.st_shndx(endian) != object::elf::SHN_UNDEF) - .map(|sym| { - let address = sym.st_value(endian).into(); - let size = sym.st_size(endian).into(); - let name = sym.st_name(endian); - ParsedSym { - address, - size, - name, - } - }) - .collect::<Vec<_>>(); - syms.sort_unstable_by_key(|s| s.address); - Some(Object { - endian, - data, - sections, - strings, - syms, - }) - } - - pub fn section(&self, stash: &'a Stash, name: &str) -> Option<&'a [u8]> { - if let Some(section) = self.section_header(name) { - let mut data = Bytes(section.data(self.endian, self.data).ok()?); - - // Check for DWARF-standard (gABI) compression, i.e., as generated - // by ld's `--compress-debug-sections=zlib-gabi` flag. - let flags: u64 = section.sh_flags(self.endian).into(); - if (flags & u64::from(SHF_COMPRESSED)) == 0 { - // Not compressed. - return Some(data.0); - } - - let header = data.read::<<Elf as FileHeader>::CompressionHeader>().ok()?; - if header.ch_type(self.endian) != ELFCOMPRESS_ZLIB { - // Zlib compression is the only known type. - return None; - } - let size = usize::try_from(header.ch_size(self.endian)).ok()?; - let buf = stash.allocate(size); - decompress_zlib(data.0, buf)?; - return Some(buf); - } - - // Check for the nonstandard GNU compression format, i.e., as generated - // by ld's `--compress-debug-sections=zlib-gnu` flag. This means that if - // we're actually asking for `.debug_info` then we need to look up a - // section named `.zdebug_info`. - if !name.starts_with(".debug_") { - return None; - } - let debug_name = name[7..].as_bytes(); - let compressed_section = self - .sections - .iter() - .filter_map(|header| { - let name = self.sections.section_name(self.endian, header).ok()?; - if name.starts_with(b".zdebug_") && &name[8..] == debug_name { - Some(header) - } else { - None - } - }) - .next()?; - let mut data = Bytes(compressed_section.data(self.endian, self.data).ok()?); - if data.read_bytes(8).ok()?.0 != b"ZLIB\0\0\0\0" { - return None; - } - let size = usize::try_from(data.read::<object::U32Bytes<_>>().ok()?.get(BigEndian)).ok()?; - let buf = stash.allocate(size); - decompress_zlib(data.0, buf)?; - Some(buf) - } - - fn section_header(&self, name: &str) -> Option<&<Elf as FileHeader>::SectionHeader> { - self.sections - .section_by_name(self.endian, name.as_bytes()) - .map(|(_index, section)| section) - } - - pub fn search_symtab<'b>(&'b self, addr: u64) -> Option<&'b [u8]> { - // Same sort of binary search as Windows above - let i = match self.syms.binary_search_by_key(&addr, |sym| sym.address) { - Ok(i) => i, - Err(i) => i.checked_sub(1)?, - }; - let sym = self.syms.get(i)?; - if sym.address <= addr && addr <= sym.address + sym.size { - self.strings.get(sym.name).ok() - } else { - None - } - } - - pub(super) fn search_object_map(&self, _addr: u64) -> Option<(&Context<'_>, u64)> { - None - } - - fn build_id(&self) -> Option<&'a [u8]> { - for section in self.sections.iter() { - if let Ok(Some(mut notes)) = section.notes(self.endian, self.data) { - while let Ok(Some(note)) = notes.next() { - if note.name() == ELF_NOTE_GNU && note.n_type(self.endian) == NT_GNU_BUILD_ID { - return Some(note.desc()); - } - } - } - } - None - } - - // The contents of the ".gnu_debuglink" section is documented at: - // https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html - fn gnu_debuglink_path(&self, path: &Path) -> Option<(PathBuf, u32)> { - let section = self.section_header(".gnu_debuglink")?; - let data = section.data(self.endian, self.data).ok()?; - let len = data.iter().position(|x| *x == 0)?; - let filename = &data[..len]; - let offset = (len + 1 + 3) & !3; - let crc_bytes = data - .get(offset..offset + 4) - .and_then(|bytes| bytes.try_into().ok())?; - let crc = u32::from_ne_bytes(crc_bytes); - let path_debug = locate_debuglink(path, filename)?; - Some((path_debug, crc)) - } - - // The format of the ".gnu_debugaltlink" section is based on gdb. - fn gnu_debugaltlink_path(&self, path: &Path) -> Option<(PathBuf, &'a [u8])> { - let section = self.section_header(".gnu_debugaltlink")?; - let data = section.data(self.endian, self.data).ok()?; - let len = data.iter().position(|x| *x == 0)?; - let filename = &data[..len]; - let build_id = &data[len + 1..]; - let path_sup = locate_debugaltlink(path, filename, build_id)?; - Some((path_sup, build_id)) - } -} - -fn decompress_zlib(input: &[u8], output: &mut [u8]) -> Option<()> { - use miniz_oxide::inflate::core::inflate_flags::{ - TINFL_FLAG_PARSE_ZLIB_HEADER, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF, - }; - use miniz_oxide::inflate::core::{decompress, DecompressorOxide}; - use miniz_oxide::inflate::TINFLStatus; - - let (status, in_read, out_read) = decompress( - &mut DecompressorOxide::new(), - input, - output, - 0, - TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | TINFL_FLAG_PARSE_ZLIB_HEADER, - ); - if status == TINFLStatus::Done && in_read == input.len() && out_read == output.len() { - Some(()) - } else { - None - } -} - -const DEBUG_PATH: &[u8] = b"/usr/lib/debug"; - -fn debug_path_exists() -> bool { - cfg_if::cfg_if! { - if #[cfg(any(target_os = "freebsd", target_os = "linux"))] { - use core::sync::atomic::{AtomicU8, Ordering}; - static DEBUG_PATH_EXISTS: AtomicU8 = AtomicU8::new(0); - - let mut exists = DEBUG_PATH_EXISTS.load(Ordering::Relaxed); - if exists == 0 { - exists = if Path::new(OsStr::from_bytes(DEBUG_PATH)).is_dir() { - 1 - } else { - 2 - }; - DEBUG_PATH_EXISTS.store(exists, Ordering::Relaxed); - } - exists == 1 - } else { - false - } - } -} - -/// Locate a debug file based on its build ID. -/// -/// The format of build id paths is documented at: -/// https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html -fn locate_build_id(build_id: &[u8]) -> Option<PathBuf> { - const BUILD_ID_PATH: &[u8] = b"/usr/lib/debug/.build-id/"; - const BUILD_ID_SUFFIX: &[u8] = b".debug"; - - if build_id.len() < 2 { - return None; - } - - if !debug_path_exists() { - return None; - } - - let mut path = - Vec::with_capacity(BUILD_ID_PATH.len() + BUILD_ID_SUFFIX.len() + build_id.len() * 2 + 1); - path.extend(BUILD_ID_PATH); - path.push(hex(build_id[0] >> 4)); - path.push(hex(build_id[0] & 0xf)); - path.push(b'/'); - for byte in &build_id[1..] { - path.push(hex(byte >> 4)); - path.push(hex(byte & 0xf)); - } - path.extend(BUILD_ID_SUFFIX); - Some(PathBuf::from(OsString::from_vec(path))) -} - -fn hex(byte: u8) -> u8 { - if byte < 10 { - b'0' + byte - } else { - b'a' + byte - 10 - } -} - -/// Locate a file specified in a `.gnu_debuglink` section. -/// -/// `path` is the file containing the section. -/// `filename` is from the contents of the section. -/// -/// Search order is based on gdb, documented at: -/// https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html -/// -/// gdb also allows the user to customize the debug search path, but we don't. -/// -/// gdb also supports debuginfod, but we don't yet. -fn locate_debuglink(path: &Path, filename: &[u8]) -> Option<PathBuf> { - let path = fs::canonicalize(path).ok()?; - let parent = path.parent()?; - let mut f = PathBuf::from(OsString::with_capacity( - DEBUG_PATH.len() + parent.as_os_str().len() + filename.len() + 2, - )); - let filename = Path::new(OsStr::from_bytes(filename)); - - // Try "/parent/filename" if it differs from "path" - f.push(parent); - f.push(filename); - if f != path && f.is_file() { - return Some(f); - } - - // Try "/parent/.debug/filename" - let mut s = OsString::from(f); - s.clear(); - f = PathBuf::from(s); - f.push(parent); - f.push(".debug"); - f.push(filename); - if f.is_file() { - return Some(f); - } - - if debug_path_exists() { - // Try "/usr/lib/debug/parent/filename" - let mut s = OsString::from(f); - s.clear(); - f = PathBuf::from(s); - f.push(OsStr::from_bytes(DEBUG_PATH)); - f.push(parent.strip_prefix("/").unwrap()); - f.push(filename); - if f.is_file() { - return Some(f); - } - } - - None -} - -/// Locate a file specified in a `.gnu_debugaltlink` section. -/// -/// `path` is the file containing the section. -/// `filename` and `build_id` are the contents of the section. -/// -/// Search order is based on gdb: -/// - filename, which is either absolute or relative to `path` -/// - the build ID path under `BUILD_ID_PATH` -/// -/// gdb also allows the user to customize the debug search path, but we don't. -/// -/// gdb also supports debuginfod, but we don't yet. -fn locate_debugaltlink(path: &Path, filename: &[u8], build_id: &[u8]) -> Option<PathBuf> { - let filename = Path::new(OsStr::from_bytes(filename)); - if filename.is_absolute() { - if filename.is_file() { - return Some(filename.into()); - } - } else { - let path = fs::canonicalize(path).ok()?; - let parent = path.parent()?; - let mut f = PathBuf::from(parent); - f.push(filename); - if f.is_file() { - return Some(f); - } - } - - locate_build_id(build_id) -} - -fn convert_path<R: gimli::Reader>(r: &R) -> Result<PathBuf, gimli::Error> { - let bytes = r.to_slice()?; - Ok(PathBuf::from(OsStr::from_bytes(&bytes))) -} - -pub(super) fn handle_split_dwarf<'data>( - package: Option<&gimli::DwarfPackage<EndianSlice<'data, Endian>>>, - stash: &'data Stash, - load: addr2line::SplitDwarfLoad<EndianSlice<'data, Endian>>, -) -> Option<Arc<gimli::Dwarf<EndianSlice<'data, Endian>>>> { - if let Some(dwp) = package.as_ref() { - if let Ok(Some(cu)) = dwp.find_cu(load.dwo_id, &load.parent) { - return Some(Arc::new(cu)); - } - } - - let mut path = PathBuf::new(); - if let Some(p) = load.comp_dir.as_ref() { - path.push(convert_path(p).ok()?); - } - - path.push(convert_path(load.path.as_ref()?).ok()?); - - if let Some(map_dwo) = super::mmap(&path) { - let map_dwo = stash.cache_mmap(map_dwo); - if let Some(dwo) = Object::parse(map_dwo) { - return gimli::Dwarf::load(|id| -> Result<_, ()> { - let data = id - .dwo_name() - .and_then(|name| dwo.section(stash, name)) - .unwrap_or(&[]); - Ok(EndianSlice::new(data, Endian)) - }) - .ok() - .map(|mut dwo_dwarf| { - dwo_dwarf.make_dwo(&load.parent); - Arc::new(dwo_dwarf) - }); - } - } - - None -} diff --git a/vendor/backtrace/src/symbolize/gimli/libs_dl_iterate_phdr.rs b/vendor/backtrace/src/symbolize/gimli/libs_dl_iterate_phdr.rs deleted file mode 100644 index 9f0304c..0000000 --- a/vendor/backtrace/src/symbolize/gimli/libs_dl_iterate_phdr.rs +++ /dev/null @@ -1,71 +0,0 @@ -// Other Unix (e.g. Linux) platforms use ELF as an object file format -// and typically implement an API called `dl_iterate_phdr` to load -// native libraries. - -use super::mystd::borrow::ToOwned; -use super::mystd::env; -use super::mystd::ffi::{CStr, OsStr}; -use super::mystd::os::unix::prelude::*; -use super::{Library, LibrarySegment, OsString, Vec}; -use core::slice; - -pub(super) fn native_libraries() -> Vec<Library> { - let mut ret = Vec::new(); - unsafe { - libc::dl_iterate_phdr(Some(callback), &mut ret as *mut Vec<_> as *mut _); - } - return ret; -} - -fn infer_current_exe(base_addr: usize) -> OsString { - if let Ok(entries) = super::parse_running_mmaps::parse_maps() { - let opt_path = entries - .iter() - .find(|e| e.ip_matches(base_addr) && e.pathname().len() > 0) - .map(|e| e.pathname()) - .cloned(); - if let Some(path) = opt_path { - return path; - } - } - env::current_exe().map(|e| e.into()).unwrap_or_default() -} - -// `info` should be a valid pointers. -// `vec` should be a valid pointer to a `std::Vec`. -unsafe extern "C" fn callback( - info: *mut libc::dl_phdr_info, - _size: libc::size_t, - vec: *mut libc::c_void, -) -> libc::c_int { - let info = &*info; - let libs = &mut *(vec as *mut Vec<Library>); - let is_main_prog = info.dlpi_name.is_null() || *info.dlpi_name == 0; - let name = if is_main_prog { - // The man page for dl_iterate_phdr says that the first object visited by - // callback is the main program; so the first time we encounter a - // nameless entry, we can assume its the main program and try to infer its path. - // After that, we cannot continue that assumption, and we use an empty string. - if libs.is_empty() { - infer_current_exe(info.dlpi_addr as usize) - } else { - OsString::new() - } - } else { - let bytes = CStr::from_ptr(info.dlpi_name).to_bytes(); - OsStr::from_bytes(bytes).to_owned() - }; - let headers = slice::from_raw_parts(info.dlpi_phdr, info.dlpi_phnum as usize); - libs.push(Library { - name, - segments: headers - .iter() - .map(|header| LibrarySegment { - len: (*header).p_memsz as usize, - stated_virtual_memory_address: (*header).p_vaddr as usize, - }) - .collect(), - bias: info.dlpi_addr as usize, - }); - 0 -} diff --git a/vendor/backtrace/src/symbolize/gimli/libs_haiku.rs b/vendor/backtrace/src/symbolize/gimli/libs_haiku.rs deleted file mode 100644 index 87e023e..0000000 --- a/vendor/backtrace/src/symbolize/gimli/libs_haiku.rs +++ /dev/null @@ -1,48 +0,0 @@ -// Haiku implements the image_info struct and the get_next_image_info() -// functions to iterate through the loaded executable images. The -// image_info struct contains a pointer to the start of the .text -// section within the virtual address space, as well as the size of -// that section. All the read-only segments of the ELF-binary are in -// that part of the address space. - -use super::mystd::borrow::ToOwned; -use super::mystd::ffi::{CStr, OsStr}; -use super::mystd::mem::MaybeUninit; -use super::mystd::os::unix::prelude::*; -use super::{Library, LibrarySegment, Vec}; - -pub(super) fn native_libraries() -> Vec<Library> { - let mut libraries: Vec<Library> = Vec::new(); - - unsafe { - let mut info = MaybeUninit::<libc::image_info>::zeroed(); - let mut cookie: i32 = 0; - // Load the first image to get a valid info struct - let mut status = - libc::get_next_image_info(libc::B_CURRENT_TEAM, &mut cookie, info.as_mut_ptr()); - if status != libc::B_OK { - return libraries; - } - let mut info = info.assume_init(); - - while status == libc::B_OK { - let mut segments = Vec::new(); - segments.push(LibrarySegment { - stated_virtual_memory_address: 0, - len: info.text_size as usize, - }); - - let bytes = CStr::from_ptr(info.name.as_ptr()).to_bytes(); - let name = OsStr::from_bytes(bytes).to_owned(); - libraries.push(Library { - name: name, - segments: segments, - bias: info.text as usize, - }); - - status = libc::get_next_image_info(libc::B_CURRENT_TEAM, &mut cookie, &mut info); - } - } - - libraries -} diff --git a/vendor/backtrace/src/symbolize/gimli/libs_illumos.rs b/vendor/backtrace/src/symbolize/gimli/libs_illumos.rs deleted file mode 100644 index e64975e..0000000 --- a/vendor/backtrace/src/symbolize/gimli/libs_illumos.rs +++ /dev/null @@ -1,99 +0,0 @@ -use super::mystd::borrow::ToOwned; -use super::mystd::ffi::{CStr, OsStr}; -use super::mystd::os::unix::prelude::*; -use super::{Library, LibrarySegment, Vec}; -use core::mem; -use object::NativeEndian; - -#[cfg(target_pointer_width = "64")] -use object::elf::{FileHeader64 as FileHeader, ProgramHeader64 as ProgramHeader}; - -type EHdr = FileHeader<NativeEndian>; -type PHdr = ProgramHeader<NativeEndian>; - -#[repr(C)] -struct LinkMap { - l_addr: libc::c_ulong, - l_name: *const libc::c_char, - l_ld: *const libc::c_void, - l_next: *const LinkMap, - l_prev: *const LinkMap, - l_refname: *const libc::c_char, -} - -const RTLD_SELF: *const libc::c_void = -3isize as *const libc::c_void; -const RTLD_DI_LINKMAP: libc::c_int = 2; - -extern "C" { - fn dlinfo( - handle: *const libc::c_void, - request: libc::c_int, - p: *mut libc::c_void, - ) -> libc::c_int; -} - -pub(super) fn native_libraries() -> Vec<Library> { - let mut libs = Vec::new(); - - // Request the current link map from the runtime linker: - let map = unsafe { - let mut map: *const LinkMap = mem::zeroed(); - if dlinfo( - RTLD_SELF, - RTLD_DI_LINKMAP, - (&mut map) as *mut *const LinkMap as *mut libc::c_void, - ) != 0 - { - return libs; - } - map - }; - - // Each entry in the link map represents a loaded object: - let mut l = map; - while !l.is_null() { - // Fetch the fully qualified path of the loaded object: - let bytes = unsafe { CStr::from_ptr((*l).l_name) }.to_bytes(); - let name = OsStr::from_bytes(bytes).to_owned(); - - // The base address of the object loaded into memory: - let addr = unsafe { (*l).l_addr }; - - // Use the ELF header for this object to locate the program - // header: - let e: *const EHdr = unsafe { (*l).l_addr as *const EHdr }; - let phoff = unsafe { (*e).e_phoff }.get(NativeEndian); - let phnum = unsafe { (*e).e_phnum }.get(NativeEndian); - let etype = unsafe { (*e).e_type }.get(NativeEndian); - - let phdr: *const PHdr = (addr + phoff) as *const PHdr; - let phdr = unsafe { core::slice::from_raw_parts(phdr, phnum as usize) }; - - libs.push(Library { - name, - segments: phdr - .iter() - .map(|p| { - let memsz = p.p_memsz.get(NativeEndian); - let vaddr = p.p_vaddr.get(NativeEndian); - LibrarySegment { - len: memsz as usize, - stated_virtual_memory_address: vaddr as usize, - } - }) - .collect(), - bias: if etype == object::elf::ET_EXEC { - // Program header addresses for the base executable are - // already absolute. - 0 - } else { - // Other addresses are relative to the object base. - addr as usize - }, - }); - - l = unsafe { (*l).l_next }; - } - - libs -} diff --git a/vendor/backtrace/src/symbolize/gimli/libs_libnx.rs b/vendor/backtrace/src/symbolize/gimli/libs_libnx.rs deleted file mode 100644 index 93b5ba1..0000000 --- a/vendor/backtrace/src/symbolize/gimli/libs_libnx.rs +++ /dev/null @@ -1,27 +0,0 @@ -use super::{Library, LibrarySegment, Vec}; - -// DevkitA64 doesn't natively support debug info, but the build system will -// place debug info at the path `romfs:/debug_info.elf`. -pub(super) fn native_libraries() -> Vec<Library> { - extern "C" { - static __start__: u8; - } - - let bias = unsafe { &__start__ } as *const u8 as usize; - - let mut ret = Vec::new(); - let mut segments = Vec::new(); - segments.push(LibrarySegment { - stated_virtual_memory_address: 0, - len: usize::max_value() - bias, - }); - - let path = "romfs:/debug_info.elf"; - ret.push(Library { - name: path.into(), - segments, - bias, - }); - - ret -} diff --git a/vendor/backtrace/src/symbolize/gimli/libs_macos.rs b/vendor/backtrace/src/symbolize/gimli/libs_macos.rs deleted file mode 100644 index 438bbff..0000000 --- a/vendor/backtrace/src/symbolize/gimli/libs_macos.rs +++ /dev/null @@ -1,146 +0,0 @@ -#![allow(deprecated)] - -use super::mystd::ffi::{CStr, OsStr}; -use super::mystd::os::unix::prelude::*; -use super::mystd::prelude::v1::*; -use super::{Library, LibrarySegment}; -use core::convert::TryInto; -use core::mem; - -pub(super) fn native_libraries() -> Vec<Library> { - let mut ret = Vec::new(); - let images = unsafe { libc::_dyld_image_count() }; - for i in 0..images { - ret.extend(native_library(i)); - } - return ret; -} - -fn native_library(i: u32) -> Option<Library> { - use object::macho; - use object::read::macho::{MachHeader, Segment}; - use object::NativeEndian; - - // Fetch the name of this library which corresponds to the path of - // where to load it as well. - let name = unsafe { - let name = libc::_dyld_get_image_name(i); - if name.is_null() { - return None; - } - CStr::from_ptr(name) - }; - - // Load the image header of this library and delegate to `object` to - // parse all the load commands so we can figure out all the segments - // involved here. - let (mut load_commands, endian) = unsafe { - let header = libc::_dyld_get_image_header(i); - if header.is_null() { - return None; - } - match (*header).magic { - macho::MH_MAGIC => { - let endian = NativeEndian; - let header = &*(header as *const macho::MachHeader32<NativeEndian>); - let data = core::slice::from_raw_parts( - header as *const _ as *const u8, - mem::size_of_val(header) + header.sizeofcmds.get(endian) as usize, - ); - (header.load_commands(endian, data, 0).ok()?, endian) - } - macho::MH_MAGIC_64 => { - let endian = NativeEndian; - let header = &*(header as *const macho::MachHeader64<NativeEndian>); - let data = core::slice::from_raw_parts( - header as *const _ as *const u8, - mem::size_of_val(header) + header.sizeofcmds.get(endian) as usize, - ); - (header.load_commands(endian, data, 0).ok()?, endian) - } - _ => return None, - } - }; - - // Iterate over the segments and register known regions for segments - // that we find. Additionally record information bout text segments - // for processing later, see comments below. - let mut segments = Vec::new(); - let mut first_text = 0; - let mut text_fileoff_zero = false; - while let Some(cmd) = load_commands.next().ok()? { - if let Some((seg, _)) = cmd.segment_32().ok()? { - if seg.name() == b"__TEXT" { - first_text = segments.len(); - if seg.fileoff(endian) == 0 && seg.filesize(endian) > 0 { - text_fileoff_zero = true; - } - } - segments.push(LibrarySegment { - len: seg.vmsize(endian).try_into().ok()?, - stated_virtual_memory_address: seg.vmaddr(endian).try_into().ok()?, - }); - } - if let Some((seg, _)) = cmd.segment_64().ok()? { - if seg.name() == b"__TEXT" { - first_text = segments.len(); - if seg.fileoff(endian) == 0 && seg.filesize(endian) > 0 { - text_fileoff_zero = true; - } - } - segments.push(LibrarySegment { - len: seg.vmsize(endian).try_into().ok()?, - stated_virtual_memory_address: seg.vmaddr(endian).try_into().ok()?, - }); - } - } - - // Determine the "slide" for this library which ends up being the - // bias we use to figure out where in memory objects are loaded. - // This is a bit of a weird computation though and is the result of - // trying a few things in the wild and seeing what sticks. - // - // The general idea is that the `bias` plus a segment's - // `stated_virtual_memory_address` is going to be where in the - // actual address space the segment resides. The other thing we rely - // on though is that a real address minus the `bias` is the index to - // look up in the symbol table and debuginfo. - // - // It turns out, though, that for system loaded libraries these - // calculations are incorrect. For native executables, however, it - // appears correct. Lifting some logic from LLDB's source it has - // some special-casing for the first `__TEXT` section loaded from - // file offset 0 with a nonzero size. For whatever reason when this - // is present it appears to mean that the symbol table is relative - // to just the vmaddr slide for the library. If it's *not* present - // then the symbol table is relative to the vmaddr slide plus the - // segment's stated address. - // - // To handle this situation if we *don't* find a text section at - // file offset zero then we increase the bias by the first text - // sections's stated address and decrease all stated addresses by - // that amount as well. That way the symbol table is always appears - // relative to the library's bias amount. This appears to have the - // right results for symbolizing via the symbol table. - // - // Honestly I'm not entirely sure whether this is right or if - // there's something else that should indicate how to do this. For - // now though this seems to work well enough (?) and we should - // always be able to tweak this over time if necessary. - // - // For some more information see #318 - let mut slide = unsafe { libc::_dyld_get_image_vmaddr_slide(i) as usize }; - if !text_fileoff_zero { - let adjust = segments[first_text].stated_virtual_memory_address; - for segment in segments.iter_mut() { - segment.stated_virtual_memory_address -= adjust; - } - slide += adjust; - } - - Some(Library { - name: OsStr::from_bytes(name.to_bytes()).to_owned(), - segments, - bias: slide, - }) -} diff --git a/vendor/backtrace/src/symbolize/gimli/libs_windows.rs b/vendor/backtrace/src/symbolize/gimli/libs_windows.rs deleted file mode 100644 index b47ed42..0000000 --- a/vendor/backtrace/src/symbolize/gimli/libs_windows.rs +++ /dev/null @@ -1,89 +0,0 @@ -use super::super::super::windows::*; -use super::mystd::os::windows::prelude::*; -use super::{coff, mmap, Library, LibrarySegment, OsString}; -use alloc::vec; -use alloc::vec::Vec; -use core::mem; -use core::mem::MaybeUninit; - -// For loading native libraries on Windows, see some discussion on -// rust-lang/rust#71060 for the various strategies here. -pub(super) fn native_libraries() -> Vec<Library> { - let mut ret = Vec::new(); - unsafe { - add_loaded_images(&mut ret); - } - return ret; -} - -unsafe fn add_loaded_images(ret: &mut Vec<Library>) { - let snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0); - if snap == INVALID_HANDLE_VALUE { - return; - } - - let mut me = MaybeUninit::<MODULEENTRY32W>::zeroed().assume_init(); - me.dwSize = mem::size_of_val(&me) as DWORD; - if Module32FirstW(snap, &mut me) == TRUE { - loop { - if let Some(lib) = load_library(&me) { - ret.push(lib); - } - - if Module32NextW(snap, &mut me) != TRUE { - break; - } - } - } - - CloseHandle(snap); -} - -unsafe fn load_library(me: &MODULEENTRY32W) -> Option<Library> { - let pos = me - .szExePath - .iter() - .position(|i| *i == 0) - .unwrap_or(me.szExePath.len()); - let name = OsString::from_wide(&me.szExePath[..pos]); - - // MinGW libraries currently don't support ASLR - // (rust-lang/rust#16514), but DLLs can still be relocated around in - // the address space. It appears that addresses in debug info are - // all as-if this library was loaded at its "image base", which is a - // field in its COFF file headers. Since this is what debuginfo - // seems to list we parse the symbol table and store addresses as if - // the library was loaded at "image base" as well. - // - // The library may not be loaded at "image base", however. - // (presumably something else may be loaded there?) This is where - // the `bias` field comes into play, and we need to figure out the - // value of `bias` here. Unfortunately though it's not clear how to - // acquire this from a loaded module. What we do have, however, is - // the actual load address (`modBaseAddr`). - // - // As a bit of a cop-out for now we mmap the file, read the file - // header information, then drop the mmap. This is wasteful because - // we'll probably reopen the mmap later, but this should work well - // enough for now. - // - // Once we have the `image_base` (desired load location) and the - // `base_addr` (actual load location) we can fill in the `bias` - // (difference between the actual and desired) and then the stated - // address of each segment is the `image_base` since that's what the - // file says. - // - // For now it appears that unlike ELF/MachO we can make do with one - // segment per library, using `modBaseSize` as the whole size. - let mmap = mmap(name.as_ref())?; - let image_base = coff::get_image_base(&mmap)?; - let base_addr = me.modBaseAddr as usize; - Some(Library { - name, - bias: base_addr.wrapping_sub(image_base), - segments: vec![LibrarySegment { - stated_virtual_memory_address: image_base, - len: me.modBaseSize as usize, - }], - }) -} diff --git a/vendor/backtrace/src/symbolize/gimli/macho.rs b/vendor/backtrace/src/symbolize/gimli/macho.rs deleted file mode 100644 index 74ed809..0000000 --- a/vendor/backtrace/src/symbolize/gimli/macho.rs +++ /dev/null @@ -1,333 +0,0 @@ -use super::{gimli, Box, Context, Endian, EndianSlice, Mapping, Path, Stash, Vec}; -use alloc::sync::Arc; -use core::convert::TryInto; -use object::macho; -use object::read::macho::{MachHeader, Nlist, Section, Segment as _}; -use object::{Bytes, NativeEndian}; - -#[cfg(target_pointer_width = "32")] -type Mach = object::macho::MachHeader32<NativeEndian>; -#[cfg(target_pointer_width = "64")] -type Mach = object::macho::MachHeader64<NativeEndian>; -type MachSegment = <Mach as MachHeader>::Segment; -type MachSection = <Mach as MachHeader>::Section; -type MachNlist = <Mach as MachHeader>::Nlist; - -impl Mapping { - // The loading path for macOS is so different we just have a completely - // different implementation of the function here. On macOS we need to go - // probing the filesystem for a bunch of files. - pub fn new(path: &Path) -> Option<Mapping> { - // First up we need to load the unique UUID which is stored in the macho - // header of the file we're reading, specified at `path`. - let map = super::mmap(path)?; - let (macho, data) = find_header(&map)?; - let endian = macho.endian().ok()?; - let uuid = macho.uuid(endian, data, 0).ok()?; - - // Next we need to look for a `*.dSYM` file. For now we just probe the - // containing directory and look around for something that matches - // `*.dSYM`. Once it's found we root through the dwarf resources that it - // contains and try to find a macho file which has a matching UUID as - // the one of our own file. If we find a match that's the dwarf file we - // want to return. - if let Some(uuid) = uuid { - if let Some(parent) = path.parent() { - if let Some(mapping) = Mapping::load_dsym(parent, uuid) { - return Some(mapping); - } - } - } - - // Looks like nothing matched our UUID, so let's at least return our own - // file. This should have the symbol table for at least some - // symbolication purposes. - Mapping::mk(map, |data, stash| { - let (macho, data) = find_header(data)?; - let endian = macho.endian().ok()?; - let obj = Object::parse(macho, endian, data)?; - Context::new(stash, obj, None, None) - }) - } - - fn load_dsym(dir: &Path, uuid: [u8; 16]) -> Option<Mapping> { - for entry in dir.read_dir().ok()? { - let entry = entry.ok()?; - let filename = match entry.file_name().into_string() { - Ok(name) => name, - Err(_) => continue, - }; - if !filename.ends_with(".dSYM") { - continue; - } - let candidates = entry.path().join("Contents/Resources/DWARF"); - if let Some(mapping) = Mapping::try_dsym_candidate(&candidates, uuid) { - return Some(mapping); - } - } - None - } - - fn try_dsym_candidate(dir: &Path, uuid: [u8; 16]) -> Option<Mapping> { - // Look for files in the `DWARF` directory which have a matching uuid to - // the original object file. If we find one then we found the debug - // information. - for entry in dir.read_dir().ok()? { - let entry = entry.ok()?; - let map = super::mmap(&entry.path())?; - let candidate = Mapping::mk(map, |data, stash| { - let (macho, data) = find_header(data)?; - let endian = macho.endian().ok()?; - let entry_uuid = macho.uuid(endian, data, 0).ok()??; - if entry_uuid != uuid { - return None; - } - let obj = Object::parse(macho, endian, data)?; - Context::new(stash, obj, None, None) - }); - if let Some(candidate) = candidate { - return Some(candidate); - } - } - - None - } -} - -fn find_header(data: &'_ [u8]) -> Option<(&'_ Mach, &'_ [u8])> { - use object::endian::BigEndian; - - let desired_cpu = || { - if cfg!(target_arch = "x86") { - Some(macho::CPU_TYPE_X86) - } else if cfg!(target_arch = "x86_64") { - Some(macho::CPU_TYPE_X86_64) - } else if cfg!(target_arch = "arm") { - Some(macho::CPU_TYPE_ARM) - } else if cfg!(target_arch = "aarch64") { - Some(macho::CPU_TYPE_ARM64) - } else { - None - } - }; - - let mut data = Bytes(data); - match data - .clone() - .read::<object::endian::U32<NativeEndian>>() - .ok()? - .get(NativeEndian) - { - macho::MH_MAGIC_64 | macho::MH_CIGAM_64 | macho::MH_MAGIC | macho::MH_CIGAM => {} - - macho::FAT_MAGIC | macho::FAT_CIGAM => { - let mut header_data = data; - let endian = BigEndian; - let header = header_data.read::<macho::FatHeader>().ok()?; - let nfat = header.nfat_arch.get(endian); - let arch = (0..nfat) - .filter_map(|_| header_data.read::<macho::FatArch32>().ok()) - .find(|arch| desired_cpu() == Some(arch.cputype.get(endian)))?; - let offset = arch.offset.get(endian); - let size = arch.size.get(endian); - data = data - .read_bytes_at(offset.try_into().ok()?, size.try_into().ok()?) - .ok()?; - } - - macho::FAT_MAGIC_64 | macho::FAT_CIGAM_64 => { - let mut header_data = data; - let endian = BigEndian; - let header = header_data.read::<macho::FatHeader>().ok()?; - let nfat = header.nfat_arch.get(endian); - let arch = (0..nfat) - .filter_map(|_| header_data.read::<macho::FatArch64>().ok()) - .find(|arch| desired_cpu() == Some(arch.cputype.get(endian)))?; - let offset = arch.offset.get(endian); - let size = arch.size.get(endian); - data = data - .read_bytes_at(offset.try_into().ok()?, size.try_into().ok()?) - .ok()?; - } - - _ => return None, - } - - Mach::parse(data.0, 0).ok().map(|h| (h, data.0)) -} - -// This is used both for executables/libraries and source object files. -pub struct Object<'a> { - endian: NativeEndian, - data: &'a [u8], - dwarf: Option<&'a [MachSection]>, - syms: Vec<(&'a [u8], u64)>, - syms_sort_by_name: bool, - // Only set for executables/libraries, and not the source object files. - object_map: Option<object::ObjectMap<'a>>, - // The outer Option is for lazy loading, and the inner Option allows load errors to be cached. - object_mappings: Box<[Option<Option<Mapping>>]>, -} - -impl<'a> Object<'a> { - fn parse(mach: &'a Mach, endian: NativeEndian, data: &'a [u8]) -> Option<Object<'a>> { - let is_object = mach.filetype(endian) == object::macho::MH_OBJECT; - let mut dwarf = None; - let mut syms = Vec::new(); - let mut syms_sort_by_name = false; - let mut commands = mach.load_commands(endian, data, 0).ok()?; - let mut object_map = None; - let mut object_mappings = Vec::new(); - while let Ok(Some(command)) = commands.next() { - if let Some((segment, section_data)) = MachSegment::from_command(command).ok()? { - // Object files should have all sections in a single unnamed segment load command. - if segment.name() == b"__DWARF" || (is_object && segment.name() == b"") { - dwarf = segment.sections(endian, section_data).ok(); - } - } else if let Some(symtab) = command.symtab().ok()? { - let symbols = symtab.symbols::<Mach, _>(endian, data).ok()?; - syms = symbols - .iter() - .filter_map(|nlist: &MachNlist| { - let name = nlist.name(endian, symbols.strings()).ok()?; - if name.len() > 0 && nlist.is_definition() { - Some((name, u64::from(nlist.n_value(endian)))) - } else { - None - } - }) - .collect(); - if is_object { - // We never search object file symbols by address. - // Instead, we already know the symbol name from the executable, and we - // need to search by name to find the matching symbol in the object file. - syms.sort_unstable_by_key(|(name, _)| *name); - syms_sort_by_name = true; - } else { - syms.sort_unstable_by_key(|(_, addr)| *addr); - let map = symbols.object_map(endian); - object_mappings.resize_with(map.objects().len(), || None); - object_map = Some(map); - } - } - } - - Some(Object { - endian, - data, - dwarf, - syms, - syms_sort_by_name, - object_map, - object_mappings: object_mappings.into_boxed_slice(), - }) - } - - pub fn section(&self, _: &Stash, name: &str) -> Option<&'a [u8]> { - let name = name.as_bytes(); - let dwarf = self.dwarf?; - let section = dwarf.into_iter().find(|section| { - let section_name = section.name(); - section_name == name || { - section_name.starts_with(b"__") - && name.starts_with(b".") - && §ion_name[2..] == &name[1..] - } - })?; - Some(section.data(self.endian, self.data).ok()?) - } - - pub fn search_symtab<'b>(&'b self, addr: u64) -> Option<&'b [u8]> { - debug_assert!(!self.syms_sort_by_name); - let i = match self.syms.binary_search_by_key(&addr, |(_, addr)| *addr) { - Ok(i) => i, - Err(i) => i.checked_sub(1)?, - }; - let (sym, _addr) = self.syms.get(i)?; - Some(sym) - } - - /// Try to load a context for an object file. - /// - /// If dsymutil was not run, then the DWARF may be found in the source object files. - pub(super) fn search_object_map<'b>(&'b mut self, addr: u64) -> Option<(&Context<'b>, u64)> { - // `object_map` contains a map from addresses to symbols and object paths. - // Look up the address and get a mapping for the object. - let object_map = self.object_map.as_ref()?; - let symbol = object_map.get(addr)?; - let object_index = symbol.object_index(); - let mapping = self.object_mappings.get_mut(object_index)?; - if mapping.is_none() { - // No cached mapping, so create it. - *mapping = Some(object_mapping(object_map.objects().get(object_index)?)); - } - let cx: &'b Context<'static> = &mapping.as_ref()?.as_ref()?.cx; - // Don't leak the `'static` lifetime, make sure it's scoped to just ourselves. - let cx = unsafe { core::mem::transmute::<&'b Context<'static>, &'b Context<'b>>(cx) }; - - // We must translate the address in order to be able to look it up - // in the DWARF in the object file. - debug_assert!(cx.object.syms.is_empty() || cx.object.syms_sort_by_name); - let i = cx - .object - .syms - .binary_search_by_key(&symbol.name(), |(name, _)| *name) - .ok()?; - let object_symbol = cx.object.syms.get(i)?; - let object_addr = addr - .wrapping_sub(symbol.address()) - .wrapping_add(object_symbol.1); - Some((cx, object_addr)) - } -} - -fn object_mapping(path: &[u8]) -> Option<Mapping> { - use super::mystd::ffi::OsStr; - use super::mystd::os::unix::prelude::*; - - let map; - - // `N_OSO` symbol names can be either `/path/to/object.o` or `/path/to/archive.a(object.o)`. - let member_name = if let Some((archive_path, member_name)) = split_archive_path(path) { - map = super::mmap(Path::new(OsStr::from_bytes(archive_path)))?; - Some(member_name) - } else { - map = super::mmap(Path::new(OsStr::from_bytes(path)))?; - None - }; - Mapping::mk(map, |data, stash| { - let data = match member_name { - Some(member_name) => { - let archive = object::read::archive::ArchiveFile::parse(data).ok()?; - let member = archive - .members() - .filter_map(Result::ok) - .find(|m| m.name() == member_name)?; - member.data(data).ok()? - } - None => data, - }; - let (macho, data) = find_header(data)?; - let endian = macho.endian().ok()?; - let obj = Object::parse(macho, endian, data)?; - Context::new(stash, obj, None, None) - }) -} - -fn split_archive_path(path: &[u8]) -> Option<(&[u8], &[u8])> { - let (last, path) = path.split_last()?; - if *last != b')' { - return None; - } - let index = path.iter().position(|&x| x == b'(')?; - let (archive, rest) = path.split_at(index); - Some((archive, &rest[1..])) -} - -pub(super) fn handle_split_dwarf<'data>( - _package: Option<&gimli::DwarfPackage<EndianSlice<'data, Endian>>>, - _stash: &'data Stash, - _load: addr2line::SplitDwarfLoad<EndianSlice<'data, Endian>>, -) -> Option<Arc<gimli::Dwarf<EndianSlice<'data, Endian>>>> { - None -} diff --git a/vendor/backtrace/src/symbolize/gimli/mmap_fake.rs b/vendor/backtrace/src/symbolize/gimli/mmap_fake.rs deleted file mode 100644 index ce50964..0000000 --- a/vendor/backtrace/src/symbolize/gimli/mmap_fake.rs +++ /dev/null @@ -1,25 +0,0 @@ -use super::{mystd::io::Read, File}; -use alloc::vec::Vec; -use core::ops::Deref; - -pub struct Mmap { - vec: Vec<u8>, -} - -impl Mmap { - pub unsafe fn map(mut file: &File, len: usize) -> Option<Mmap> { - let mut mmap = Mmap { - vec: Vec::with_capacity(len), - }; - file.read_to_end(&mut mmap.vec).ok()?; - Some(mmap) - } -} - -impl Deref for Mmap { - type Target = [u8]; - - fn deref(&self) -> &[u8] { - &self.vec[..] - } -} diff --git a/vendor/backtrace/src/symbolize/gimli/mmap_unix.rs b/vendor/backtrace/src/symbolize/gimli/mmap_unix.rs deleted file mode 100644 index 261ffc1..0000000 --- a/vendor/backtrace/src/symbolize/gimli/mmap_unix.rs +++ /dev/null @@ -1,49 +0,0 @@ -use super::mystd::fs::File; -use super::mystd::os::unix::prelude::*; -use core::ops::Deref; -use core::ptr; -use core::slice; - -#[cfg(not(all(target_os = "linux", target_env = "gnu")))] -use libc::mmap as mmap64; -#[cfg(all(target_os = "linux", target_env = "gnu"))] -use libc::mmap64; - -pub struct Mmap { - ptr: *mut libc::c_void, - len: usize, -} - -impl Mmap { - pub unsafe fn map(file: &File, len: usize) -> Option<Mmap> { - let ptr = mmap64( - ptr::null_mut(), - len, - libc::PROT_READ, - libc::MAP_PRIVATE, - file.as_raw_fd(), - 0, - ); - if ptr == libc::MAP_FAILED { - return None; - } - Some(Mmap { ptr, len }) - } -} - -impl Deref for Mmap { - type Target = [u8]; - - fn deref(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.ptr as *const u8, self.len) } - } -} - -impl Drop for Mmap { - fn drop(&mut self) { - unsafe { - let r = libc::munmap(self.ptr, self.len); - debug_assert_eq!(r, 0); - } - } -} diff --git a/vendor/backtrace/src/symbolize/gimli/mmap_windows.rs b/vendor/backtrace/src/symbolize/gimli/mmap_windows.rs deleted file mode 100644 index b39509d..0000000 --- a/vendor/backtrace/src/symbolize/gimli/mmap_windows.rs +++ /dev/null @@ -1,57 +0,0 @@ -use super::super::super::windows::*; -use super::mystd::fs::File; -use super::mystd::os::windows::prelude::*; -use core::ops::Deref; -use core::ptr; -use core::slice; - -pub struct Mmap { - // keep the file alive to prevent it from being deleted which would cause - // us to read bad data. - _file: File, - ptr: *mut c_void, - len: usize, -} - -impl Mmap { - pub unsafe fn map(file: &File, len: usize) -> Option<Mmap> { - let file = file.try_clone().ok()?; - let mapping = CreateFileMappingA( - file.as_raw_handle() as *mut _, - ptr::null_mut(), - PAGE_READONLY, - 0, - 0, - ptr::null(), - ); - if mapping.is_null() { - return None; - } - let ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, len); - CloseHandle(mapping); - if ptr.is_null() { - return None; - } - Some(Mmap { - _file: file, - ptr, - len, - }) - } -} -impl Deref for Mmap { - type Target = [u8]; - - fn deref(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.ptr as *const u8, self.len) } - } -} - -impl Drop for Mmap { - fn drop(&mut self) { - unsafe { - let r = UnmapViewOfFile(self.ptr); - debug_assert!(r != 0); - } - } -} diff --git a/vendor/backtrace/src/symbolize/gimli/parse_running_mmaps_unix.rs b/vendor/backtrace/src/symbolize/gimli/parse_running_mmaps_unix.rs deleted file mode 100644 index 5d4b346..0000000 --- a/vendor/backtrace/src/symbolize/gimli/parse_running_mmaps_unix.rs +++ /dev/null @@ -1,295 +0,0 @@ -// Note: This file is only currently used on targets that call out to the code -// in `mod libs_dl_iterate_phdr` (e.g. linux, freebsd, ...); it may be more -// general purpose, but it hasn't been tested elsewhere. - -use super::mystd::fs::File; -use super::mystd::io::Read; -use super::mystd::str::FromStr; -use super::{OsString, String, Vec}; - -#[derive(PartialEq, Eq, Debug)] -pub(super) struct MapsEntry { - /// start (inclusive) and limit (exclusive) of address range. - address: (usize, usize), - /// The perms field are the permissions for the entry - /// - /// r = read - /// w = write - /// x = execute - /// s = shared - /// p = private (copy on write) - perms: [char; 4], - /// Offset into the file (or "whatever"). - offset: usize, - /// device (major, minor) - dev: (usize, usize), - /// inode on the device. 0 indicates that no inode is associated with the memory region (e.g. uninitalized data aka BSS). - inode: usize, - /// Usually the file backing the mapping. - /// - /// Note: The man page for proc includes a note about "coordination" by - /// using readelf to see the Offset field in ELF program headers. pnkfelix - /// is not yet sure if that is intended to be a comment on pathname, or what - /// form/purpose such coordination is meant to have. - /// - /// There are also some pseudo-paths: - /// "[stack]": The initial process's (aka main thread's) stack. - /// "[stack:<tid>]": a specific thread's stack. (This was only present for a limited range of Linux verisons; it was determined to be too expensive to provide.) - /// "[vdso]": Virtual dynamically linked shared object - /// "[heap]": The process's heap - /// - /// The pathname can be blank, which means it is an anonymous mapping - /// obtained via mmap. - /// - /// Newlines in pathname are replaced with an octal escape sequence. - /// - /// The pathname may have "(deleted)" appended onto it if the file-backed - /// path has been deleted. - /// - /// Note that modifications like the latter two indicated above imply that - /// in general the pathname may be ambiguous. (I.e. you cannot tell if the - /// denoted filename actually ended with the text "(deleted)", or if that - /// was added by the maps rendering. - pathname: OsString, -} - -pub(super) fn parse_maps() -> Result<Vec<MapsEntry>, &'static str> { - let mut v = Vec::new(); - let mut proc_self_maps = - File::open("/proc/self/maps").map_err(|_| "Couldn't open /proc/self/maps")?; - let mut buf = String::new(); - let _bytes_read = proc_self_maps - .read_to_string(&mut buf) - .map_err(|_| "Couldn't read /proc/self/maps")?; - for line in buf.lines() { - v.push(line.parse()?); - } - - Ok(v) -} - -impl MapsEntry { - pub(super) fn pathname(&self) -> &OsString { - &self.pathname - } - - pub(super) fn ip_matches(&self, ip: usize) -> bool { - self.address.0 <= ip && ip < self.address.1 - } -} - -impl FromStr for MapsEntry { - type Err = &'static str; - - // Format: address perms offset dev inode pathname - // e.g.: "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]" - // e.g.: "7f5985f46000-7f5985f48000 rw-p 00039000 103:06 76021795 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2" - // e.g.: "35b1a21000-35b1a22000 rw-p 00000000 00:00 0" - // - // Note that paths may contain spaces, so we can't use `str::split` for parsing (until - // Split::remainder is stabilized #77998). - fn from_str(s: &str) -> Result<Self, Self::Err> { - let (range_str, s) = s.trim_start().split_once(' ').unwrap_or((s, "")); - if range_str.is_empty() { - return Err("Couldn't find address"); - } - - let (perms_str, s) = s.trim_start().split_once(' ').unwrap_or((s, "")); - if perms_str.is_empty() { - return Err("Couldn't find permissions"); - } - - let (offset_str, s) = s.trim_start().split_once(' ').unwrap_or((s, "")); - if offset_str.is_empty() { - return Err("Couldn't find offset"); - } - - let (dev_str, s) = s.trim_start().split_once(' ').unwrap_or((s, "")); - if dev_str.is_empty() { - return Err("Couldn't find dev"); - } - - let (inode_str, s) = s.trim_start().split_once(' ').unwrap_or((s, "")); - if inode_str.is_empty() { - return Err("Couldn't find inode"); - } - - // Pathname may be omitted in which case it will be empty - let pathname_str = s.trim_start(); - - let hex = |s| usize::from_str_radix(s, 16).map_err(|_| "Couldn't parse hex number"); - let address = if let Some((start, limit)) = range_str.split_once('-') { - (hex(start)?, hex(limit)?) - } else { - return Err("Couldn't parse address range"); - }; - let perms: [char; 4] = { - let mut chars = perms_str.chars(); - let mut c = || chars.next().ok_or("insufficient perms"); - let perms = [c()?, c()?, c()?, c()?]; - if chars.next().is_some() { - return Err("too many perms"); - } - perms - }; - let offset = hex(offset_str)?; - let dev = if let Some((major, minor)) = dev_str.split_once(':') { - (hex(major)?, hex(minor)?) - } else { - return Err("Couldn't parse dev"); - }; - let inode = hex(inode_str)?; - let pathname = pathname_str.into(); - - Ok(MapsEntry { - address, - perms, - offset, - dev, - inode, - pathname, - }) - } -} - -// Make sure we can parse 64-bit sample output if we're on a 64-bit target. -#[cfg(target_pointer_width = "64")] -#[test] -fn check_maps_entry_parsing_64bit() { - assert_eq!( - "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 \ - [vsyscall]" - .parse::<MapsEntry>() - .unwrap(), - MapsEntry { - address: (0xffffffffff600000, 0xffffffffff601000), - perms: ['-', '-', 'x', 'p'], - offset: 0x00000000, - dev: (0x00, 0x00), - inode: 0x0, - pathname: "[vsyscall]".into(), - } - ); - - assert_eq!( - "7f5985f46000-7f5985f48000 rw-p 00039000 103:06 76021795 \ - /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2" - .parse::<MapsEntry>() - .unwrap(), - MapsEntry { - address: (0x7f5985f46000, 0x7f5985f48000), - perms: ['r', 'w', '-', 'p'], - offset: 0x00039000, - dev: (0x103, 0x06), - inode: 0x76021795, - pathname: "/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2".into(), - } - ); - assert_eq!( - "35b1a21000-35b1a22000 rw-p 00000000 00:00 0" - .parse::<MapsEntry>() - .unwrap(), - MapsEntry { - address: (0x35b1a21000, 0x35b1a22000), - perms: ['r', 'w', '-', 'p'], - offset: 0x00000000, - dev: (0x00, 0x00), - inode: 0x0, - pathname: Default::default(), - } - ); -} - -// (This output was taken from a 32-bit machine, but will work on any target) -#[test] -fn check_maps_entry_parsing_32bit() { - /* Example snippet of output: - 08056000-08077000 rw-p 00000000 00:00 0 [heap] - b7c79000-b7e02000 r--p 00000000 08:01 60662705 /usr/lib/locale/locale-archive - b7e02000-b7e03000 rw-p 00000000 00:00 0 - */ - assert_eq!( - "08056000-08077000 rw-p 00000000 00:00 0 \ - [heap]" - .parse::<MapsEntry>() - .unwrap(), - MapsEntry { - address: (0x08056000, 0x08077000), - perms: ['r', 'w', '-', 'p'], - offset: 0x00000000, - dev: (0x00, 0x00), - inode: 0x0, - pathname: "[heap]".into(), - } - ); - - assert_eq!( - "b7c79000-b7e02000 r--p 00000000 08:01 60662705 \ - /usr/lib/locale/locale-archive" - .parse::<MapsEntry>() - .unwrap(), - MapsEntry { - address: (0xb7c79000, 0xb7e02000), - perms: ['r', '-', '-', 'p'], - offset: 0x00000000, - dev: (0x08, 0x01), - inode: 0x60662705, - pathname: "/usr/lib/locale/locale-archive".into(), - } - ); - assert_eq!( - "b7e02000-b7e03000 rw-p 00000000 00:00 0" - .parse::<MapsEntry>() - .unwrap(), - MapsEntry { - address: (0xb7e02000, 0xb7e03000), - perms: ['r', 'w', '-', 'p'], - offset: 0x00000000, - dev: (0x00, 0x00), - inode: 0x0, - pathname: Default::default(), - } - ); - assert_eq!( - "b7c79000-b7e02000 r--p 00000000 08:01 60662705 \ - /executable/path/with some spaces" - .parse::<MapsEntry>() - .unwrap(), - MapsEntry { - address: (0xb7c79000, 0xb7e02000), - perms: ['r', '-', '-', 'p'], - offset: 0x00000000, - dev: (0x08, 0x01), - inode: 0x60662705, - pathname: "/executable/path/with some spaces".into(), - } - ); - assert_eq!( - "b7c79000-b7e02000 r--p 00000000 08:01 60662705 \ - /executable/path/with multiple-continuous spaces " - .parse::<MapsEntry>() - .unwrap(), - MapsEntry { - address: (0xb7c79000, 0xb7e02000), - perms: ['r', '-', '-', 'p'], - offset: 0x00000000, - dev: (0x08, 0x01), - inode: 0x60662705, - pathname: "/executable/path/with multiple-continuous spaces ".into(), - } - ); - assert_eq!( - " b7c79000-b7e02000 r--p 00000000 08:01 60662705 \ - /executable/path/starts-with-spaces" - .parse::<MapsEntry>() - .unwrap(), - MapsEntry { - address: (0xb7c79000, 0xb7e02000), - perms: ['r', '-', '-', 'p'], - offset: 0x00000000, - dev: (0x08, 0x01), - inode: 0x60662705, - pathname: "/executable/path/starts-with-spaces".into(), - } - ); -} diff --git a/vendor/backtrace/src/symbolize/gimli/stash.rs b/vendor/backtrace/src/symbolize/gimli/stash.rs deleted file mode 100644 index 792f9a6..0000000 --- a/vendor/backtrace/src/symbolize/gimli/stash.rs +++ /dev/null @@ -1,50 +0,0 @@ -// only used on Linux right now, so allow dead code elsewhere -#![cfg_attr(not(target_os = "linux"), allow(dead_code))] - -use super::Mmap; -use alloc::vec; -use alloc::vec::Vec; -use core::cell::UnsafeCell; - -/// A simple arena allocator for byte buffers. -pub struct Stash { - buffers: UnsafeCell<Vec<Vec<u8>>>, - mmaps: UnsafeCell<Vec<Mmap>>, -} - -impl Stash { - pub fn new() -> Stash { - Stash { - buffers: UnsafeCell::new(Vec::new()), - mmaps: UnsafeCell::new(Vec::new()), - } - } - - /// Allocates a buffer of the specified size and returns a mutable reference - /// to it. - pub fn allocate(&self, size: usize) -> &mut [u8] { - // SAFETY: this is the only function that ever constructs a mutable - // reference to `self.buffers`. - let buffers = unsafe { &mut *self.buffers.get() }; - let i = buffers.len(); - buffers.push(vec![0; size]); - // SAFETY: we never remove elements from `self.buffers`, so a reference - // to the data inside any buffer will live as long as `self` does. - &mut buffers[i] - } - - /// Stores a `Mmap` for the lifetime of this `Stash`, returning a pointer - /// which is scoped to just this lifetime. - pub fn cache_mmap(&self, map: Mmap) -> &[u8] { - // SAFETY: this is the only location for a mutable pointer to - // `mmaps`, and this structure isn't threadsafe to shared across - // threads either. We also never remove elements from `self.mmaps`, - // so a reference to the data inside the map will live as long as - // `self` does. - unsafe { - let mmaps = &mut *self.mmaps.get(); - mmaps.push(map); - mmaps.last().unwrap() - } - } -} diff --git a/vendor/backtrace/src/symbolize/miri.rs b/vendor/backtrace/src/symbolize/miri.rs deleted file mode 100644 index 5b0dc30..0000000 --- a/vendor/backtrace/src/symbolize/miri.rs +++ /dev/null @@ -1,56 +0,0 @@ -use core::ffi::c_void; -use core::marker::PhantomData; - -use super::super::backtrace::miri::{resolve_addr, Frame}; -use super::BytesOrWideString; -use super::{ResolveWhat, SymbolName}; - -pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol)) { - let sym = match what { - ResolveWhat::Address(addr) => Symbol { - inner: resolve_addr(addr), - _unused: PhantomData, - }, - ResolveWhat::Frame(frame) => Symbol { - inner: frame.inner.clone(), - _unused: PhantomData, - }, - }; - cb(&super::Symbol { inner: sym }) -} - -pub struct Symbol<'a> { - inner: Frame, - _unused: PhantomData<&'a ()>, -} - -impl<'a> Symbol<'a> { - pub fn name(&self) -> Option<SymbolName<'_>> { - Some(SymbolName::new(&self.inner.inner.name)) - } - - pub fn addr(&self) -> Option<*mut c_void> { - Some(self.inner.addr) - } - - pub fn filename_raw(&self) -> Option<BytesOrWideString<'_>> { - Some(BytesOrWideString::Bytes(&self.inner.inner.filename)) - } - - pub fn lineno(&self) -> Option<u32> { - Some(self.inner.inner.lineno) - } - - pub fn colno(&self) -> Option<u32> { - Some(self.inner.inner.colno) - } - - #[cfg(feature = "std")] - pub fn filename(&self) -> Option<&std::path::Path> { - Some(std::path::Path::new( - core::str::from_utf8(&self.inner.inner.filename).unwrap(), - )) - } -} - -pub unsafe fn clear_symbol_cache() {} diff --git a/vendor/backtrace/src/symbolize/mod.rs b/vendor/backtrace/src/symbolize/mod.rs deleted file mode 100644 index a7c1995..0000000 --- a/vendor/backtrace/src/symbolize/mod.rs +++ /dev/null @@ -1,485 +0,0 @@ -use core::{fmt, str}; - -cfg_if::cfg_if! { - if #[cfg(feature = "std")] { - use std::path::Path; - use std::prelude::v1::*; - } -} - -use super::backtrace::Frame; -use super::types::BytesOrWideString; -use core::ffi::c_void; -use rustc_demangle::{try_demangle, Demangle}; - -/// Resolve an address to a symbol, passing the symbol to the specified -/// closure. -/// -/// This function will look up the given address in areas such as the local -/// symbol table, dynamic symbol table, or DWARF debug info (depending on the -/// activated implementation) to find symbols to yield. -/// -/// The closure may not be called if resolution could not be performed, and it -/// also may be called more than once in the case of inlined functions. -/// -/// Symbols yielded represent the execution at the specified `addr`, returning -/// file/line pairs for that address (if available). -/// -/// Note that if you have a `Frame` then it's recommended to use the -/// `resolve_frame` function instead of this one. -/// -/// # Required features -/// -/// This function requires the `std` feature of the `backtrace` crate to be -/// enabled, and the `std` feature is enabled by default. -/// -/// # Panics -/// -/// This function strives to never panic, but if the `cb` provided panics then -/// some platforms will force a double panic to abort the process. Some -/// platforms use a C library which internally uses callbacks which cannot be -/// unwound through, so panicking from `cb` may trigger a process abort. -/// -/// # Example -/// -/// ``` -/// extern crate backtrace; -/// -/// fn main() { -/// backtrace::trace(|frame| { -/// let ip = frame.ip(); -/// -/// backtrace::resolve(ip, |symbol| { -/// // ... -/// }); -/// -/// false // only look at the top frame -/// }); -/// } -/// ``` -#[cfg(feature = "std")] -pub fn resolve<F: FnMut(&Symbol)>(addr: *mut c_void, cb: F) { - let _guard = crate::lock::lock(); - unsafe { resolve_unsynchronized(addr, cb) } -} - -/// Resolve a previously capture frame to a symbol, passing the symbol to the -/// specified closure. -/// -/// This function performs the same function as `resolve` except that it takes a -/// `Frame` as an argument instead of an address. This can allow some platform -/// implementations of backtracing to provide more accurate symbol information -/// or information about inline frames for example. It's recommended to use this -/// if you can. -/// -/// # Required features -/// -/// This function requires the `std` feature of the `backtrace` crate to be -/// enabled, and the `std` feature is enabled by default. -/// -/// # Panics -/// -/// This function strives to never panic, but if the `cb` provided panics then -/// some platforms will force a double panic to abort the process. Some -/// platforms use a C library which internally uses callbacks which cannot be -/// unwound through, so panicking from `cb` may trigger a process abort. -/// -/// # Example -/// -/// ``` -/// extern crate backtrace; -/// -/// fn main() { -/// backtrace::trace(|frame| { -/// backtrace::resolve_frame(frame, |symbol| { -/// // ... -/// }); -/// -/// false // only look at the top frame -/// }); -/// } -/// ``` -#[cfg(feature = "std")] -pub fn resolve_frame<F: FnMut(&Symbol)>(frame: &Frame, cb: F) { - let _guard = crate::lock::lock(); - unsafe { resolve_frame_unsynchronized(frame, cb) } -} - -pub enum ResolveWhat<'a> { - Address(*mut c_void), - Frame(&'a Frame), -} - -impl<'a> ResolveWhat<'a> { - #[allow(dead_code)] - fn address_or_ip(&self) -> *mut c_void { - match self { - ResolveWhat::Address(a) => adjust_ip(*a), - ResolveWhat::Frame(f) => adjust_ip(f.ip()), - } - } -} - -// IP values from stack frames are typically (always?) the instruction -// *after* the call that's the actual stack trace. Symbolizing this on -// causes the filename/line number to be one ahead and perhaps into -// the void if it's near the end of the function. -// -// This appears to basically always be the case on all platforms, so we always -// subtract one from a resolved ip to resolve it to the previous call -// instruction instead of the instruction being returned to. -// -// Ideally we would not do this. Ideally we would require callers of the -// `resolve` APIs here to manually do the -1 and account that they want location -// information for the *previous* instruction, not the current. Ideally we'd -// also expose on `Frame` if we are indeed the address of the next instruction -// or the current. -// -// For now though this is a pretty niche concern so we just internally always -// subtract one. Consumers should keep working and getting pretty good results, -// so we should be good enough. -fn adjust_ip(a: *mut c_void) -> *mut c_void { - if a.is_null() { - a - } else { - (a as usize - 1) as *mut c_void - } -} - -/// Same as `resolve`, only unsafe as it's unsynchronized. -/// -/// This function does not have synchronization guarantees but is available when -/// the `std` feature of this crate isn't compiled in. See the `resolve` -/// function for more documentation and examples. -/// -/// # Panics -/// -/// See information on `resolve` for caveats on `cb` panicking. -pub unsafe fn resolve_unsynchronized<F>(addr: *mut c_void, mut cb: F) -where - F: FnMut(&Symbol), -{ - imp::resolve(ResolveWhat::Address(addr), &mut cb) -} - -/// Same as `resolve_frame`, only unsafe as it's unsynchronized. -/// -/// This function does not have synchronization guarantees but is available -/// when the `std` feature of this crate isn't compiled in. See the -/// `resolve_frame` function for more documentation and examples. -/// -/// # Panics -/// -/// See information on `resolve_frame` for caveats on `cb` panicking. -pub unsafe fn resolve_frame_unsynchronized<F>(frame: &Frame, mut cb: F) -where - F: FnMut(&Symbol), -{ - imp::resolve(ResolveWhat::Frame(frame), &mut cb) -} - -/// A trait representing the resolution of a symbol in a file. -/// -/// This trait is yielded as a trait object to the closure given to the -/// `backtrace::resolve` function, and it is virtually dispatched as it's -/// unknown which implementation is behind it. -/// -/// A symbol can give contextual information about a function, for example the -/// name, filename, line number, precise address, etc. Not all information is -/// always available in a symbol, however, so all methods return an `Option`. -pub struct Symbol { - // TODO: this lifetime bound needs to be persisted eventually to `Symbol`, - // but that's currently a breaking change. For now this is safe since - // `Symbol` is only ever handed out by reference and can't be cloned. - inner: imp::Symbol<'static>, -} - -impl Symbol { - /// Returns the name of this function. - /// - /// The returned structure can be used to query various properties about the - /// symbol name: - /// - /// * The `Display` implementation will print out the demangled symbol. - /// * The raw `str` value of the symbol can be accessed (if it's valid - /// utf-8). - /// * The raw bytes for the symbol name can be accessed. - pub fn name(&self) -> Option<SymbolName<'_>> { - self.inner.name() - } - - /// Returns the starting address of this function. - pub fn addr(&self) -> Option<*mut c_void> { - self.inner.addr().map(|p| p as *mut _) - } - - /// Returns the raw filename as a slice. This is mainly useful for `no_std` - /// environments. - pub fn filename_raw(&self) -> Option<BytesOrWideString<'_>> { - self.inner.filename_raw() - } - - /// Returns the column number for where this symbol is currently executing. - /// - /// Only gimli currently provides a value here and even then only if `filename` - /// returns `Some`, and so it is then consequently subject to similar caveats. - pub fn colno(&self) -> Option<u32> { - self.inner.colno() - } - - /// Returns the line number for where this symbol is currently executing. - /// - /// This return value is typically `Some` if `filename` returns `Some`, and - /// is consequently subject to similar caveats. - pub fn lineno(&self) -> Option<u32> { - self.inner.lineno() - } - - /// Returns the file name where this function was defined. - /// - /// This is currently only available when libbacktrace or gimli is being - /// used (e.g. unix platforms other) and when a binary is compiled with - /// debuginfo. If neither of these conditions is met then this will likely - /// return `None`. - /// - /// # Required features - /// - /// This function requires the `std` feature of the `backtrace` crate to be - /// enabled, and the `std` feature is enabled by default. - #[cfg(feature = "std")] - #[allow(unreachable_code)] - pub fn filename(&self) -> Option<&Path> { - self.inner.filename() - } -} - -impl fmt::Debug for Symbol { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut d = f.debug_struct("Symbol"); - if let Some(name) = self.name() { - d.field("name", &name); - } - if let Some(addr) = self.addr() { - d.field("addr", &addr); - } - - #[cfg(feature = "std")] - { - if let Some(filename) = self.filename() { - d.field("filename", &filename); - } - } - - if let Some(lineno) = self.lineno() { - d.field("lineno", &lineno); - } - d.finish() - } -} - -cfg_if::cfg_if! { - if #[cfg(feature = "cpp_demangle")] { - // Maybe a parsed C++ symbol, if parsing the mangled symbol as Rust - // failed. - struct OptionCppSymbol<'a>(Option<::cpp_demangle::BorrowedSymbol<'a>>); - - impl<'a> OptionCppSymbol<'a> { - fn parse(input: &'a [u8]) -> OptionCppSymbol<'a> { - OptionCppSymbol(::cpp_demangle::BorrowedSymbol::new(input).ok()) - } - - fn none() -> OptionCppSymbol<'a> { - OptionCppSymbol(None) - } - } - } else { - use core::marker::PhantomData; - - // Make sure to keep this zero-sized, so that the `cpp_demangle` feature - // has no cost when disabled. - struct OptionCppSymbol<'a>(PhantomData<&'a ()>); - - impl<'a> OptionCppSymbol<'a> { - fn parse(_: &'a [u8]) -> OptionCppSymbol<'a> { - OptionCppSymbol(PhantomData) - } - - fn none() -> OptionCppSymbol<'a> { - OptionCppSymbol(PhantomData) - } - } - } -} - -/// A wrapper around a symbol name to provide ergonomic accessors to the -/// demangled name, the raw bytes, the raw string, etc. -// Allow dead code for when the `cpp_demangle` feature is not enabled. -#[allow(dead_code)] -pub struct SymbolName<'a> { - bytes: &'a [u8], - demangled: Option<Demangle<'a>>, - cpp_demangled: OptionCppSymbol<'a>, -} - -impl<'a> SymbolName<'a> { - /// Creates a new symbol name from the raw underlying bytes. - pub fn new(bytes: &'a [u8]) -> SymbolName<'a> { - let str_bytes = str::from_utf8(bytes).ok(); - let demangled = str_bytes.and_then(|s| try_demangle(s).ok()); - - let cpp = if demangled.is_none() { - OptionCppSymbol::parse(bytes) - } else { - OptionCppSymbol::none() - }; - - SymbolName { - bytes: bytes, - demangled: demangled, - cpp_demangled: cpp, - } - } - - /// Returns the raw (mangled) symbol name as a `str` if the symbol is valid utf-8. - /// - /// Use the `Display` implementation if you want the demangled version. - pub fn as_str(&self) -> Option<&'a str> { - self.demangled - .as_ref() - .map(|s| s.as_str()) - .or_else(|| str::from_utf8(self.bytes).ok()) - } - - /// Returns the raw symbol name as a list of bytes - pub fn as_bytes(&self) -> &'a [u8] { - self.bytes - } -} - -fn format_symbol_name( - fmt: fn(&str, &mut fmt::Formatter<'_>) -> fmt::Result, - mut bytes: &[u8], - f: &mut fmt::Formatter<'_>, -) -> fmt::Result { - while bytes.len() > 0 { - match str::from_utf8(bytes) { - Ok(name) => { - fmt(name, f)?; - break; - } - Err(err) => { - fmt("\u{FFFD}", f)?; - - match err.error_len() { - Some(len) => bytes = &bytes[err.valid_up_to() + len..], - None => break, - } - } - } - } - Ok(()) -} - -cfg_if::cfg_if! { - if #[cfg(feature = "cpp_demangle")] { - impl<'a> fmt::Display for SymbolName<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(ref s) = self.demangled { - s.fmt(f) - } else if let Some(ref cpp) = self.cpp_demangled.0 { - cpp.fmt(f) - } else { - format_symbol_name(fmt::Display::fmt, self.bytes, f) - } - } - } - } else { - impl<'a> fmt::Display for SymbolName<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(ref s) = self.demangled { - s.fmt(f) - } else { - format_symbol_name(fmt::Display::fmt, self.bytes, f) - } - } - } - } -} - -cfg_if::cfg_if! { - if #[cfg(all(feature = "std", feature = "cpp_demangle"))] { - impl<'a> fmt::Debug for SymbolName<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use std::fmt::Write; - - if let Some(ref s) = self.demangled { - return s.fmt(f) - } - - // This may to print if the demangled symbol isn't actually - // valid, so handle the error here gracefully by not propagating - // it outwards. - if let Some(ref cpp) = self.cpp_demangled.0 { - let mut s = String::new(); - if write!(s, "{}", cpp).is_ok() { - return s.fmt(f) - } - } - - format_symbol_name(fmt::Debug::fmt, self.bytes, f) - } - } - } else { - impl<'a> fmt::Debug for SymbolName<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(ref s) = self.demangled { - s.fmt(f) - } else { - format_symbol_name(fmt::Debug::fmt, self.bytes, f) - } - } - } - } -} - -/// Attempt to reclaim that cached memory used to symbolicate addresses. -/// -/// This method will attempt to release any global data structures that have -/// otherwise been cached globally or in the thread which typically represent -/// parsed DWARF information or similar. -/// -/// # Caveats -/// -/// While this function is always available it doesn't actually do anything on -/// most implementations. Libraries like dbghelp or libbacktrace do not provide -/// facilities to deallocate state and manage the allocated memory. For now the -/// `gimli-symbolize` feature of this crate is the only feature where this -/// function has any effect. -#[cfg(feature = "std")] -pub fn clear_symbol_cache() { - let _guard = crate::lock::lock(); - unsafe { - imp::clear_symbol_cache(); - } -} - -cfg_if::cfg_if! { - if #[cfg(miri)] { - mod miri; - use miri as imp; - } else if #[cfg(all(windows, target_env = "msvc", not(target_vendor = "uwp")))] { - mod dbghelp; - use dbghelp as imp; - } else if #[cfg(all( - any(unix, all(windows, target_env = "gnu")), - not(target_vendor = "uwp"), - not(target_os = "emscripten"), - any(not(backtrace_in_libstd), feature = "backtrace"), - ))] { - mod gimli; - use gimli as imp; - } else { - mod noop; - use noop as imp; - } -} diff --git a/vendor/backtrace/src/symbolize/noop.rs b/vendor/backtrace/src/symbolize/noop.rs deleted file mode 100644 index c533365..0000000 --- a/vendor/backtrace/src/symbolize/noop.rs +++ /dev/null @@ -1,41 +0,0 @@ -//! Empty symbolication strategy used to compile for platforms that have no -//! support. - -use super::{BytesOrWideString, ResolveWhat, SymbolName}; -use core::ffi::c_void; -use core::marker; - -pub unsafe fn resolve(_addr: ResolveWhat<'_>, _cb: &mut dyn FnMut(&super::Symbol)) {} - -pub struct Symbol<'a> { - _marker: marker::PhantomData<&'a i32>, -} - -impl Symbol<'_> { - pub fn name(&self) -> Option<SymbolName<'_>> { - None - } - - pub fn addr(&self) -> Option<*mut c_void> { - None - } - - pub fn filename_raw(&self) -> Option<BytesOrWideString<'_>> { - None - } - - #[cfg(feature = "std")] - pub fn filename(&self) -> Option<&::std::path::Path> { - None - } - - pub fn lineno(&self) -> Option<u32> { - None - } - - pub fn colno(&self) -> Option<u32> { - None - } -} - -pub unsafe fn clear_symbol_cache() {} |