summaryrefslogtreecommitdiffstats
path: root/third_party/rust/object/src/read/xcoff
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/object/src/read/xcoff
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/object/src/read/xcoff')
-rw-r--r--third_party/rust/object/src/read/xcoff/comdat.rs130
-rw-r--r--third_party/rust/object/src/read/xcoff/file.rs629
-rw-r--r--third_party/rust/object/src/read/xcoff/mod.rs21
-rw-r--r--third_party/rust/object/src/read/xcoff/relocation.rs128
-rw-r--r--third_party/rust/object/src/read/xcoff/section.rs426
-rw-r--r--third_party/rust/object/src/read/xcoff/segment.rs115
-rw-r--r--third_party/rust/object/src/read/xcoff/symbol.rs634
7 files changed, 2083 insertions, 0 deletions
diff --git a/third_party/rust/object/src/read/xcoff/comdat.rs b/third_party/rust/object/src/read/xcoff/comdat.rs
new file mode 100644
index 0000000000..eeed2f54d6
--- /dev/null
+++ b/third_party/rust/object/src/read/xcoff/comdat.rs
@@ -0,0 +1,130 @@
+//! XCOFF doesn't support the COMDAT section.
+
+use core::fmt::Debug;
+
+use crate::xcoff;
+
+use crate::read::{self, ComdatKind, ObjectComdat, ReadRef, Result, SectionIndex, SymbolIndex};
+
+use super::{FileHeader, XcoffFile};
+
+/// An iterator over the COMDAT section groups of a `XcoffFile32`.
+pub type XcoffComdatIterator32<'data, 'file, R = &'data [u8]> =
+ XcoffComdatIterator<'data, 'file, xcoff::FileHeader32, R>;
+/// An iterator over the COMDAT section groups of a `XcoffFile64`.
+pub type XcoffComdatIterator64<'data, 'file, R = &'data [u8]> =
+ XcoffComdatIterator<'data, 'file, xcoff::FileHeader64, R>;
+
+/// An iterator over the COMDAT section groups of a `XcoffFile`.
+#[derive(Debug)]
+pub struct XcoffComdatIterator<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ #[allow(unused)]
+ pub(crate) file: &'file XcoffFile<'data, Xcoff, R>,
+}
+
+impl<'data, 'file, Xcoff, R> Iterator for XcoffComdatIterator<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ type Item = XcoffComdat<'data, 'file, Xcoff, R>;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
+
+/// A COMDAT section group of a `XcoffFile32`.
+pub type XcoffComdat32<'data, 'file, R = &'data [u8]> =
+ XcoffComdat<'data, 'file, xcoff::FileHeader32, R>;
+
+/// A COMDAT section group of a `XcoffFile64`.
+pub type XcoffComdat64<'data, 'file, R = &'data [u8]> =
+ XcoffComdat<'data, 'file, xcoff::FileHeader64, R>;
+
+/// A COMDAT section group of a `XcoffFile`.
+#[derive(Debug)]
+pub struct XcoffComdat<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ #[allow(unused)]
+ file: &'file XcoffFile<'data, Xcoff, R>,
+}
+
+impl<'data, 'file, Xcoff, R> read::private::Sealed for XcoffComdat<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Xcoff, R> ObjectComdat<'data> for XcoffComdat<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ type SectionIterator = XcoffComdatSectionIterator<'data, 'file, Xcoff, R>;
+
+ #[inline]
+ fn kind(&self) -> ComdatKind {
+ unreachable!();
+ }
+
+ #[inline]
+ fn symbol(&self) -> SymbolIndex {
+ unreachable!();
+ }
+
+ #[inline]
+ fn name_bytes(&self) -> Result<&[u8]> {
+ unreachable!();
+ }
+
+ #[inline]
+ fn name(&self) -> Result<&str> {
+ unreachable!();
+ }
+
+ #[inline]
+ fn sections(&self) -> Self::SectionIterator {
+ unreachable!();
+ }
+}
+
+/// An iterator over the sections in a COMDAT section group of a `XcoffFile32`.
+pub type XcoffComdatSectionIterator32<'data, 'file, R = &'data [u8]> =
+ XcoffComdatSectionIterator<'data, 'file, xcoff::FileHeader32, R>;
+/// An iterator over the sections in a COMDAT section group of a `XcoffFile64`.
+pub type XcoffComdatSectionIterator64<'data, 'file, R = &'data [u8]> =
+ XcoffComdatSectionIterator<'data, 'file, xcoff::FileHeader64, R>;
+
+/// An iterator over the sections in a COMDAT section group of a `XcoffFile`.
+#[derive(Debug)]
+pub struct XcoffComdatSectionIterator<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ 'data: 'file,
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ #[allow(unused)]
+ file: &'file XcoffFile<'data, Xcoff, R>,
+}
+
+impl<'data, 'file, Xcoff, R> Iterator for XcoffComdatSectionIterator<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ type Item = SectionIndex;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
diff --git a/third_party/rust/object/src/read/xcoff/file.rs b/third_party/rust/object/src/read/xcoff/file.rs
new file mode 100644
index 0000000000..bac9e70756
--- /dev/null
+++ b/third_party/rust/object/src/read/xcoff/file.rs
@@ -0,0 +1,629 @@
+use core::fmt::Debug;
+use core::mem;
+
+use alloc::vec::Vec;
+
+use crate::read::{self, Error, NoDynamicRelocationIterator, Object, ReadError, ReadRef, Result};
+
+use crate::{
+ xcoff, Architecture, BigEndian as BE, FileFlags, ObjectKind, ObjectSection, Pod, SectionIndex,
+ SymbolIndex,
+};
+
+use super::{
+ CsectAux, FileAux, SectionHeader, SectionTable, Symbol, SymbolTable, XcoffComdat,
+ XcoffComdatIterator, XcoffSection, XcoffSectionIterator, XcoffSegment, XcoffSegmentIterator,
+ XcoffSymbol, XcoffSymbolIterator, XcoffSymbolTable,
+};
+
+/// A 32-bit XCOFF object file.
+pub type XcoffFile32<'data, R = &'data [u8]> = XcoffFile<'data, xcoff::FileHeader32, R>;
+/// A 64-bit XCOFF object file.
+pub type XcoffFile64<'data, R = &'data [u8]> = XcoffFile<'data, xcoff::FileHeader64, R>;
+
+/// A partially parsed XCOFF file.
+///
+/// Most of the functionality of this type is provided by the `Object` trait implementation.
+#[derive(Debug)]
+pub struct XcoffFile<'data, Xcoff, R = &'data [u8]>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) data: R,
+ pub(super) header: &'data Xcoff,
+ pub(super) aux_header: Option<&'data Xcoff::AuxHeader>,
+ pub(super) sections: SectionTable<'data, Xcoff>,
+ pub(super) symbols: SymbolTable<'data, Xcoff, R>,
+}
+
+impl<'data, Xcoff, R> XcoffFile<'data, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ /// Parse the raw XCOFF file data.
+ pub fn parse(data: R) -> Result<Self> {
+ let mut offset = 0;
+ let header = Xcoff::parse(data, &mut offset)?;
+ let aux_header = header.aux_header(data, &mut offset)?;
+ let sections = header.sections(data, &mut offset)?;
+ let symbols = header.symbols(data)?;
+
+ Ok(XcoffFile {
+ data,
+ header,
+ aux_header,
+ sections,
+ symbols,
+ })
+ }
+
+ /// Returns the raw data.
+ pub fn data(&self) -> R {
+ self.data
+ }
+
+ /// Returns the raw XCOFF file header.
+ pub fn raw_header(&self) -> &'data Xcoff {
+ self.header
+ }
+}
+
+impl<'data, Xcoff, R> read::private::Sealed for XcoffFile<'data, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Xcoff, R> Object<'data, 'file> for XcoffFile<'data, Xcoff, R>
+where
+ 'data: 'file,
+ Xcoff: FileHeader,
+ R: 'file + ReadRef<'data>,
+{
+ type Segment = XcoffSegment<'data, 'file, Xcoff, R>;
+ type SegmentIterator = XcoffSegmentIterator<'data, 'file, Xcoff, R>;
+ type Section = XcoffSection<'data, 'file, Xcoff, R>;
+ type SectionIterator = XcoffSectionIterator<'data, 'file, Xcoff, R>;
+ type Comdat = XcoffComdat<'data, 'file, Xcoff, R>;
+ type ComdatIterator = XcoffComdatIterator<'data, 'file, Xcoff, R>;
+ type Symbol = XcoffSymbol<'data, 'file, Xcoff, R>;
+ type SymbolIterator = XcoffSymbolIterator<'data, 'file, Xcoff, R>;
+ type SymbolTable = XcoffSymbolTable<'data, 'file, Xcoff, R>;
+ type DynamicRelocationIterator = NoDynamicRelocationIterator;
+
+ fn architecture(&self) -> crate::Architecture {
+ if self.is_64() {
+ Architecture::PowerPc64
+ } else {
+ Architecture::PowerPc
+ }
+ }
+
+ fn is_little_endian(&self) -> bool {
+ false
+ }
+
+ fn is_64(&self) -> bool {
+ self.header.is_type_64()
+ }
+
+ fn kind(&self) -> ObjectKind {
+ let flags = self.header.f_flags();
+ if flags & xcoff::F_EXEC != 0 {
+ ObjectKind::Executable
+ } else if flags & xcoff::F_SHROBJ != 0 {
+ ObjectKind::Dynamic
+ } else if flags & xcoff::F_RELFLG == 0 {
+ ObjectKind::Relocatable
+ } else {
+ ObjectKind::Unknown
+ }
+ }
+
+ fn segments(&'file self) -> XcoffSegmentIterator<'data, 'file, Xcoff, R> {
+ XcoffSegmentIterator { file: self }
+ }
+
+ fn section_by_name_bytes(
+ &'file self,
+ section_name: &[u8],
+ ) -> Option<XcoffSection<'data, 'file, Xcoff, R>> {
+ self.sections()
+ .find(|section| section.name_bytes() == Ok(section_name))
+ }
+
+ fn section_by_index(
+ &'file self,
+ index: SectionIndex,
+ ) -> Result<XcoffSection<'data, 'file, Xcoff, R>> {
+ let section = self.sections.section(index)?;
+ Ok(XcoffSection {
+ file: self,
+ section,
+ index,
+ })
+ }
+
+ fn sections(&'file self) -> XcoffSectionIterator<'data, 'file, Xcoff, R> {
+ XcoffSectionIterator {
+ file: self,
+ iter: self.sections.iter().enumerate(),
+ }
+ }
+
+ fn comdats(&'file self) -> XcoffComdatIterator<'data, 'file, Xcoff, R> {
+ XcoffComdatIterator { file: self }
+ }
+
+ fn symbol_table(&'file self) -> Option<XcoffSymbolTable<'data, 'file, Xcoff, R>> {
+ if self.symbols.is_empty() {
+ return None;
+ }
+ Some(XcoffSymbolTable {
+ symbols: &self.symbols,
+ file: self,
+ })
+ }
+
+ fn symbol_by_index(
+ &'file self,
+ index: SymbolIndex,
+ ) -> Result<XcoffSymbol<'data, 'file, Xcoff, R>> {
+ let symbol = self.symbols.symbol(index.0)?;
+ Ok(XcoffSymbol {
+ symbols: &self.symbols,
+ index,
+ symbol,
+ file: self,
+ })
+ }
+
+ fn symbols(&'file self) -> XcoffSymbolIterator<'data, 'file, Xcoff, R> {
+ XcoffSymbolIterator {
+ symbols: &self.symbols,
+ index: 0,
+ file: self,
+ }
+ }
+
+ fn dynamic_symbol_table(&'file self) -> Option<XcoffSymbolTable<'data, 'file, Xcoff, R>> {
+ None
+ }
+
+ fn dynamic_symbols(&'file self) -> XcoffSymbolIterator<'data, 'file, Xcoff, R> {
+ // TODO: return the symbols in the STYP_LOADER section.
+ XcoffSymbolIterator {
+ file: self,
+ symbols: &self.symbols,
+ // Hack: don't return any.
+ index: self.symbols.len(),
+ }
+ }
+
+ fn dynamic_relocations(&'file self) -> Option<Self::DynamicRelocationIterator> {
+ // TODO: return the relocations in the STYP_LOADER section.
+ None
+ }
+
+ fn imports(&self) -> Result<alloc::vec::Vec<crate::Import<'data>>> {
+ // TODO: return the imports in the STYP_LOADER section.
+ Ok(Vec::new())
+ }
+
+ fn exports(&self) -> Result<alloc::vec::Vec<crate::Export<'data>>> {
+ // TODO: return the exports in the STYP_LOADER section.
+ Ok(Vec::new())
+ }
+
+ fn has_debug_symbols(&self) -> bool {
+ self.section_by_name(".debug").is_some() || self.section_by_name(".dwinfo").is_some()
+ }
+
+ fn relative_address_base(&'file self) -> u64 {
+ 0
+ }
+
+ fn entry(&'file self) -> u64 {
+ if let Some(aux_header) = self.aux_header {
+ aux_header.o_entry().into()
+ } else {
+ 0
+ }
+ }
+
+ fn flags(&self) -> FileFlags {
+ FileFlags::Xcoff {
+ f_flags: self.header.f_flags(),
+ }
+ }
+}
+
+/// A trait for generic access to `FileHeader32` and `FileHeader64`.
+#[allow(missing_docs)]
+pub trait FileHeader: Debug + Pod {
+ type Word: Into<u64>;
+ type AuxHeader: AuxHeader<Word = Self::Word>;
+ type SectionHeader: SectionHeader<Word = Self::Word>;
+ type Symbol: Symbol<Word = Self::Word>;
+ type FileAux: FileAux;
+ type CsectAux: CsectAux;
+
+ /// Return true if this type is a 64-bit header.
+ fn is_type_64(&self) -> bool;
+
+ fn f_magic(&self) -> u16;
+ fn f_nscns(&self) -> u16;
+ fn f_timdat(&self) -> u32;
+ fn f_symptr(&self) -> Self::Word;
+ fn f_nsyms(&self) -> u32;
+ fn f_opthdr(&self) -> u16;
+ fn f_flags(&self) -> u16;
+
+ // Provided methods.
+
+ /// Read the file header.
+ ///
+ /// Also checks that the magic field in the file header is a supported format.
+ fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> Result<&'data Self> {
+ let header = data
+ .read::<Self>(offset)
+ .read_error("Invalid XCOFF header size or alignment")?;
+ if !header.is_supported() {
+ return Err(Error("Unsupported XCOFF header"));
+ }
+ Ok(header)
+ }
+
+ fn is_supported(&self) -> bool {
+ (self.is_type_64() && self.f_magic() == xcoff::MAGIC_64)
+ || (!self.is_type_64() && self.f_magic() == xcoff::MAGIC_32)
+ }
+
+ /// Read the auxiliary file header.
+ fn aux_header<'data, R: ReadRef<'data>>(
+ &self,
+ data: R,
+ offset: &mut u64,
+ ) -> Result<Option<&'data Self::AuxHeader>> {
+ let aux_header_size = self.f_opthdr();
+ if self.f_flags() & xcoff::F_EXEC == 0 {
+ // No auxiliary header is required for an object file that is not an executable.
+ // TODO: Some AIX programs generate auxiliary headers for 32-bit object files
+ // that end after the data_start field.
+ *offset += u64::from(aux_header_size);
+ return Ok(None);
+ }
+ // Executables, however, must have auxiliary headers that include the
+ // full structure definitions.
+ if aux_header_size != mem::size_of::<Self::AuxHeader>() as u16 {
+ *offset += u64::from(aux_header_size);
+ return Ok(None);
+ }
+ let aux_header = data
+ .read::<Self::AuxHeader>(offset)
+ .read_error("Invalid XCOFF auxiliary header size")?;
+ Ok(Some(aux_header))
+ }
+
+ /// Read the section table.
+ #[inline]
+ fn sections<'data, R: ReadRef<'data>>(
+ &self,
+ data: R,
+ offset: &mut u64,
+ ) -> Result<SectionTable<'data, Self>> {
+ SectionTable::parse(self, data, offset)
+ }
+
+ /// Return the symbol table.
+ #[inline]
+ fn symbols<'data, R: ReadRef<'data>>(&self, data: R) -> Result<SymbolTable<'data, Self, R>> {
+ SymbolTable::parse(*self, data)
+ }
+}
+
+impl FileHeader for xcoff::FileHeader32 {
+ type Word = u32;
+ type AuxHeader = xcoff::AuxHeader32;
+ type SectionHeader = xcoff::SectionHeader32;
+ type Symbol = xcoff::Symbol32;
+ type FileAux = xcoff::FileAux32;
+ type CsectAux = xcoff::CsectAux32;
+
+ fn is_type_64(&self) -> bool {
+ false
+ }
+
+ fn f_magic(&self) -> u16 {
+ self.f_magic.get(BE)
+ }
+
+ fn f_nscns(&self) -> u16 {
+ self.f_nscns.get(BE)
+ }
+
+ fn f_timdat(&self) -> u32 {
+ self.f_timdat.get(BE)
+ }
+
+ fn f_symptr(&self) -> Self::Word {
+ self.f_symptr.get(BE)
+ }
+
+ fn f_nsyms(&self) -> u32 {
+ self.f_nsyms.get(BE)
+ }
+
+ fn f_opthdr(&self) -> u16 {
+ self.f_opthdr.get(BE)
+ }
+
+ fn f_flags(&self) -> u16 {
+ self.f_flags.get(BE)
+ }
+}
+
+impl FileHeader for xcoff::FileHeader64 {
+ type Word = u64;
+ type AuxHeader = xcoff::AuxHeader64;
+ type SectionHeader = xcoff::SectionHeader64;
+ type Symbol = xcoff::Symbol64;
+ type FileAux = xcoff::FileAux64;
+ type CsectAux = xcoff::CsectAux64;
+
+ fn is_type_64(&self) -> bool {
+ true
+ }
+
+ fn f_magic(&self) -> u16 {
+ self.f_magic.get(BE)
+ }
+
+ fn f_nscns(&self) -> u16 {
+ self.f_nscns.get(BE)
+ }
+
+ fn f_timdat(&self) -> u32 {
+ self.f_timdat.get(BE)
+ }
+
+ fn f_symptr(&self) -> Self::Word {
+ self.f_symptr.get(BE)
+ }
+
+ fn f_nsyms(&self) -> u32 {
+ self.f_nsyms.get(BE)
+ }
+
+ fn f_opthdr(&self) -> u16 {
+ self.f_opthdr.get(BE)
+ }
+
+ fn f_flags(&self) -> u16 {
+ self.f_flags.get(BE)
+ }
+}
+
+#[allow(missing_docs)]
+pub trait AuxHeader: Debug + Pod {
+ type Word: Into<u64>;
+
+ fn o_vstamp(&self) -> u16;
+ fn o_tsize(&self) -> Self::Word;
+ fn o_dsize(&self) -> Self::Word;
+ fn o_bsize(&self) -> Self::Word;
+ fn o_entry(&self) -> Self::Word;
+ fn o_text_start(&self) -> Self::Word;
+ fn o_data_start(&self) -> Self::Word;
+ fn o_toc(&self) -> Self::Word;
+ fn o_snentry(&self) -> u16;
+ fn o_sntext(&self) -> u16;
+ fn o_sndata(&self) -> u16;
+ fn o_sntoc(&self) -> u16;
+ fn o_snloader(&self) -> u16;
+ fn o_snbss(&self) -> u16;
+ fn o_sntdata(&self) -> u16;
+ fn o_sntbss(&self) -> u16;
+ fn o_algntext(&self) -> u16;
+ fn o_algndata(&self) -> u16;
+ fn o_maxstack(&self) -> Self::Word;
+ fn o_maxdata(&self) -> Self::Word;
+ fn o_textpsize(&self) -> u8;
+ fn o_datapsize(&self) -> u8;
+ fn o_stackpsize(&self) -> u8;
+}
+
+impl AuxHeader for xcoff::AuxHeader32 {
+ type Word = u32;
+
+ fn o_vstamp(&self) -> u16 {
+ self.o_vstamp.get(BE)
+ }
+
+ fn o_tsize(&self) -> Self::Word {
+ self.o_tsize.get(BE)
+ }
+
+ fn o_dsize(&self) -> Self::Word {
+ self.o_dsize.get(BE)
+ }
+
+ fn o_bsize(&self) -> Self::Word {
+ self.o_bsize.get(BE)
+ }
+
+ fn o_entry(&self) -> Self::Word {
+ self.o_entry.get(BE)
+ }
+
+ fn o_text_start(&self) -> Self::Word {
+ self.o_text_start.get(BE)
+ }
+
+ fn o_data_start(&self) -> Self::Word {
+ self.o_data_start.get(BE)
+ }
+
+ fn o_toc(&self) -> Self::Word {
+ self.o_toc.get(BE)
+ }
+
+ fn o_snentry(&self) -> u16 {
+ self.o_snentry.get(BE)
+ }
+
+ fn o_sntext(&self) -> u16 {
+ self.o_sntext.get(BE)
+ }
+
+ fn o_sndata(&self) -> u16 {
+ self.o_sndata.get(BE)
+ }
+
+ fn o_sntoc(&self) -> u16 {
+ self.o_sntoc.get(BE)
+ }
+
+ fn o_snloader(&self) -> u16 {
+ self.o_snloader.get(BE)
+ }
+
+ fn o_snbss(&self) -> u16 {
+ self.o_snbss.get(BE)
+ }
+
+ fn o_sntdata(&self) -> u16 {
+ self.o_sntdata.get(BE)
+ }
+
+ fn o_sntbss(&self) -> u16 {
+ self.o_sntbss.get(BE)
+ }
+
+ fn o_algntext(&self) -> u16 {
+ self.o_algntext.get(BE)
+ }
+
+ fn o_algndata(&self) -> u16 {
+ self.o_algndata.get(BE)
+ }
+
+ fn o_maxstack(&self) -> Self::Word {
+ self.o_maxstack.get(BE)
+ }
+
+ fn o_maxdata(&self) -> Self::Word {
+ self.o_maxdata.get(BE)
+ }
+
+ fn o_textpsize(&self) -> u8 {
+ self.o_textpsize
+ }
+
+ fn o_datapsize(&self) -> u8 {
+ self.o_datapsize
+ }
+
+ fn o_stackpsize(&self) -> u8 {
+ self.o_stackpsize
+ }
+}
+
+impl AuxHeader for xcoff::AuxHeader64 {
+ type Word = u64;
+
+ fn o_vstamp(&self) -> u16 {
+ self.o_vstamp.get(BE)
+ }
+
+ fn o_tsize(&self) -> Self::Word {
+ self.o_tsize.get(BE)
+ }
+
+ fn o_dsize(&self) -> Self::Word {
+ self.o_dsize.get(BE)
+ }
+
+ fn o_bsize(&self) -> Self::Word {
+ self.o_bsize.get(BE)
+ }
+
+ fn o_entry(&self) -> Self::Word {
+ self.o_entry.get(BE)
+ }
+
+ fn o_text_start(&self) -> Self::Word {
+ self.o_text_start.get(BE)
+ }
+
+ fn o_data_start(&self) -> Self::Word {
+ self.o_data_start.get(BE)
+ }
+
+ fn o_toc(&self) -> Self::Word {
+ self.o_toc.get(BE)
+ }
+
+ fn o_snentry(&self) -> u16 {
+ self.o_snentry.get(BE)
+ }
+
+ fn o_sntext(&self) -> u16 {
+ self.o_sntext.get(BE)
+ }
+
+ fn o_sndata(&self) -> u16 {
+ self.o_sndata.get(BE)
+ }
+
+ fn o_sntoc(&self) -> u16 {
+ self.o_sntoc.get(BE)
+ }
+
+ fn o_snloader(&self) -> u16 {
+ self.o_snloader.get(BE)
+ }
+
+ fn o_snbss(&self) -> u16 {
+ self.o_snbss.get(BE)
+ }
+
+ fn o_sntdata(&self) -> u16 {
+ self.o_sntdata.get(BE)
+ }
+
+ fn o_sntbss(&self) -> u16 {
+ self.o_sntbss.get(BE)
+ }
+
+ fn o_algntext(&self) -> u16 {
+ self.o_algntext.get(BE)
+ }
+
+ fn o_algndata(&self) -> u16 {
+ self.o_algndata.get(BE)
+ }
+
+ fn o_maxstack(&self) -> Self::Word {
+ self.o_maxstack.get(BE)
+ }
+
+ fn o_maxdata(&self) -> Self::Word {
+ self.o_maxdata.get(BE)
+ }
+
+ fn o_textpsize(&self) -> u8 {
+ self.o_textpsize
+ }
+
+ fn o_datapsize(&self) -> u8 {
+ self.o_datapsize
+ }
+
+ fn o_stackpsize(&self) -> u8 {
+ self.o_stackpsize
+ }
+}
diff --git a/third_party/rust/object/src/read/xcoff/mod.rs b/third_party/rust/object/src/read/xcoff/mod.rs
new file mode 100644
index 0000000000..136e31073b
--- /dev/null
+++ b/third_party/rust/object/src/read/xcoff/mod.rs
@@ -0,0 +1,21 @@
+//! Support for reading AIX XCOFF files.
+//!
+//! Provides `XcoffFile` and related types which implement the `Object` trait.
+
+mod file;
+pub use file::*;
+
+mod section;
+pub use section::*;
+
+mod symbol;
+pub use symbol::*;
+
+mod relocation;
+pub use relocation::*;
+
+mod comdat;
+pub use comdat::*;
+
+mod segment;
+pub use segment::*;
diff --git a/third_party/rust/object/src/read/xcoff/relocation.rs b/third_party/rust/object/src/read/xcoff/relocation.rs
new file mode 100644
index 0000000000..8107a2e826
--- /dev/null
+++ b/third_party/rust/object/src/read/xcoff/relocation.rs
@@ -0,0 +1,128 @@
+use alloc::fmt;
+use core::fmt::Debug;
+use core::slice;
+
+use crate::pod::Pod;
+use crate::{xcoff, BigEndian as BE, Relocation};
+
+use crate::read::{ReadRef, RelocationEncoding, RelocationKind, RelocationTarget, SymbolIndex};
+
+use super::{FileHeader, SectionHeader, XcoffFile};
+
+/// An iterator over the relocations in a `XcoffSection32`.
+pub type XcoffRelocationIterator32<'data, 'file, R = &'data [u8]> =
+ XcoffRelocationIterator<'data, 'file, xcoff::FileHeader32, R>;
+/// An iterator over the relocations in a `XcoffSection64`.
+pub type XcoffRelocationIterator64<'data, 'file, R = &'data [u8]> =
+ XcoffRelocationIterator<'data, 'file, xcoff::FileHeader64, R>;
+
+/// An iterator over the relocations in a `XcoffSection`.
+pub struct XcoffRelocationIterator<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ 'data: 'file,
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ #[allow(unused)]
+ pub(super) file: &'file XcoffFile<'data, Xcoff, R>,
+ pub(super) relocations:
+ slice::Iter<'data, <<Xcoff as FileHeader>::SectionHeader as SectionHeader>::Rel>,
+}
+
+impl<'data, 'file, Xcoff, R> Iterator for XcoffRelocationIterator<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ type Item = (u64, Relocation);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.relocations.next().map(|relocation| {
+ let encoding = RelocationEncoding::Generic;
+ let (kind, addend) = match relocation.r_rtype() {
+ xcoff::R_POS
+ | xcoff::R_RL
+ | xcoff::R_RLA
+ | xcoff::R_BA
+ | xcoff::R_RBA
+ | xcoff::R_TLS => (RelocationKind::Absolute, 0),
+ xcoff::R_REL | xcoff::R_BR | xcoff::R_RBR => (RelocationKind::Relative, -4),
+ xcoff::R_TOC | xcoff::R_TOCL | xcoff::R_TOCU => (RelocationKind::Got, 0),
+ r_type => (RelocationKind::Xcoff(r_type), 0),
+ };
+ let size = (relocation.r_rsize() & 0x3F) + 1;
+ let target = RelocationTarget::Symbol(SymbolIndex(relocation.r_symndx() as usize));
+ (
+ relocation.r_vaddr().into(),
+ Relocation {
+ kind,
+ encoding,
+ size,
+ target,
+ addend,
+ implicit_addend: true,
+ },
+ )
+ })
+ }
+}
+
+impl<'data, 'file, Xcoff, R> fmt::Debug for XcoffRelocationIterator<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("XcoffRelocationIterator").finish()
+ }
+}
+
+/// A trait for generic access to `Rel32` and `Rel64`.
+#[allow(missing_docs)]
+pub trait Rel: Debug + Pod {
+ type Word: Into<u64>;
+ fn r_vaddr(&self) -> Self::Word;
+ fn r_symndx(&self) -> u32;
+ fn r_rsize(&self) -> u8;
+ fn r_rtype(&self) -> u8;
+}
+
+impl Rel for xcoff::Rel32 {
+ type Word = u32;
+
+ fn r_vaddr(&self) -> Self::Word {
+ self.r_vaddr.get(BE)
+ }
+
+ fn r_symndx(&self) -> u32 {
+ self.r_symndx.get(BE)
+ }
+
+ fn r_rsize(&self) -> u8 {
+ self.r_rsize
+ }
+
+ fn r_rtype(&self) -> u8 {
+ self.r_rtype
+ }
+}
+
+impl Rel for xcoff::Rel64 {
+ type Word = u64;
+
+ fn r_vaddr(&self) -> Self::Word {
+ self.r_vaddr.get(BE)
+ }
+
+ fn r_symndx(&self) -> u32 {
+ self.r_symndx.get(BE)
+ }
+
+ fn r_rsize(&self) -> u8 {
+ self.r_rsize
+ }
+
+ fn r_rtype(&self) -> u8 {
+ self.r_rtype
+ }
+}
diff --git a/third_party/rust/object/src/read/xcoff/section.rs b/third_party/rust/object/src/read/xcoff/section.rs
new file mode 100644
index 0000000000..0944e10c83
--- /dev/null
+++ b/third_party/rust/object/src/read/xcoff/section.rs
@@ -0,0 +1,426 @@
+use core::fmt::Debug;
+use core::{iter, result, slice, str};
+
+use crate::{
+ xcoff, BigEndian as BE, CompressedData, CompressedFileRange, Pod, SectionFlags, SectionKind,
+};
+
+use crate::read::{self, Error, ObjectSection, ReadError, ReadRef, Result, SectionIndex};
+
+use super::{AuxHeader, FileHeader, Rel, XcoffFile, XcoffRelocationIterator};
+
+/// An iterator over the sections of an `XcoffFile32`.
+pub type XcoffSectionIterator32<'data, 'file, R = &'data [u8]> =
+ XcoffSectionIterator<'data, 'file, xcoff::FileHeader32, R>;
+/// An iterator over the sections of an `XcoffFile64`.
+pub type XcoffSectionIterator64<'data, 'file, R = &'data [u8]> =
+ XcoffSectionIterator<'data, 'file, xcoff::FileHeader64, R>;
+
+/// An iterator over the sections of an `XcoffFile`.
+#[derive(Debug)]
+pub struct XcoffSectionIterator<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) file: &'file XcoffFile<'data, Xcoff, R>,
+ pub(super) iter: iter::Enumerate<slice::Iter<'data, Xcoff::SectionHeader>>,
+}
+
+impl<'data, 'file, Xcoff, R> Iterator for XcoffSectionIterator<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ type Item = XcoffSection<'data, 'file, Xcoff, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next().map(|(index, section)| XcoffSection {
+ index: SectionIndex(index),
+ file: self.file,
+ section,
+ })
+ }
+}
+
+/// A section of an `XcoffFile32`.
+pub type XcoffSection32<'data, 'file, R = &'data [u8]> =
+ XcoffSection<'data, 'file, xcoff::FileHeader32, R>;
+/// A section of an `XcoffFile64`.
+pub type XcoffSection64<'data, 'file, R = &'data [u8]> =
+ XcoffSection<'data, 'file, xcoff::FileHeader64, R>;
+
+/// A section of an `XcoffFile`.
+#[derive(Debug)]
+pub struct XcoffSection<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ 'data: 'file,
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) file: &'file XcoffFile<'data, Xcoff, R>,
+ pub(super) section: &'data Xcoff::SectionHeader,
+ pub(super) index: SectionIndex,
+}
+
+impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> XcoffSection<'data, 'file, Xcoff, R> {
+ fn bytes(&self) -> Result<&'data [u8]> {
+ self.section
+ .data(self.file.data)
+ .read_error("Invalid XCOFF section offset or size")
+ }
+}
+
+impl<'data, 'file, Xcoff, R> read::private::Sealed for XcoffSection<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Xcoff, R> ObjectSection<'data> for XcoffSection<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ type RelocationIterator = XcoffRelocationIterator<'data, 'file, Xcoff, R>;
+
+ fn index(&self) -> SectionIndex {
+ self.index
+ }
+
+ fn address(&self) -> u64 {
+ self.section.s_paddr().into()
+ }
+
+ fn size(&self) -> u64 {
+ self.section.s_size().into()
+ }
+
+ fn align(&self) -> u64 {
+ // The default section alignment is 4.
+ if let Some(aux_header) = self.file.aux_header {
+ match self.kind() {
+ SectionKind::Text => aux_header.o_algntext().into(),
+ SectionKind::Data => aux_header.o_algndata().into(),
+ _ => 4,
+ }
+ } else {
+ 4
+ }
+ }
+
+ fn file_range(&self) -> Option<(u64, u64)> {
+ self.section.file_range()
+ }
+
+ fn data(&self) -> Result<&'data [u8]> {
+ self.bytes()
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
+ Ok(read::util::data_range(
+ self.bytes()?,
+ self.address(),
+ address,
+ size,
+ ))
+ }
+
+ fn compressed_file_range(&self) -> Result<CompressedFileRange> {
+ Ok(CompressedFileRange::none(self.file_range()))
+ }
+
+ fn compressed_data(&self) -> Result<CompressedData<'data>> {
+ self.data().map(CompressedData::none)
+ }
+
+ fn name_bytes(&self) -> read::Result<&[u8]> {
+ Ok(self.section.name())
+ }
+
+ fn name(&self) -> read::Result<&str> {
+ let name = self.name_bytes()?;
+ str::from_utf8(name)
+ .ok()
+ .read_error("Non UTF-8 XCOFF section name")
+ }
+
+ fn segment_name_bytes(&self) -> Result<Option<&[u8]>> {
+ Ok(None)
+ }
+
+ fn segment_name(&self) -> Result<Option<&str>> {
+ Ok(None)
+ }
+
+ fn kind(&self) -> SectionKind {
+ let section_type = self.section.s_flags() as u16;
+ if section_type & xcoff::STYP_TEXT != 0 {
+ SectionKind::Text
+ } else if section_type & xcoff::STYP_DATA != 0 {
+ SectionKind::Data
+ } else if section_type & xcoff::STYP_TDATA != 0 {
+ SectionKind::Tls
+ } else if section_type & xcoff::STYP_BSS != 0 {
+ SectionKind::UninitializedData
+ } else if section_type & xcoff::STYP_TBSS != 0 {
+ SectionKind::UninitializedTls
+ } else if section_type & (xcoff::STYP_DEBUG | xcoff::STYP_DWARF) != 0 {
+ SectionKind::Debug
+ } else if section_type & (xcoff::STYP_LOADER | xcoff::STYP_OVRFLO) != 0 {
+ SectionKind::Metadata
+ } else if section_type
+ & (xcoff::STYP_INFO | xcoff::STYP_EXCEPT | xcoff::STYP_PAD | xcoff::STYP_TYPCHK)
+ != 0
+ {
+ SectionKind::Other
+ } else {
+ SectionKind::Unknown
+ }
+ }
+
+ fn relocations(&self) -> Self::RelocationIterator {
+ let rel = self.section.relocations(self.file.data).unwrap_or(&[]);
+ XcoffRelocationIterator {
+ file: self.file,
+ relocations: rel.iter(),
+ }
+ }
+
+ fn flags(&self) -> SectionFlags {
+ SectionFlags::Xcoff {
+ s_flags: self.section.s_flags(),
+ }
+ }
+
+ fn uncompressed_data(&self) -> Result<alloc::borrow::Cow<'data, [u8]>> {
+ self.compressed_data()?.decompress()
+ }
+}
+
+/// The table of section headers in an XCOFF file.
+#[derive(Debug, Clone, Copy)]
+pub struct SectionTable<'data, Xcoff: FileHeader> {
+ sections: &'data [Xcoff::SectionHeader],
+}
+
+impl<'data, Xcoff> Default for SectionTable<'data, Xcoff>
+where
+ Xcoff: FileHeader,
+{
+ fn default() -> Self {
+ Self { sections: &[] }
+ }
+}
+
+impl<'data, Xcoff> SectionTable<'data, Xcoff>
+where
+ Xcoff: FileHeader,
+{
+ /// Parse the section table.
+ ///
+ /// `data` must be the entire file data.
+ /// `offset` must be after the optional file header.
+ pub fn parse<R: ReadRef<'data>>(header: &Xcoff, data: R, offset: &mut u64) -> Result<Self> {
+ let section_num = header.f_nscns();
+ if section_num == 0 {
+ return Ok(SectionTable::default());
+ }
+ let sections = data
+ .read_slice(offset, section_num as usize)
+ .read_error("Invalid XCOFF section headers")?;
+ Ok(SectionTable { sections })
+ }
+
+ /// Iterate over the section headers.
+ #[inline]
+ pub fn iter(&self) -> slice::Iter<'data, Xcoff::SectionHeader> {
+ self.sections.iter()
+ }
+
+ /// Return true if the section table is empty.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.sections.is_empty()
+ }
+
+ /// The number of section headers.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.sections.len()
+ }
+
+ /// Return the section header at the given index.
+ pub fn section(&self, index: SectionIndex) -> read::Result<&'data Xcoff::SectionHeader> {
+ self.sections
+ .get(index.0)
+ .read_error("Invalid XCOFF section index")
+ }
+}
+
+/// A trait for generic access to `SectionHeader32` and `SectionHeader64`.
+#[allow(missing_docs)]
+pub trait SectionHeader: Debug + Pod {
+ type Word: Into<u64>;
+ type HalfWord: Into<u32>;
+ type Xcoff: FileHeader<SectionHeader = Self, Word = Self::Word>;
+ type Rel: Rel<Word = Self::Word>;
+
+ fn s_name(&self) -> &[u8; 8];
+ fn s_paddr(&self) -> Self::Word;
+ fn s_vaddr(&self) -> Self::Word;
+ fn s_size(&self) -> Self::Word;
+ fn s_scnptr(&self) -> Self::Word;
+ fn s_relptr(&self) -> Self::Word;
+ fn s_lnnoptr(&self) -> Self::Word;
+ fn s_nreloc(&self) -> Self::HalfWord;
+ fn s_nlnno(&self) -> Self::HalfWord;
+ fn s_flags(&self) -> u32;
+
+ /// Return the section name.
+ fn name(&self) -> &[u8] {
+ let sectname = &self.s_name()[..];
+ match memchr::memchr(b'\0', sectname) {
+ Some(end) => &sectname[..end],
+ None => sectname,
+ }
+ }
+
+ /// Return the offset and size of the section in the file.
+ fn file_range(&self) -> Option<(u64, u64)> {
+ Some((self.s_scnptr().into(), self.s_size().into()))
+ }
+
+ /// Return the section data.
+ ///
+ /// Returns `Ok(&[])` if the section has no data.
+ /// Returns `Err` for invalid values.
+ fn data<'data, R: ReadRef<'data>>(&self, data: R) -> result::Result<&'data [u8], ()> {
+ if let Some((offset, size)) = self.file_range() {
+ data.read_bytes_at(offset, size)
+ } else {
+ Ok(&[])
+ }
+ }
+
+ /// Read the relocations.
+ fn relocations<'data, R: ReadRef<'data>>(&self, data: R) -> read::Result<&'data [Self::Rel]>;
+}
+
+impl SectionHeader for xcoff::SectionHeader32 {
+ type Word = u32;
+ type HalfWord = u16;
+ type Xcoff = xcoff::FileHeader32;
+ type Rel = xcoff::Rel32;
+
+ fn s_name(&self) -> &[u8; 8] {
+ &self.s_name
+ }
+
+ fn s_paddr(&self) -> Self::Word {
+ self.s_paddr.get(BE)
+ }
+
+ fn s_vaddr(&self) -> Self::Word {
+ self.s_vaddr.get(BE)
+ }
+
+ fn s_size(&self) -> Self::Word {
+ self.s_size.get(BE)
+ }
+
+ fn s_scnptr(&self) -> Self::Word {
+ self.s_scnptr.get(BE)
+ }
+
+ fn s_relptr(&self) -> Self::Word {
+ self.s_relptr.get(BE)
+ }
+
+ fn s_lnnoptr(&self) -> Self::Word {
+ self.s_lnnoptr.get(BE)
+ }
+
+ fn s_nreloc(&self) -> Self::HalfWord {
+ self.s_nreloc.get(BE)
+ }
+
+ fn s_nlnno(&self) -> Self::HalfWord {
+ self.s_nlnno.get(BE)
+ }
+
+ fn s_flags(&self) -> u32 {
+ self.s_flags.get(BE)
+ }
+
+ /// Read the relocations in a XCOFF32 file.
+ ///
+ /// `data` must be the entire file data.
+ fn relocations<'data, R: ReadRef<'data>>(&self, data: R) -> read::Result<&'data [Self::Rel]> {
+ let reloc_num = self.s_nreloc() as usize;
+ // TODO: If more than 65,534 relocation entries are required, the field value will be 65535,
+ // and an STYP_OVRFLO section header will contain the actual count of relocation entries in
+ // the s_paddr field.
+ if reloc_num == 65535 {
+ return Err(Error("Overflow section is not supported yet."));
+ }
+ data.read_slice_at(self.s_relptr().into(), reloc_num)
+ .read_error("Invalid XCOFF relocation offset or number")
+ }
+}
+
+impl SectionHeader for xcoff::SectionHeader64 {
+ type Word = u64;
+ type HalfWord = u32;
+ type Xcoff = xcoff::FileHeader64;
+ type Rel = xcoff::Rel64;
+
+ fn s_name(&self) -> &[u8; 8] {
+ &self.s_name
+ }
+
+ fn s_paddr(&self) -> Self::Word {
+ self.s_paddr.get(BE)
+ }
+
+ fn s_vaddr(&self) -> Self::Word {
+ self.s_vaddr.get(BE)
+ }
+
+ fn s_size(&self) -> Self::Word {
+ self.s_size.get(BE)
+ }
+
+ fn s_scnptr(&self) -> Self::Word {
+ self.s_scnptr.get(BE)
+ }
+
+ fn s_relptr(&self) -> Self::Word {
+ self.s_relptr.get(BE)
+ }
+
+ fn s_lnnoptr(&self) -> Self::Word {
+ self.s_lnnoptr.get(BE)
+ }
+
+ fn s_nreloc(&self) -> Self::HalfWord {
+ self.s_nreloc.get(BE)
+ }
+
+ fn s_nlnno(&self) -> Self::HalfWord {
+ self.s_nlnno.get(BE)
+ }
+
+ fn s_flags(&self) -> u32 {
+ self.s_flags.get(BE)
+ }
+
+ /// Read the relocations in a XCOFF64 file.
+ ///
+ /// `data` must be the entire file data.
+ fn relocations<'data, R: ReadRef<'data>>(&self, data: R) -> read::Result<&'data [Self::Rel]> {
+ data.read_slice_at(self.s_relptr(), self.s_nreloc() as usize)
+ .read_error("Invalid XCOFF relocation offset or number")
+ }
+}
diff --git a/third_party/rust/object/src/read/xcoff/segment.rs b/third_party/rust/object/src/read/xcoff/segment.rs
new file mode 100644
index 0000000000..49969438de
--- /dev/null
+++ b/third_party/rust/object/src/read/xcoff/segment.rs
@@ -0,0 +1,115 @@
+//! TODO: Support the segment for XCOFF when auxiliary file header and loader section is ready.
+
+use core::fmt::Debug;
+use core::str;
+
+use crate::read::{self, ObjectSegment, ReadRef, Result};
+use crate::xcoff;
+
+use super::{FileHeader, XcoffFile};
+
+/// An iterator over the segments of an `XcoffFile32`.
+pub type XcoffSegmentIterator32<'data, 'file, R = &'data [u8]> =
+ XcoffSegmentIterator<'data, 'file, xcoff::FileHeader32, R>;
+/// An iterator over the segments of an `XcoffFile64`.
+pub type XcoffSegmentIterator64<'data, 'file, R = &'data [u8]> =
+ XcoffSegmentIterator<'data, 'file, xcoff::FileHeader64, R>;
+
+/// An iterator over the segments of an `XcoffFile`.
+#[derive(Debug)]
+pub struct XcoffSegmentIterator<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ 'data: 'file,
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ #[allow(unused)]
+ pub(super) file: &'file XcoffFile<'data, Xcoff, R>,
+}
+
+impl<'data, 'file, Xcoff, R> Iterator for XcoffSegmentIterator<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ type Item = XcoffSegment<'data, 'file, Xcoff, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
+
+/// A segment of an `XcoffFile32`.
+pub type XcoffSegment32<'data, 'file, R = &'data [u8]> =
+ XcoffSegment<'data, 'file, xcoff::FileHeader32, R>;
+/// A segment of an `XcoffFile64`.
+pub type XcoffSegment64<'data, 'file, R = &'data [u8]> =
+ XcoffSegment<'data, 'file, xcoff::FileHeader64, R>;
+
+/// A loadable section of an `XcoffFile`.
+#[derive(Debug)]
+pub struct XcoffSegment<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ 'data: 'file,
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ #[allow(unused)]
+ pub(super) file: &'file XcoffFile<'data, Xcoff, R>,
+}
+
+impl<'data, 'file, Xcoff, R> XcoffSegment<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Xcoff, R> read::private::Sealed for XcoffSegment<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Xcoff, R> ObjectSegment<'data> for XcoffSegment<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ fn address(&self) -> u64 {
+ unreachable!();
+ }
+
+ fn size(&self) -> u64 {
+ unreachable!();
+ }
+
+ fn align(&self) -> u64 {
+ unreachable!();
+ }
+
+ fn file_range(&self) -> (u64, u64) {
+ unreachable!();
+ }
+
+ fn data(&self) -> Result<&'data [u8]> {
+ unreachable!();
+ }
+
+ fn data_range(&self, _address: u64, _size: u64) -> Result<Option<&'data [u8]>> {
+ unreachable!();
+ }
+
+ fn name_bytes(&self) -> Result<Option<&[u8]>> {
+ unreachable!();
+ }
+
+ fn name(&self) -> Result<Option<&str>> {
+ unreachable!();
+ }
+
+ fn flags(&self) -> crate::SegmentFlags {
+ unreachable!();
+ }
+}
diff --git a/third_party/rust/object/src/read/xcoff/symbol.rs b/third_party/rust/object/src/read/xcoff/symbol.rs
new file mode 100644
index 0000000000..6738ad1714
--- /dev/null
+++ b/third_party/rust/object/src/read/xcoff/symbol.rs
@@ -0,0 +1,634 @@
+use alloc::fmt;
+use core::convert::TryInto;
+use core::fmt::Debug;
+use core::marker::PhantomData;
+use core::str;
+
+use crate::endian::{BigEndian as BE, U32Bytes};
+use crate::pod::Pod;
+use crate::read::util::StringTable;
+use crate::{bytes_of, xcoff, Object, ObjectSection, SectionKind};
+
+use crate::read::{
+ self, Bytes, Error, ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, Result, SectionIndex,
+ SymbolFlags, SymbolIndex, SymbolKind, SymbolScope, SymbolSection,
+};
+
+use super::{FileHeader, XcoffFile};
+
+/// A table of symbol entries in an XCOFF file.
+///
+/// Also includes the string table used for the symbol names.
+#[derive(Debug)]
+pub struct SymbolTable<'data, Xcoff, R = &'data [u8]>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ symbols: &'data [xcoff::SymbolBytes],
+ strings: StringTable<'data, R>,
+ header: PhantomData<Xcoff>,
+}
+
+impl<'data, Xcoff, R> Default for SymbolTable<'data, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ fn default() -> Self {
+ Self {
+ symbols: &[],
+ strings: StringTable::default(),
+ header: PhantomData,
+ }
+ }
+}
+
+impl<'data, Xcoff, R> SymbolTable<'data, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ /// Parse the symbol table.
+ pub fn parse(header: Xcoff, data: R) -> Result<Self> {
+ let mut offset = header.f_symptr().into();
+ let (symbols, strings) = if offset != 0 {
+ let symbols = data
+ .read_slice(&mut offset, header.f_nsyms() as usize)
+ .read_error("Invalid XCOFF symbol table offset or size")?;
+
+ // Parse the string table.
+ // Note: don't update data when reading length; the length includes itself.
+ let length = data
+ .read_at::<U32Bytes<_>>(offset)
+ .read_error("Missing XCOFF string table")?
+ .get(BE);
+ let str_end = offset
+ .checked_add(length as u64)
+ .read_error("Invalid XCOFF string table length")?;
+ let strings = StringTable::new(data, offset, str_end);
+
+ (symbols, strings)
+ } else {
+ (&[][..], StringTable::default())
+ };
+
+ Ok(SymbolTable {
+ symbols,
+ strings,
+ header: PhantomData,
+ })
+ }
+
+ /// Return the symbol entry at the given index and offset.
+ pub fn get<T: Pod>(&self, index: usize, offset: usize) -> Result<&'data T> {
+ let entry = index
+ .checked_add(offset)
+ .and_then(|x| self.symbols.get(x))
+ .read_error("Invalid XCOFF symbol index")?;
+ let bytes = bytes_of(entry);
+ Bytes(bytes).read().read_error("Invalid XCOFF symbol data")
+ }
+
+ /// Return the symbol at the given index.
+ pub fn symbol(&self, index: usize) -> Result<&'data Xcoff::Symbol> {
+ self.get::<Xcoff::Symbol>(index, 0)
+ }
+
+ /// Return the file auxiliary symbol.
+ pub fn aux_file(&self, index: usize) -> Result<&'data Xcoff::FileAux> {
+ debug_assert!(self.symbol(index)?.has_aux_file());
+ let aux_file = self.get::<Xcoff::FileAux>(index, 1)?;
+ if let Some(aux_type) = aux_file.x_auxtype() {
+ if aux_type != xcoff::AUX_FILE {
+ return Err(Error("Invalid index for file auxiliary symbol."));
+ }
+ }
+ Ok(aux_file)
+ }
+
+ /// Return the csect auxiliary symbol.
+ pub fn aux_csect(&self, index: usize, offset: usize) -> Result<&'data Xcoff::CsectAux> {
+ debug_assert!(self.symbol(index)?.has_aux_csect());
+ let aux_csect = self.get::<Xcoff::CsectAux>(index, offset)?;
+ if let Some(aux_type) = aux_csect.x_auxtype() {
+ if aux_type != xcoff::AUX_CSECT {
+ return Err(Error("Invalid index/offset for csect auxiliary symbol."));
+ }
+ }
+ Ok(aux_csect)
+ }
+
+ /// Return true if the symbol table is empty.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.symbols.is_empty()
+ }
+
+ /// The number of symbol table entries.
+ ///
+ /// This includes auxiliary symbol table entries.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.symbols.len()
+ }
+}
+
+/// A symbol table of an `XcoffFile32`.
+pub type XcoffSymbolTable32<'data, 'file, R = &'data [u8]> =
+ XcoffSymbolTable<'data, 'file, xcoff::FileHeader32, R>;
+/// A symbol table of an `XcoffFile64`.
+pub type XcoffSymbolTable64<'data, 'file, R = &'data [u8]> =
+ XcoffSymbolTable<'data, 'file, xcoff::FileHeader64, R>;
+
+/// A symbol table of an `XcoffFile`.
+#[derive(Debug, Clone, Copy)]
+pub struct XcoffSymbolTable<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ 'data: 'file,
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(crate) file: &'file XcoffFile<'data, Xcoff, R>,
+ pub(super) symbols: &'file SymbolTable<'data, Xcoff, R>,
+}
+
+impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> read::private::Sealed
+ for XcoffSymbolTable<'data, 'file, Xcoff, R>
+{
+}
+
+impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> ObjectSymbolTable<'data>
+ for XcoffSymbolTable<'data, 'file, Xcoff, R>
+{
+ type Symbol = XcoffSymbol<'data, 'file, Xcoff, R>;
+ type SymbolIterator = XcoffSymbolIterator<'data, 'file, Xcoff, R>;
+
+ fn symbols(&self) -> Self::SymbolIterator {
+ XcoffSymbolIterator {
+ file: self.file,
+ symbols: self.symbols,
+ index: 0,
+ }
+ }
+
+ fn symbol_by_index(&self, index: SymbolIndex) -> read::Result<Self::Symbol> {
+ let symbol = self.symbols.symbol(index.0)?;
+ Ok(XcoffSymbol {
+ file: self.file,
+ symbols: self.symbols,
+ index,
+ symbol,
+ })
+ }
+}
+
+/// An iterator over the symbols of an `XcoffFile32`.
+pub type XcoffSymbolIterator32<'data, 'file, R = &'data [u8]> =
+ XcoffSymbolIterator<'data, 'file, xcoff::FileHeader32, R>;
+/// An iterator over the symbols of an `XcoffFile64`.
+pub type XcoffSymbolIterator64<'data, 'file, R = &'data [u8]> =
+ XcoffSymbolIterator<'data, 'file, xcoff::FileHeader64, R>;
+
+/// An iterator over the symbols of an `XcoffFile`.
+pub struct XcoffSymbolIterator<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ 'data: 'file,
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(crate) file: &'file XcoffFile<'data, Xcoff, R>,
+ pub(super) symbols: &'file SymbolTable<'data, Xcoff, R>,
+ pub(super) index: usize,
+}
+
+impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> fmt::Debug
+ for XcoffSymbolIterator<'data, 'file, Xcoff, R>
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("XcoffSymbolIterator").finish()
+ }
+}
+
+impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> Iterator
+ for XcoffSymbolIterator<'data, 'file, Xcoff, R>
+{
+ type Item = XcoffSymbol<'data, 'file, Xcoff, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let index = self.index;
+ let symbol = self.symbols.symbol(index).ok()?;
+ // TODO: skip over the auxiliary symbols for now.
+ self.index += 1 + symbol.n_numaux() as usize;
+ Some(XcoffSymbol {
+ file: self.file,
+ symbols: self.symbols,
+ index: SymbolIndex(index),
+ symbol,
+ })
+ }
+}
+
+/// A symbol of an `XcoffFile32`.
+pub type XcoffSymbol32<'data, 'file, R = &'data [u8]> =
+ XcoffSymbol<'data, 'file, xcoff::FileHeader32, R>;
+/// A symbol of an `XcoffFile64`.
+pub type XcoffSymbol64<'data, 'file, R = &'data [u8]> =
+ XcoffSymbol<'data, 'file, xcoff::FileHeader64, R>;
+
+/// A symbol of an `XcoffFile`.
+#[derive(Debug, Clone, Copy)]
+pub struct XcoffSymbol<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ 'data: 'file,
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(crate) file: &'file XcoffFile<'data, Xcoff, R>,
+ pub(super) symbols: &'file SymbolTable<'data, Xcoff, R>,
+ pub(super) index: SymbolIndex,
+ pub(super) symbol: &'data Xcoff::Symbol,
+}
+
+impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> read::private::Sealed
+ for XcoffSymbol<'data, 'file, Xcoff, R>
+{
+}
+
+impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> ObjectSymbol<'data>
+ for XcoffSymbol<'data, 'file, Xcoff, R>
+{
+ #[inline]
+ fn index(&self) -> SymbolIndex {
+ self.index
+ }
+
+ fn name_bytes(&self) -> Result<&'data [u8]> {
+ self.symbol.name(self.symbols.strings)
+ }
+
+ fn name(&self) -> Result<&'data str> {
+ let name = self.name_bytes()?;
+ str::from_utf8(name)
+ .ok()
+ .read_error("Non UTF-8 XCOFF symbol name")
+ }
+
+ #[inline]
+ fn address(&self) -> u64 {
+ match self.symbol.n_sclass() {
+ // Relocatable address.
+ xcoff::C_EXT
+ | xcoff::C_WEAKEXT
+ | xcoff::C_HIDEXT
+ | xcoff::C_FCN
+ | xcoff::C_BLOCK
+ | xcoff::C_STAT => self.symbol.n_value().into(),
+ _ => 0,
+ }
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ if self.symbol.has_aux_csect() {
+ // XCOFF32 must have the csect auxiliary entry as the last auxiliary entry.
+ // XCOFF64 doesn't require this, but conventionally does.
+ if let Ok(aux_csect) = self
+ .file
+ .symbols
+ .aux_csect(self.index.0, self.symbol.n_numaux() as usize)
+ {
+ let sym_type = aux_csect.sym_type() & 0x07;
+ if sym_type == xcoff::XTY_SD || sym_type == xcoff::XTY_CM {
+ aux_csect.x_scnlen()
+ } else {
+ 0
+ }
+ } else {
+ 0
+ }
+ } else {
+ 0
+ }
+ }
+
+ fn kind(&self) -> SymbolKind {
+ match self.symbol.n_sclass() {
+ xcoff::C_FILE => SymbolKind::File,
+ xcoff::C_NULL => SymbolKind::Null,
+ _ => self
+ .file
+ .section_by_index(SectionIndex((self.symbol.n_scnum() - 1) as usize))
+ .map(|section| match section.kind() {
+ SectionKind::Data | SectionKind::UninitializedData => SymbolKind::Data,
+ SectionKind::UninitializedTls | SectionKind::Tls => SymbolKind::Tls,
+ SectionKind::Text => SymbolKind::Text,
+ _ => SymbolKind::Unknown,
+ })
+ .unwrap_or(SymbolKind::Unknown),
+ }
+ }
+
+ fn section(&self) -> SymbolSection {
+ match self.symbol.n_scnum() {
+ xcoff::N_ABS => SymbolSection::Absolute,
+ xcoff::N_UNDEF => SymbolSection::Undefined,
+ xcoff::N_DEBUG => SymbolSection::None,
+ index if index > 0 => SymbolSection::Section(SectionIndex(index as usize)),
+ _ => SymbolSection::Unknown,
+ }
+ }
+
+ #[inline]
+ fn is_undefined(&self) -> bool {
+ self.symbol.is_undefined()
+ }
+
+ /// Return true if the symbol is a definition of a function or data object.
+ #[inline]
+ fn is_definition(&self) -> bool {
+ if self.symbol.has_aux_csect() {
+ if let Ok(aux_csect) = self
+ .symbols
+ .aux_csect(self.index.0, self.symbol.n_numaux() as usize)
+ {
+ let smclas = aux_csect.x_smclas();
+ self.symbol.n_scnum() != xcoff::N_UNDEF
+ && (smclas == xcoff::XMC_PR
+ || smclas == xcoff::XMC_RW
+ || smclas == xcoff::XMC_RO)
+ } else {
+ false
+ }
+ } else {
+ false
+ }
+ }
+
+ #[inline]
+ fn is_common(&self) -> bool {
+ self.symbol.n_sclass() == xcoff::C_EXT && self.symbol.n_scnum() == xcoff::N_UNDEF
+ }
+
+ #[inline]
+ fn is_weak(&self) -> bool {
+ self.symbol.n_sclass() == xcoff::C_WEAKEXT
+ }
+
+ fn scope(&self) -> SymbolScope {
+ if self.symbol.n_scnum() == xcoff::N_UNDEF {
+ SymbolScope::Unknown
+ } else {
+ match self.symbol.n_sclass() {
+ xcoff::C_EXT | xcoff::C_WEAKEXT | xcoff::C_HIDEXT => {
+ let visibility = self.symbol.n_type() & xcoff::SYM_V_MASK;
+ if visibility == xcoff::SYM_V_HIDDEN {
+ SymbolScope::Linkage
+ } else {
+ SymbolScope::Dynamic
+ }
+ }
+ _ => SymbolScope::Compilation,
+ }
+ }
+ }
+
+ #[inline]
+ fn is_global(&self) -> bool {
+ match self.symbol.n_sclass() {
+ xcoff::C_EXT | xcoff::C_WEAKEXT => true,
+ _ => false,
+ }
+ }
+
+ #[inline]
+ fn is_local(&self) -> bool {
+ !self.is_global()
+ }
+
+ #[inline]
+ fn flags(&self) -> SymbolFlags<SectionIndex> {
+ SymbolFlags::None
+ }
+}
+
+/// A trait for generic access to `Symbol32` and `Symbol64`.
+#[allow(missing_docs)]
+pub trait Symbol: Debug + Pod {
+ type Word: Into<u64>;
+
+ fn n_value(&self) -> Self::Word;
+ fn n_scnum(&self) -> i16;
+ fn n_type(&self) -> u16;
+ fn n_sclass(&self) -> u8;
+ fn n_numaux(&self) -> u8;
+
+ fn name<'data, R: ReadRef<'data>>(
+ &'data self,
+ strings: StringTable<'data, R>,
+ ) -> Result<&'data [u8]>;
+
+ /// Return true if the symbol is undefined.
+ #[inline]
+ fn is_undefined(&self) -> bool {
+ let n_sclass = self.n_sclass();
+ (n_sclass == xcoff::C_EXT || n_sclass == xcoff::C_WEAKEXT)
+ && self.n_scnum() == xcoff::N_UNDEF
+ }
+
+ /// Return true if the symbol has file auxiliary entry.
+ fn has_aux_file(&self) -> bool {
+ self.n_numaux() > 0 && self.n_sclass() == xcoff::C_FILE
+ }
+
+ /// Return true if the symbol has csect auxiliary entry.
+ ///
+ /// A csect auxiliary entry is required for each symbol table entry that has
+ /// a storage class value of C_EXT, C_WEAKEXT, or C_HIDEXT.
+ fn has_aux_csect(&self) -> bool {
+ let sclass = self.n_sclass();
+ self.n_numaux() > 0
+ && (sclass == xcoff::C_EXT || sclass == xcoff::C_WEAKEXT || sclass == xcoff::C_HIDEXT)
+ }
+}
+
+impl Symbol for xcoff::Symbol64 {
+ type Word = u64;
+
+ fn n_value(&self) -> Self::Word {
+ self.n_value.get(BE)
+ }
+
+ fn n_scnum(&self) -> i16 {
+ self.n_scnum.get(BE)
+ }
+
+ fn n_type(&self) -> u16 {
+ self.n_type.get(BE)
+ }
+
+ fn n_sclass(&self) -> u8 {
+ self.n_sclass
+ }
+
+ fn n_numaux(&self) -> u8 {
+ self.n_numaux
+ }
+
+ /// Parse the symbol name for XCOFF64.
+ fn name<'data, R: ReadRef<'data>>(
+ &'data self,
+ strings: StringTable<'data, R>,
+ ) -> Result<&'data [u8]> {
+ strings
+ .get(self.n_offset.get(BE))
+ .read_error("Invalid XCOFF symbol name offset")
+ }
+}
+
+impl Symbol for xcoff::Symbol32 {
+ type Word = u32;
+
+ fn n_value(&self) -> Self::Word {
+ self.n_value.get(BE)
+ }
+
+ fn n_scnum(&self) -> i16 {
+ self.n_scnum.get(BE)
+ }
+
+ fn n_type(&self) -> u16 {
+ self.n_type.get(BE)
+ }
+
+ fn n_sclass(&self) -> u8 {
+ self.n_sclass
+ }
+
+ fn n_numaux(&self) -> u8 {
+ self.n_numaux
+ }
+
+ /// Parse the symbol name for XCOFF32.
+ fn name<'data, R: ReadRef<'data>>(
+ &'data self,
+ strings: StringTable<'data, R>,
+ ) -> Result<&'data [u8]> {
+ if self.n_name[0] == 0 {
+ // If the name starts with 0 then the last 4 bytes are a string table offset.
+ let offset = u32::from_be_bytes(self.n_name[4..8].try_into().unwrap());
+ strings
+ .get(offset)
+ .read_error("Invalid XCOFF symbol name offset")
+ } else {
+ // The name is inline and padded with nulls.
+ Ok(match memchr::memchr(b'\0', &self.n_name) {
+ Some(end) => &self.n_name[..end],
+ None => &self.n_name,
+ })
+ }
+ }
+}
+
+/// A trait for generic access to `FileAux32` and `FileAux64`.
+#[allow(missing_docs)]
+pub trait FileAux: Debug + Pod {
+ fn x_fname(&self) -> &[u8; 8];
+ fn x_ftype(&self) -> u8;
+ fn x_auxtype(&self) -> Option<u8>;
+}
+
+impl FileAux for xcoff::FileAux64 {
+ fn x_fname(&self) -> &[u8; 8] {
+ &self.x_fname
+ }
+
+ fn x_ftype(&self) -> u8 {
+ self.x_ftype
+ }
+
+ fn x_auxtype(&self) -> Option<u8> {
+ Some(self.x_auxtype)
+ }
+}
+
+impl FileAux for xcoff::FileAux32 {
+ fn x_fname(&self) -> &[u8; 8] {
+ &self.x_fname
+ }
+
+ fn x_ftype(&self) -> u8 {
+ self.x_ftype
+ }
+
+ fn x_auxtype(&self) -> Option<u8> {
+ None
+ }
+}
+
+/// A trait for generic access to `CsectAux32` and `CsectAux64`.
+#[allow(missing_docs)]
+pub trait CsectAux: Debug + Pod {
+ fn x_scnlen(&self) -> u64;
+ fn x_parmhash(&self) -> u32;
+ fn x_snhash(&self) -> u16;
+ fn x_smtyp(&self) -> u8;
+ fn x_smclas(&self) -> u8;
+ fn x_auxtype(&self) -> Option<u8>;
+
+ fn sym_type(&self) -> u8 {
+ self.x_smtyp() & 0x07
+ }
+}
+
+impl CsectAux for xcoff::CsectAux64 {
+ fn x_scnlen(&self) -> u64 {
+ self.x_scnlen_lo.get(BE) as u64 | ((self.x_scnlen_hi.get(BE) as u64) << 32)
+ }
+
+ fn x_parmhash(&self) -> u32 {
+ self.x_parmhash.get(BE)
+ }
+
+ fn x_snhash(&self) -> u16 {
+ self.x_snhash.get(BE)
+ }
+
+ fn x_smtyp(&self) -> u8 {
+ self.x_smtyp
+ }
+
+ fn x_smclas(&self) -> u8 {
+ self.x_smclas
+ }
+
+ fn x_auxtype(&self) -> Option<u8> {
+ Some(self.x_auxtype)
+ }
+}
+
+impl CsectAux for xcoff::CsectAux32 {
+ fn x_scnlen(&self) -> u64 {
+ self.x_scnlen.get(BE) as u64
+ }
+
+ fn x_parmhash(&self) -> u32 {
+ self.x_parmhash.get(BE)
+ }
+
+ fn x_snhash(&self) -> u16 {
+ self.x_snhash.get(BE)
+ }
+
+ fn x_smtyp(&self) -> u8 {
+ self.x_smtyp
+ }
+
+ fn x_smclas(&self) -> u8 {
+ self.x_smclas
+ }
+
+ fn x_auxtype(&self) -> Option<u8> {
+ None
+ }
+}