/* Legal values for p_type (segment type). */ /// Program 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; 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 { (self.p_offset as usize..self.p_offset as usize + self.p_filesz as usize) } /// Returns this program header's virtual memory range pub fn vm_range(&self) -> Range { (self.p_vaddr as usize..self.p_vaddr as usize + 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> { use scroll::Pread; 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 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::(0, le)?.into(), program_header32::SIZEOF_PHDR) }, Container::Big => { (bytes.pread_with::(0, le)?.into(), program_header64::SIZEOF_PHDR) } }; Ok(res) } } impl ctx::TryIntoCtx for ProgramHeader { type Error = crate::error::Error; fn try_into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) -> result::Result { 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::(), SIZEOF_PHDR); } } if_alloc! { use crate::elf::program_header::ProgramHeader as ElfProgramHeader; #[cfg(any(feature = "std", feature = "endian_fd"))] use crate::error::Result; use core::slice; use core::fmt; use plain::Plain; if_std! { use std::fs::File; use std::io::{Seek, Read}; use std::io::SeekFrom::Start; } impl From 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 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, } } } 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> { 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) } pub fn from_bytes(bytes: &[u8], phnum: usize) -> Vec { let mut phdrs = vec![ProgramHeader::default(); phnum]; phdrs.copy_from_bytes(bytes).expect("buffer is too short for given number of entries"); phdrs } 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> { let mut phdrs = vec![ProgramHeader::default(); count]; fd.seek(Start(offset))?; unsafe { fd.read_exact(plain::as_mut_bytes(&mut *phdrs))?; } Ok(phdrs) } } } // end if_alloc };} #[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 64-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; use plain; // 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 32-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; use plain; // Declare that this is a plain type. unsafe impl plain::Plain for ProgramHeader {} elf_program_header_std_impl!(u64); }