summaryrefslogtreecommitdiffstats
path: root/third_party/rust/object/src/read
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/object/src/read
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/object/src/read')
-rw-r--r--third_party/rust/object/src/read/any.rs523
-rw-r--r--third_party/rust/object/src/read/coff.rs527
-rw-r--r--third_party/rust/object/src/read/elf.rs709
-rw-r--r--third_party/rust/object/src/read/macho.rs615
-rw-r--r--third_party/rust/object/src/read/mod.rs250
-rw-r--r--third_party/rust/object/src/read/pe.rs407
-rw-r--r--third_party/rust/object/src/read/traits.rs220
-rw-r--r--third_party/rust/object/src/read/wasm.rs315
8 files changed, 3566 insertions, 0 deletions
diff --git a/third_party/rust/object/src/read/any.rs b/third_party/rust/object/src/read/any.rs
new file mode 100644
index 0000000000..74f03f735f
--- /dev/null
+++ b/third_party/rust/object/src/read/any.rs
@@ -0,0 +1,523 @@
+use crate::alloc::borrow::Cow;
+use crate::alloc::fmt;
+use target_lexicon::{Architecture, BinaryFormat};
+use uuid::Uuid;
+
+#[cfg(feature = "wasm")]
+use crate::read::wasm;
+use crate::read::{coff, elf, macho, pe};
+use crate::read::{
+ Object, ObjectSection, ObjectSegment, Relocation, SectionIndex, SectionKind, Symbol,
+ SymbolIndex, SymbolMap,
+};
+
+/// Evaluate an expression on the contents of a file format enum.
+///
+/// This is a hack to avoid virtual calls.
+macro_rules! with_inner {
+ ($inner:expr, $enum:ident, | $var:ident | $body:expr) => {
+ match $inner {
+ $enum::Coff(ref $var) => $body,
+ $enum::Elf(ref $var) => $body,
+ $enum::MachO(ref $var) => $body,
+ $enum::Pe(ref $var) => $body,
+ #[cfg(feature = "wasm")]
+ $enum::Wasm(ref $var) => $body,
+ }
+ };
+}
+
+macro_rules! with_inner_mut {
+ ($inner:expr, $enum:ident, | $var:ident | $body:expr) => {
+ match $inner {
+ $enum::Coff(ref mut $var) => $body,
+ $enum::Elf(ref mut $var) => $body,
+ $enum::MachO(ref mut $var) => $body,
+ $enum::Pe(ref mut $var) => $body,
+ #[cfg(feature = "wasm")]
+ $enum::Wasm(ref mut $var) => $body,
+ }
+ };
+}
+
+/// Like `with_inner!`, but wraps the result in another enum.
+macro_rules! map_inner {
+ ($inner:expr, $from:ident, $to:ident, | $var:ident | $body:expr) => {
+ match $inner {
+ $from::Coff(ref $var) => $to::Coff($body),
+ $from::Elf(ref $var) => $to::Elf($body),
+ $from::MachO(ref $var) => $to::MachO($body),
+ $from::Pe(ref $var) => $to::Pe($body),
+ #[cfg(feature = "wasm")]
+ $from::Wasm(ref $var) => $to::Wasm($body),
+ }
+ };
+}
+
+/// Like `map_inner!`, but the result is a Result or Option.
+macro_rules! map_inner_option {
+ ($inner:expr, $from:ident, $to:ident, | $var:ident | $body:expr) => {
+ match $inner {
+ $from::Coff(ref $var) => $body.map($to::Coff),
+ $from::Elf(ref $var) => $body.map($to::Elf),
+ $from::MachO(ref $var) => $body.map($to::MachO),
+ $from::Pe(ref $var) => $body.map($to::Pe),
+ #[cfg(feature = "wasm")]
+ $from::Wasm(ref $var) => $body.map($to::Wasm),
+ }
+ };
+}
+
+/// Call `next` for a file format iterator.
+macro_rules! next_inner {
+ ($inner:expr, $from:ident, $to:ident) => {
+ match $inner {
+ $from::Coff(ref mut iter) => iter.next().map($to::Coff),
+ $from::Elf(ref mut iter) => iter.next().map($to::Elf),
+ $from::MachO(ref mut iter) => iter.next().map($to::MachO),
+ $from::Pe(ref mut iter) => iter.next().map($to::Pe),
+ #[cfg(feature = "wasm")]
+ $from::Wasm(ref mut iter) => iter.next().map($to::Wasm),
+ }
+ };
+}
+
+/// An object file.
+///
+/// Most functionality is provided by the `Object` trait implementation.
+#[derive(Debug)]
+pub struct File<'data> {
+ inner: FileInternal<'data>,
+}
+
+#[allow(clippy::large_enum_variant)]
+#[derive(Debug)]
+enum FileInternal<'data> {
+ Coff(coff::CoffFile<'data>),
+ Elf(elf::ElfFile<'data>),
+ MachO(macho::MachOFile<'data>),
+ Pe(pe::PeFile<'data>),
+ #[cfg(feature = "wasm")]
+ Wasm(wasm::WasmFile),
+}
+
+impl<'data> File<'data> {
+ /// Parse the raw file data.
+ pub fn parse(data: &'data [u8]) -> Result<Self, &'static str> {
+ if data.len() < 16 {
+ return Err("File too short");
+ }
+
+ let inner = match [data[0], data[1], data[2], data[3]] {
+ // ELF
+ [0x7f, b'E', b'L', b'F'] => FileInternal::Elf(elf::ElfFile::parse(data)?),
+ // 32-bit Mach-O
+ [0xfe, 0xed, 0xfa, 0xce]
+ | [0xce, 0xfa, 0xed, 0xfe]
+ // 64-bit Mach-O
+ | [0xfe, 0xed, 0xfa, 0xcf]
+ | [0xcf, 0xfa, 0xed, 0xfe] => FileInternal::MachO(macho::MachOFile::parse(data)?),
+ // WASM
+ #[cfg(feature = "wasm")]
+ [0x00, b'a', b's', b'm'] => FileInternal::Wasm(wasm::WasmFile::parse(data)?),
+ // MS-DOS, assume stub for Windows PE
+ [b'M', b'Z', _, _] => FileInternal::Pe(pe::PeFile::parse(data)?),
+ // TODO: more COFF machines
+ // COFF x86
+ [0x4c, 0x01, _, _]
+ // COFF x86-64
+ | [0x64, 0x86, _, _] => FileInternal::Coff(coff::CoffFile::parse(data)?),
+ _ => return Err("Unknown file magic"),
+ };
+ Ok(File { inner })
+ }
+
+ /// Return the file format.
+ pub fn format(&self) -> BinaryFormat {
+ match self.inner {
+ FileInternal::Elf(_) => BinaryFormat::Elf,
+ FileInternal::MachO(_) => BinaryFormat::Macho,
+ FileInternal::Coff(_) | FileInternal::Pe(_) => BinaryFormat::Coff,
+ #[cfg(feature = "wasm")]
+ FileInternal::Wasm(_) => BinaryFormat::Wasm,
+ }
+ }
+}
+
+impl<'data, 'file> Object<'data, 'file> for File<'data>
+where
+ 'data: 'file,
+{
+ type Segment = Segment<'data, 'file>;
+ type SegmentIterator = SegmentIterator<'data, 'file>;
+ type Section = Section<'data, 'file>;
+ type SectionIterator = SectionIterator<'data, 'file>;
+ type SymbolIterator = SymbolIterator<'data, 'file>;
+
+ fn architecture(&self) -> Architecture {
+ with_inner!(self.inner, FileInternal, |x| x.architecture())
+ }
+
+ fn is_little_endian(&self) -> bool {
+ with_inner!(self.inner, FileInternal, |x| x.is_little_endian())
+ }
+
+ fn is_64(&self) -> bool {
+ with_inner!(self.inner, FileInternal, |x| x.is_64())
+ }
+
+ fn segments(&'file self) -> SegmentIterator<'data, 'file> {
+ SegmentIterator {
+ inner: map_inner!(self.inner, FileInternal, SegmentIteratorInternal, |x| x
+ .segments()),
+ }
+ }
+
+ fn section_by_name(&'file self, section_name: &str) -> Option<Section<'data, 'file>> {
+ map_inner_option!(self.inner, FileInternal, SectionInternal, |x| x
+ .section_by_name(section_name))
+ .map(|inner| Section { inner })
+ }
+
+ fn section_by_index(&'file self, index: SectionIndex) -> Option<Section<'data, 'file>> {
+ map_inner_option!(self.inner, FileInternal, SectionInternal, |x| x
+ .section_by_index(index))
+ .map(|inner| Section { inner })
+ }
+
+ fn section_data_by_name(&self, section_name: &str) -> Option<Cow<'data, [u8]>> {
+ with_inner!(self.inner, FileInternal, |x| x
+ .section_data_by_name(section_name))
+ }
+
+ fn sections(&'file self) -> SectionIterator<'data, 'file> {
+ SectionIterator {
+ inner: map_inner!(self.inner, FileInternal, SectionIteratorInternal, |x| x
+ .sections()),
+ }
+ }
+
+ fn symbol_by_index(&self, index: SymbolIndex) -> Option<Symbol<'data>> {
+ with_inner!(self.inner, FileInternal, |x| x.symbol_by_index(index))
+ }
+
+ fn symbols(&'file self) -> SymbolIterator<'data, 'file> {
+ SymbolIterator {
+ inner: map_inner!(self.inner, FileInternal, SymbolIteratorInternal, |x| x
+ .symbols()),
+ }
+ }
+
+ fn dynamic_symbols(&'file self) -> SymbolIterator<'data, 'file> {
+ SymbolIterator {
+ inner: map_inner!(self.inner, FileInternal, SymbolIteratorInternal, |x| x
+ .dynamic_symbols()),
+ }
+ }
+
+ fn symbol_map(&self) -> SymbolMap<'data> {
+ with_inner!(self.inner, FileInternal, |x| x.symbol_map())
+ }
+
+ fn has_debug_symbols(&self) -> bool {
+ with_inner!(self.inner, FileInternal, |x| x.has_debug_symbols())
+ }
+
+ #[inline]
+ fn mach_uuid(&self) -> Option<Uuid> {
+ with_inner!(self.inner, FileInternal, |x| x.mach_uuid())
+ }
+
+ #[inline]
+ fn build_id(&self) -> Option<&'data [u8]> {
+ with_inner!(self.inner, FileInternal, |x| x.build_id())
+ }
+
+ #[inline]
+ fn gnu_debuglink(&self) -> Option<(&'data [u8], u32)> {
+ with_inner!(self.inner, FileInternal, |x| x.gnu_debuglink())
+ }
+
+ fn entry(&self) -> u64 {
+ with_inner!(self.inner, FileInternal, |x| x.entry())
+ }
+}
+
+/// An iterator over the segments of a `File`.
+#[derive(Debug)]
+pub struct SegmentIterator<'data, 'file>
+where
+ 'data: 'file,
+{
+ inner: SegmentIteratorInternal<'data, 'file>,
+}
+
+#[derive(Debug)]
+enum SegmentIteratorInternal<'data, 'file>
+where
+ 'data: 'file,
+{
+ Coff(coff::CoffSegmentIterator<'data, 'file>),
+ Elf(elf::ElfSegmentIterator<'data, 'file>),
+ MachO(macho::MachOSegmentIterator<'data, 'file>),
+ Pe(pe::PeSegmentIterator<'data, 'file>),
+ #[cfg(feature = "wasm")]
+ Wasm(wasm::WasmSegmentIterator<'file>),
+}
+
+impl<'data, 'file> Iterator for SegmentIterator<'data, 'file> {
+ type Item = Segment<'data, 'file>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ next_inner!(self.inner, SegmentIteratorInternal, SegmentInternal)
+ .map(|inner| Segment { inner })
+ }
+}
+
+/// A segment of a `File`.
+pub struct Segment<'data, 'file>
+where
+ 'data: 'file,
+{
+ inner: SegmentInternal<'data, 'file>,
+}
+
+#[derive(Debug)]
+enum SegmentInternal<'data, 'file>
+where
+ 'data: 'file,
+{
+ Coff(coff::CoffSegment<'data, 'file>),
+ Elf(elf::ElfSegment<'data, 'file>),
+ MachO(macho::MachOSegment<'data, 'file>),
+ Pe(pe::PeSegment<'data, 'file>),
+ #[cfg(feature = "wasm")]
+ Wasm(wasm::WasmSegment<'file>),
+}
+
+impl<'data, 'file> fmt::Debug for Segment<'data, 'file> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // It's painful to do much better than this
+ f.debug_struct("Segment")
+ .field("name", &self.name().unwrap_or("<unnamed>"))
+ .field("address", &self.address())
+ .field("size", &self.data().len())
+ .finish()
+ }
+}
+
+impl<'data, 'file> ObjectSegment<'data> for Segment<'data, 'file> {
+ fn address(&self) -> u64 {
+ with_inner!(self.inner, SegmentInternal, |x| x.address())
+ }
+
+ fn size(&self) -> u64 {
+ with_inner!(self.inner, SegmentInternal, |x| x.size())
+ }
+
+ fn align(&self) -> u64 {
+ with_inner!(self.inner, SegmentInternal, |x| x.align())
+ }
+
+ fn file_range(&self) -> (u64, u64) {
+ with_inner!(self.inner, SegmentInternal, |x| x.file_range())
+ }
+
+ fn data(&self) -> &'data [u8] {
+ with_inner!(self.inner, SegmentInternal, |x| x.data())
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]> {
+ with_inner!(self.inner, SegmentInternal, |x| x.data_range(address, size))
+ }
+
+ fn name(&self) -> Option<&str> {
+ with_inner!(self.inner, SegmentInternal, |x| x.name())
+ }
+}
+
+/// An iterator of the sections of a `File`.
+#[derive(Debug)]
+pub struct SectionIterator<'data, 'file>
+where
+ 'data: 'file,
+{
+ inner: SectionIteratorInternal<'data, 'file>,
+}
+
+// we wrap our enums in a struct so that they are kept private.
+#[derive(Debug)]
+enum SectionIteratorInternal<'data, 'file>
+where
+ 'data: 'file,
+{
+ Coff(coff::CoffSectionIterator<'data, 'file>),
+ Elf(elf::ElfSectionIterator<'data, 'file>),
+ MachO(macho::MachOSectionIterator<'data, 'file>),
+ Pe(pe::PeSectionIterator<'data, 'file>),
+ #[cfg(feature = "wasm")]
+ Wasm(wasm::WasmSectionIterator<'file>),
+}
+
+impl<'data, 'file> Iterator for SectionIterator<'data, 'file> {
+ type Item = Section<'data, 'file>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ next_inner!(self.inner, SectionIteratorInternal, SectionInternal)
+ .map(|inner| Section { inner })
+ }
+}
+
+/// A Section of a File
+pub struct Section<'data, 'file>
+where
+ 'data: 'file,
+{
+ inner: SectionInternal<'data, 'file>,
+}
+
+enum SectionInternal<'data, 'file>
+where
+ 'data: 'file,
+{
+ Coff(coff::CoffSection<'data, 'file>),
+ Elf(elf::ElfSection<'data, 'file>),
+ MachO(macho::MachOSection<'data, 'file>),
+ Pe(pe::PeSection<'data, 'file>),
+ #[cfg(feature = "wasm")]
+ Wasm(wasm::WasmSection<'file>),
+}
+
+impl<'data, 'file> fmt::Debug for Section<'data, 'file> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // It's painful to do much better than this
+ let mut s = f.debug_struct("Section");
+ if let Some(segment) = self.segment_name() {
+ s.field("segment", &segment);
+ }
+ s.field("name", &self.name().unwrap_or("<invalid name>"))
+ .field("address", &self.address())
+ .field("size", &self.data().len())
+ .field("kind", &self.kind())
+ .finish()
+ }
+}
+
+impl<'data, 'file> ObjectSection<'data> for Section<'data, 'file> {
+ type RelocationIterator = RelocationIterator<'data, 'file>;
+
+ fn index(&self) -> SectionIndex {
+ with_inner!(self.inner, SectionInternal, |x| x.index())
+ }
+
+ fn address(&self) -> u64 {
+ with_inner!(self.inner, SectionInternal, |x| x.address())
+ }
+
+ fn size(&self) -> u64 {
+ with_inner!(self.inner, SectionInternal, |x| x.size())
+ }
+
+ fn align(&self) -> u64 {
+ with_inner!(self.inner, SectionInternal, |x| x.align())
+ }
+
+ fn file_range(&self) -> Option<(u64, u64)> {
+ with_inner!(self.inner, SectionInternal, |x| x.file_range())
+ }
+
+ fn data(&self) -> Cow<'data, [u8]> {
+ with_inner!(self.inner, SectionInternal, |x| x.data())
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]> {
+ with_inner!(self.inner, SectionInternal, |x| x.data_range(address, size))
+ }
+
+ fn uncompressed_data(&self) -> Cow<'data, [u8]> {
+ with_inner!(self.inner, SectionInternal, |x| x.uncompressed_data())
+ }
+
+ fn name(&self) -> Option<&str> {
+ with_inner!(self.inner, SectionInternal, |x| x.name())
+ }
+
+ fn segment_name(&self) -> Option<&str> {
+ with_inner!(self.inner, SectionInternal, |x| x.segment_name())
+ }
+
+ fn kind(&self) -> SectionKind {
+ with_inner!(self.inner, SectionInternal, |x| x.kind())
+ }
+
+ fn relocations(&self) -> RelocationIterator<'data, 'file> {
+ RelocationIterator {
+ inner: map_inner!(
+ self.inner,
+ SectionInternal,
+ RelocationIteratorInternal,
+ |x| x.relocations()
+ ),
+ }
+ }
+}
+
+/// An iterator over symbol table entries.
+#[derive(Debug)]
+pub struct SymbolIterator<'data, 'file>
+where
+ 'data: 'file,
+{
+ inner: SymbolIteratorInternal<'data, 'file>,
+}
+
+#[derive(Debug)]
+enum SymbolIteratorInternal<'data, 'file>
+where
+ 'data: 'file,
+{
+ Coff(coff::CoffSymbolIterator<'data, 'file>),
+ Elf(elf::ElfSymbolIterator<'data, 'file>),
+ MachO(macho::MachOSymbolIterator<'data, 'file>),
+ Pe(pe::PeSymbolIterator<'data, 'file>),
+ #[cfg(feature = "wasm")]
+ Wasm(wasm::WasmSymbolIterator<'file>),
+}
+
+impl<'data, 'file> Iterator for SymbolIterator<'data, 'file> {
+ type Item = (SymbolIndex, Symbol<'data>);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ with_inner_mut!(self.inner, SymbolIteratorInternal, |x| x.next())
+ }
+}
+
+/// An iterator over relocation entries
+#[derive(Debug)]
+pub struct RelocationIterator<'data, 'file>
+where
+ 'data: 'file,
+{
+ inner: RelocationIteratorInternal<'data, 'file>,
+}
+
+#[derive(Debug)]
+enum RelocationIteratorInternal<'data, 'file>
+where
+ 'data: 'file,
+{
+ Coff(coff::CoffRelocationIterator<'data, 'file>),
+ Elf(elf::ElfRelocationIterator<'data, 'file>),
+ MachO(macho::MachORelocationIterator<'data, 'file>),
+ Pe(pe::PeRelocationIterator),
+ #[cfg(feature = "wasm")]
+ Wasm(wasm::WasmRelocationIterator),
+}
+
+impl<'data, 'file> Iterator for RelocationIterator<'data, 'file> {
+ type Item = (u64, Relocation);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ with_inner_mut!(self.inner, RelocationIteratorInternal, |x| x.next())
+ }
+}
diff --git a/third_party/rust/object/src/read/coff.rs b/third_party/rust/object/src/read/coff.rs
new file mode 100644
index 0000000000..72f985e458
--- /dev/null
+++ b/third_party/rust/object/src/read/coff.rs
@@ -0,0 +1,527 @@
+use crate::alloc::borrow::Cow;
+use crate::alloc::fmt;
+use crate::alloc::vec::Vec;
+use goblin::pe;
+use std::{iter, slice};
+use target_lexicon::Architecture;
+
+use crate::read::{
+ self, Object, ObjectSection, ObjectSegment, Relocation, RelocationEncoding, RelocationKind,
+ RelocationTarget, SectionIndex, SectionKind, Symbol, SymbolIndex, SymbolKind, SymbolMap,
+ SymbolScope,
+};
+
+/// A COFF object file.
+#[derive(Debug)]
+pub struct CoffFile<'data> {
+ coff: pe::Coff<'data>,
+ data: &'data [u8],
+}
+
+/// An iterator over the loadable sections of a `CoffFile`.
+#[derive(Debug)]
+pub struct CoffSegmentIterator<'data, 'file>
+where
+ 'data: 'file,
+{
+ file: &'file CoffFile<'data>,
+ iter: slice::Iter<'file, pe::section_table::SectionTable>,
+}
+
+/// A loadable section of a `CoffFile`.
+#[derive(Debug)]
+pub struct CoffSegment<'data, 'file>
+where
+ 'data: 'file,
+{
+ file: &'file CoffFile<'data>,
+ section: &'file pe::section_table::SectionTable,
+}
+
+/// An iterator over the sections of a `CoffFile`.
+#[derive(Debug)]
+pub struct CoffSectionIterator<'data, 'file>
+where
+ 'data: 'file,
+{
+ file: &'file CoffFile<'data>,
+ iter: iter::Enumerate<slice::Iter<'file, pe::section_table::SectionTable>>,
+}
+
+/// A section of a `CoffFile`.
+#[derive(Debug)]
+pub struct CoffSection<'data, 'file>
+where
+ 'data: 'file,
+{
+ file: &'file CoffFile<'data>,
+ index: SectionIndex,
+ section: &'file pe::section_table::SectionTable,
+}
+
+/// An iterator over the symbols of a `CoffFile`.
+pub struct CoffSymbolIterator<'data, 'file>
+where
+ 'data: 'file,
+{
+ file: &'file CoffFile<'data>,
+ symbols: pe::symbol::SymbolIterator<'data>,
+}
+
+/// An iterator over the relocations in an `CoffSection`.
+pub struct CoffRelocationIterator<'data, 'file> {
+ file: &'file CoffFile<'data>,
+ relocations: pe::relocation::Relocations<'data>,
+}
+
+impl<'data> CoffFile<'data> {
+ /// Get the COFF headers of the file.
+ // TODO: this is temporary to allow access to features this crate doesn't provide yet
+ #[inline]
+ pub fn coff(&self) -> &pe::Coff<'data> {
+ &self.coff
+ }
+
+ /// Parse the raw COFF file data.
+ pub fn parse(data: &'data [u8]) -> Result<Self, &'static str> {
+ let coff = pe::Coff::parse(data).map_err(|_| "Could not parse COFF header")?;
+ Ok(CoffFile { coff, data })
+ }
+}
+
+impl<'data, 'file> Object<'data, 'file> for CoffFile<'data>
+where
+ 'data: 'file,
+{
+ type Segment = CoffSegment<'data, 'file>;
+ type SegmentIterator = CoffSegmentIterator<'data, 'file>;
+ type Section = CoffSection<'data, 'file>;
+ type SectionIterator = CoffSectionIterator<'data, 'file>;
+ type SymbolIterator = CoffSymbolIterator<'data, 'file>;
+
+ fn architecture(&self) -> Architecture {
+ match self.coff.header.machine {
+ pe::header::COFF_MACHINE_X86 => Architecture::I386,
+ pe::header::COFF_MACHINE_X86_64 => Architecture::X86_64,
+ _ => Architecture::Unknown,
+ }
+ }
+
+ #[inline]
+ fn is_little_endian(&self) -> bool {
+ true
+ }
+
+ #[inline]
+ fn is_64(&self) -> bool {
+ false
+ }
+
+ fn segments(&'file self) -> CoffSegmentIterator<'data, 'file> {
+ CoffSegmentIterator {
+ file: self,
+ iter: self.coff.sections.iter(),
+ }
+ }
+
+ fn section_by_name(&'file self, section_name: &str) -> Option<CoffSection<'data, 'file>> {
+ self.sections()
+ .find(|section| section.name() == Some(section_name))
+ }
+
+ fn section_by_index(&'file self, index: SectionIndex) -> Option<CoffSection<'data, 'file>> {
+ self.sections().find(|section| section.index() == index)
+ }
+
+ fn sections(&'file self) -> CoffSectionIterator<'data, 'file> {
+ CoffSectionIterator {
+ file: self,
+ iter: self.coff.sections.iter().enumerate(),
+ }
+ }
+
+ fn symbol_by_index(&self, index: SymbolIndex) -> Option<Symbol<'data>> {
+ self.coff
+ .symbols
+ .get(index.0)
+ .map(|(name, symbol)| parse_symbol(index.0, name, &symbol, &self.coff))
+ }
+
+ fn symbols(&'file self) -> CoffSymbolIterator<'data, 'file> {
+ CoffSymbolIterator {
+ file: self,
+ symbols: self.coff.symbols.iter(),
+ }
+ }
+
+ fn dynamic_symbols(&'file self) -> CoffSymbolIterator<'data, 'file> {
+ CoffSymbolIterator {
+ file: self,
+ symbols: goblin::pe::symbol::SymbolIterator::default(),
+ }
+ }
+
+ fn symbol_map(&self) -> SymbolMap<'data> {
+ // TODO: untested
+ let mut symbols: Vec<_> = self
+ .symbols()
+ .map(|(_, s)| s)
+ .filter(SymbolMap::filter)
+ .collect();
+ symbols.sort_by_key(|x| x.address);
+ SymbolMap { symbols }
+ }
+
+ fn has_debug_symbols(&self) -> bool {
+ for section in &self.coff.sections {
+ if let Ok(name) = section.name() {
+ if name == ".debug_info" {
+ return true;
+ }
+ }
+ }
+ false
+ }
+
+ fn entry(&self) -> u64 {
+ 0
+ }
+}
+
+impl<'data, 'file> Iterator for CoffSegmentIterator<'data, 'file> {
+ type Item = CoffSegment<'data, 'file>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next().map(|section| CoffSegment {
+ file: self.file,
+ section,
+ })
+ }
+}
+
+fn section_alignment(characteristics: u32) -> u64 {
+ match characteristics & pe::section_table::IMAGE_SCN_ALIGN_MASK {
+ pe::section_table::IMAGE_SCN_ALIGN_2BYTES => 2,
+ pe::section_table::IMAGE_SCN_ALIGN_4BYTES => 4,
+ pe::section_table::IMAGE_SCN_ALIGN_8BYTES => 8,
+ pe::section_table::IMAGE_SCN_ALIGN_16BYTES => 16,
+ pe::section_table::IMAGE_SCN_ALIGN_32BYTES => 32,
+ pe::section_table::IMAGE_SCN_ALIGN_64BYTES => 64,
+ pe::section_table::IMAGE_SCN_ALIGN_128BYTES => 128,
+ pe::section_table::IMAGE_SCN_ALIGN_256BYTES => 256,
+ pe::section_table::IMAGE_SCN_ALIGN_512BYTES => 512,
+ pe::section_table::IMAGE_SCN_ALIGN_1024BYTES => 1024,
+ pe::section_table::IMAGE_SCN_ALIGN_2048BYTES => 2048,
+ pe::section_table::IMAGE_SCN_ALIGN_4096BYTES => 4096,
+ pe::section_table::IMAGE_SCN_ALIGN_8192BYTES => 8192,
+ _ => 1,
+ }
+}
+
+impl<'data, 'file> ObjectSegment<'data> for CoffSegment<'data, 'file> {
+ #[inline]
+ fn address(&self) -> u64 {
+ u64::from(self.section.virtual_address)
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ u64::from(self.section.virtual_size)
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ section_alignment(self.section.characteristics)
+ }
+
+ #[inline]
+ fn file_range(&self) -> (u64, u64) {
+ (
+ self.section.pointer_to_raw_data as u64,
+ self.section.size_of_raw_data as u64,
+ )
+ }
+
+ fn data(&self) -> &'data [u8] {
+ let offset = self.section.pointer_to_raw_data as usize;
+ let size = self.section.size_of_raw_data as usize;
+ &self.file.data[offset..][..size]
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]> {
+ read::data_range(self.data(), self.address(), address, size)
+ }
+
+ #[inline]
+ fn name(&self) -> Option<&str> {
+ self.section.name().ok()
+ }
+}
+
+impl<'data, 'file> Iterator for CoffSectionIterator<'data, 'file> {
+ type Item = CoffSection<'data, 'file>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next().map(|(index, section)| CoffSection {
+ file: self.file,
+ index: SectionIndex(index),
+ section,
+ })
+ }
+}
+
+impl<'data, 'file> CoffSection<'data, 'file> {
+ fn raw_data(&self) -> &'data [u8] {
+ let offset = self.section.pointer_to_raw_data as usize;
+ let size = self.section.size_of_raw_data as usize;
+ &self.file.data[offset..][..size]
+ }
+}
+
+impl<'data, 'file> ObjectSection<'data> for CoffSection<'data, 'file> {
+ type RelocationIterator = CoffRelocationIterator<'data, 'file>;
+
+ #[inline]
+ fn index(&self) -> SectionIndex {
+ self.index
+ }
+
+ #[inline]
+ fn address(&self) -> u64 {
+ u64::from(self.section.virtual_address)
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ u64::from(self.section.size_of_raw_data)
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ section_alignment(self.section.characteristics)
+ }
+
+ #[inline]
+ fn file_range(&self) -> Option<(u64, u64)> {
+ Some((
+ self.section.pointer_to_raw_data as u64,
+ self.section.size_of_raw_data as u64,
+ ))
+ }
+
+ fn data(&self) -> Cow<'data, [u8]> {
+ Cow::from(self.raw_data())
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]> {
+ read::data_range(self.raw_data(), self.address(), address, size)
+ }
+
+ #[inline]
+ fn uncompressed_data(&self) -> Cow<'data, [u8]> {
+ self.data()
+ }
+
+ fn name(&self) -> Option<&str> {
+ self.section.name().ok()
+ }
+
+ #[inline]
+ fn segment_name(&self) -> Option<&str> {
+ None
+ }
+
+ #[inline]
+ fn kind(&self) -> SectionKind {
+ if self.section.characteristics
+ & (pe::section_table::IMAGE_SCN_CNT_CODE | pe::section_table::IMAGE_SCN_MEM_EXECUTE)
+ != 0
+ {
+ SectionKind::Text
+ } else if self.section.characteristics & pe::section_table::IMAGE_SCN_CNT_INITIALIZED_DATA
+ != 0
+ {
+ if self.section.characteristics & pe::section_table::IMAGE_SCN_MEM_DISCARDABLE != 0 {
+ SectionKind::Other
+ } else if self.section.characteristics & pe::section_table::IMAGE_SCN_MEM_WRITE != 0 {
+ SectionKind::Data
+ } else {
+ SectionKind::ReadOnlyData
+ }
+ } else if self.section.characteristics & pe::section_table::IMAGE_SCN_CNT_UNINITIALIZED_DATA
+ != 0
+ {
+ SectionKind::UninitializedData
+ } else if self.section.characteristics & pe::section_table::IMAGE_SCN_LNK_INFO != 0 {
+ SectionKind::Linker
+ } else {
+ SectionKind::Unknown
+ }
+ }
+
+ fn relocations(&self) -> CoffRelocationIterator<'data, 'file> {
+ CoffRelocationIterator {
+ file: self.file,
+ relocations: self.section.relocations(self.file.data).unwrap_or_default(),
+ }
+ }
+}
+
+impl<'data, 'file> fmt::Debug for CoffSymbolIterator<'data, 'file> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("CoffSymbolIterator").finish()
+ }
+}
+
+impl<'data, 'file> Iterator for CoffSymbolIterator<'data, 'file> {
+ type Item = (SymbolIndex, Symbol<'data>);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.symbols.next().map(|(index, name, symbol)| {
+ (
+ SymbolIndex(index),
+ parse_symbol(index, name, &symbol, &self.file.coff),
+ )
+ })
+ }
+}
+
+fn parse_symbol<'data>(
+ index: usize,
+ name: Option<&'data str>,
+ symbol: &pe::symbol::Symbol,
+ coff: &pe::Coff<'data>,
+) -> Symbol<'data> {
+ let name = if symbol.is_file() {
+ coff.symbols
+ .aux_file(index + 1, symbol.number_of_aux_symbols as usize)
+ } else {
+ name.or_else(|| {
+ symbol.name_offset().and_then(|offset| {
+ coff.strings
+ .get(offset as usize)
+ .map(Result::ok)
+ .unwrap_or_default()
+ })
+ })
+ };
+ let size = if symbol.is_function_definition() && symbol.number_of_aux_symbols > 0 {
+ coff.symbols
+ .aux_function_definition(index + 1)
+ .map(|aux| u64::from(aux.total_size))
+ .unwrap_or(0)
+ } else {
+ 0
+ };
+ let kind = if symbol.is_section_definition() {
+ SymbolKind::Section
+ } else {
+ match symbol.storage_class {
+ pe::symbol::IMAGE_SYM_CLASS_SECTION => SymbolKind::Section,
+ pe::symbol::IMAGE_SYM_CLASS_FILE => SymbolKind::File,
+ pe::symbol::IMAGE_SYM_CLASS_LABEL => SymbolKind::Label,
+ pe::symbol::IMAGE_SYM_CLASS_EXTERNAL
+ | pe::symbol::IMAGE_SYM_CLASS_WEAK_EXTERNAL
+ | pe::symbol::IMAGE_SYM_CLASS_STATIC => {
+ if symbol.derived_type() == pe::symbol::IMAGE_SYM_DTYPE_FUNCTION {
+ SymbolKind::Text
+ } else {
+ SymbolKind::Data
+ }
+ }
+ _ => SymbolKind::Unknown,
+ }
+ };
+ let section_index = if symbol.section_number <= 0 {
+ None
+ } else {
+ Some(SectionIndex(symbol.section_number as usize - 1))
+ };
+ let undefined = symbol.section_number == pe::symbol::IMAGE_SYM_UNDEFINED;
+ let weak = symbol.storage_class == pe::symbol::IMAGE_SYM_CLASS_WEAK_EXTERNAL;
+ let scope = match symbol.storage_class {
+ _ if undefined => SymbolScope::Unknown,
+ pe::symbol::IMAGE_SYM_CLASS_EXTERNAL
+ | pe::symbol::IMAGE_SYM_CLASS_EXTERNAL_DEF
+ | pe::symbol::IMAGE_SYM_CLASS_WEAK_EXTERNAL => {
+ // TODO: determine if symbol is exported
+ SymbolScope::Linkage
+ }
+ _ => SymbolScope::Compilation,
+ };
+ Symbol {
+ name,
+ address: u64::from(symbol.value),
+ size,
+ kind,
+ section_index,
+ undefined,
+ weak,
+ scope,
+ }
+}
+
+impl<'data, 'file> Iterator for CoffRelocationIterator<'data, 'file> {
+ type Item = (u64, Relocation);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.relocations.next().map(|relocation| {
+ let (kind, size, addend) = match self.file.coff.header.machine {
+ pe::header::COFF_MACHINE_X86 => match relocation.typ {
+ pe::relocation::IMAGE_REL_I386_DIR16 => (RelocationKind::Absolute, 16, 0),
+ pe::relocation::IMAGE_REL_I386_REL16 => (RelocationKind::Relative, 16, 0),
+ pe::relocation::IMAGE_REL_I386_DIR32 => (RelocationKind::Absolute, 32, 0),
+ pe::relocation::IMAGE_REL_I386_DIR32NB => (RelocationKind::ImageOffset, 32, 0),
+ pe::relocation::IMAGE_REL_I386_SECTION => (RelocationKind::SectionIndex, 16, 0),
+ pe::relocation::IMAGE_REL_I386_SECREL => (RelocationKind::SectionOffset, 32, 0),
+ pe::relocation::IMAGE_REL_I386_SECREL7 => (RelocationKind::SectionOffset, 7, 0),
+ pe::relocation::IMAGE_REL_I386_REL32 => (RelocationKind::Relative, 32, -4),
+ _ => (RelocationKind::Coff(relocation.typ), 0, 0),
+ },
+ pe::header::COFF_MACHINE_X86_64 => match relocation.typ {
+ pe::relocation::IMAGE_REL_AMD64_ADDR64 => (RelocationKind::Absolute, 64, 0),
+ pe::relocation::IMAGE_REL_AMD64_ADDR32 => (RelocationKind::Absolute, 32, 0),
+ pe::relocation::IMAGE_REL_AMD64_ADDR32NB => {
+ (RelocationKind::ImageOffset, 32, 0)
+ }
+ pe::relocation::IMAGE_REL_AMD64_REL32 => (RelocationKind::Relative, 32, -4),
+ pe::relocation::IMAGE_REL_AMD64_REL32_1 => (RelocationKind::Relative, 32, -5),
+ pe::relocation::IMAGE_REL_AMD64_REL32_2 => (RelocationKind::Relative, 32, -6),
+ pe::relocation::IMAGE_REL_AMD64_REL32_3 => (RelocationKind::Relative, 32, -7),
+ pe::relocation::IMAGE_REL_AMD64_REL32_4 => (RelocationKind::Relative, 32, -8),
+ pe::relocation::IMAGE_REL_AMD64_REL32_5 => (RelocationKind::Relative, 32, -9),
+ pe::relocation::IMAGE_REL_AMD64_SECTION => {
+ (RelocationKind::SectionIndex, 16, 0)
+ }
+ pe::relocation::IMAGE_REL_AMD64_SECREL => {
+ (RelocationKind::SectionOffset, 32, 0)
+ }
+ pe::relocation::IMAGE_REL_AMD64_SECREL7 => {
+ (RelocationKind::SectionOffset, 7, 0)
+ }
+ _ => (RelocationKind::Coff(relocation.typ), 0, 0),
+ },
+ _ => (RelocationKind::Coff(relocation.typ), 0, 0),
+ };
+ let target =
+ RelocationTarget::Symbol(SymbolIndex(relocation.symbol_table_index as usize));
+ (
+ u64::from(relocation.virtual_address),
+ Relocation {
+ kind,
+ encoding: RelocationEncoding::Generic,
+ size,
+ target,
+ addend,
+ implicit_addend: true,
+ },
+ )
+ })
+ }
+}
+
+impl<'data, 'file> fmt::Debug for CoffRelocationIterator<'data, 'file> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("CoffRelocationIterator").finish()
+ }
+}
diff --git a/third_party/rust/object/src/read/elf.rs b/third_party/rust/object/src/read/elf.rs
new file mode 100644
index 0000000000..6af690756a
--- /dev/null
+++ b/third_party/rust/object/src/read/elf.rs
@@ -0,0 +1,709 @@
+use crate::alloc::borrow::Cow;
+use crate::alloc::fmt;
+use crate::alloc::vec::Vec;
+#[cfg(feature = "compression")]
+use flate2::{Decompress, FlushDecompress};
+#[cfg(feature = "compression")]
+use goblin::container;
+use goblin::{elf, strtab};
+#[cfg(feature = "compression")]
+use scroll::ctx::TryFromCtx;
+use scroll::{self, Pread};
+use std::{iter, slice};
+use target_lexicon::{Aarch64Architecture, Architecture, ArmArchitecture};
+
+use crate::read::{
+ self, Object, ObjectSection, ObjectSegment, Relocation, RelocationEncoding, RelocationKind,
+ RelocationTarget, SectionIndex, SectionKind, Symbol, SymbolIndex, SymbolKind, SymbolMap,
+ SymbolScope,
+};
+
+/// An ELF object file.
+#[derive(Debug)]
+pub struct ElfFile<'data> {
+ elf: elf::Elf<'data>,
+ data: &'data [u8],
+}
+
+impl<'data> ElfFile<'data> {
+ /// Get the ELF headers of the file.
+ // TODO: this is temporary to allow access to features this crate doesn't provide yet
+ #[inline]
+ pub fn elf(&self) -> &elf::Elf<'data> {
+ &self.elf
+ }
+
+ /// Parse the raw ELF file data.
+ pub fn parse(data: &'data [u8]) -> Result<Self, &'static str> {
+ let elf = elf::Elf::parse(data).map_err(|_| "Could not parse ELF header")?;
+ Ok(ElfFile { elf, data })
+ }
+
+ fn raw_section_by_name<'file>(
+ &'file self,
+ section_name: &str,
+ ) -> Option<ElfSection<'data, 'file>> {
+ for (index, section) in self.elf.section_headers.iter().enumerate() {
+ if let Some(Ok(name)) = self.elf.shdr_strtab.get(section.sh_name) {
+ if name == section_name {
+ return Some(ElfSection {
+ file: self,
+ index: SectionIndex(index),
+ section,
+ });
+ }
+ }
+ }
+ None
+ }
+
+ #[cfg(feature = "compression")]
+ fn zdebug_section_by_name<'file>(
+ &'file self,
+ section_name: &str,
+ ) -> Option<ElfSection<'data, 'file>> {
+ if !section_name.starts_with(".debug_") {
+ return None;
+ }
+ self.raw_section_by_name(&format!(".zdebug_{}", &section_name[7..]))
+ }
+
+ #[cfg(not(feature = "compression"))]
+ fn zdebug_section_by_name<'file>(
+ &'file self,
+ _section_name: &str,
+ ) -> Option<ElfSection<'data, 'file>> {
+ None
+ }
+}
+
+impl<'data, 'file> Object<'data, 'file> for ElfFile<'data>
+where
+ 'data: 'file,
+{
+ type Segment = ElfSegment<'data, 'file>;
+ type SegmentIterator = ElfSegmentIterator<'data, 'file>;
+ type Section = ElfSection<'data, 'file>;
+ type SectionIterator = ElfSectionIterator<'data, 'file>;
+ type SymbolIterator = ElfSymbolIterator<'data, 'file>;
+
+ fn architecture(&self) -> Architecture {
+ match self.elf.header.e_machine {
+ elf::header::EM_ARM => Architecture::Arm(ArmArchitecture::Arm),
+ elf::header::EM_AARCH64 => Architecture::Aarch64(Aarch64Architecture::Aarch64),
+ elf::header::EM_386 => Architecture::I386,
+ elf::header::EM_X86_64 => Architecture::X86_64,
+ elf::header::EM_MIPS => Architecture::Mips,
+ _ => Architecture::Unknown,
+ }
+ }
+
+ #[inline]
+ fn is_little_endian(&self) -> bool {
+ self.elf.little_endian
+ }
+
+ #[inline]
+ fn is_64(&self) -> bool {
+ self.elf.is_64
+ }
+
+ fn segments(&'file self) -> ElfSegmentIterator<'data, 'file> {
+ ElfSegmentIterator {
+ file: self,
+ iter: self.elf.program_headers.iter(),
+ }
+ }
+
+ fn section_by_name(&'file self, section_name: &str) -> Option<ElfSection<'data, 'file>> {
+ self.raw_section_by_name(section_name)
+ .or_else(|| self.zdebug_section_by_name(section_name))
+ }
+
+ fn section_by_index(&'file self, index: SectionIndex) -> Option<ElfSection<'data, 'file>> {
+ self.elf
+ .section_headers
+ .get(index.0)
+ .map(|section| ElfSection {
+ file: self,
+ index,
+ section,
+ })
+ }
+
+ fn sections(&'file self) -> ElfSectionIterator<'data, 'file> {
+ ElfSectionIterator {
+ file: self,
+ iter: self.elf.section_headers.iter().enumerate(),
+ }
+ }
+
+ fn symbol_by_index(&self, index: SymbolIndex) -> Option<Symbol<'data>> {
+ self.elf
+ .syms
+ .get(index.0)
+ .map(|symbol| parse_symbol(index.0, &symbol, &self.elf.strtab))
+ }
+
+ fn symbols(&'file self) -> ElfSymbolIterator<'data, 'file> {
+ ElfSymbolIterator {
+ strtab: &self.elf.strtab,
+ symbols: self.elf.syms.iter().enumerate(),
+ }
+ }
+
+ fn dynamic_symbols(&'file self) -> ElfSymbolIterator<'data, 'file> {
+ ElfSymbolIterator {
+ strtab: &self.elf.dynstrtab,
+ symbols: self.elf.dynsyms.iter().enumerate(),
+ }
+ }
+
+ fn symbol_map(&self) -> SymbolMap<'data> {
+ let mut symbols: Vec<_> = self
+ .symbols()
+ .map(|(_, s)| s)
+ .filter(SymbolMap::filter)
+ .collect();
+ symbols.sort_by_key(|x| x.address);
+ SymbolMap { symbols }
+ }
+
+ fn has_debug_symbols(&self) -> bool {
+ for header in &self.elf.section_headers {
+ if let Some(Ok(name)) = self.elf.shdr_strtab.get(header.sh_name) {
+ if name == ".debug_info" || name == ".zdebug_info" {
+ return true;
+ }
+ }
+ }
+ false
+ }
+
+ fn build_id(&self) -> Option<&'data [u8]> {
+ if let Some(mut notes) = self.elf.iter_note_headers(self.data) {
+ while let Some(Ok(note)) = notes.next() {
+ if note.n_type == elf::note::NT_GNU_BUILD_ID {
+ return Some(note.desc);
+ }
+ }
+ }
+ if let Some(mut notes) = self
+ .elf
+ .iter_note_sections(self.data, Some(".note.gnu.build-id"))
+ {
+ while let Some(Ok(note)) = notes.next() {
+ if note.n_type == elf::note::NT_GNU_BUILD_ID {
+ return Some(note.desc);
+ }
+ }
+ }
+ None
+ }
+
+ fn gnu_debuglink(&self) -> Option<(&'data [u8], u32)> {
+ if let Some(Cow::Borrowed(data)) = self.section_data_by_name(".gnu_debuglink") {
+ if let Some(filename_len) = data.iter().position(|x| *x == 0) {
+ let filename = &data[..filename_len];
+ // Round to 4 byte alignment after null terminator.
+ let offset = (filename_len + 1 + 3) & !3;
+ if offset + 4 <= data.len() {
+ let endian = if self.is_little_endian() {
+ scroll::LE
+ } else {
+ scroll::BE
+ };
+ let crc: u32 = data.pread_with(offset, endian).unwrap();
+ return Some((filename, crc));
+ }
+ }
+ }
+ None
+ }
+
+ fn entry(&self) -> u64 {
+ self.elf.entry
+ }
+}
+
+/// An iterator over the segments of an `ElfFile`.
+#[derive(Debug)]
+pub struct ElfSegmentIterator<'data, 'file>
+where
+ 'data: 'file,
+{
+ file: &'file ElfFile<'data>,
+ iter: slice::Iter<'file, elf::ProgramHeader>,
+}
+
+impl<'data, 'file> Iterator for ElfSegmentIterator<'data, 'file> {
+ type Item = ElfSegment<'data, 'file>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ while let Some(segment) = self.iter.next() {
+ if segment.p_type == elf::program_header::PT_LOAD {
+ return Some(ElfSegment {
+ file: self.file,
+ segment,
+ });
+ }
+ }
+ None
+ }
+}
+
+/// A segment of an `ElfFile`.
+#[derive(Debug)]
+pub struct ElfSegment<'data, 'file>
+where
+ 'data: 'file,
+{
+ file: &'file ElfFile<'data>,
+ segment: &'file elf::ProgramHeader,
+}
+
+impl<'data, 'file> ObjectSegment<'data> for ElfSegment<'data, 'file> {
+ #[inline]
+ fn address(&self) -> u64 {
+ self.segment.p_vaddr
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ self.segment.p_memsz
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ self.segment.p_align
+ }
+
+ #[inline]
+ fn file_range(&self) -> (u64, u64) {
+ (self.segment.p_offset, self.segment.p_filesz)
+ }
+
+ fn data(&self) -> &'data [u8] {
+ &self.file.data[self.segment.p_offset as usize..][..self.segment.p_filesz as usize]
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]> {
+ read::data_range(self.data(), self.address(), address, size)
+ }
+
+ #[inline]
+ fn name(&self) -> Option<&str> {
+ None
+ }
+}
+
+/// An iterator over the sections of an `ElfFile`.
+#[derive(Debug)]
+pub struct ElfSectionIterator<'data, 'file>
+where
+ 'data: 'file,
+{
+ file: &'file ElfFile<'data>,
+ iter: iter::Enumerate<slice::Iter<'file, elf::SectionHeader>>,
+}
+
+impl<'data, 'file> Iterator for ElfSectionIterator<'data, 'file> {
+ type Item = ElfSection<'data, 'file>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next().map(|(index, section)| ElfSection {
+ index: SectionIndex(index),
+ file: self.file,
+ section,
+ })
+ }
+}
+
+/// A section of an `ElfFile`.
+#[derive(Debug)]
+pub struct ElfSection<'data, 'file>
+where
+ 'data: 'file,
+{
+ file: &'file ElfFile<'data>,
+ index: SectionIndex,
+ section: &'file elf::SectionHeader,
+}
+
+impl<'data, 'file> ElfSection<'data, 'file> {
+ fn raw_offset(&self) -> Option<(u64, u64)> {
+ if self.section.sh_type == elf::section_header::SHT_NOBITS {
+ None
+ } else {
+ Some((self.section.sh_offset, self.section.sh_size))
+ }
+ }
+
+ fn raw_data(&self) -> &'data [u8] {
+ if let Some((offset, size)) = self.raw_offset() {
+ &self.file.data[offset as usize..][..size as usize]
+ } else {
+ &[]
+ }
+ }
+
+ #[cfg(feature = "compression")]
+ fn maybe_decompress_data(&self) -> Option<Cow<'data, [u8]>> {
+ if (self.section.sh_flags & u64::from(elf::section_header::SHF_COMPRESSED)) == 0 {
+ return None;
+ }
+
+ let container = match self.file.elf.header.container() {
+ Ok(c) => c,
+ Err(_) => return None,
+ };
+ let endianness = match self.file.elf.header.endianness() {
+ Ok(e) => e,
+ Err(_) => return None,
+ };
+ let ctx = container::Ctx::new(container, endianness);
+ let data = self.raw_data();
+ let (compression_type, uncompressed_size, compressed_data) =
+ match elf::compression_header::CompressionHeader::try_from_ctx(&data, ctx) {
+ Ok((chdr, size)) => (chdr.ch_type, chdr.ch_size, &data[size..]),
+ Err(_) => return None,
+ };
+ if compression_type != elf::compression_header::ELFCOMPRESS_ZLIB {
+ return None;
+ }
+
+ let mut decompressed = Vec::with_capacity(uncompressed_size as usize);
+ let mut decompress = Decompress::new(true);
+ if decompress
+ .decompress_vec(compressed_data, &mut decompressed, FlushDecompress::Finish)
+ .is_err()
+ {
+ return None;
+ }
+ Some(Cow::Owned(decompressed))
+ }
+
+ /// Try GNU-style "ZLIB" header decompression.
+ #[cfg(feature = "compression")]
+ fn maybe_decompress_data_gnu(&self) -> Option<Cow<'data, [u8]>> {
+ let name = match self.name() {
+ Some(name) => name,
+ None => return None,
+ };
+ if !name.starts_with(".zdebug_") {
+ return None;
+ }
+ let data = self.raw_data();
+ // Assume ZLIB-style uncompressed data is no more than 4GB to avoid accidentally
+ // huge allocations. This also reduces the chance of accidentally matching on a
+ // .debug_str that happens to start with "ZLIB".
+ if data.len() < 12 || &data[..8] != b"ZLIB\0\0\0\0" {
+ return None;
+ }
+ let uncompressed_size: u32 = data.pread_with(8, scroll::BE).unwrap();
+ let mut decompressed = Vec::with_capacity(uncompressed_size as usize);
+ let mut decompress = Decompress::new(true);
+ if decompress
+ .decompress_vec(&data[12..], &mut decompressed, FlushDecompress::Finish)
+ .is_err()
+ {
+ return None;
+ }
+ Some(Cow::Owned(decompressed))
+ }
+}
+
+impl<'data, 'file> ObjectSection<'data> for ElfSection<'data, 'file> {
+ type RelocationIterator = ElfRelocationIterator<'data, 'file>;
+
+ #[inline]
+ fn index(&self) -> SectionIndex {
+ self.index
+ }
+
+ #[inline]
+ fn address(&self) -> u64 {
+ self.section.sh_addr
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ self.section.sh_size
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ self.section.sh_addralign
+ }
+
+ #[inline]
+ fn file_range(&self) -> Option<(u64, u64)> {
+ self.raw_offset()
+ }
+
+ #[inline]
+ fn data(&self) -> Cow<'data, [u8]> {
+ Cow::from(self.raw_data())
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]> {
+ read::data_range(self.raw_data(), self.address(), address, size)
+ }
+
+ #[cfg(feature = "compression")]
+ fn uncompressed_data(&self) -> Cow<'data, [u8]> {
+ self.maybe_decompress_data()
+ .or_else(|| self.maybe_decompress_data_gnu())
+ .unwrap_or_else(|| self.data())
+ }
+
+ #[cfg(not(feature = "compression"))]
+ #[inline]
+ fn uncompressed_data(&self) -> Cow<'data, [u8]> {
+ self.data()
+ }
+
+ fn name(&self) -> Option<&str> {
+ self.file
+ .elf
+ .shdr_strtab
+ .get(self.section.sh_name)
+ .and_then(Result::ok)
+ }
+
+ #[inline]
+ fn segment_name(&self) -> Option<&str> {
+ None
+ }
+
+ fn kind(&self) -> SectionKind {
+ match self.section.sh_type {
+ elf::section_header::SHT_PROGBITS => {
+ if self.section.sh_flags & u64::from(elf::section_header::SHF_ALLOC) != 0 {
+ if self.section.sh_flags & u64::from(elf::section_header::SHF_EXECINSTR) != 0 {
+ SectionKind::Text
+ } else if self.section.sh_flags & u64::from(elf::section_header::SHF_TLS) != 0 {
+ SectionKind::Tls
+ } else if self.section.sh_flags & u64::from(elf::section_header::SHF_WRITE) != 0
+ {
+ SectionKind::Data
+ } else if self.section.sh_flags & u64::from(elf::section_header::SHF_STRINGS)
+ != 0
+ {
+ SectionKind::ReadOnlyString
+ } else {
+ SectionKind::ReadOnlyData
+ }
+ } else if self.section.sh_flags & u64::from(elf::section_header::SHF_STRINGS) != 0 {
+ SectionKind::OtherString
+ } else {
+ SectionKind::Other
+ }
+ }
+ elf::section_header::SHT_NOBITS => {
+ if self.section.sh_flags & u64::from(elf::section_header::SHF_TLS) != 0 {
+ SectionKind::UninitializedTls
+ } else {
+ SectionKind::UninitializedData
+ }
+ }
+ elf::section_header::SHT_NULL
+ | elf::section_header::SHT_SYMTAB
+ | elf::section_header::SHT_STRTAB
+ | elf::section_header::SHT_RELA
+ | elf::section_header::SHT_HASH
+ | elf::section_header::SHT_DYNAMIC
+ | elf::section_header::SHT_REL
+ | elf::section_header::SHT_DYNSYM => SectionKind::Metadata,
+ _ => {
+ // TODO: maybe add more specialised kinds based on sh_type (e.g. Unwind)
+ SectionKind::Unknown
+ }
+ }
+ }
+
+ fn relocations(&self) -> ElfRelocationIterator<'data, 'file> {
+ ElfRelocationIterator {
+ section_index: self.index,
+ file: self.file,
+ sections: self.file.elf.shdr_relocs.iter(),
+ relocations: None,
+ }
+ }
+}
+
+/// An iterator over the symbols of an `ElfFile`.
+pub struct ElfSymbolIterator<'data, 'file>
+where
+ 'data: 'file,
+{
+ strtab: &'file strtab::Strtab<'data>,
+ symbols: iter::Enumerate<elf::sym::SymIterator<'data>>,
+}
+
+impl<'data, 'file> fmt::Debug for ElfSymbolIterator<'data, 'file> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("ElfSymbolIterator").finish()
+ }
+}
+
+impl<'data, 'file> Iterator for ElfSymbolIterator<'data, 'file> {
+ type Item = (SymbolIndex, Symbol<'data>);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.symbols.next().map(|(index, symbol)| {
+ (
+ SymbolIndex(index),
+ parse_symbol(index, &symbol, self.strtab),
+ )
+ })
+ }
+}
+
+fn parse_symbol<'data>(
+ index: usize,
+ symbol: &elf::sym::Sym,
+ strtab: &strtab::Strtab<'data>,
+) -> Symbol<'data> {
+ let name = strtab.get(symbol.st_name).and_then(Result::ok);
+ let kind = match elf::sym::st_type(symbol.st_info) {
+ elf::sym::STT_NOTYPE if index == 0 => SymbolKind::Null,
+ elf::sym::STT_OBJECT => SymbolKind::Data,
+ elf::sym::STT_FUNC => SymbolKind::Text,
+ elf::sym::STT_SECTION => SymbolKind::Section,
+ elf::sym::STT_FILE => SymbolKind::File,
+ elf::sym::STT_COMMON => SymbolKind::Common,
+ elf::sym::STT_TLS => SymbolKind::Tls,
+ _ => SymbolKind::Unknown,
+ };
+ let undefined = symbol.st_shndx == elf::section_header::SHN_UNDEF as usize;
+ let section_index =
+ if undefined || symbol.st_shndx >= elf::section_header::SHN_LORESERVE as usize {
+ None
+ } else {
+ Some(SectionIndex(symbol.st_shndx))
+ };
+ let weak = symbol.st_bind() == elf::sym::STB_WEAK;
+ let scope = match symbol.st_bind() {
+ _ if undefined => SymbolScope::Unknown,
+ elf::sym::STB_LOCAL => SymbolScope::Compilation,
+ elf::sym::STB_GLOBAL | elf::sym::STB_WEAK => {
+ if symbol.st_visibility() == elf::sym::STV_HIDDEN {
+ SymbolScope::Linkage
+ } else {
+ SymbolScope::Dynamic
+ }
+ }
+ _ => SymbolScope::Unknown,
+ };
+ Symbol {
+ name,
+ address: symbol.st_value,
+ size: symbol.st_size,
+ kind,
+ section_index,
+ undefined,
+ weak,
+ scope,
+ }
+}
+
+/// An iterator over the relocations in an `ElfSection`.
+pub struct ElfRelocationIterator<'data, 'file>
+where
+ 'data: 'file,
+{
+ /// The index of the section that the relocations apply to.
+ section_index: SectionIndex,
+ file: &'file ElfFile<'data>,
+ sections: slice::Iter<'file, (elf::ShdrIdx, elf::RelocSection<'data>)>,
+ relocations: Option<elf::reloc::RelocIterator<'data>>,
+}
+
+impl<'data, 'file> Iterator for ElfRelocationIterator<'data, 'file> {
+ type Item = (u64, Relocation);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ loop {
+ if let Some(ref mut relocations) = self.relocations {
+ if let Some(reloc) = relocations.next() {
+ let mut encoding = RelocationEncoding::Generic;
+ let (kind, size) = match self.file.elf.header.e_machine {
+ elf::header::EM_ARM => match reloc.r_type {
+ elf::reloc::R_ARM_ABS32 => (RelocationKind::Absolute, 32),
+ _ => (RelocationKind::Elf(reloc.r_type), 0),
+ },
+ elf::header::EM_AARCH64 => match reloc.r_type {
+ elf::reloc::R_AARCH64_ABS64 => (RelocationKind::Absolute, 64),
+ elf::reloc::R_AARCH64_ABS32 => (RelocationKind::Absolute, 32),
+ elf::reloc::R_AARCH64_ABS16 => (RelocationKind::Absolute, 16),
+ elf::reloc::R_AARCH64_PREL64 => (RelocationKind::Relative, 64),
+ elf::reloc::R_AARCH64_PREL32 => (RelocationKind::Relative, 32),
+ elf::reloc::R_AARCH64_PREL16 => (RelocationKind::Relative, 16),
+ _ => (RelocationKind::Elf(reloc.r_type), 0),
+ },
+ elf::header::EM_386 => match reloc.r_type {
+ elf::reloc::R_386_32 => (RelocationKind::Absolute, 32),
+ elf::reloc::R_386_PC32 => (RelocationKind::Relative, 32),
+ elf::reloc::R_386_GOT32 => (RelocationKind::Got, 32),
+ elf::reloc::R_386_PLT32 => (RelocationKind::PltRelative, 32),
+ elf::reloc::R_386_GOTOFF => (RelocationKind::GotBaseOffset, 32),
+ elf::reloc::R_386_GOTPC => (RelocationKind::GotBaseRelative, 32),
+ elf::reloc::R_386_16 => (RelocationKind::Absolute, 16),
+ elf::reloc::R_386_PC16 => (RelocationKind::Relative, 16),
+ elf::reloc::R_386_8 => (RelocationKind::Absolute, 8),
+ elf::reloc::R_386_PC8 => (RelocationKind::Relative, 8),
+ _ => (RelocationKind::Elf(reloc.r_type), 0),
+ },
+ elf::header::EM_X86_64 => match reloc.r_type {
+ elf::reloc::R_X86_64_64 => (RelocationKind::Absolute, 64),
+ elf::reloc::R_X86_64_PC32 => (RelocationKind::Relative, 32),
+ elf::reloc::R_X86_64_GOT32 => (RelocationKind::Got, 32),
+ elf::reloc::R_X86_64_PLT32 => (RelocationKind::PltRelative, 32),
+ elf::reloc::R_X86_64_GOTPCREL => (RelocationKind::GotRelative, 32),
+ elf::reloc::R_X86_64_32 => (RelocationKind::Absolute, 32),
+ elf::reloc::R_X86_64_32S => {
+ encoding = RelocationEncoding::X86Signed;
+ (RelocationKind::Absolute, 32)
+ }
+ elf::reloc::R_X86_64_16 => (RelocationKind::Absolute, 16),
+ elf::reloc::R_X86_64_PC16 => (RelocationKind::Relative, 16),
+ elf::reloc::R_X86_64_8 => (RelocationKind::Absolute, 8),
+ elf::reloc::R_X86_64_PC8 => (RelocationKind::Relative, 8),
+ _ => (RelocationKind::Elf(reloc.r_type), 0),
+ },
+ _ => (RelocationKind::Elf(reloc.r_type), 0),
+ };
+ let target = RelocationTarget::Symbol(SymbolIndex(reloc.r_sym as usize));
+ return Some((
+ reloc.r_offset,
+ Relocation {
+ kind,
+ encoding,
+ size,
+ target,
+ addend: reloc.r_addend.unwrap_or(0),
+ implicit_addend: reloc.r_addend.is_none(),
+ },
+ ));
+ }
+ }
+ match self.sections.next() {
+ None => return None,
+ Some((index, relocs)) => {
+ let section = &self.file.elf.section_headers[*index];
+ if section.sh_info as usize == self.section_index.0 {
+ self.relocations = Some(relocs.into_iter());
+ }
+ // TODO: do we need to return section.sh_link?
+ }
+ }
+ }
+ }
+}
+
+impl<'data, 'file> fmt::Debug for ElfRelocationIterator<'data, 'file> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("ElfRelocationIterator").finish()
+ }
+}
diff --git a/third_party/rust/object/src/read/macho.rs b/third_party/rust/object/src/read/macho.rs
new file mode 100644
index 0000000000..ce54938a10
--- /dev/null
+++ b/third_party/rust/object/src/read/macho.rs
@@ -0,0 +1,615 @@
+use crate::alloc::borrow::Cow;
+use crate::alloc::vec::Vec;
+use goblin::container;
+use goblin::mach;
+use goblin::mach::load_command::CommandVariant;
+use std::{fmt, iter, ops, slice};
+use target_lexicon::{Aarch64Architecture, Architecture, ArmArchitecture};
+use uuid::Uuid;
+
+use crate::read::{
+ self, Object, ObjectSection, ObjectSegment, Relocation, RelocationEncoding, RelocationKind,
+ RelocationTarget, SectionIndex, SectionKind, Symbol, SymbolIndex, SymbolKind, SymbolMap,
+ SymbolScope,
+};
+
+/// A Mach-O object file.
+#[derive(Debug)]
+pub struct MachOFile<'data> {
+ macho: mach::MachO<'data>,
+ data: &'data [u8],
+ ctx: container::Ctx,
+ sections: Vec<MachOSectionInternal<'data>>,
+}
+
+impl<'data> MachOFile<'data> {
+ /// Get the Mach-O headers of the file.
+ // TODO: this is temporary to allow access to features this crate doesn't provide yet
+ #[inline]
+ pub fn macho(&self) -> &mach::MachO<'data> {
+ &self.macho
+ }
+
+ /// Parse the raw Mach-O file data.
+ pub fn parse(data: &'data [u8]) -> Result<Self, &'static str> {
+ let (_magic, ctx) =
+ mach::parse_magic_and_ctx(data, 0).map_err(|_| "Could not parse Mach-O magic")?;
+ let ctx = ctx.ok_or("Invalid Mach-O magic")?;
+ let macho = mach::MachO::parse(data, 0).map_err(|_| "Could not parse Mach-O header")?;
+ // Build a list of sections to make some operations more efficient.
+ let mut sections = Vec::new();
+ 'segments: for segment in &macho.segments {
+ for section_result in segment {
+ if let Ok((section, data)) = section_result {
+ sections.push(MachOSectionInternal::parse(section, data));
+ } else {
+ break 'segments;
+ }
+ }
+ }
+ Ok(MachOFile {
+ macho,
+ data,
+ ctx,
+ sections,
+ })
+ }
+
+ /// Return the section at the given index.
+ #[inline]
+ fn section_internal(&self, index: SectionIndex) -> Option<&MachOSectionInternal<'data>> {
+ index
+ .0
+ .checked_sub(1)
+ .and_then(|index| self.sections.get(index))
+ }
+}
+
+impl<'data, 'file> Object<'data, 'file> for MachOFile<'data>
+where
+ 'data: 'file,
+{
+ type Segment = MachOSegment<'data, 'file>;
+ type SegmentIterator = MachOSegmentIterator<'data, 'file>;
+ type Section = MachOSection<'data, 'file>;
+ type SectionIterator = MachOSectionIterator<'data, 'file>;
+ type SymbolIterator = MachOSymbolIterator<'data, 'file>;
+
+ fn architecture(&self) -> Architecture {
+ match self.macho.header.cputype {
+ mach::cputype::CPU_TYPE_ARM => Architecture::Arm(ArmArchitecture::Arm),
+ mach::cputype::CPU_TYPE_ARM64 => Architecture::Aarch64(Aarch64Architecture::Aarch64),
+ mach::cputype::CPU_TYPE_X86 => Architecture::I386,
+ mach::cputype::CPU_TYPE_X86_64 => Architecture::X86_64,
+ mach::cputype::CPU_TYPE_MIPS => Architecture::Mips,
+ _ => Architecture::Unknown,
+ }
+ }
+
+ #[inline]
+ fn is_little_endian(&self) -> bool {
+ self.macho.little_endian
+ }
+
+ #[inline]
+ fn is_64(&self) -> bool {
+ self.macho.is_64
+ }
+
+ fn segments(&'file self) -> MachOSegmentIterator<'data, 'file> {
+ MachOSegmentIterator {
+ segments: self.macho.segments.iter(),
+ }
+ }
+
+ fn section_by_name(&'file self, section_name: &str) -> Option<MachOSection<'data, 'file>> {
+ // Translate the "." prefix to the "__" prefix used by OSX/Mach-O, eg
+ // ".debug_info" to "__debug_info".
+ let system_section = section_name.starts_with('.');
+ let cmp_section_name = |section: &MachOSection| {
+ section
+ .name()
+ .map(|name| {
+ section_name == name
+ || (system_section
+ && name.starts_with("__")
+ && &section_name[1..] == &name[2..])
+ })
+ .unwrap_or(false)
+ };
+
+ self.sections().find(cmp_section_name)
+ }
+
+ fn section_by_index(&'file self, index: SectionIndex) -> Option<MachOSection<'data, 'file>> {
+ self.section_internal(index)
+ .map(|_| MachOSection { file: self, index })
+ }
+
+ fn sections(&'file self) -> MachOSectionIterator<'data, 'file> {
+ MachOSectionIterator {
+ file: self,
+ iter: 0..self.sections.len(),
+ }
+ }
+
+ fn symbol_by_index(&self, index: SymbolIndex) -> Option<Symbol<'data>> {
+ self.macho
+ .symbols
+ .as_ref()
+ .and_then(|symbols| symbols.get(index.0).ok())
+ .and_then(|(name, nlist)| parse_symbol(self, name, &nlist))
+ }
+
+ fn symbols(&'file self) -> MachOSymbolIterator<'data, 'file> {
+ let symbols = match self.macho.symbols {
+ Some(ref symbols) => symbols.into_iter(),
+ None => mach::symbols::SymbolIterator::default(),
+ }
+ .enumerate();
+
+ MachOSymbolIterator {
+ file: self,
+ symbols,
+ }
+ }
+
+ fn dynamic_symbols(&'file self) -> MachOSymbolIterator<'data, 'file> {
+ // The LC_DYSYMTAB command contains indices into the same symbol
+ // table as the LC_SYMTAB command, so return all of them.
+ self.symbols()
+ }
+
+ fn symbol_map(&self) -> SymbolMap<'data> {
+ let mut symbols: Vec<_> = self.symbols().map(|(_, s)| s).collect();
+
+ // Add symbols for the end of each section.
+ for section in self.sections() {
+ symbols.push(Symbol {
+ name: None,
+ address: section.address() + section.size(),
+ size: 0,
+ kind: SymbolKind::Section,
+ section_index: None,
+ undefined: false,
+ weak: false,
+ scope: SymbolScope::Compilation,
+ });
+ }
+
+ // Calculate symbol sizes by sorting and finding the next symbol.
+ symbols.sort_by(|a, b| {
+ a.address.cmp(&b.address).then_with(|| {
+ // Place the end of section symbols last.
+ (a.kind == SymbolKind::Section).cmp(&(b.kind == SymbolKind::Section))
+ })
+ });
+
+ for i in 0..symbols.len() {
+ let (before, after) = symbols.split_at_mut(i + 1);
+ let symbol = &mut before[i];
+ if symbol.kind != SymbolKind::Section {
+ if let Some(next) = after
+ .iter()
+ .skip_while(|x| x.kind != SymbolKind::Section && x.address == symbol.address)
+ .next()
+ {
+ symbol.size = next.address - symbol.address;
+ }
+ }
+ }
+
+ symbols.retain(SymbolMap::filter);
+ SymbolMap { symbols }
+ }
+
+ fn has_debug_symbols(&self) -> bool {
+ self.section_data_by_name(".debug_info").is_some()
+ }
+
+ fn mach_uuid(&self) -> Option<Uuid> {
+ // Return the UUID from the `LC_UUID` load command, if one is present.
+ self.macho
+ .load_commands
+ .iter()
+ .filter_map(|lc| {
+ match lc.command {
+ CommandVariant::Uuid(ref cmd) => {
+ //TODO: Uuid should have a `from_array` method that can't fail.
+ Uuid::from_slice(&cmd.uuid).ok()
+ }
+ _ => None,
+ }
+ })
+ .nth(0)
+ }
+
+ fn entry(&self) -> u64 {
+ self.macho.entry
+ }
+}
+
+/// An iterator over the segments of a `MachOFile`.
+#[derive(Debug)]
+pub struct MachOSegmentIterator<'data, 'file>
+where
+ 'data: 'file,
+{
+ segments: slice::Iter<'file, mach::segment::Segment<'data>>,
+}
+
+impl<'data, 'file> Iterator for MachOSegmentIterator<'data, 'file> {
+ type Item = MachOSegment<'data, 'file>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.segments.next().map(|segment| MachOSegment { segment })
+ }
+}
+
+/// A segment of a `MachOFile`.
+#[derive(Debug)]
+pub struct MachOSegment<'data, 'file>
+where
+ 'data: 'file,
+{
+ segment: &'file mach::segment::Segment<'data>,
+}
+
+impl<'data, 'file> ObjectSegment<'data> for MachOSegment<'data, 'file> {
+ #[inline]
+ fn address(&self) -> u64 {
+ self.segment.vmaddr
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ self.segment.vmsize
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ // Page size.
+ 0x1000
+ }
+
+ #[inline]
+ fn file_range(&self) -> (u64, u64) {
+ (self.segment.fileoff, self.segment.filesize)
+ }
+
+ #[inline]
+ fn data(&self) -> &'data [u8] {
+ self.segment.data
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]> {
+ read::data_range(self.data(), self.address(), address, size)
+ }
+
+ #[inline]
+ fn name(&self) -> Option<&str> {
+ self.segment.name().ok()
+ }
+}
+
+/// An iterator over the sections of a `MachOFile`.
+pub struct MachOSectionIterator<'data, 'file>
+where
+ 'data: 'file,
+{
+ file: &'file MachOFile<'data>,
+ iter: ops::Range<usize>,
+}
+
+impl<'data, 'file> fmt::Debug for MachOSectionIterator<'data, 'file> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // It's painful to do much better than this
+ f.debug_struct("MachOSectionIterator").finish()
+ }
+}
+
+impl<'data, 'file> Iterator for MachOSectionIterator<'data, 'file> {
+ type Item = MachOSection<'data, 'file>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next().map(|index| MachOSection {
+ file: self.file,
+ index: SectionIndex(index + 1),
+ })
+ }
+}
+
+/// A section of a `MachOFile`.
+#[derive(Debug)]
+pub struct MachOSection<'data, 'file>
+where
+ 'data: 'file,
+{
+ file: &'file MachOFile<'data>,
+ index: SectionIndex,
+}
+
+impl<'data, 'file> MachOSection<'data, 'file> {
+ #[inline]
+ fn internal(&self) -> &'file MachOSectionInternal<'data> {
+ // We ensure the index is always valid.
+ &self.file.section_internal(self.index).unwrap()
+ }
+}
+
+impl<'data, 'file> ObjectSection<'data> for MachOSection<'data, 'file> {
+ type RelocationIterator = MachORelocationIterator<'data, 'file>;
+
+ #[inline]
+ fn index(&self) -> SectionIndex {
+ self.index
+ }
+
+ #[inline]
+ fn address(&self) -> u64 {
+ self.internal().section.addr
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ self.internal().section.size
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ 1 << self.internal().section.align
+ }
+
+ #[inline]
+ fn file_range(&self) -> Option<(u64, u64)> {
+ let internal = &self.internal().section;
+ Some((internal.offset as u64, internal.size))
+ }
+
+ #[inline]
+ fn data(&self) -> Cow<'data, [u8]> {
+ Cow::from(self.internal().data)
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]> {
+ read::data_range(self.internal().data, self.address(), address, size)
+ }
+
+ #[inline]
+ fn uncompressed_data(&self) -> Cow<'data, [u8]> {
+ // TODO: does MachO support compression?
+ self.data()
+ }
+
+ #[inline]
+ fn name(&self) -> Option<&str> {
+ self.internal().section.name().ok()
+ }
+
+ #[inline]
+ fn segment_name(&self) -> Option<&str> {
+ self.internal().section.segname().ok()
+ }
+
+ fn kind(&self) -> SectionKind {
+ self.internal().kind
+ }
+
+ fn relocations(&self) -> MachORelocationIterator<'data, 'file> {
+ MachORelocationIterator {
+ file: self.file,
+ relocations: self
+ .internal()
+ .section
+ .iter_relocations(self.file.data, self.file.ctx),
+ }
+ }
+}
+
+#[derive(Debug)]
+struct MachOSectionInternal<'data> {
+ section: mach::segment::Section,
+ data: mach::segment::SectionData<'data>,
+ kind: SectionKind,
+}
+
+impl<'data> MachOSectionInternal<'data> {
+ fn parse(section: mach::segment::Section, data: mach::segment::SectionData<'data>) -> Self {
+ let kind = if let (Ok(segname), Ok(name)) = (section.segname(), section.name()) {
+ match (segname, name) {
+ ("__TEXT", "__text") => SectionKind::Text,
+ ("__TEXT", "__const") => SectionKind::ReadOnlyData,
+ ("__TEXT", "__cstring") => SectionKind::ReadOnlyString,
+ ("__TEXT", "__eh_frame") => SectionKind::ReadOnlyData,
+ ("__TEXT", "__gcc_except_tab") => SectionKind::ReadOnlyData,
+ ("__DATA", "__data") => SectionKind::Data,
+ ("__DATA", "__const") => SectionKind::ReadOnlyData,
+ ("__DATA", "__bss") => SectionKind::UninitializedData,
+ ("__DATA", "__thread_data") => SectionKind::Tls,
+ ("__DATA", "__thread_bss") => SectionKind::UninitializedTls,
+ ("__DATA", "__thread_vars") => SectionKind::TlsVariables,
+ ("__DWARF", _) => SectionKind::Debug,
+ _ => SectionKind::Unknown,
+ }
+ } else {
+ SectionKind::Unknown
+ };
+ MachOSectionInternal {
+ section,
+ data,
+ kind,
+ }
+ }
+}
+
+/// An iterator over the symbols of a `MachOFile`.
+pub struct MachOSymbolIterator<'data, 'file> {
+ file: &'file MachOFile<'data>,
+ symbols: iter::Enumerate<mach::symbols::SymbolIterator<'data>>,
+}
+
+impl<'data, 'file> fmt::Debug for MachOSymbolIterator<'data, 'file> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("MachOSymbolIterator").finish()
+ }
+}
+
+impl<'data, 'file> Iterator for MachOSymbolIterator<'data, 'file> {
+ type Item = (SymbolIndex, Symbol<'data>);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ while let Some((index, Ok((name, nlist)))) = self.symbols.next() {
+ if let Some(symbol) = parse_symbol(self.file, name, &nlist) {
+ return Some((SymbolIndex(index), symbol));
+ }
+ }
+ None
+ }
+}
+
+fn parse_symbol<'data>(
+ file: &MachOFile<'data>,
+ name: &'data str,
+ nlist: &mach::symbols::Nlist,
+) -> Option<Symbol<'data>> {
+ if nlist.n_type & mach::symbols::N_STAB != 0 {
+ return None;
+ }
+ let n_type = nlist.n_type & mach::symbols::NLIST_TYPE_MASK;
+ let section_index = if n_type == mach::symbols::N_SECT {
+ if nlist.n_sect == 0 {
+ None
+ } else {
+ Some(SectionIndex(nlist.n_sect))
+ }
+ } else {
+ // TODO: better handling for other n_type values
+ None
+ };
+ let kind = section_index
+ .and_then(|index| file.section_internal(index))
+ .map(|section| match section.kind {
+ SectionKind::Text => SymbolKind::Text,
+ SectionKind::Data
+ | SectionKind::ReadOnlyData
+ | SectionKind::ReadOnlyString
+ | SectionKind::UninitializedData => SymbolKind::Data,
+ SectionKind::Tls | SectionKind::UninitializedTls | SectionKind::TlsVariables => {
+ SymbolKind::Tls
+ }
+ _ => SymbolKind::Unknown,
+ })
+ .unwrap_or(SymbolKind::Unknown);
+ let undefined = nlist.is_undefined();
+ let weak = nlist.is_weak();
+ let scope = if undefined {
+ SymbolScope::Unknown
+ } else if nlist.n_type & mach::symbols::N_EXT == 0 {
+ SymbolScope::Compilation
+ } else if nlist.n_type & mach::symbols::N_PEXT != 0 {
+ SymbolScope::Linkage
+ } else {
+ SymbolScope::Dynamic
+ };
+ Some(Symbol {
+ name: Some(name),
+ address: nlist.n_value,
+ // Only calculated for symbol maps
+ size: 0,
+ kind,
+ section_index,
+ undefined,
+ weak,
+ scope,
+ })
+}
+
+/// An iterator over the relocations in an `MachOSection`.
+pub struct MachORelocationIterator<'data, 'file>
+where
+ 'data: 'file,
+{
+ file: &'file MachOFile<'data>,
+ relocations: mach::segment::RelocationIterator<'data>,
+}
+
+impl<'data, 'file> Iterator for MachORelocationIterator<'data, 'file> {
+ type Item = (u64, Relocation);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.relocations.next()?.ok().map(|reloc| {
+ let mut encoding = RelocationEncoding::Generic;
+ let kind = match self.file.macho.header.cputype {
+ mach::cputype::CPU_TYPE_ARM => match (reloc.r_type(), reloc.r_pcrel()) {
+ (mach::relocation::ARM_RELOC_VANILLA, 0) => RelocationKind::Absolute,
+ _ => RelocationKind::MachO {
+ value: reloc.r_type(),
+ relative: reloc.is_pic(),
+ },
+ },
+ mach::cputype::CPU_TYPE_ARM64 => match (reloc.r_type(), reloc.r_pcrel()) {
+ (mach::relocation::ARM64_RELOC_UNSIGNED, 0) => RelocationKind::Absolute,
+ _ => RelocationKind::MachO {
+ value: reloc.r_type(),
+ relative: reloc.is_pic(),
+ },
+ },
+ mach::cputype::CPU_TYPE_X86 => match (reloc.r_type(), reloc.r_pcrel()) {
+ (mach::relocation::GENERIC_RELOC_VANILLA, 0) => RelocationKind::Absolute,
+ _ => RelocationKind::MachO {
+ value: reloc.r_type(),
+ relative: reloc.is_pic(),
+ },
+ },
+ mach::cputype::CPU_TYPE_X86_64 => match (reloc.r_type(), reloc.r_pcrel()) {
+ (mach::relocation::X86_64_RELOC_UNSIGNED, 0) => RelocationKind::Absolute,
+ (mach::relocation::X86_64_RELOC_SIGNED, 1) => {
+ encoding = RelocationEncoding::X86RipRelative;
+ RelocationKind::Relative
+ }
+ (mach::relocation::X86_64_RELOC_BRANCH, 1) => {
+ encoding = RelocationEncoding::X86Branch;
+ RelocationKind::Relative
+ }
+ (mach::relocation::X86_64_RELOC_GOT, 1) => RelocationKind::GotRelative,
+ (mach::relocation::X86_64_RELOC_GOT_LOAD, 1) => {
+ encoding = RelocationEncoding::X86RipRelativeMovq;
+ RelocationKind::GotRelative
+ }
+ _ => RelocationKind::MachO {
+ value: reloc.r_type(),
+ relative: reloc.is_pic(),
+ },
+ },
+ _ => RelocationKind::MachO {
+ value: reloc.r_type(),
+ relative: reloc.is_pic(),
+ },
+ };
+ let size = 8 << reloc.r_length();
+ let target = if reloc.is_extern() {
+ RelocationTarget::Symbol(SymbolIndex(reloc.r_symbolnum()))
+ } else {
+ RelocationTarget::Section(SectionIndex(reloc.r_symbolnum()))
+ };
+ let addend = if reloc.r_pcrel() != 0 { -4 } else { 0 };
+ (
+ reloc.r_address as u64,
+ Relocation {
+ kind,
+ encoding,
+ size,
+ target,
+ addend,
+ implicit_addend: true,
+ },
+ )
+ })
+ }
+}
+
+impl<'data, 'file> fmt::Debug for MachORelocationIterator<'data, 'file> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("MachORelocationIterator").finish()
+ }
+}
diff --git a/third_party/rust/object/src/read/mod.rs b/third_party/rust/object/src/read/mod.rs
new file mode 100644
index 0000000000..c120db9a83
--- /dev/null
+++ b/third_party/rust/object/src/read/mod.rs
@@ -0,0 +1,250 @@
+//! Interface for reading object files.
+
+use crate::alloc::vec::Vec;
+use crate::common::{RelocationEncoding, RelocationKind, SectionKind, SymbolKind, SymbolScope};
+
+mod any;
+pub use any::*;
+
+mod coff;
+pub use coff::*;
+
+mod elf;
+pub use elf::*;
+
+mod macho;
+pub use macho::*;
+
+mod pe;
+pub use pe::*;
+
+mod traits;
+pub use traits::*;
+
+#[cfg(feature = "wasm")]
+mod wasm;
+#[cfg(feature = "wasm")]
+pub use wasm::*;
+
+/// The native object file for the target platform.
+#[cfg(target_os = "linux")]
+pub type NativeFile<'data> = ElfFile<'data>;
+
+/// The native object file for the target platform.
+#[cfg(target_os = "macos")]
+pub type NativeFile<'data> = MachOFile<'data>;
+
+/// The native object file for the target platform.
+#[cfg(target_os = "windows")]
+pub type NativeFile<'data> = PeFile<'data>;
+
+/// The native object file for the target platform.
+#[cfg(all(feature = "wasm", target_arch = "wasm32"))]
+pub type NativeFile<'data> = WasmFile<'data>;
+
+/// The index used to identify a section of a file.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct SectionIndex(pub usize);
+
+/// The index used to identify a symbol of a file.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct SymbolIndex(pub usize);
+
+/// A symbol table entry.
+#[derive(Debug)]
+pub struct Symbol<'data> {
+ name: Option<&'data str>,
+ address: u64,
+ size: u64,
+ kind: SymbolKind,
+ section_index: Option<SectionIndex>,
+ undefined: bool,
+ weak: bool,
+ scope: SymbolScope,
+}
+
+impl<'data> Symbol<'data> {
+ /// Return the kind of this symbol.
+ #[inline]
+ pub fn kind(&self) -> SymbolKind {
+ self.kind
+ }
+
+ /// Returns the section index for the section containing this symbol.
+ ///
+ /// May return `None` if the section is unknown or the symbol is undefined.
+ #[inline]
+ pub fn section_index(&self) -> Option<SectionIndex> {
+ self.section_index
+ }
+
+ /// Return true if the symbol is undefined.
+ #[inline]
+ pub fn is_undefined(&self) -> bool {
+ self.undefined
+ }
+
+ /// Return true if the symbol is weak.
+ #[inline]
+ pub fn is_weak(&self) -> bool {
+ self.weak
+ }
+
+ /// Return true if the symbol visible outside of the compilation unit.
+ ///
+ /// This treats `SymbolScope::Unknown` as global.
+ #[inline]
+ pub fn is_global(&self) -> bool {
+ !self.is_local()
+ }
+
+ /// Return true if the symbol is only visible within the compilation unit.
+ #[inline]
+ pub fn is_local(&self) -> bool {
+ self.scope == SymbolScope::Compilation
+ }
+
+ /// Returns the symbol scope.
+ #[inline]
+ pub fn scope(&self) -> SymbolScope {
+ self.scope
+ }
+
+ /// The name of the symbol.
+ #[inline]
+ pub fn name(&self) -> Option<&'data str> {
+ self.name
+ }
+
+ /// The address of the symbol. May be zero if the address is unknown.
+ #[inline]
+ pub fn address(&self) -> u64 {
+ self.address
+ }
+
+ /// The size of the symbol. May be zero if the size is unknown.
+ #[inline]
+ pub fn size(&self) -> u64 {
+ self.size
+ }
+}
+
+/// A map from addresses to symbols.
+#[derive(Debug)]
+pub struct SymbolMap<'data> {
+ symbols: Vec<Symbol<'data>>,
+}
+
+impl<'data> SymbolMap<'data> {
+ /// Get the symbol containing the given address.
+ pub fn get(&self, address: u64) -> Option<&Symbol<'data>> {
+ self.symbols
+ .binary_search_by(|symbol| {
+ if address < symbol.address {
+ std::cmp::Ordering::Greater
+ } else if address < symbol.address + symbol.size {
+ std::cmp::Ordering::Equal
+ } else {
+ std::cmp::Ordering::Less
+ }
+ })
+ .ok()
+ .and_then(|index| self.symbols.get(index))
+ }
+
+ /// Get all symbols in the map.
+ pub fn symbols(&self) -> &[Symbol<'data>] {
+ &self.symbols
+ }
+
+ /// Return true for symbols that should be included in the map.
+ fn filter(symbol: &Symbol<'_>) -> bool {
+ match symbol.kind() {
+ SymbolKind::Unknown | SymbolKind::Text | SymbolKind::Data => {}
+ SymbolKind::Null
+ | SymbolKind::Section
+ | SymbolKind::File
+ | SymbolKind::Label
+ | SymbolKind::Common
+ | SymbolKind::Tls => {
+ return false;
+ }
+ }
+ !symbol.is_undefined() && symbol.size() > 0
+ }
+}
+
+/// The target referenced by a relocation.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum RelocationTarget {
+ /// The target is a symbol.
+ Symbol(SymbolIndex),
+ /// The target is a section.
+ Section(SectionIndex),
+}
+
+/// A relocation entry.
+#[derive(Debug)]
+pub struct Relocation {
+ kind: RelocationKind,
+ encoding: RelocationEncoding,
+ size: u8,
+ target: RelocationTarget,
+ addend: i64,
+ implicit_addend: bool,
+}
+
+impl Relocation {
+ /// The operation used to calculate the result of the relocation.
+ #[inline]
+ pub fn kind(&self) -> RelocationKind {
+ self.kind
+ }
+
+ /// Information about how the result of the relocation operation is encoded in the place.
+ #[inline]
+ pub fn encoding(&self) -> RelocationEncoding {
+ self.encoding
+ }
+
+ /// The size in bits of the place of the relocation.
+ ///
+ /// If 0, then the size is determined by the relocation kind.
+ #[inline]
+ pub fn size(&self) -> u8 {
+ self.size
+ }
+
+ /// The target of the relocation.
+ #[inline]
+ pub fn target(&self) -> RelocationTarget {
+ self.target
+ }
+
+ /// The addend to use in the relocation calculation.
+ pub fn addend(&self) -> i64 {
+ self.addend
+ }
+
+ /// Set the addend to use in the relocation calculation.
+ pub fn set_addend(&mut self, addend: i64) {
+ self.addend = addend
+ }
+
+ /// Returns true if there is an implicit addend stored in the data at the offset
+ /// to be relocated.
+ pub fn has_implicit_addend(&self) -> bool {
+ self.implicit_addend
+ }
+}
+
+fn data_range(data: &[u8], data_address: u64, range_address: u64, size: u64) -> Option<&[u8]> {
+ if range_address >= data_address {
+ let start_offset = (range_address - data_address) as usize;
+ let end_offset = start_offset + size as usize;
+ if end_offset <= data.len() {
+ return Some(&data[start_offset..end_offset]);
+ }
+ }
+ None
+}
diff --git a/third_party/rust/object/src/read/pe.rs b/third_party/rust/object/src/read/pe.rs
new file mode 100644
index 0000000000..49d3fe83ce
--- /dev/null
+++ b/third_party/rust/object/src/read/pe.rs
@@ -0,0 +1,407 @@
+use crate::alloc::borrow::Cow;
+use crate::alloc::vec::Vec;
+use goblin::pe;
+use std::{cmp, iter, slice};
+use target_lexicon::Architecture;
+
+use crate::read::{
+ self, Object, ObjectSection, ObjectSegment, Relocation, SectionIndex, SectionKind, Symbol,
+ SymbolIndex, SymbolKind, SymbolMap, SymbolScope,
+};
+
+/// A PE object file.
+#[derive(Debug)]
+pub struct PeFile<'data> {
+ pe: pe::PE<'data>,
+ data: &'data [u8],
+}
+
+impl<'data> PeFile<'data> {
+ /// Get the PE headers of the file.
+ // TODO: this is temporary to allow access to features this crate doesn't provide yet
+ #[inline]
+ pub fn pe(&self) -> &pe::PE<'data> {
+ &self.pe
+ }
+
+ /// Parse the raw PE file data.
+ pub fn parse(data: &'data [u8]) -> Result<Self, &'static str> {
+ let pe = pe::PE::parse(data).map_err(|_| "Could not parse PE header")?;
+ Ok(PeFile { pe, data })
+ }
+
+ fn section_alignment(&self) -> u64 {
+ u64::from(
+ self.pe
+ .header
+ .optional_header
+ .map(|h| h.windows_fields.section_alignment)
+ .unwrap_or(0x1000),
+ )
+ }
+}
+
+impl<'data, 'file> Object<'data, 'file> for PeFile<'data>
+where
+ 'data: 'file,
+{
+ type Segment = PeSegment<'data, 'file>;
+ type SegmentIterator = PeSegmentIterator<'data, 'file>;
+ type Section = PeSection<'data, 'file>;
+ type SectionIterator = PeSectionIterator<'data, 'file>;
+ type SymbolIterator = PeSymbolIterator<'data, 'file>;
+
+ fn architecture(&self) -> Architecture {
+ match self.pe.header.coff_header.machine {
+ // TODO: Arm/Arm64
+ pe::header::COFF_MACHINE_X86 => Architecture::I386,
+ pe::header::COFF_MACHINE_X86_64 => Architecture::X86_64,
+ _ => Architecture::Unknown,
+ }
+ }
+
+ #[inline]
+ fn is_little_endian(&self) -> bool {
+ // TODO: always little endian? The COFF header has some bits in the
+ // characteristics flags, but these are obsolete.
+ true
+ }
+
+ #[inline]
+ fn is_64(&self) -> bool {
+ self.pe.is_64
+ }
+
+ fn segments(&'file self) -> PeSegmentIterator<'data, 'file> {
+ PeSegmentIterator {
+ file: self,
+ iter: self.pe.sections.iter(),
+ }
+ }
+
+ fn section_by_name(&'file self, section_name: &str) -> Option<PeSection<'data, 'file>> {
+ self.sections()
+ .find(|section| section.name() == Some(section_name))
+ }
+
+ fn section_by_index(&'file self, index: SectionIndex) -> Option<PeSection<'data, 'file>> {
+ self.sections().find(|section| section.index() == index)
+ }
+
+ fn sections(&'file self) -> PeSectionIterator<'data, 'file> {
+ PeSectionIterator {
+ file: self,
+ iter: self.pe.sections.iter().enumerate(),
+ }
+ }
+
+ fn symbol_by_index(&self, _index: SymbolIndex) -> Option<Symbol<'data>> {
+ // TODO: return COFF symbols for object files
+ None
+ }
+
+ fn symbols(&'file self) -> PeSymbolIterator<'data, 'file> {
+ // TODO: return COFF symbols for object files
+ PeSymbolIterator {
+ index: 0,
+ exports: [].iter(),
+ imports: [].iter(),
+ }
+ }
+
+ fn dynamic_symbols(&'file self) -> PeSymbolIterator<'data, 'file> {
+ PeSymbolIterator {
+ index: 0,
+ exports: self.pe.exports.iter(),
+ imports: self.pe.imports.iter(),
+ }
+ }
+
+ fn symbol_map(&self) -> SymbolMap<'data> {
+ // TODO: untested
+ let mut symbols: Vec<_> = self
+ .symbols()
+ .map(|(_, s)| s)
+ .filter(SymbolMap::filter)
+ .collect();
+ symbols.sort_by_key(|x| x.address);
+ SymbolMap { symbols }
+ }
+
+ fn has_debug_symbols(&self) -> bool {
+ // TODO: check if CodeView-in-PE still works
+ for section in &self.pe.sections {
+ if let Ok(name) = section.name() {
+ if name == ".debug_info" {
+ return true;
+ }
+ }
+ }
+ false
+ }
+
+ fn entry(&self) -> u64 {
+ self.pe.entry as u64
+ }
+}
+
+/// An iterator over the loadable sections of a `PeFile`.
+#[derive(Debug)]
+pub struct PeSegmentIterator<'data, 'file>
+where
+ 'data: 'file,
+{
+ file: &'file PeFile<'data>,
+ iter: slice::Iter<'file, pe::section_table::SectionTable>,
+}
+
+impl<'data, 'file> Iterator for PeSegmentIterator<'data, 'file> {
+ type Item = PeSegment<'data, 'file>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next().map(|section| PeSegment {
+ file: self.file,
+ section,
+ })
+ }
+}
+
+/// A loadable section of a `PeFile`.
+#[derive(Debug)]
+pub struct PeSegment<'data, 'file>
+where
+ 'data: 'file,
+{
+ file: &'file PeFile<'data>,
+ section: &'file pe::section_table::SectionTable,
+}
+
+impl<'data, 'file> ObjectSegment<'data> for PeSegment<'data, 'file> {
+ #[inline]
+ fn address(&self) -> u64 {
+ u64::from(self.section.virtual_address)
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ u64::from(self.section.virtual_size)
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ self.file.section_alignment()
+ }
+
+ #[inline]
+ fn file_range(&self) -> (u64, u64) {
+ (
+ self.section.pointer_to_raw_data as u64,
+ self.section.size_of_raw_data as u64,
+ )
+ }
+
+ fn data(&self) -> &'data [u8] {
+ let offset = self.section.pointer_to_raw_data as usize;
+ let size = cmp::min(self.section.virtual_size, self.section.size_of_raw_data) as usize;
+ &self.file.data[offset..][..size]
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]> {
+ read::data_range(self.data(), self.address(), address, size)
+ }
+
+ #[inline]
+ fn name(&self) -> Option<&str> {
+ self.section.name().ok()
+ }
+}
+
+/// An iterator over the sections of a `PeFile`.
+#[derive(Debug)]
+pub struct PeSectionIterator<'data, 'file>
+where
+ 'data: 'file,
+{
+ file: &'file PeFile<'data>,
+ iter: iter::Enumerate<slice::Iter<'file, pe::section_table::SectionTable>>,
+}
+
+impl<'data, 'file> Iterator for PeSectionIterator<'data, 'file> {
+ type Item = PeSection<'data, 'file>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next().map(|(index, section)| PeSection {
+ file: self.file,
+ index: SectionIndex(index),
+ section,
+ })
+ }
+}
+
+/// A section of a `PeFile`.
+#[derive(Debug)]
+pub struct PeSection<'data, 'file>
+where
+ 'data: 'file,
+{
+ file: &'file PeFile<'data>,
+ index: SectionIndex,
+ section: &'file pe::section_table::SectionTable,
+}
+
+impl<'data, 'file> PeSection<'data, 'file> {
+ fn raw_data(&self) -> &'data [u8] {
+ let offset = self.section.pointer_to_raw_data as usize;
+ let size = cmp::min(self.section.virtual_size, self.section.size_of_raw_data) as usize;
+ &self.file.data[offset..][..size]
+ }
+}
+
+impl<'data, 'file> ObjectSection<'data> for PeSection<'data, 'file> {
+ type RelocationIterator = PeRelocationIterator;
+
+ #[inline]
+ fn index(&self) -> SectionIndex {
+ self.index
+ }
+
+ #[inline]
+ fn address(&self) -> u64 {
+ u64::from(self.section.virtual_address)
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ u64::from(self.section.virtual_size)
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ self.file.section_alignment()
+ }
+
+ #[inline]
+ fn file_range(&self) -> Option<(u64, u64)> {
+ Some((
+ self.section.pointer_to_raw_data as u64,
+ self.section.size_of_raw_data as u64,
+ ))
+ }
+
+ fn data(&self) -> Cow<'data, [u8]> {
+ Cow::from(self.raw_data())
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]> {
+ read::data_range(self.raw_data(), self.address(), address, size)
+ }
+
+ #[inline]
+ fn uncompressed_data(&self) -> Cow<'data, [u8]> {
+ // TODO: does PE support compression?
+ self.data()
+ }
+
+ fn name(&self) -> Option<&str> {
+ self.section.name().ok()
+ }
+
+ #[inline]
+ fn segment_name(&self) -> Option<&str> {
+ None
+ }
+
+ #[inline]
+ fn kind(&self) -> SectionKind {
+ if self.section.characteristics
+ & (pe::section_table::IMAGE_SCN_CNT_CODE | pe::section_table::IMAGE_SCN_MEM_EXECUTE)
+ != 0
+ {
+ SectionKind::Text
+ } else if self.section.characteristics & pe::section_table::IMAGE_SCN_CNT_INITIALIZED_DATA
+ != 0
+ {
+ SectionKind::Data
+ } else if self.section.characteristics & pe::section_table::IMAGE_SCN_CNT_UNINITIALIZED_DATA
+ != 0
+ {
+ SectionKind::UninitializedData
+ } else {
+ SectionKind::Unknown
+ }
+ }
+
+ fn relocations(&self) -> PeRelocationIterator {
+ PeRelocationIterator
+ }
+}
+
+/// An iterator over the symbols of a `PeFile`.
+#[derive(Debug)]
+pub struct PeSymbolIterator<'data, 'file>
+where
+ 'data: 'file,
+{
+ index: usize,
+ exports: slice::Iter<'file, pe::export::Export<'data>>,
+ imports: slice::Iter<'file, pe::import::Import<'data>>,
+}
+
+impl<'data, 'file> Iterator for PeSymbolIterator<'data, 'file> {
+ type Item = (SymbolIndex, Symbol<'data>);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if let Some(export) = self.exports.next() {
+ let index = SymbolIndex(self.index);
+ self.index += 1;
+ return Some((
+ index,
+ Symbol {
+ name: export.name,
+ address: export.rva as u64,
+ size: 0,
+ kind: SymbolKind::Unknown,
+ // TODO: can we find a section?
+ section_index: None,
+ undefined: false,
+ weak: false,
+ scope: SymbolScope::Dynamic,
+ },
+ ));
+ }
+ if let Some(import) = self.imports.next() {
+ let index = SymbolIndex(self.index);
+ self.index += 1;
+ let name = match import.name {
+ Cow::Borrowed(name) => Some(name),
+ _ => None,
+ };
+ return Some((
+ index,
+ Symbol {
+ name,
+ address: 0,
+ size: 0,
+ kind: SymbolKind::Unknown,
+ section_index: None,
+ undefined: true,
+ weak: false,
+ scope: SymbolScope::Dynamic,
+ },
+ ));
+ }
+ None
+ }
+}
+
+/// An iterator over the relocations in an `PeSection`.
+#[derive(Debug)]
+pub struct PeRelocationIterator;
+
+impl Iterator for PeRelocationIterator {
+ type Item = (u64, Relocation);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
diff --git a/third_party/rust/object/src/read/traits.rs b/third_party/rust/object/src/read/traits.rs
new file mode 100644
index 0000000000..70b11e798a
--- /dev/null
+++ b/third_party/rust/object/src/read/traits.rs
@@ -0,0 +1,220 @@
+use crate::alloc::borrow::Cow;
+use crate::{Relocation, SectionIndex, SectionKind, Symbol, SymbolIndex, SymbolMap};
+use target_lexicon::{Architecture, Endianness};
+use uuid::Uuid;
+
+/// An object file.
+pub trait Object<'data, 'file> {
+ /// A segment in the object file.
+ type Segment: ObjectSegment<'data>;
+
+ /// An iterator over the segments in the object file.
+ type SegmentIterator: Iterator<Item = Self::Segment>;
+
+ /// A section in the object file.
+ type Section: ObjectSection<'data>;
+
+ /// An iterator over the sections in the object file.
+ type SectionIterator: Iterator<Item = Self::Section>;
+
+ /// An iterator over the symbols in the object file.
+ type SymbolIterator: Iterator<Item = (SymbolIndex, Symbol<'data>)>;
+
+ /// Get the architecture type of the file.
+ fn architecture(&self) -> Architecture;
+
+ /// Get the endianness of the file.
+ #[inline]
+ fn endianness(&self) -> Endianness {
+ if self.is_little_endian() {
+ Endianness::Little
+ } else {
+ Endianness::Big
+ }
+ }
+
+ /// Return true if the file is little endian, false if it is big endian.
+ fn is_little_endian(&self) -> bool;
+
+ /// Return true if the file can contain 64-bit addresses.
+ fn is_64(&self) -> bool;
+
+ /// Get an iterator over the segments in the file.
+ fn segments(&'file self) -> Self::SegmentIterator;
+
+ /// Get the entry point address of the binary
+ fn entry(&'file self) -> u64;
+
+ /// Get the section named `section_name`, if such a section exists.
+ ///
+ /// If `section_name` starts with a '.' then it is treated as a system section name,
+ /// and is compared using the conventions specific to the object file format. This
+ /// includes:
+ /// - if ".text" is requested for a Mach-O object file, then the actual
+ /// section name that is searched for is "__text".
+ /// - if ".debug_info" is requested for an ELF object file, then
+ /// ".zdebug_info" may be returned (and similarly for other debug sections).
+ ///
+ /// For some object files, multiple segments may contain sections with the same
+ /// name. In this case, the first matching section will be used.
+ fn section_by_name(&'file self, section_name: &str) -> Option<Self::Section>;
+
+ /// Get the section at the given index.
+ ///
+ /// The meaning of the index depends on the object file.
+ ///
+ /// For some object files, this requires iterating through all sections.
+ fn section_by_index(&'file self, index: SectionIndex) -> Option<Self::Section>;
+
+ /// Get the contents of the section named `section_name`, if such
+ /// a section exists.
+ ///
+ /// The `section_name` is interpreted according to `Self::section_by_name`.
+ ///
+ /// This may decompress section data.
+ fn section_data_by_name(&'file self, section_name: &str) -> Option<Cow<'data, [u8]>> {
+ self.section_by_name(section_name)
+ .map(|section| section.uncompressed_data())
+ }
+
+ /// Get an iterator over the sections in the file.
+ fn sections(&'file self) -> Self::SectionIterator;
+
+ /// Get the debugging symbol at the given index.
+ ///
+ /// This is similar to `self.symbols().nth(index)`, except that
+ /// the index will take into account malformed or unsupported symbols.
+ fn symbol_by_index(&self, index: SymbolIndex) -> Option<Symbol<'data>>;
+
+ /// Get an iterator over the debugging symbols in the file.
+ ///
+ /// This may skip over symbols that are malformed or unsupported.
+ fn symbols(&'file self) -> Self::SymbolIterator;
+
+ /// Get the data for the given symbol.
+ fn symbol_data(&'file self, symbol: &Symbol<'data>) -> Option<&'data [u8]> {
+ if symbol.is_undefined() {
+ return None;
+ }
+ let address = symbol.address();
+ let size = symbol.size();
+ if let Some(index) = symbol.section_index() {
+ self.section_by_index(index)
+ .and_then(|section| section.data_range(address, size))
+ } else {
+ self.segments()
+ .find_map(|segment| segment.data_range(address, size))
+ }
+ }
+
+ /// Get an iterator over the dynamic linking symbols in the file.
+ ///
+ /// This may skip over symbols that are malformed or unsupported.
+ fn dynamic_symbols(&'file self) -> Self::SymbolIterator;
+
+ /// Construct a map from addresses to symbols.
+ fn symbol_map(&self) -> SymbolMap<'data>;
+
+ /// Return true if the file contains debug information sections, false if not.
+ fn has_debug_symbols(&self) -> bool;
+
+ /// The UUID from a Mach-O `LC_UUID` load command.
+ #[inline]
+ fn mach_uuid(&self) -> Option<Uuid> {
+ None
+ }
+
+ /// The build ID from an ELF `NT_GNU_BUILD_ID` note.
+ #[inline]
+ fn build_id(&self) -> Option<&'data [u8]> {
+ None
+ }
+
+ /// The filename and CRC from a `.gnu_debuglink` section.
+ #[inline]
+ fn gnu_debuglink(&self) -> Option<(&'data [u8], u32)> {
+ None
+ }
+}
+
+/// A loadable segment defined in an object file.
+///
+/// For ELF, this is a program header with type `PT_LOAD`.
+/// For Mach-O, this is a load command with type `LC_SEGMENT` or `LC_SEGMENT_64`.
+pub trait ObjectSegment<'data> {
+ /// Returns the virtual address of the segment.
+ fn address(&self) -> u64;
+
+ /// Returns the size of the segment in memory.
+ fn size(&self) -> u64;
+
+ /// Returns the alignment of the segment in memory.
+ fn align(&self) -> u64;
+
+ /// Returns the offset and size of the segment in the file.
+ fn file_range(&self) -> (u64, u64);
+
+ /// Returns a reference to the file contents of the segment.
+ /// The length of this data may be different from the size of the
+ /// segment in memory.
+ fn data(&self) -> &'data [u8];
+
+ /// Return the segment data in the given range.
+ fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]>;
+
+ /// Returns the name of the segment.
+ fn name(&self) -> Option<&str>;
+}
+
+/// A section defined in an object file.
+pub trait ObjectSection<'data> {
+ /// An iterator over the relocations for a section.
+ ///
+ /// The first field in the item tuple is the section offset
+ /// that the relocation applies to.
+ type RelocationIterator: Iterator<Item = (u64, Relocation)>;
+
+ /// Returns the section index.
+ fn index(&self) -> SectionIndex;
+
+ /// Returns the address of the section.
+ fn address(&self) -> u64;
+
+ /// Returns the size of the section in memory.
+ fn size(&self) -> u64;
+
+ /// Returns the alignment of the section in memory.
+ fn align(&self) -> u64;
+
+ /// Returns offset and size of on-disk segment (if any)
+ fn file_range(&self) -> Option<(u64, u64)>;
+
+ /// Returns the raw contents of the section.
+ /// The length of this data may be different from the size of the
+ /// section in memory.
+ ///
+ /// This does not do any decompression.
+ fn data(&self) -> Cow<'data, [u8]>;
+
+ /// Return the raw contents of the section data in the given range.
+ ///
+ /// This does not do any decompression.
+ fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]>;
+
+ /// Returns the uncompressed contents of the section.
+ /// The length of this data may be different from the size of the
+ /// section in memory.
+ fn uncompressed_data(&self) -> Cow<'data, [u8]>;
+
+ /// Returns the name of the section.
+ fn name(&self) -> Option<&str>;
+
+ /// Returns the name of the segment for this section.
+ fn segment_name(&self) -> Option<&str>;
+
+ /// Return the kind of this section.
+ fn kind(&self) -> SectionKind;
+
+ /// Get the relocations for this section.
+ fn relocations(&self) -> Self::RelocationIterator;
+}
diff --git a/third_party/rust/object/src/read/wasm.rs b/third_party/rust/object/src/read/wasm.rs
new file mode 100644
index 0000000000..e13343e5b1
--- /dev/null
+++ b/third_party/rust/object/src/read/wasm.rs
@@ -0,0 +1,315 @@
+use crate::alloc::vec::Vec;
+use parity_wasm::elements::{self, Deserialize};
+use std::borrow::Cow;
+use std::{iter, slice};
+use target_lexicon::Architecture;
+
+use crate::read::{
+ Object, ObjectSection, ObjectSegment, Relocation, SectionIndex, SectionKind, Symbol,
+ SymbolIndex, SymbolMap,
+};
+
+/// A WebAssembly object file.
+#[derive(Debug)]
+pub struct WasmFile {
+ module: elements::Module,
+}
+
+impl<'data> WasmFile {
+ /// Parse the raw wasm data.
+ pub fn parse(mut data: &'data [u8]) -> Result<Self, &'static str> {
+ let module =
+ elements::Module::deserialize(&mut data).map_err(|_| "failed to parse wasm")?;
+ Ok(WasmFile { module })
+ }
+}
+
+fn serialize_to_cow<'a, S>(s: S) -> Option<Cow<'a, [u8]>>
+where
+ S: elements::Serialize,
+{
+ let mut buf = Vec::new();
+ s.serialize(&mut buf).ok()?;
+ Some(Cow::from(buf))
+}
+
+impl<'file> Object<'static, 'file> for WasmFile {
+ type Segment = WasmSegment<'file>;
+ type SegmentIterator = WasmSegmentIterator<'file>;
+ type Section = WasmSection<'file>;
+ type SectionIterator = WasmSectionIterator<'file>;
+ type SymbolIterator = WasmSymbolIterator<'file>;
+
+ #[inline]
+ fn architecture(&self) -> Architecture {
+ Architecture::Wasm32
+ }
+
+ #[inline]
+ fn is_little_endian(&self) -> bool {
+ true
+ }
+
+ #[inline]
+ fn is_64(&self) -> bool {
+ false
+ }
+
+ fn segments(&'file self) -> Self::SegmentIterator {
+ WasmSegmentIterator { file: self }
+ }
+
+ fn entry(&'file self) -> u64 {
+ self.module
+ .start_section()
+ .map_or(u64::max_value(), u64::from)
+ }
+
+ fn section_by_name(&'file self, section_name: &str) -> Option<WasmSection<'file>> {
+ self.sections()
+ .find(|section| section.name() == Some(section_name))
+ }
+
+ fn section_by_index(&'file self, index: SectionIndex) -> Option<WasmSection<'file>> {
+ self.sections().find(|section| section.index() == index)
+ }
+
+ fn sections(&'file self) -> Self::SectionIterator {
+ WasmSectionIterator {
+ sections: self.module.sections().iter().enumerate(),
+ }
+ }
+
+ fn symbol_by_index(&self, _index: SymbolIndex) -> Option<Symbol<'static>> {
+ unimplemented!()
+ }
+
+ fn symbols(&'file self) -> Self::SymbolIterator {
+ WasmSymbolIterator { file: self }
+ }
+
+ fn dynamic_symbols(&'file self) -> Self::SymbolIterator {
+ WasmSymbolIterator { file: self }
+ }
+
+ fn symbol_map(&self) -> SymbolMap<'static> {
+ SymbolMap {
+ symbols: Vec::new(),
+ }
+ }
+
+ fn has_debug_symbols(&self) -> bool {
+ // We ignore the "name" section, and use this to mean whether the wasm
+ // has DWARF.
+ self.module.sections().iter().any(|s| match *s {
+ elements::Section::Custom(ref c) => c.name().starts_with(".debug_"),
+ _ => false,
+ })
+ }
+}
+
+/// An iterator over the segments of an `WasmFile`.
+#[derive(Debug)]
+pub struct WasmSegmentIterator<'file> {
+ file: &'file WasmFile,
+}
+
+impl<'file> Iterator for WasmSegmentIterator<'file> {
+ type Item = WasmSegment<'file>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
+
+/// A segment of an `WasmFile`.
+#[derive(Debug)]
+pub struct WasmSegment<'file> {
+ file: &'file WasmFile,
+}
+
+impl<'file> ObjectSegment<'static> for WasmSegment<'file> {
+ #[inline]
+ fn address(&self) -> u64 {
+ unreachable!()
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ unreachable!()
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ unreachable!()
+ }
+
+ #[inline]
+ fn file_range(&self) -> (u64, u64) {
+ unreachable!()
+ }
+
+ fn data(&self) -> &'static [u8] {
+ unreachable!()
+ }
+
+ fn data_range(&self, _address: u64, _size: u64) -> Option<&'static [u8]> {
+ unreachable!()
+ }
+
+ #[inline]
+ fn name(&self) -> Option<&str> {
+ unreachable!()
+ }
+}
+
+/// An iterator over the sections of an `WasmFile`.
+#[derive(Debug)]
+pub struct WasmSectionIterator<'file> {
+ sections: iter::Enumerate<slice::Iter<'file, elements::Section>>,
+}
+
+impl<'file> Iterator for WasmSectionIterator<'file> {
+ type Item = WasmSection<'file>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.sections.next().map(|(index, section)| WasmSection {
+ index: SectionIndex(index),
+ section,
+ })
+ }
+}
+
+/// A section of an `WasmFile`.
+#[derive(Debug)]
+pub struct WasmSection<'file> {
+ index: SectionIndex,
+ section: &'file elements::Section,
+}
+
+impl<'file> ObjectSection<'static> for WasmSection<'file> {
+ type RelocationIterator = WasmRelocationIterator;
+
+ #[inline]
+ fn index(&self) -> SectionIndex {
+ self.index
+ }
+
+ #[inline]
+ fn address(&self) -> u64 {
+ 1
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ serialize_to_cow(self.section.clone()).map_or(0, |b| b.len() as u64)
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ 1
+ }
+
+ #[inline]
+ fn file_range(&self) -> Option<(u64, u64)> {
+ None
+ }
+
+ fn data(&self) -> Cow<'static, [u8]> {
+ match *self.section {
+ elements::Section::Custom(ref section) => Some(section.payload().to_vec().into()),
+ elements::Section::Start(section) => {
+ serialize_to_cow(elements::VarUint32::from(section))
+ }
+ _ => serialize_to_cow(self.section.clone()),
+ }
+ .unwrap_or_else(|| Cow::from(&[][..]))
+ }
+
+ fn data_range(&self, _address: u64, _size: u64) -> Option<&'static [u8]> {
+ unimplemented!()
+ }
+
+ #[inline]
+ fn uncompressed_data(&self) -> Cow<'static, [u8]> {
+ // TODO: does wasm support compression?
+ self.data()
+ }
+
+ fn name(&self) -> Option<&str> {
+ match *self.section {
+ elements::Section::Unparsed { .. } => None,
+ elements::Section::Custom(ref c) => Some(c.name()),
+ elements::Section::Type(_) => Some("Type"),
+ elements::Section::Import(_) => Some("Import"),
+ elements::Section::Function(_) => Some("Function"),
+ elements::Section::Table(_) => Some("Table"),
+ elements::Section::Memory(_) => Some("Memory"),
+ elements::Section::Global(_) => Some("Global"),
+ elements::Section::Export(_) => Some("Export"),
+ elements::Section::Start(_) => Some("Start"),
+ elements::Section::Element(_) => Some("Element"),
+ elements::Section::Code(_) => Some("Code"),
+ elements::Section::DataCount(_) => Some("DataCount"),
+ elements::Section::Data(_) => Some("Data"),
+ elements::Section::Name(_) => Some("Name"),
+ elements::Section::Reloc(_) => Some("Reloc"),
+ }
+ }
+
+ #[inline]
+ fn segment_name(&self) -> Option<&str> {
+ None
+ }
+
+ fn kind(&self) -> SectionKind {
+ match *self.section {
+ elements::Section::Unparsed { .. } => SectionKind::Unknown,
+ elements::Section::Custom(_) => SectionKind::Unknown,
+ elements::Section::Type(_) => SectionKind::Other,
+ elements::Section::Import(_) => SectionKind::Other,
+ elements::Section::Function(_) => SectionKind::Other,
+ elements::Section::Table(_) => SectionKind::Other,
+ elements::Section::Memory(_) => SectionKind::Other,
+ elements::Section::Global(_) => SectionKind::Other,
+ elements::Section::Export(_) => SectionKind::Other,
+ elements::Section::Start(_) => SectionKind::Other,
+ elements::Section::Element(_) => SectionKind::Other,
+ elements::Section::Code(_) => SectionKind::Text,
+ elements::Section::DataCount(_) => SectionKind::Other,
+ elements::Section::Data(_) => SectionKind::Data,
+ elements::Section::Name(_) => SectionKind::Other,
+ elements::Section::Reloc(_) => SectionKind::Other,
+ }
+ }
+
+ fn relocations(&self) -> WasmRelocationIterator {
+ WasmRelocationIterator
+ }
+}
+
+/// An iterator over the symbols of an `WasmFile`.
+#[derive(Debug)]
+pub struct WasmSymbolIterator<'file> {
+ file: &'file WasmFile,
+}
+
+impl<'file> Iterator for WasmSymbolIterator<'file> {
+ type Item = (SymbolIndex, Symbol<'static>);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ unimplemented!()
+ }
+}
+
+/// An iterator over the relocations in an `WasmSection`.
+#[derive(Debug)]
+pub struct WasmRelocationIterator;
+
+impl Iterator for WasmRelocationIterator {
+ type Item = (u64, Relocation);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}