123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430 |
- //! Module for [`ElfSectionsTag`].
- #[cfg(feature = "builder")]
- use crate::builder::BoxedDst;
- use crate::{TagHeader, TagTrait, TagType};
- use core::fmt::{Debug, Formatter};
- use core::mem;
- use core::str::Utf8Error;
- const METADATA_SIZE: usize = mem::size_of::<TagHeader>() + 3 * mem::size_of::<u32>();
- /// This tag contains the section header table from an ELF binary.
- // The sections iterator is provided via the [`ElfSectionsTag::sections`]
- // method.
- #[derive(ptr_meta::Pointee, PartialEq, Eq)]
- #[repr(C, align(8))]
- pub struct ElfSectionsTag {
- header: TagHeader,
- number_of_sections: u32,
- pub(crate) entry_size: u32,
- pub(crate) shndx: u32, // string table
- sections: [u8],
- }
- impl ElfSectionsTag {
- /// Create a new ElfSectionsTag with the given data.
- #[cfg(feature = "builder")]
- #[must_use]
- pub fn new(
- number_of_sections: u32,
- entry_size: u32,
- shndx: u32,
- sections: &[u8],
- ) -> BoxedDst<Self> {
- let mut bytes = [
- number_of_sections.to_le_bytes(),
- entry_size.to_le_bytes(),
- shndx.to_le_bytes(),
- ]
- .concat();
- bytes.extend_from_slice(sections);
- BoxedDst::new(&bytes)
- }
- /// Get an iterator of loaded ELF sections.
- pub(crate) const fn sections(&self) -> ElfSectionIter {
- let string_section_offset = (self.shndx * self.entry_size) as isize;
- let string_section_ptr =
- unsafe { self.first_section().offset(string_section_offset) as *const _ };
- ElfSectionIter {
- current_section: self.first_section(),
- remaining_sections: self.number_of_sections,
- entry_size: self.entry_size,
- string_section: string_section_ptr,
- }
- }
- const fn first_section(&self) -> *const u8 {
- &(self.sections[0]) as *const _
- }
- }
- impl TagTrait for ElfSectionsTag {
- const ID: TagType = TagType::ElfSections;
- fn dst_len(header: &TagHeader) -> usize {
- assert!(header.size as usize >= METADATA_SIZE);
- header.size as usize - METADATA_SIZE
- }
- }
- impl Debug for ElfSectionsTag {
- fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
- f.debug_struct("ElfSectionsTag")
- .field("typ", &self.header.typ)
- .field("size", &self.header.size)
- .field("number_of_sections", &self.number_of_sections)
- .field("entry_size", &self.entry_size)
- .field("shndx", &self.shndx)
- .field("sections", &self.sections())
- .finish()
- }
- }
- /// An iterator over some ELF sections.
- #[derive(Clone)]
- /// TODO make this memory safe with lifetime capture.
- pub struct ElfSectionIter {
- current_section: *const u8,
- remaining_sections: u32,
- entry_size: u32,
- string_section: *const u8,
- }
- impl Iterator for ElfSectionIter {
- type Item = ElfSection;
- fn next(&mut self) -> Option<ElfSection> {
- while self.remaining_sections != 0 {
- let section = ElfSection {
- inner: self.current_section,
- string_section: self.string_section,
- entry_size: self.entry_size,
- };
- self.current_section = unsafe { self.current_section.offset(self.entry_size as isize) };
- self.remaining_sections -= 1;
- if section.section_type() != ElfSectionType::Unused {
- return Some(section);
- }
- }
- None
- }
- }
- impl Debug for ElfSectionIter {
- fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
- let mut debug = f.debug_list();
- self.clone().for_each(|ref e| {
- debug.entry(e);
- });
- debug.finish()
- }
- }
- impl Default for ElfSectionIter {
- fn default() -> Self {
- Self {
- current_section: core::ptr::null(),
- remaining_sections: 0,
- entry_size: 0,
- string_section: core::ptr::null(),
- }
- }
- }
- /// A single generic ELF Section.
- #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
- pub struct ElfSection {
- inner: *const u8,
- string_section: *const u8,
- entry_size: u32,
- }
- #[derive(Clone, Copy, Debug)]
- #[repr(C, packed)]
- struct ElfSectionInner32 {
- name_index: u32,
- typ: u32,
- flags: u32,
- addr: u32,
- offset: u32,
- size: u32,
- link: u32,
- info: u32,
- addralign: u32,
- entry_size: u32,
- }
- #[derive(Clone, Copy, Debug)]
- #[repr(C, packed)]
- struct ElfSectionInner64 {
- name_index: u32,
- typ: u32,
- flags: u64,
- addr: u64,
- offset: u64,
- size: u64,
- link: u32,
- info: u32,
- addralign: u64,
- entry_size: u64,
- }
- impl ElfSection {
- /// Get the section type as a `ElfSectionType` enum variant.
- #[must_use]
- pub fn section_type(&self) -> ElfSectionType {
- match self.get().typ() {
- 0 => ElfSectionType::Unused,
- 1 => ElfSectionType::ProgramSection,
- 2 => ElfSectionType::LinkerSymbolTable,
- 3 => ElfSectionType::StringTable,
- 4 => ElfSectionType::RelaRelocation,
- 5 => ElfSectionType::SymbolHashTable,
- 6 => ElfSectionType::DynamicLinkingTable,
- 7 => ElfSectionType::Note,
- 8 => ElfSectionType::Uninitialized,
- 9 => ElfSectionType::RelRelocation,
- 10 => ElfSectionType::Reserved,
- 11 => ElfSectionType::DynamicLoaderSymbolTable,
- 0x6000_0000..=0x6FFF_FFFF => ElfSectionType::EnvironmentSpecific,
- 0x7000_0000..=0x7FFF_FFFF => ElfSectionType::ProcessorSpecific,
- e => {
- log::warn!(
- "Unknown section type {:x}. Treating as ElfSectionType::Unused",
- e
- );
- ElfSectionType::Unused
- }
- }
- }
- /// Get the "raw" section type as a `u32`
- #[must_use]
- pub fn section_type_raw(&self) -> u32 {
- self.get().typ()
- }
- /// Read the name of the section.
- pub fn name(&self) -> Result<&str, Utf8Error> {
- use core::{slice, str};
- let name_ptr = unsafe { self.string_table().offset(self.get().name_index() as isize) };
- // strlen without null byte
- let strlen = {
- let mut len = 0;
- while unsafe { *name_ptr.offset(len) } != 0 {
- len += 1;
- }
- len as usize
- };
- str::from_utf8(unsafe { slice::from_raw_parts(name_ptr, strlen) })
- }
- /// Get the physical start address of the section.
- #[must_use]
- pub fn start_address(&self) -> u64 {
- self.get().addr()
- }
- /// Get the physical end address of the section.
- ///
- /// This is the same as doing `section.start_address() + section.size()`
- #[must_use]
- pub fn end_address(&self) -> u64 {
- self.get().addr() + self.get().size()
- }
- /// Get the section's size in bytes.
- #[must_use]
- pub fn size(&self) -> u64 {
- self.get().size()
- }
- /// Get the section's address alignment constraints.
- ///
- /// That is, the value of `start_address` must be congruent to 0,
- /// modulo the value of `addrlign`. Currently, only 0 and positive
- /// integral powers of two are allowed. Values 0 and 1 mean the section has no
- /// alignment constraints.
- #[must_use]
- pub fn addralign(&self) -> u64 {
- self.get().addralign()
- }
- /// Get the section's flags.
- #[must_use]
- pub fn flags(&self) -> ElfSectionFlags {
- ElfSectionFlags::from_bits_truncate(self.get().flags())
- }
- /// Check if the `ALLOCATED` flag is set in the section flags.
- #[must_use]
- pub fn is_allocated(&self) -> bool {
- self.flags().contains(ElfSectionFlags::ALLOCATED)
- }
- fn get(&self) -> &dyn ElfSectionInner {
- match self.entry_size {
- 40 => unsafe { &*(self.inner as *const ElfSectionInner32) },
- 64 => unsafe { &*(self.inner as *const ElfSectionInner64) },
- s => panic!("Unexpected entry size: {}", s),
- }
- }
- unsafe fn string_table(&self) -> *const u8 {
- let addr = match self.entry_size {
- 40 => (*(self.string_section as *const ElfSectionInner32)).addr as usize,
- 64 => (*(self.string_section as *const ElfSectionInner64)).addr as usize,
- s => panic!("Unexpected entry size: {}", s),
- };
- addr as *const _
- }
- }
- trait ElfSectionInner {
- fn name_index(&self) -> u32;
- fn typ(&self) -> u32;
- fn flags(&self) -> u64;
- fn addr(&self) -> u64;
- fn size(&self) -> u64;
- fn addralign(&self) -> u64;
- }
- impl ElfSectionInner for ElfSectionInner32 {
- fn name_index(&self) -> u32 {
- self.name_index
- }
- fn typ(&self) -> u32 {
- self.typ
- }
- fn flags(&self) -> u64 {
- self.flags.into()
- }
- fn addr(&self) -> u64 {
- self.addr.into()
- }
- fn size(&self) -> u64 {
- self.size.into()
- }
- fn addralign(&self) -> u64 {
- self.addralign.into()
- }
- }
- impl ElfSectionInner for ElfSectionInner64 {
- fn name_index(&self) -> u32 {
- self.name_index
- }
- fn typ(&self) -> u32 {
- self.typ
- }
- fn flags(&self) -> u64 {
- self.flags
- }
- fn addr(&self) -> u64 {
- self.addr
- }
- fn size(&self) -> u64 {
- self.size
- }
- fn addralign(&self) -> u64 {
- self.addralign
- }
- }
- /// An enum abstraction over raw ELF section types.
- #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
- #[repr(u32)]
- pub enum ElfSectionType {
- /// This value marks the section header as inactive; it does not have an
- /// associated section. Other members of the section header have undefined
- /// values.
- Unused = 0,
- /// The section holds information defined by the program, whose format and
- /// meaning are determined solely by the program.
- ProgramSection = 1,
- /// This section holds a linker symbol table.
- LinkerSymbolTable = 2,
- /// The section holds a string table.
- StringTable = 3,
- /// The section holds relocation entries with explicit addends, such as type
- /// Elf32_Rela for the 32-bit class of object files. An object file may have
- /// multiple relocation sections.
- RelaRelocation = 4,
- /// The section holds a symbol hash table.
- SymbolHashTable = 5,
- /// The section holds dynamic linking tables.
- DynamicLinkingTable = 6,
- /// This section holds information that marks the file in some way.
- Note = 7,
- /// A section of this type occupies no space in the file but otherwise resembles
- /// `ProgramSection`. Although this section contains no bytes, the
- /// sh_offset member contains the conceptual file offset.
- Uninitialized = 8,
- /// The section holds relocation entries without explicit addends, such as type
- /// Elf32_Rel for the 32-bit class of object files. An object file may have
- /// multiple relocation sections.
- RelRelocation = 9,
- /// This section type is reserved but has unspecified semantics.
- Reserved = 10,
- /// This section holds a dynamic loader symbol table.
- DynamicLoaderSymbolTable = 11,
- /// Values in this inclusive range (`[0x6000_0000, 0x6FFF_FFFF)`) are
- /// reserved for environment-specific semantics.
- EnvironmentSpecific = 0x6000_0000,
- /// Values in this inclusive range (`[0x7000_0000, 0x7FFF_FFFF)`) are
- /// reserved for processor-specific semantics.
- ProcessorSpecific = 0x7000_0000,
- }
- bitflags! {
- /// ELF Section bitflags.
- #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
- #[repr(transparent)]
- pub struct ElfSectionFlags: u64 {
- /// The section contains data that should be writable during program execution.
- const WRITABLE = 0x1;
- /// The section occupies memory during the process execution.
- const ALLOCATED = 0x2;
- /// The section contains executable machine instructions.
- const EXECUTABLE = 0x4;
- // plus environment-specific use at 0x0F000000
- // plus processor-specific use at 0xF0000000
- }
- }
|