use crate::elf::Property;
use bytesize::ByteSize;
use elf::parse::ParsingTable;
use elf::section::SectionHeader;
use elf::segment::ProgramHeader;
use elf::string_table::StringTable;
use elf::{endian::AnyEndian, file::FileHeader as ElfFileHeader};
use elf::{to_str::*, ParseError};
use std::io::Error as IoError;
#[derive(Clone, Copy, Debug)]
pub struct FileHeaders {
inner: ElfFileHeader<AnyEndian>,
}
impl From<ElfFileHeader<AnyEndian>> for FileHeaders {
fn from(inner: ElfFileHeader<AnyEndian>) -> Self {
Self { inner }
}
}
impl Property<'_> for FileHeaders {
fn items(&self) -> Vec<Vec<String>> {
let mut headers = Vec::new();
headers.push(vec![
String::from("Class"),
format!("{:?}", self.inner.class),
]);
headers.push(vec![
String::from("Endianness"),
format!("{:?}", self.inner.endianness),
]);
headers.push(vec![
String::from("Version"),
match self.inner.version {
1 => String::from("1 (current)"),
v => v.to_string(),
},
]);
headers.push(vec![
String::from("OS/ABI"),
e_osabi_to_string(self.inner.osabi)
.trim_start_matches("ELFOSABI_")
.to_string(),
]);
headers.push(vec![
String::from("ABI Version"),
self.inner.abiversion.to_string(),
]);
headers.push(vec![
String::from("Type"),
match e_type_to_human_str(self.inner.e_type) {
Some(s) => s.to_string(),
None => format!("e_type({:#x})", self.inner.e_type),
},
]);
headers.push(vec![
String::from("Arch"),
match e_machine_to_human_str(self.inner.e_machine) {
Some(s) => s.to_string(),
None => format!("e_machine({:#x})", self.inner.e_machine),
},
]);
headers.push(vec![
String::from("Entry point address"),
format!("{:#x}", self.inner.e_entry),
]);
headers.push(vec![
String::from("Start of program headers"),
format!("{} (bytes into file)", self.inner.e_phoff),
]);
headers.push(vec![
String::from("Start of section headers"),
format!("{} (bytes into file)", self.inner.e_shoff),
]);
headers.push(vec![
String::from("Flags"),
format!("{:#x}", self.inner.e_flags),
]);
headers.push(vec![
String::from("Size of this header"),
format!("{} (bytes)", self.inner.e_ehsize),
]);
headers.push(vec![
String::from("Size of program header"),
format!("{} (bytes)", self.inner.e_phentsize),
]);
headers.push(vec![
String::from("Number of program headers"),
self.inner.e_phnum.to_string(),
]);
headers.push(vec![
String::from("Size of section headers"),
format!("{} (bytes)", self.inner.e_shentsize),
]);
headers.push(vec![
String::from("Number of section headers"),
self.inner.e_shnum.to_string(),
]);
headers.push(vec![
String::from("Section headers string table section index"),
self.inner.e_shstrndx.to_string(),
]);
headers
}
}
#[derive(Clone, Debug)]
pub struct ProgramHeaders {
inner: Vec<ProgramHeader>,
human_readable: bool,
}
impl ProgramHeaders {
pub fn toggle_readability(&mut self) {
self.human_readable = !self.human_readable;
}
}
impl From<Vec<ProgramHeader>> for ProgramHeaders {
fn from(inner: Vec<ProgramHeader>) -> Self {
Self {
inner,
human_readable: true,
}
}
}
impl Property<'_> for ProgramHeaders {
fn items(&self) -> Vec<Vec<String>> {
self.inner
.iter()
.map(|item| {
vec![
elf::to_str::p_type_to_string(item.p_type)
.trim_start_matches("PT_")
.to_string(),
format!("{:#x}", item.p_offset),
format!("{:#x}", item.p_vaddr),
format!("{:#x}", item.p_paddr),
if self.human_readable {
format!("{}", ByteSize(item.p_filesz))
} else {
format!("{:#x}", item.p_filesz)
},
if self.human_readable {
format!("{}", ByteSize(item.p_memsz))
} else {
format!("{:#x}", item.p_memsz)
},
elf::to_str::p_flags_to_string(item.p_flags),
format!("{:#x}", item.p_align),
]
})
.collect()
}
}
#[derive(Clone, Debug, Default)]
pub struct SectionHeaders {
inner: Vec<SectionHeader>,
names: Vec<String>,
human_readable: bool,
}
impl SectionHeaders {
pub fn toggle_readability(&mut self) {
self.human_readable = !self.human_readable;
}
}
impl<'a>
TryFrom<(
Option<ParsingTable<'a, AnyEndian, SectionHeader>>,
Option<StringTable<'a>>,
)> for SectionHeaders
{
type Error = ParseError;
fn try_from(
value: (
Option<ParsingTable<'a, AnyEndian, SectionHeader>>,
Option<StringTable<'a>>,
),
) -> Result<Self, Self::Error> {
let (parsing_table, string_table) = (
value.0.ok_or_else(|| {
ParseError::IOError(IoError::other("parsing table does not exist"))
})?,
value.1.ok_or_else(|| {
ParseError::IOError(IoError::other("string table does not exist"))
})?,
);
Ok(Self {
inner: parsing_table.iter().collect(),
names: parsing_table
.iter()
.map(|v| {
string_table
.get(v.sh_name as usize)
.map(|v| v.to_string())
.unwrap_or_else(|_| String::from("unknown"))
})
.collect(),
human_readable: true,
})
}
}
impl Property<'_> for SectionHeaders {
fn items(&self) -> Vec<Vec<String>> {
self.inner
.iter()
.enumerate()
.map(|(i, header)| {
vec![
self.names[i].to_string(),
elf::to_str::sh_type_to_string(header.sh_type)
.trim_start_matches("SHT_")
.to_string(),
format!("{:#x}", header.sh_addr),
format!("{:#x}", header.sh_offset),
if self.human_readable {
format!("{}", ByteSize(header.sh_size))
} else {
format!("{:#x}", header.sh_size)
},
header.sh_entsize.to_string(),
format!("{:#x}", header.sh_flags),
header.sh_link.to_string(),
header.sh_info.to_string(),
header.sh_addralign.to_string(),
]
})
.collect()
}
}