diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /third_party/rust/goblin/src/elf/program_header.rs | |
parent | Initial commit. (diff) | |
download | thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/goblin/src/elf/program_header.rs')
-rw-r--r-- | third_party/rust/goblin/src/elf/program_header.rs | 427 |
1 files changed, 427 insertions, 0 deletions
diff --git a/third_party/rust/goblin/src/elf/program_header.rs b/third_party/rust/goblin/src/elf/program_header.rs new file mode 100644 index 0000000000..3525bb4e4a --- /dev/null +++ b/third_party/rust/goblin/src/elf/program_header.rs @@ -0,0 +1,427 @@ +/* Legal values for p_type (segment type). */ + +/// Programg header table entry unused +pub const PT_NULL: u32 = 0; +/// Loadable program segment +pub const PT_LOAD: u32 = 1; +/// Dynamic linking information +pub const PT_DYNAMIC: u32 = 2; +/// Program interpreter +pub const PT_INTERP: u32 = 3; +/// Auxiliary information +pub const PT_NOTE: u32 = 4; +/// Reserved +pub const PT_SHLIB: u32 = 5; +/// Entry for header table itself +pub const PT_PHDR: u32 = 6; +/// Thread-local storage segment +pub const PT_TLS: u32 = 7; +/// Number of defined types +pub const PT_NUM: u32 = 8; +/// Start of OS-specific +pub const PT_LOOS: u32 = 0x6000_0000; +/// GCC .eh_frame_hdr segment +pub const PT_GNU_EH_FRAME: u32 = 0x6474_e550; +/// Indicates stack executability +pub const PT_GNU_STACK: u32 = 0x6474_e551; +/// Read-only after relocation +pub const PT_GNU_RELRO: u32 = 0x6474_e552; +/// Sun Specific segment +pub const PT_LOSUNW: u32 = 0x6fff_fffa; +/// Sun Specific segment +pub const PT_SUNWBSS: u32 = 0x6fff_fffa; +/// Stack segment +pub const PT_SUNWSTACK: u32 = 0x6fff_fffb; +/// End of OS-specific +pub const PT_HISUNW: u32 = 0x6fff_ffff; +/// End of OS-specific +pub const PT_HIOS: u32 = 0x6fff_ffff; +/// Start of processor-specific +pub const PT_LOPROC: u32 = 0x7000_0000; +/// ARM unwind segment +pub const PT_ARM_EXIDX: u32 = 0x7000_0001; +/// End of processor-specific +pub const PT_HIPROC: u32 = 0x7fff_ffff; + +/* Legal values for p_flags (segment flags). */ + +/// Segment is executable +pub const PF_X: u32 = 1; +/// Segment is writable +pub const PF_W: u32 = 1 << 1; +/// Segment is readable +pub const PF_R: u32 = 1 << 2; +/// Bits reserved for OS-specific usage +pub const PF_MASKOS: u32 = 0x0ff0_0000; +/// Bits reserved for processor-specific usage +pub const PF_MASKPROC: u32 = 0xf000_0000; + +pub fn pt_to_str(pt: u32) -> &'static str { + match pt { + PT_NULL => "PT_NULL", + PT_LOAD => "PT_LOAD", + PT_DYNAMIC => "PT_DYNAMIC", + PT_INTERP => "PT_INTERP", + PT_NOTE => "PT_NOTE", + PT_SHLIB => "PT_SHLIB", + PT_PHDR => "PT_PHDR", + PT_TLS => "PT_TLS", + PT_NUM => "PT_NUM", + PT_LOOS => "PT_LOOS", + PT_GNU_EH_FRAME => "PT_GNU_EH_FRAME", + PT_GNU_STACK => "PT_GNU_STACK", + PT_GNU_RELRO => "PT_GNU_RELRO", + PT_SUNWBSS => "PT_SUNWBSS", + PT_SUNWSTACK => "PT_SUNWSTACK", + PT_HIOS => "PT_HIOS", + PT_LOPROC => "PT_LOPROC", + PT_HIPROC => "PT_HIPROC", + PT_ARM_EXIDX => "PT_ARM_EXIDX", + _ => "UNKNOWN_PT", + } +} + +if_alloc! { + use core::fmt; + use scroll::ctx; + use core::result; + use core::ops::Range; + use crate::container::{Ctx, Container}; + use alloc::vec::Vec; + + #[derive(Default, PartialEq, Clone)] + /// A unified ProgramHeader - convertable to and from 32-bit and 64-bit variants + pub struct ProgramHeader { + pub p_type : u32, + pub p_flags : u32, + pub p_offset: u64, + pub p_vaddr : u64, + pub p_paddr : u64, + pub p_filesz: u64, + pub p_memsz : u64, + pub p_align : u64, + } + + impl ProgramHeader { + /// Return the size of the underlying program header, given a `Ctx` + #[inline] + pub fn size(ctx: Ctx) -> usize { + use scroll::ctx::SizeWith; + Self::size_with(&ctx) + } + /// Create a new `PT_LOAD` ELF program header + pub fn new() -> Self { + ProgramHeader { + p_type : PT_LOAD, + p_flags : 0, + p_offset: 0, + p_vaddr : 0, + p_paddr : 0, + p_filesz: 0, + p_memsz : 0, + //TODO: check if this is true for 32-bit pt_load + p_align : 2 << 20, + } + } + /// Returns this program header's file offset range + pub fn file_range(&self) -> Range<usize> { + self.p_offset as usize..self.p_offset.saturating_add(self.p_filesz) as usize + } + /// Returns this program header's virtual memory range + pub fn vm_range(&self) -> Range<usize> { + self.p_vaddr as usize..self.p_vaddr.saturating_add(self.p_memsz) as usize + } + /// Sets the executable flag + pub fn executable(&mut self) { + self.p_flags |= PF_X; + } + /// Sets the write flag + pub fn write(&mut self) { + self.p_flags |= PF_W; + } + /// Sets the read flag + pub fn read(&mut self) { + self.p_flags |= PF_R; + } + /// Whether this program header is executable + pub fn is_executable(&self) -> bool { + self.p_flags & PF_X != 0 + } + /// Whether this program header is readable + pub fn is_read(&self) -> bool { + self.p_flags & PF_R != 0 + } + /// Whether this program header is writable + pub fn is_write(&self) -> bool { + self.p_flags & PF_W != 0 + } + #[cfg(feature = "endian_fd")] + pub fn parse(bytes: &[u8], mut offset: usize, count: usize, ctx: Ctx) -> crate::error::Result<Vec<ProgramHeader>> { + use scroll::Pread; + // Sanity check to avoid OOM + if count > bytes.len() / Self::size(ctx) { + return Err(crate::error::Error::BufferTooShort(count, "program headers")); + } + let mut program_headers = Vec::with_capacity(count); + for _ in 0..count { + let phdr = bytes.gread_with(&mut offset, ctx)?; + program_headers.push(phdr); + } + Ok(program_headers) + } + } + + impl fmt::Debug for ProgramHeader { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("ProgramHeader") + .field("p_type", &pt_to_str(self.p_type)) + .field("p_flags", &format_args!("0x{:x}", self.p_flags)) + .field("p_offset", &format_args!("0x{:x}", self.p_offset)) + .field("p_vaddr", &format_args!("0x{:x}", self.p_vaddr)) + .field("p_paddr", &format_args!("0x{:x}", self.p_paddr)) + .field("p_filesz", &format_args!("0x{:x}", self.p_filesz)) + .field("p_memsz", &format_args!("0x{:x}", self.p_memsz)) + .field("p_align", &self.p_align) + .finish() + } + } + + impl ctx::SizeWith<Ctx> for ProgramHeader { + fn size_with(ctx: &Ctx) -> usize { + match ctx.container { + Container::Little => { + program_header32::SIZEOF_PHDR + }, + Container::Big => { + program_header64::SIZEOF_PHDR + }, + } + } + } + + impl<'a> ctx::TryFromCtx<'a, Ctx> for ProgramHeader { + type Error = crate::error::Error; + fn try_from_ctx(bytes: &'a [u8], Ctx { container, le}: Ctx) -> result::Result<(Self, usize), Self::Error> { + use scroll::Pread; + let res = match container { + Container::Little => { + (bytes.pread_with::<program_header32::ProgramHeader>(0, le)?.into(), program_header32::SIZEOF_PHDR) + }, + Container::Big => { + (bytes.pread_with::<program_header64::ProgramHeader>(0, le)?.into(), program_header64::SIZEOF_PHDR) + } + }; + Ok(res) + } + } + + impl ctx::TryIntoCtx<Ctx> for ProgramHeader { + type Error = crate::error::Error; + fn try_into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) -> result::Result<usize, Self::Error> { + use scroll::Pwrite; + match container { + Container::Little => { + let phdr: program_header32::ProgramHeader = self.into(); + Ok(bytes.pwrite_with(phdr, 0, le)?) + }, + Container::Big => { + let phdr: program_header64::ProgramHeader = self.into(); + Ok(bytes.pwrite_with(phdr, 0, le)?) + } + } + } + } +} // end if_alloc + +macro_rules! elf_program_header_std_impl { + ($size:ty) => { + #[cfg(test)] + mod tests { + use super::*; + #[test] + fn size_of() { + assert_eq!(::std::mem::size_of::<ProgramHeader>(), SIZEOF_PHDR); + } + } + + if_alloc! { + + + use crate::elf::program_header::ProgramHeader as ElfProgramHeader; + #[cfg(any(feature = "std", feature = "endian_fd"))] + use crate::error::Result; + + use plain::Plain; + + if_std! { + use std::fs::File; + use std::io::{Seek, Read}; + use std::io::SeekFrom::Start; + } + + impl From<ProgramHeader> for ElfProgramHeader { + fn from(ph: ProgramHeader) -> Self { + ElfProgramHeader { + p_type : ph.p_type, + p_flags : ph.p_flags, + p_offset : u64::from(ph.p_offset), + p_vaddr : u64::from(ph.p_vaddr), + p_paddr : u64::from(ph.p_paddr), + p_filesz : u64::from(ph.p_filesz), + p_memsz : u64::from(ph.p_memsz), + p_align : u64::from(ph.p_align), + } + } + } + + impl From<ElfProgramHeader> for ProgramHeader { + fn from(ph: ElfProgramHeader) -> Self { + ProgramHeader { + p_type : ph.p_type, + p_flags : ph.p_flags, + p_offset : ph.p_offset as $size, + p_vaddr : ph.p_vaddr as $size, + p_paddr : ph.p_paddr as $size, + p_filesz : ph.p_filesz as $size, + p_memsz : ph.p_memsz as $size, + p_align : ph.p_align as $size, + } + } + } + } // end if_alloc + + use core::fmt; + use core::slice; + + impl fmt::Debug for ProgramHeader { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("ProgramHeader") + .field("p_type", &pt_to_str(self.p_type)) + .field("p_flags", &format_args!("0x{:x}", self.p_flags)) + .field("p_offset", &format_args!("0x{:x}", self.p_offset)) + .field("p_vaddr", &format_args!("0x{:x}", self.p_vaddr)) + .field("p_paddr", &format_args!("0x{:x}", self.p_paddr)) + .field("p_filesz", &format_args!("0x{:x}", self.p_filesz)) + .field("p_memsz", &format_args!("0x{:x}", self.p_memsz)) + .field("p_align", &self.p_align) + .finish() + } + } + + impl ProgramHeader { + #[cfg(feature = "endian_fd")] + pub fn parse( + bytes: &[u8], + mut offset: usize, + count: usize, + ctx: ::scroll::Endian, + ) -> Result<Vec<ProgramHeader>> { + use scroll::Pread; + let mut program_headers = vec![ProgramHeader::default(); count]; + let offset = &mut offset; + bytes.gread_inout_with(offset, &mut program_headers, ctx)?; + Ok(program_headers) + } + + #[cfg(feature = "alloc")] + pub fn from_bytes(bytes: &[u8], phnum: usize) -> Vec<ProgramHeader> { + let mut phdrs = vec![ProgramHeader::default(); phnum]; + phdrs + .copy_from_bytes(bytes) + .expect("buffer is too short for given number of entries"); + phdrs + } + + /// # Safety + /// + /// This function creates a `ProgramHeader` directly from a raw pointer + pub unsafe fn from_raw_parts<'a>( + phdrp: *const ProgramHeader, + phnum: usize, + ) -> &'a [ProgramHeader] { + slice::from_raw_parts(phdrp, phnum) + } + + #[cfg(feature = "std")] + pub fn from_fd(fd: &mut File, offset: u64, count: usize) -> Result<Vec<ProgramHeader>> { + let mut phdrs = vec![ProgramHeader::default(); count]; + fd.seek(Start(offset))?; + unsafe { + fd.read_exact(plain::as_mut_bytes(&mut *phdrs))?; + } + Ok(phdrs) + } + } + }; +} + +#[cfg(feature = "alloc")] +use scroll::{Pread, Pwrite, SizeWith}; + +pub mod program_header32 { + pub use crate::elf::program_header::*; + + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Default)] + #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))] + /// A 32-bit ProgramHeader typically specifies how to map executable and data segments into memory + pub struct ProgramHeader { + /// Segment type + pub p_type: u32, + /// Segment file offset + pub p_offset: u32, + /// Segment virtual address + pub p_vaddr: u32, + /// Segment physical address + pub p_paddr: u32, + /// Segment size in file + pub p_filesz: u32, + /// Segment size in memory + pub p_memsz: u32, + /// Segment flags + pub p_flags: u32, + /// Segment alignment + pub p_align: u32, + } + + pub const SIZEOF_PHDR: usize = 32; + + // Declare that this is a plain type. + unsafe impl plain::Plain for ProgramHeader {} + + elf_program_header_std_impl!(u32); +} + +pub mod program_header64 { + pub use crate::elf::program_header::*; + + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Default)] + #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))] + /// A 64-bit ProgramHeader typically specifies how to map executable and data segments into memory + pub struct ProgramHeader { + /// Segment type + pub p_type: u32, + /// Segment flags + pub p_flags: u32, + /// Segment file offset + pub p_offset: u64, + /// Segment virtual address + pub p_vaddr: u64, + /// Segment physical address + pub p_paddr: u64, + /// Segment size in file + pub p_filesz: u64, + /// Segment size in memory + pub p_memsz: u64, + /// Segment alignment + pub p_align: u64, + } + + pub const SIZEOF_PHDR: usize = 56; + + // Declare that this is a plain type. + unsafe impl plain::Plain for ProgramHeader {} + + elf_program_header_std_impl!(u64); +} |