Revision control

Copy as Markdown

Other Tools

/* 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;
/// GNU property notes for linker and run-time loaders
pub const PT_GNU_PROPERTY: u32 = 0x6474_e553;
/// 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_PROPERTY => "PT_GNU_PROPERTY",
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);
}