summaryrefslogtreecommitdiffstats
path: root/third_party/rust/goblin/src/elf/program_header.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/goblin/src/elf/program_header.rs')
-rw-r--r--third_party/rust/goblin/src/elf/program_header.rs427
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);
+}