use super::utils::Convert;
use super::*;
use std::convert::TryFrom;
#[derive(Debug, Default)]
pub struct Symbol {
pub name: String,
pub value: Elf64Addr,
pub size: ElfXword,
pub bind: u8,
pub stype: u8,
pub other: u8,
pub shndx: ElfHalf,
}
#[repr(C)]
#[derive(Default)]
struct Elf32Sym {
st_name: ElfWord,
st_value: Elf32Addr,
st_size: ElfWord,
st_info: u8,
st_other: u8,
st_shndx: ElfHalf,
}
#[repr(C)]
#[derive(Default)]
struct Elf64Sym {
st_name: ElfWord,
st_info: u8,
st_other: u8,
st_shndx: ElfHalf,
st_value: Elf64Addr,
st_size: ElfXword,
}
pub struct SymbolSectionAccessor<'a> {
elfio: &'a Elfio,
section: &'a dyn ElfSectionTrait,
}
impl<'a> SymbolSectionAccessor<'a> {
pub fn new(elfio: &'a Elfio, section: &'a dyn ElfSectionTrait) -> SymbolSectionAccessor<'a> {
SymbolSectionAccessor { elfio, section }
}
pub fn get_symbols_num(&self) -> ElfXword {
if self.section.get_entry_size() != 0 {
return self.section.get_size() / self.section.get_entry_size();
}
0
}
pub fn get_symbol(&self, index: ElfXword) -> Option<Symbol> {
let symbols_num = self.get_symbols_num();
if symbols_num == 0 || index > symbols_num - 1 {
return None;
}
let offset: usize = (index * self.section.get_entry_size()) as usize;
let end: usize = offset + self.section.get_entry_size() as usize;
let symbol_area = &self.section.get_data()[offset..end];
let converter = self.elfio.get_converter();
if self.elfio.get_class() == constant::ELFCLASS64 {
let sym = Elf64Sym {
st_name: converter.convert(u32::from_ne_bytes(
<[u8; 4]>::try_from(&symbol_area[0..4]).unwrap_or([0u8, 0u8, 0u8, 0u8]),
)),
st_info: converter.convert(symbol_area[4]),
st_other: converter.convert(symbol_area[5]),
st_shndx: converter.convert(u16::from_ne_bytes(
<[u8; 2]>::try_from(&symbol_area[6..8]).unwrap_or([0u8, 0u8]),
)),
st_value: converter.convert(u64::from_ne_bytes(
<[u8; 8]>::try_from(&symbol_area[8..16])
.unwrap_or([0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8]),
)),
st_size: converter.convert(u64::from_ne_bytes(
<[u8; 8]>::try_from(&symbol_area[16..24])
.unwrap_or([0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8]),
)),
};
let string_section = self
.elfio
.get_section_by_index(self.section.get_link() as ElfHalf);
let string_accessor = StringSectionAccessor::new(self.elfio, string_section.unwrap());
let name = string_accessor.get_string(sym.st_name);
Some(Symbol {
name,
value: sym.st_value,
size: sym.st_size,
bind: sym.st_info >> 4,
stype: sym.st_info & 0xF,
other: sym.st_other,
shndx: sym.st_shndx,
})
} else {
let sym = Elf32Sym {
st_name: converter.convert(u32::from_ne_bytes(
<[u8; 4]>::try_from(&symbol_area[0..4]).unwrap_or([0u8, 0u8, 0u8, 0u8]),
)),
st_value: converter.convert(u32::from_ne_bytes(
<[u8; 4]>::try_from(&symbol_area[4..8]).unwrap_or([0u8, 0u8, 0u8, 0u8]),
)),
st_size: converter.convert(u32::from_ne_bytes(
<[u8; 4]>::try_from(&symbol_area[8..12]).unwrap_or([0u8, 0u8, 0u8, 0u8]),
)),
st_info: converter.convert(symbol_area[12]),
st_other: converter.convert(symbol_area[13]),
st_shndx: converter.convert(u16::from_ne_bytes(
<[u8; 2]>::try_from(&symbol_area[14..16]).unwrap_or([0u8, 0u8]),
)),
};
let string_section = self
.elfio
.get_section_by_index(self.section.get_link() as ElfHalf);
let string_accessor = StringSectionAccessor::new(self.elfio, string_section.unwrap());
let name = string_accessor.get_string(sym.st_name);
Some(Symbol {
name,
value: sym.st_value as u64,
size: sym.st_size as u64,
bind: sym.st_info >> 4,
stype: sym.st_info & 0xF,
other: sym.st_other,
shndx: sym.st_shndx,
})
}
}
}