use std::fs::File;
use std::io::Read;
use std::io::Seek;
use std::io::SeekFrom::Start;
use std::io;
use std::fmt;
use std::slice;
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Default)]
pub struct Sym {
pub st_name: u32, pub st_info: u8, pub st_other: u8, pub st_shndx: u16, pub st_value: u64, pub st_size: u64, }
pub const SIZEOF_SYM: usize = 4 + 1 + 1 + 2 + 8 + 8;
#[inline(always)]
pub fn st_bind(info: u8) -> u8 {
info >> 4
}
#[inline(always)]
pub fn st_type(info: u8) -> u8 {
info & 0xf
}
#[inline(always)]
pub fn is_import(sym: &Sym) -> bool {
let binding = st_bind(sym.st_info);
binding == STB_GLOBAL && sym.st_value == 0
}
pub fn get_type(sym: &Sym) -> &'static str {
type_to_str(st_type(sym.st_info))
}
pub const STB_LOCAL: u8 = 0; pub const STB_GLOBAL: u8 = 1; pub const STB_WEAK: u8 = 2; pub const STB_NUM: u8 = 3; pub const STB_LOOS: u8 = 10; pub const STB_GNU_UNIQUE: u8 = 10; pub const STB_HIOS: u8 = 12; pub const STB_LOPROC: u8 = 13; pub const STB_HIPROC: u8 = 15;
#[inline]
pub fn bind_to_str(typ: u8) -> &'static str {
match typ {
STB_LOCAL => "LOCAL",
STB_GLOBAL => "GLOBAL",
STB_WEAK => "WEAK",
STB_NUM => "NUM",
STB_GNU_UNIQUE => "GNU_UNIQUE",
_ => "UNKNOWN_STB",
}
}
pub const STT_NOTYPE: u8 = 0; pub const STT_OBJECT: u8 = 1; pub const STT_FUNC: u8 = 2; pub const STT_SECTION: u8 = 3; pub const STT_FILE: u8 = 4; pub const STT_COMMON: u8 = 5; pub const STT_TLS: u8 = 6; pub const STT_NUM: u8 = 7; pub const STT_LOOS: u8 = 10; pub const STT_GNU_IFUNC: u8 = 10; pub const STT_HIOS: u8 = 12; pub const STT_LOPROC: u8 = 13; pub const STT_HIPROC: u8 = 15;
#[inline]
pub fn type_to_str(typ: u8) -> &'static str {
match typ {
STT_NOTYPE => "NOTYPE",
STT_OBJECT => "OBJECT",
STT_FUNC => "FUNC",
STT_SECTION => "SECTION",
STT_FILE => "FILE",
STT_COMMON => "COMMON",
STT_TLS => "TLS",
STT_NUM => "NUM",
STT_GNU_IFUNC => "GNU_IFUNC",
_ => "UNKNOWN_STT",
}
}
impl fmt::Debug for Sym {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let bind = st_bind(self.st_info);
let typ = st_type(self.st_info);
write!(f,
"st_name: {} {} {} st_other: {} st_shndx: {} st_value: {:x} st_size: {}",
self.st_name,
bind_to_str(bind),
type_to_str(typ),
self.st_other,
self.st_shndx,
self.st_value,
self.st_size)
}
}
pub unsafe fn from_raw<'a>(symp: *const Sym, count: usize) -> &'a [Sym] {
slice::from_raw_parts(symp, count)
}
#[cfg(not(feature = "no_endian_fd"))]
pub fn from_fd<'a>(fd: &mut File, offset: usize, count: usize, is_lsb: bool) -> io::Result<Vec<Sym>> {
use byteorder::{LittleEndian,BigEndian,ReadBytesExt};
let mut syms = Vec::with_capacity(count);
try!(fd.seek(Start(offset as u64)));
for _ in 0..count {
let mut sym = Sym::default();
if is_lsb {
sym.st_name = try!(fd.read_u32::<LittleEndian>());
sym.st_info = try!(try!(fd.bytes().next().ok_or(io::Error::new(io::ErrorKind::UnexpectedEof, ""))));
sym.st_other = try!(try!(fd.bytes().next().ok_or(io::Error::new(io::ErrorKind::UnexpectedEof, ""))));
sym.st_shndx = try!(fd.read_u16::<LittleEndian>());
sym.st_value = try!(fd.read_u64::<LittleEndian>());
sym.st_size = try!(fd.read_u64::<LittleEndian>());
} else {
sym.st_name = try!(fd.read_u32::<BigEndian>());
sym.st_info = try!(try!(fd.bytes().next().ok_or(io::Error::new(io::ErrorKind::UnexpectedEof, ""))));
sym.st_other = try!(try!(fd.bytes().next().ok_or(io::Error::new(io::ErrorKind::UnexpectedEof, ""))));
sym.st_shndx = try!(fd.read_u16::<BigEndian>());
sym.st_value = try!(fd.read_u64::<BigEndian>());
sym.st_size = try!(fd.read_u64::<BigEndian>());
}
syms.push(sym);
}
syms.dedup();
Ok(syms)
}
#[cfg(feature = "no_endian_fd")]
pub fn from_fd<'a>(fd: &mut File, offset: usize, count: usize, _: bool) -> io::Result<Vec<Sym>> {
let mut bytes = vec![0u8; count * SIZEOF_SYM]; try!(fd.seek(Start(offset as u64)));
try!(fd.read(&mut bytes));
let bytes = unsafe { slice::from_raw_parts(bytes.as_ptr() as *mut Sym, count) };
let mut syms = Vec::with_capacity(count);
syms.extend_from_slice(bytes);
syms.dedup();
Ok(syms)
}