pub mod header;
pub mod program_header;
pub mod dyn;
pub mod rela;
pub mod sym;
pub mod strtab;
pub mod gnu_hash;
use std::path::Path;
use std::fs::File;
use std::io;
use std::io::Read;
use std::io::Seek;
use std::io::SeekFrom::Start;
#[derive(Debug)]
pub struct Elf {
pub header: header::Header,
pub program_headers: Vec<program_header::ProgramHeader>,
pub dynamic: Option<Vec<dyn::Dyn>>,
pub symtab: Vec<sym::Sym>,
pub rela: Vec<rela::Rela>,
pub pltrela: Vec<rela::Rela>,
pub strtab: Vec<String>,
pub soname: Option<String>,
pub interpreter: Option<String>,
pub libraries: Vec<String>,
pub is_lib: bool,
pub size: usize,
pub entry: usize,
}
impl Elf {
pub fn from_path<'a>(path: &Path) -> io::Result<Elf> {
let mut fd = try!(File::open(&path));
let metadata = fd.metadata().unwrap();
if metadata.len() < header::EHDR_SIZE as u64 {
let error = io::Error::new(io::ErrorKind::Other,
format!("Error: {:?} size is smaller than an ELF header",
path.as_os_str()));
Err(error)
} else {
let header = try!(header::Header::from_fd(&mut fd));
let entry = header.e_entry as usize;
let is_lib = header.e_type == header::ET_DYN;
let is_lsb = header.e_ident[header::EI_DATA] == header::ELFDATA2LSB;
let program_headers = try!(program_header::ProgramHeader::from_fd(&mut fd, header.e_phoff, header.e_phnum as usize, is_lsb));
let dynamic = try!(dyn::from_fd(&mut fd, &program_headers, is_lsb));
let mut bias: usize = 0;
for ph in &program_headers {
if ph.p_type == program_header::PT_LOAD {
bias = ((::std::u64::MAX - ph.p_vaddr).wrapping_add(1)) as usize; break;
}
}
let mut interpreter = None;
for ph in &program_headers {
if ph.p_type == program_header::PT_INTERP {
let mut bytes = vec![0u8; (ph.p_filesz - 1) as usize];
try!(fd.seek(Start(ph.p_offset)));
try!(fd.read(&mut bytes));
interpreter = Some(String::from_utf8(bytes).unwrap())
}
}
let mut soname = None;
let mut libraries = vec![];
let mut symtab = vec![];
let mut rela = vec![];
let mut pltrela = vec![];
let mut strtabv = vec![];
if let Some(ref dynamic) = dynamic {
let link_info = dyn::DynamicInfo::new(&dynamic, bias); let strtab = try!(strtab::Strtab::from_fd(&mut fd,
link_info.strtab,
link_info.strsz));
if link_info.soname != 0 {
soname = Some(strtab.get(link_info.soname).to_owned())
}
if link_info.needed_count > 0 {
let needed = dyn::get_needed(dynamic, &strtab, link_info.needed_count);
libraries = Vec::with_capacity(link_info.needed_count);
for lib in needed {
libraries.push(lib.to_owned());
}
}
let num_syms = (link_info.strtab - link_info.symtab) / link_info.syment; symtab = try!(sym::from_fd(&mut fd, link_info.symtab, num_syms, is_lsb));
rela = try!(rela::from_fd(&mut fd, link_info.rela, link_info.relasz, is_lsb));
pltrela = try!(rela::from_fd(&mut fd, link_info.jmprel, link_info.pltrelsz, is_lsb));
strtabv = strtab.to_vec();
}
let elf = Elf {
header: header,
program_headers: program_headers,
dynamic: dynamic,
symtab: symtab,
rela: rela,
pltrela: pltrela,
strtab: strtabv,
soname: soname,
interpreter: interpreter,
libraries: libraries,
is_lib: is_lib,
size: metadata.len() as usize,
entry: entry,
};
Ok(elf)
}
}
}
#[cfg(test)]
mod tests {
use std::path::Path;
use elf;
#[test]
fn read_ls() {
let _ = elf::Elf::from_path(Path::new("/bin/ls"));
}
}