///|
/// Lazy table of `.dynamic` entries.
///
/// Dynamic tables can come from an `SHT_DYNAMIC` section or from a `PT_DYNAMIC`
/// program segment. Entries are parsed on demand as `Dyn` records.
pub struct DynamicTable {
table : ParsingTable[Dyn]
}
///|
fn DynamicTable::DynamicTable(
endian : Endian,
class : Class,
data : BytesView,
) -> DynamicTable {
{
table: ParsingTable(
endian,
class,
data,
Dyn::size_for(class),
Dyn::parse_at,
),
}
}
///|
/// Number of dynamic entries in the table.
pub fn DynamicTable::len(self : DynamicTable) -> Int {
self.table.len()
}
///|
/// Returns `true` when the dynamic table has no entries.
pub fn DynamicTable::is_empty(self : DynamicTable) -> Bool {
self.table.is_empty()
}
///|
/// Parse the dynamic entry at `index`.
pub fn DynamicTable::get(
self : DynamicTable,
index : Int,
) -> Dyn raise ParseError {
self.table.get(index)
}
///|
/// Iterate over dynamic entries, parsing each entry as needed.
pub fn DynamicTable::iter(self : DynamicTable) -> Iter[Dyn] {
self.table.iter()
}
///|
/// One ELF dynamic-section entry.
///
/// `d_tag` identifies the meaning of `d_un`. The ELF ABI models `d_un` as a
/// union, so both `d_val` and `d_ptr` return the same stored word.
pub(all) struct Dyn {
/// Dynamic tag such as `DT_NEEDED`, `DT_STRTAB`, or `DT_RELA`.
d_tag : Int64
/// Raw union payload for `d_val` or `d_ptr`.
d_un : UInt64
} derive(Debug, Eq)
///|
/// Interpret the union payload as an integer value.
pub fn Dyn::d_val(self : Dyn) -> UInt64 {
self.d_un
}
///|
/// Interpret the union payload as a virtual address or pointer value.
pub fn Dyn::d_ptr(self : Dyn) -> UInt64 {
self.d_un
}
///|
impl ParseAt for Dyn with parse_at(endian, class, offset, data) {
let end = checked_add(offset, Dyn::size_for(class))
let record = slice_checked(data, offset, end)
let entry = match (class, endian) {
(ELF32, Little) =>
match record {
[u32le(d_tag32), u32le(d_un32)] =>
{
d_tag: d_tag32.reinterpret_as_int().to_int64(),
d_un: d_un32.to_uint64(),
}
_ => raise SliceReadError(offset, end)
}
(ELF32, Big) =>
match record {
[u32be(d_tag32), u32be(d_un32)] =>
{
d_tag: d_tag32.reinterpret_as_int().to_int64(),
d_un: d_un32.to_uint64(),
}
_ => raise SliceReadError(offset, end)
}
(ELF64, Little) =>
match record {
[u64le(d_tag), u64le(d_un)] =>
{ d_tag: d_tag.reinterpret_as_int64(), d_un }
_ => raise SliceReadError(offset, end)
}
(ELF64, Big) =>
match record {
[u64be(d_tag), u64be(d_un)] =>
{ d_tag: d_tag.reinterpret_as_int64(), d_un }
_ => raise SliceReadError(offset, end)
}
}
(entry, end)
}
///|
/// Size in bytes of one dynamic entry for the given ELF class.
pub fn Dyn::size_for(class : Class) -> Int {
match class {
ELF32 => 8
ELF64 => 16
}
}