use super::header::ElfClass;
use crate::errors::FileParseError;
use crate::field::{ByteOrder, Field, NumericFieldMut};
pub const DT_NULL: u64 = 0;
pub const DT_NEEDED: u64 = 1;
pub const DT_PLTRELSZ: u64 = 2;
pub const DT_PLTGOT: u64 = 3;
pub const DT_HASH: u64 = 4;
pub const DT_STRTAB: u64 = 5;
pub const DT_SYMTAB: u64 = 6;
pub const DT_RELA: u64 = 7;
pub const DT_RELASZ: u64 = 8;
pub const DT_RELAENT: u64 = 9;
pub const DT_STRSZ: u64 = 10;
pub const DT_SYMENT: u64 = 11;
pub const DT_INIT: u64 = 12;
pub const DT_FINI: u64 = 13;
pub const DT_SONAME: u64 = 14;
pub const DT_RPATH: u64 = 15;
pub const DT_SYMBOLIC: u64 = 16;
pub const DT_REL: u64 = 17;
pub const DT_RELSZ: u64 = 18;
pub const DT_RELENT: u64 = 19;
pub const DT_PLTREL: u64 = 20;
pub const DT_DEBUG: u64 = 21;
pub const DT_TEXTREL: u64 = 22;
pub const DT_JMPREL: u64 = 23;
pub const DT_RUNPATH: u64 = 29;
pub const DT_FLAGS: u64 = 30;
pub const DT_GNU_HASH: u64 = 0x6fff_fef5;
pub const DT_VERSYM: u64 = 0x6fff_fff0;
pub const DT_VERDEF: u64 = 0x6fff_fffc;
pub const DT_VERDEFNUM: u64 = 0x6fff_fffd;
pub const DT_VERNEED: u64 = 0x6fff_fffe;
pub const DT_VERNEEDNUM: u64 = 0x6fff_ffff;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DynamicTag {
Null,
Needed,
PltRelSz,
PltGot,
Hash,
StrTab,
SymTab,
Rela,
RelaSz,
RelaEnt,
StrSz,
SymEnt,
Init,
Fini,
SoName,
RPath,
Symbolic,
Rel,
RelSz,
RelEnt,
PltRel,
Debug,
TextRel,
JmpRel,
RunPath,
Flags,
GnuHash,
VerSym,
VerDef,
VerDefNum,
VerNeed,
VerNeedNum,
Other(u64),
}
impl From<u64> for DynamicTag {
fn from(value: u64) -> Self {
match value {
DT_NULL => DynamicTag::Null,
DT_NEEDED => DynamicTag::Needed,
DT_PLTRELSZ => DynamicTag::PltRelSz,
DT_PLTGOT => DynamicTag::PltGot,
DT_HASH => DynamicTag::Hash,
DT_STRTAB => DynamicTag::StrTab,
DT_SYMTAB => DynamicTag::SymTab,
DT_RELA => DynamicTag::Rela,
DT_RELASZ => DynamicTag::RelaSz,
DT_RELAENT => DynamicTag::RelaEnt,
DT_STRSZ => DynamicTag::StrSz,
DT_SYMENT => DynamicTag::SymEnt,
DT_INIT => DynamicTag::Init,
DT_FINI => DynamicTag::Fini,
DT_SONAME => DynamicTag::SoName,
DT_RPATH => DynamicTag::RPath,
DT_SYMBOLIC => DynamicTag::Symbolic,
DT_REL => DynamicTag::Rel,
DT_RELSZ => DynamicTag::RelSz,
DT_RELENT => DynamicTag::RelEnt,
DT_PLTREL => DynamicTag::PltRel,
DT_DEBUG => DynamicTag::Debug,
DT_TEXTREL => DynamicTag::TextRel,
DT_JMPREL => DynamicTag::JmpRel,
DT_RUNPATH => DynamicTag::RunPath,
DT_FLAGS => DynamicTag::Flags,
DT_GNU_HASH => DynamicTag::GnuHash,
DT_VERSYM => DynamicTag::VerSym,
DT_VERDEF => DynamicTag::VerDef,
DT_VERDEFNUM => DynamicTag::VerDefNum,
DT_VERNEED => DynamicTag::VerNeed,
DT_VERNEEDNUM => DynamicTag::VerNeedNum,
other => DynamicTag::Other(other),
}
}
}
pub struct DynamicEntry {
pub d_tag: Field<u64>,
pub d_val: Field<u64>,
}
impl DynamicEntry {
pub fn tag(&self) -> u64 {
self.d_tag.value
}
pub fn tag_kind(&self) -> DynamicTag {
DynamicTag::from(self.d_tag.value)
}
pub fn value(&self) -> u64 {
self.d_val.value
}
pub fn value_mut(&mut self) -> NumericFieldMut<'_> {
NumericFieldMut::U64(&mut self.d_val)
}
}
pub struct DynamicTable {
pub offset: usize,
pub entries: Vec<DynamicEntry>,
}
impl DynamicTable {
pub fn parse(
buffer: &[u8],
offset: usize,
max_size: usize,
class: ElfClass,
order: ByteOrder,
) -> Result<Self, FileParseError> {
let ent_size = match class {
ElfClass::Elf32 => 8,
ElfClass::Elf64 => 16,
};
let end = offset
.checked_add(max_size)
.ok_or(FileParseError::BufferOverflow)?;
let mut entries = Vec::new();
let mut cursor = offset;
loop {
if cursor + ent_size > end || cursor + ent_size > buffer.len() {
break;
}
let (tag, val, val_off, val_width) = match class {
ElfClass::Elf32 => (
order.read_u32(buffer, cursor)? as u64,
order.read_u32(buffer, cursor + 4)? as u64,
cursor + 4,
4,
),
ElfClass::Elf64 => (
order.read_u64(buffer, cursor)?,
order.read_u64(buffer, cursor + 8)?,
cursor + 8,
8,
),
};
let entry = DynamicEntry {
d_tag: Field::new(tag, cursor, ent_size / 2),
d_val: Field::new(val, val_off, val_width),
};
cursor += ent_size;
if tag == DT_NULL {
break;
}
entries.push(entry);
}
Ok(DynamicTable { offset, entries })
}
pub fn find(&self, tag: u64) -> Option<&DynamicEntry> {
self.entries.iter().find(|e| e.d_tag.value == tag)
}
}