macro_rules! elf_dyn { ($size:ty) => { // XXX: Do not import scroll traits here. // See: https://github.com/rust-lang/rust/issues/65090#issuecomment-538668155 #[repr(C)] #[derive(Copy, Clone, PartialEq, Default)] #[cfg_attr( feature = "alloc", derive(scroll::Pread, scroll::Pwrite, scroll::SizeWith) )] /// An entry in the dynamic array pub struct Dyn { /// Dynamic entry type pub d_tag: $size, /// Integer value pub d_val: $size, } use plain; unsafe impl plain::Plain for Dyn {} }; } // TODO: figure out what's the best, most friendly + safe API choice here - u32s or u64s // remember that DT_TAG is "pointer sized"/used as address sometimes Original rationale: I // decided to use u64 instead of u32 due to pattern matching use case seems safer to cast the // elf32's d_tag from u32 -> u64 at runtime instead of casting the elf64's d_tag from u64 -> // u32 at runtime /// Marks end of dynamic section pub const DT_NULL: u64 = 0; /// Name of needed library pub const DT_NEEDED: u64 = 1; /// Size in bytes of PLT relocs pub const DT_PLTRELSZ: u64 = 2; /// Processor defined value pub const DT_PLTGOT: u64 = 3; /// Address of symbol hash table pub const DT_HASH: u64 = 4; /// Address of string table pub const DT_STRTAB: u64 = 5; /// Address of symbol table pub const DT_SYMTAB: u64 = 6; /// Address of Rela relocs pub const DT_RELA: u64 = 7; /// Total size of Rela relocs pub const DT_RELASZ: u64 = 8; /// Size of one Rela reloc pub const DT_RELAENT: u64 = 9; /// Size of string table pub const DT_STRSZ: u64 = 10; /// Size of one symbol table entry pub const DT_SYMENT: u64 = 11; /// Address of init function pub const DT_INIT: u64 = 12; /// Address of termination function pub const DT_FINI: u64 = 13; /// Name of shared object pub const DT_SONAME: u64 = 14; /// Library search path (deprecated) pub const DT_RPATH: u64 = 15; /// Start symbol search here pub const DT_SYMBOLIC: u64 = 16; /// Address of Rel relocs pub const DT_REL: u64 = 17; /// Total size of Rel relocs pub const DT_RELSZ: u64 = 18; /// Size of one Rel reloc pub const DT_RELENT: u64 = 19; /// Type of reloc in PLT pub const DT_PLTREL: u64 = 20; /// For debugging; unspecified pub const DT_DEBUG: u64 = 21; /// Reloc might modify .text pub const DT_TEXTREL: u64 = 22; /// Address of PLT relocs pub const DT_JMPREL: u64 = 23; /// Process relocations of object pub const DT_BIND_NOW: u64 = 24; /// Array with addresses of init fct pub const DT_INIT_ARRAY: u64 = 25; /// Array with addresses of fini fct pub const DT_FINI_ARRAY: u64 = 26; /// Size in bytes of DT_INIT_ARRAY pub const DT_INIT_ARRAYSZ: u64 = 27; /// Size in bytes of DT_FINI_ARRAY pub const DT_FINI_ARRAYSZ: u64 = 28; /// Library search path pub const DT_RUNPATH: u64 = 29; /// Flags for the object being loaded pub const DT_FLAGS: u64 = 30; /// Start of encoded range pub const DT_ENCODING: u64 = 32; /// Array with addresses of preinit fct pub const DT_PREINIT_ARRAY: u64 = 32; /// size in bytes of DT_PREINIT_ARRAY pub const DT_PREINIT_ARRAYSZ: u64 = 33; /// Number used pub const DT_NUM: u64 = 34; /// Start of OS-specific pub const DT_LOOS: u64 = 0x6000_000d; /// End of OS-specific pub const DT_HIOS: u64 = 0x6fff_f000; /// Start of processor-specific pub const DT_LOPROC: u64 = 0x7000_0000; /// End of processor-specific pub const DT_HIPROC: u64 = 0x7fff_ffff; // Most used by any processor // pub const DT_PROCNUM: u64 = DT_MIPS_NUM; /// DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the /// Dyn.d_un.d_ptr field of the Elf*_Dyn structure. /// /// If any adjustment is made to the ELF object after it has been /// built these entries will need to be adjusted. pub const DT_ADDRRNGLO: u64 = 0x6fff_fe00; /// GNU-style hash table pub const DT_GNU_HASH: u64 = 0x6fff_fef5; /// pub const DT_TLSDESC_PLT: u64 = 0x6fff_fef6; /// pub const DT_TLSDESC_GOT: u64 = 0x6fff_fef7; /// Start of conflict section pub const DT_GNU_CONFLICT: u64 = 0x6fff_fef8; /// Library list pub const DT_GNU_LIBLIST: u64 = 0x6fff_fef9; /// Configuration information pub const DT_CONFIG: u64 = 0x6fff_fefa; /// Dependency auditing pub const DT_DEPAUDIT: u64 = 0x6fff_fefb; /// Object auditing pub const DT_AUDIT: u64 = 0x6fff_fefc; /// PLT padding pub const DT_PLTPAD: u64 = 0x6fff_fefd; /// Move table pub const DT_MOVETAB: u64 = 0x6fff_fefe; /// Syminfo table pub const DT_SYMINFO: u64 = 0x6fff_feff; /// pub const DT_ADDRRNGHI: u64 = 0x6fff_feff; //DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ pub const DT_ADDRNUM: u64 = 11; /// The versioning entry types. The next are defined as part of the GNU extension pub const DT_VERSYM: u64 = 0x6fff_fff0; pub const DT_RELACOUNT: u64 = 0x6fff_fff9; pub const DT_RELCOUNT: u64 = 0x6fff_fffa; /// State flags, see DF_1_* below pub const DT_FLAGS_1: u64 = 0x6fff_fffb; /// Address of version definition table pub const DT_VERDEF: u64 = 0x6fff_fffc; /// Number of version definitions pub const DT_VERDEFNUM: u64 = 0x6fff_fffd; /// Address of table with needed versions pub const DT_VERNEED: u64 = 0x6fff_fffe; /// Number of needed versions pub const DT_VERNEEDNUM: u64 = 0x6fff_ffff; /// Converts a tag to its string representation. #[inline] pub fn tag_to_str(tag: u64) -> &'static str { match tag { DT_NULL => "DT_NULL", DT_NEEDED => "DT_NEEDED", DT_PLTRELSZ => "DT_PLTRELSZ", DT_PLTGOT => "DT_PLTGOT", DT_HASH => "DT_HASH", DT_STRTAB => "DT_STRTAB", DT_SYMTAB => "DT_SYMTAB", DT_RELA => "DT_RELA", DT_RELASZ => "DT_RELASZ", DT_RELAENT => "DT_RELAENT", DT_STRSZ => "DT_STRSZ", DT_SYMENT => "DT_SYMENT", DT_INIT => "DT_INIT", DT_FINI => "DT_FINI", DT_SONAME => "DT_SONAME", DT_RPATH => "DT_RPATH", DT_SYMBOLIC => "DT_SYMBOLIC", DT_REL => "DT_REL", DT_RELSZ => "DT_RELSZ", DT_RELENT => "DT_RELENT", DT_PLTREL => "DT_PLTREL", DT_DEBUG => "DT_DEBUG", DT_TEXTREL => "DT_TEXTREL", DT_JMPREL => "DT_JMPREL", DT_BIND_NOW => "DT_BIND_NOW", DT_INIT_ARRAY => "DT_INIT_ARRAY", DT_FINI_ARRAY => "DT_FINI_ARRAY", DT_INIT_ARRAYSZ => "DT_INIT_ARRAYSZ", DT_FINI_ARRAYSZ => "DT_FINI_ARRAYSZ", DT_RUNPATH => "DT_RUNPATH", DT_FLAGS => "DT_FLAGS", DT_PREINIT_ARRAY => "DT_PREINIT_ARRAY", DT_PREINIT_ARRAYSZ => "DT_PREINIT_ARRAYSZ", DT_NUM => "DT_NUM", DT_LOOS => "DT_LOOS", DT_HIOS => "DT_HIOS", DT_LOPROC => "DT_LOPROC", DT_HIPROC => "DT_HIPROC", DT_VERSYM => "DT_VERSYM", DT_RELACOUNT => "DT_RELACOUNT", DT_RELCOUNT => "DT_RELCOUNT", DT_GNU_HASH => "DT_GNU_HASH", DT_VERDEF => "DT_VERDEF", DT_VERDEFNUM => "DT_VERDEFNUM", DT_VERNEED => "DT_VERNEED", DT_VERNEEDNUM => "DT_VERNEEDNUM", DT_FLAGS_1 => "DT_FLAGS_1", _ => "UNKNOWN_TAG", } } // Values of `d_un.d_val` in the DT_FLAGS entry /// Object may use DF_ORIGIN. pub const DF_ORIGIN: u64 = 0x0000_0001; /// Symbol resolutions starts here. pub const DF_SYMBOLIC: u64 = 0x0000_0002; /// Object contains text relocations. pub const DF_TEXTREL: u64 = 0x0000_0004; /// No lazy binding for this object. pub const DF_BIND_NOW: u64 = 0x0000_0008; /// Module uses the static TLS model. pub const DF_STATIC_TLS: u64 = 0x0000_0010; pub fn df_tag_to_str(tag: u64) -> &'static str { match tag { DF_ORIGIN => "DF_ORIGIN", DF_SYMBOLIC => "DF_SYMBOLIC", DF_TEXTREL => "DF_TEXTREL", DF_BIND_NOW => "DF_BIND_NOW", DF_STATIC_TLS => "DF_STATIC_TLS", _ => "UNKNOWN_TAG", } } /// === State flags === /// selectable in the `d_un.d_val` element of the DT_FLAGS_1 entry in the dynamic section. /// /// Set RTLD_NOW for this object. pub const DF_1_NOW: u64 = 0x0000_0001; /// Set RTLD_GLOBAL for this object. pub const DF_1_GLOBAL: u64 = 0x0000_0002; /// Set RTLD_GROUP for this object. pub const DF_1_GROUP: u64 = 0x0000_0004; /// Set RTLD_NODELETE for this object. pub const DF_1_NODELETE: u64 = 0x0000_0008; /// Trigger filtee loading at runtime. pub const DF_1_LOADFLTR: u64 = 0x0000_0010; /// Set RTLD_INITFIRST for this object. pub const DF_1_INITFIRST: u64 = 0x0000_0020; /// Set RTLD_NOOPEN for this object. pub const DF_1_NOOPEN: u64 = 0x0000_0040; /// $ORIGIN must be handled. pub const DF_1_ORIGIN: u64 = 0x0000_0080; /// Direct binding enabled. pub const DF_1_DIRECT: u64 = 0x0000_0100; pub const DF_1_TRANS: u64 = 0x0000_0200; /// Object is used to interpose. pub const DF_1_INTERPOSE: u64 = 0x0000_0400; /// Ignore default lib search path. pub const DF_1_NODEFLIB: u64 = 0x0000_0800; /// Object can't be dldump'ed. pub const DF_1_NODUMP: u64 = 0x0000_1000; /// Configuration alternative created. pub const DF_1_CONFALT: u64 = 0x0000_2000; /// Filtee terminates filters search. pub const DF_1_ENDFILTEE: u64 = 0x0000_4000; /// Disp reloc applied at build time. pub const DF_1_DISPRELDNE: u64 = 0x0000_8000; /// Disp reloc applied at run-time. pub const DF_1_DISPRELPND: u64 = 0x0001_0000; /// Object has no-direct binding. pub const DF_1_NODIRECT: u64 = 0x0002_0000; pub const DF_1_IGNMULDEF: u64 = 0x0004_0000; pub const DF_1_NOKSYMS: u64 = 0x0008_0000; pub const DF_1_NOHDR: u64 = 0x0010_0000; /// Object is modified after built. pub const DF_1_EDITED: u64 = 0x0020_0000; pub const DF_1_NORELOC: u64 = 0x0040_0000; /// Object has individual interposers. pub const DF_1_SYMINTPOSE: u64 = 0x0080_0000; /// Global auditing required. pub const DF_1_GLOBAUDIT: u64 = 0x0100_0000; /// Singleton dyn are used. pub const DF_1_SINGLETON: u64 = 0x0200_0000; /// Object is a Position Independent Executable (PIE). pub const DF_1_PIE: u64 = 0x0800_0000; pub fn df_1_tag_to_str(tag: u64) -> &'static str { match tag { DF_1_NOW => "DF_1_NOW", DF_1_GLOBAL => "DF_1_GLOBAL", DF_1_GROUP => "DF_1_GROUP", DF_1_NODELETE => "DF_1_NODELETE", DF_1_LOADFLTR => "DF_1_LOADFLTR", DF_1_INITFIRST => "DF_1_INITFIRST", DF_1_NOOPEN => "DF_1_NOOPEN", DF_1_ORIGIN => "DF_1_ORIGIN", DF_1_DIRECT => "DF_1_DIRECT", DF_1_TRANS => "DF_1_TRANS", DF_1_INTERPOSE => "DF_1_INTERPOSE", DF_1_NODEFLIB => "DF_1_NODEFLIB", DF_1_NODUMP => "DF_1_NODUMP", DF_1_CONFALT => "DF_1_CONFALT", DF_1_ENDFILTEE => "DF_1_ENDFILTEE", DF_1_DISPRELDNE => "DF_1_DISPRELDNE", DF_1_DISPRELPND => "DF_1_DISPRELPND", DF_1_NODIRECT => "DF_1_NODIRECT", DF_1_IGNMULDEF => "DF_1_IGNMULDEF", DF_1_NOKSYMS => "DF_1_NOKSYMS", DF_1_NOHDR => "DF_1_NOHDR", DF_1_EDITED => "DF_1_EDITED", DF_1_NORELOC => "DF_1_NORELOC", DF_1_SYMINTPOSE => "DF_1_SYMINTPOSE", DF_1_GLOBAUDIT => "DF_1_GLOBAUDIT", DF_1_SINGLETON => "DF_1_SINGLETON", DF_1_PIE => "DF_1_PIE", _ => "UNKNOWN_TAG", } } if_alloc! { use core::fmt; use scroll::ctx; use core::result; use crate::container::{Ctx, Container}; use crate::strtab::Strtab; use alloc::vec::Vec; #[derive(Default, PartialEq, Clone)] pub struct Dyn { pub d_tag: u64, pub d_val: u64, } impl Dyn { #[inline] pub fn size(container: Container) -> usize { use scroll::ctx::SizeWith; Self::size_with(&Ctx::from(container)) } } impl fmt::Debug for Dyn { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Dyn") .field("d_tag", &tag_to_str(self.d_tag)) .field("d_val", &format_args!("0x{:x}", self.d_val)) .finish() } } impl ctx::SizeWith for Dyn { fn size_with(&Ctx { container, .. }: &Ctx) -> usize { match container { Container::Little => { dyn32::SIZEOF_DYN }, Container::Big => { dyn64::SIZEOF_DYN }, } } } impl<'a> ctx::TryFromCtx<'a, Ctx> for Dyn { 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 dynamic = match container { Container::Little => { (bytes.pread_with::(0, le)?.into(), dyn32::SIZEOF_DYN) }, Container::Big => { (bytes.pread_with::(0, le)?.into(), dyn64::SIZEOF_DYN) } }; Ok(dynamic) } } impl ctx::TryIntoCtx for Dyn { 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 dynamic: dyn32::Dyn = self.into(); Ok(bytes.pwrite_with(dynamic, 0, le)?) }, Container::Big => { let dynamic: dyn64::Dyn = self.into(); Ok(bytes.pwrite_with(dynamic, 0, le)?) } } } } #[derive(Debug)] pub struct Dynamic { pub dyns: Vec, pub info: DynamicInfo, } impl Dynamic { #[cfg(feature = "endian_fd")] /// Returns a vector of dynamic entries from the underlying byte `bytes`, with `endianness`, using the provided `phdrs` pub fn parse(bytes: &[u8], phdrs: &[crate::elf::program_header::ProgramHeader], ctx: Ctx) -> crate::error::Result> { use scroll::ctx::SizeWith; use scroll::Pread; use crate::elf::program_header; for phdr in phdrs { if phdr.p_type == program_header::PT_DYNAMIC { let offset = phdr.p_offset as usize; let filesz = phdr.p_filesz as usize; // Ensure offset and filesz are valid. let bytes = if filesz > 0 { bytes .pread_with::<&[u8]>(offset, filesz) .map_err(|_| crate::error::Error::Malformed(format!("Invalid PT_DYNAMIC size (offset {:#x}, filesz {:#x})", offset, filesz)))? } else { &[] }; let size = Dyn::size_with(&ctx); // the validity of `count` was implicitly checked by reading `bytes`. let count = filesz / size; let mut dyns = Vec::with_capacity(count); let mut offset = 0; for _ in 0..count { let dynamic = bytes.gread_with::(&mut offset, ctx)?; let tag = dynamic.d_tag; dyns.push(dynamic); if tag == DT_NULL { break } } let mut info = DynamicInfo::default(); for dynamic in &dyns { info.update(phdrs, dynamic); } return Ok(Some(Dynamic { dyns: dyns, info: info, })); } } Ok(None) } pub fn get_libraries<'a>(&self, strtab: &Strtab<'a>) -> Vec<&'a str> { use log::warn; let count = self.info.needed_count.min(self.dyns.len()); let mut needed = Vec::with_capacity(count); for dynamic in &self.dyns { if dynamic.d_tag as u64 == DT_NEEDED { if let Some(lib) = strtab.get_at(dynamic.d_val as usize) { needed.push(lib) } else { warn!("Invalid DT_NEEDED {}", dynamic.d_val) } } } needed } } } macro_rules! elf_dyn_std_impl { ($size:ident, $phdr:ty) => { #[cfg(test)] mod tests { use super::*; #[test] fn size_of() { assert_eq!(::std::mem::size_of::(), SIZEOF_DYN); } } if_alloc! { use core::fmt; use core::slice; use alloc::vec::Vec; use crate::elf::program_header::{PT_DYNAMIC}; use crate::strtab::Strtab; use crate::elf::dynamic::Dyn as ElfDyn; if_std! { use std::fs::File; use std::io::{Read, Seek}; use std::io::SeekFrom::Start; use crate::error::Result; } impl From for Dyn { fn from(dynamic: ElfDyn) -> Self { Dyn { d_tag: dynamic.d_tag as $size, d_val: dynamic.d_val as $size, } } } impl From for ElfDyn { fn from(dynamic: Dyn) -> Self { ElfDyn { d_tag: u64::from(dynamic.d_tag), d_val: u64::from(dynamic.d_val), } } } impl fmt::Debug for Dyn { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Dyn") .field("d_tag", &tag_to_str(u64::from(self.d_tag))) .field("d_val", &format_args!("0x{:x}", self.d_val)) .finish() } } /// Returns a vector of dynamic entries from the given fd and program headers #[cfg(feature = "std")] pub fn from_fd(mut fd: &File, phdrs: &[$phdr]) -> Result>> { for phdr in phdrs { if phdr.p_type == PT_DYNAMIC { // FIXME: validate filesz before allocating let filesz = phdr.p_filesz as usize; let dync = filesz / SIZEOF_DYN; let mut dyns = vec![Dyn::default(); dync]; fd.seek(Start(u64::from(phdr.p_offset)))?; unsafe { fd.read_exact(plain::as_mut_bytes(&mut *dyns))?; } dyns.dedup(); return Ok(Some(dyns)); } } Ok(None) } /// Given a bias and a memory address (typically for a _correctly_ mmap'd binary in memory), returns the `_DYNAMIC` array as a slice of that memory pub unsafe fn from_raw<'a>(bias: usize, vaddr: usize) -> &'a [Dyn] { let dynp = vaddr.wrapping_add(bias) as *const Dyn; let mut idx = 0; while u64::from((*dynp.offset(idx)).d_tag) != DT_NULL { idx += 1; } slice::from_raw_parts(dynp, idx as usize) } // TODO: these bare functions have always seemed awkward, but not sure where they should go... /// Maybe gets and returns the dynamic array with the same lifetime as the [phdrs], using the provided bias with wrapping addition. /// If the bias is wrong, it will either segfault or give you incorrect values, beware pub unsafe fn from_phdrs(bias: usize, phdrs: &[$phdr]) -> Option<&[Dyn]> { for phdr in phdrs { // FIXME: change to casting to u64 similar to DT_*? if phdr.p_type as u32 == PT_DYNAMIC { return Some(from_raw(bias, phdr.p_vaddr as usize)); } } None } /// Gets the needed libraries from the `_DYNAMIC` array, with the str slices lifetime tied to the dynamic array/strtab's lifetime(s) pub unsafe fn get_needed<'a>(dyns: &[Dyn], strtab: *const Strtab<'a>, count: usize) -> Vec<&'a str> { let mut needed = Vec::with_capacity(count.min(dyns.len())); for dynamic in dyns { if u64::from(dynamic.d_tag) == DT_NEEDED { let lib = &(*strtab)[dynamic.d_val as usize]; needed.push(lib); } } needed } } }; } macro_rules! elf_dynamic_info_std_impl { ($size:ident, $phdr:ty) => { /// Convert a virtual memory address to a file offset fn vm_to_offset(phdrs: &[$phdr], address: $size) -> Option<$size> { for ph in phdrs { if ph.p_type == crate::elf::program_header::PT_LOAD && address >= ph.p_vaddr { let offset = address - ph.p_vaddr; if offset < ph.p_memsz { return ph.p_offset.checked_add(offset); } } } None } /// Important dynamic linking info generated via a single pass through the `_DYNAMIC` array #[derive(Default, PartialEq)] pub struct DynamicInfo { pub rela: usize, pub relasz: usize, pub relaent: $size, pub relacount: usize, pub rel: usize, pub relsz: usize, pub relent: $size, pub relcount: usize, pub gnu_hash: Option<$size>, pub hash: Option<$size>, pub strtab: usize, pub strsz: usize, pub symtab: usize, pub syment: usize, pub pltgot: Option<$size>, pub pltrelsz: usize, pub pltrel: $size, pub jmprel: usize, pub verdef: $size, pub verdefnum: $size, pub verneed: $size, pub verneednum: $size, pub versym: $size, pub init: $size, pub fini: $size, pub init_array: $size, pub init_arraysz: usize, pub fini_array: $size, pub fini_arraysz: usize, pub needed_count: usize, pub flags: $size, pub flags_1: $size, pub soname: usize, pub textrel: bool, } impl DynamicInfo { #[inline] pub fn update(&mut self, phdrs: &[$phdr], dynamic: &Dyn) { match u64::from(dynamic.d_tag) { DT_RELA => self.rela = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0) as usize, // .rela.dyn DT_RELASZ => self.relasz = dynamic.d_val as usize, DT_RELAENT => self.relaent = dynamic.d_val as _, DT_RELACOUNT => self.relacount = dynamic.d_val as usize, DT_REL => self.rel = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0) as usize, // .rel.dyn DT_RELSZ => self.relsz = dynamic.d_val as usize, DT_RELENT => self.relent = dynamic.d_val as _, DT_RELCOUNT => self.relcount = dynamic.d_val as usize, DT_GNU_HASH => self.gnu_hash = vm_to_offset(phdrs, dynamic.d_val), DT_HASH => self.hash = vm_to_offset(phdrs, dynamic.d_val), DT_STRTAB => { self.strtab = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0) as usize } DT_STRSZ => self.strsz = dynamic.d_val as usize, DT_SYMTAB => { self.symtab = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0) as usize } DT_SYMENT => self.syment = dynamic.d_val as usize, DT_PLTGOT => self.pltgot = vm_to_offset(phdrs, dynamic.d_val), DT_PLTRELSZ => self.pltrelsz = dynamic.d_val as usize, DT_PLTREL => self.pltrel = dynamic.d_val as _, DT_JMPREL => { self.jmprel = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0) as usize } // .rela.plt DT_VERDEF => self.verdef = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0), DT_VERDEFNUM => self.verdefnum = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0), DT_VERNEED => self.verneed = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0), DT_VERNEEDNUM => self.verneednum = dynamic.d_val as _, DT_VERSYM => self.versym = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0), DT_INIT => self.init = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0), DT_FINI => self.fini = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0), DT_INIT_ARRAY => { self.init_array = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0) } DT_INIT_ARRAYSZ => self.init_arraysz = dynamic.d_val as _, DT_FINI_ARRAY => { self.fini_array = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0) } DT_FINI_ARRAYSZ => self.fini_arraysz = dynamic.d_val as _, DT_NEEDED => self.needed_count += 1, DT_FLAGS => self.flags = dynamic.d_val as _, DT_FLAGS_1 => self.flags_1 = dynamic.d_val as _, DT_SONAME => self.soname = dynamic.d_val as _, DT_TEXTREL => self.textrel = true, _ => (), } } pub fn new(dynamic: &[Dyn], phdrs: &[$phdr]) -> DynamicInfo { let mut info = DynamicInfo::default(); for dyna in dynamic { info.update(phdrs, &dyna); } info } } if_alloc! { impl fmt::Debug for DynamicInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let gnu_hash = self.gnu_hash.unwrap_or(0); let hash = self.hash.unwrap_or(0); let pltgot = self.pltgot.unwrap_or(0); let flags: Vec<&'static str> = [DF_ORIGIN, DF_SYMBOLIC, DF_TEXTREL, DF_BIND_NOW, DF_STATIC_TLS,][..] .iter() .filter(|f| (self.flags as u64 & *f) != 0) .map(|f| df_tag_to_str(*f)) .collect(); let flags_1: Vec<&'static str> = [ DF_1_NOW, DF_1_GLOBAL, DF_1_GROUP, DF_1_NODELETE, DF_1_LOADFLTR, DF_1_INITFIRST, DF_1_NOOPEN, DF_1_ORIGIN, DF_1_DIRECT, DF_1_TRANS, DF_1_INTERPOSE, DF_1_NODEFLIB, DF_1_NODUMP, DF_1_CONFALT, DF_1_ENDFILTEE, DF_1_DISPRELDNE, DF_1_DISPRELPND, DF_1_NODIRECT, DF_1_IGNMULDEF, DF_1_NOKSYMS, DF_1_NOHDR, DF_1_EDITED, DF_1_NORELOC, DF_1_SYMINTPOSE, DF_1_GLOBAUDIT, DF_1_SINGLETON, DF_1_PIE, ][..] .iter() .filter(|f| (self.flags_1 as u64 & *f) != 0) .map(|f| df_1_tag_to_str(*f)) .collect(); f.debug_struct("DynamicInfo") .field("rela", &format_args!("0x{:x}", self.rela)) .field("relasz", &self.relasz) .field("relaent", &self.relaent) .field("relacount", &self.relacount) .field("gnu_hash", &format_args!("0x{:x}", gnu_hash)) .field("hash", &format_args!("0x{:x}", hash)) .field("strtab", &format_args!("0x{:x}", self.strtab)) .field("strsz", &self.strsz) .field("symtab", &format_args!("0x{:x}", self.symtab)) .field("syment", &self.syment) .field("pltgot", &format_args!("0x{:x}", pltgot)) .field("pltrelsz", &self.pltrelsz) .field("pltrel", &self.pltrel) .field("jmprel", &format_args!("0x{:x}", self.jmprel)) .field("verdef", &format_args!("0x{:x}", self.verdef)) .field("verdefnum", &self.verdefnum) .field("verneed", &format_args!("0x{:x}", self.verneed)) .field("verneednum", &self.verneednum) .field("versym", &format_args!("0x{:x}", self.versym)) .field("init", &format_args!("0x{:x}", self.init)) .field("fini", &format_args!("0x{:x}", self.fini)) .field("init_array", &format_args!("{:#x}", self.init_array)) .field("init_arraysz", &self.init_arraysz) .field("needed_count", &self.needed_count) .field("flags", &format_args!("{:#0width$x} {:?}", self.flags, flags, width = core::mem::size_of_val(&self.flags))) .field("flags_1", &format_args!("{:#0width$x} {:?}", self.flags_1, flags_1, width = core::mem::size_of_val(&self.flags_1))) .field("soname", &self.soname) .field("textrel", &self.textrel) .finish() } } } }; } if_alloc! { elf_dynamic_info_std_impl!(u64, crate::elf::program_header::ProgramHeader); } pub mod dyn32 { pub use crate::elf::dynamic::*; elf_dyn!(u32); pub const SIZEOF_DYN: usize = 8; elf_dyn_std_impl!(u32, crate::elf32::program_header::ProgramHeader); elf_dynamic_info_std_impl!( u32, crate::elf::program_header::program_header32::ProgramHeader ); } pub mod dyn64 { pub use crate::elf::dynamic::*; elf_dyn!(u64); pub const SIZEOF_DYN: usize = 16; elf_dyn_std_impl!(u64, crate::elf64::program_header::ProgramHeader); elf_dynamic_info_std_impl!( u64, crate::elf::program_header::program_header64::ProgramHeader ); }