use std::cmp;
use goblin::elf;
use uuid::Uuid;
use symbolic_common::Result;
use object::ObjectId;
const UUID_SIZE: usize = 16;
const PAGE_SIZE: usize = 4096;
pub struct ElfSection<'elf, 'data> {
pub header: &'elf elf::SectionHeader,
pub data: &'data [u8],
}
pub fn find_elf_section<'elf, 'data>(
elf: &'elf elf::Elf,
data: &'data [u8],
sh_type: u32,
name: &str,
) -> Option<ElfSection<'elf, 'data>> {
for header in &elf.section_headers {
if header.sh_type != sh_type {
continue;
}
if let Some(Ok(section_name)) = elf.shdr_strtab.get(header.sh_name) {
if section_name != name {
continue;
}
let offset = header.sh_offset as usize;
let size = header.sh_size as usize;
return Some(ElfSection {
header: header,
data: &data[offset..][..size],
});
}
}
None
}
pub fn has_elf_section(elf: &elf::Elf, sh_type: u32, name: &str) -> bool {
for header in &elf.section_headers {
if header.sh_type != sh_type {
continue;
}
if let Some(Ok(section_name)) = elf.shdr_strtab.get(header.sh_name) {
if section_name == name {
return true;
}
}
}
false
}
fn find_build_id<'data>(elf: &elf::Elf<'data>, data: &'data [u8]) -> Option<&'data [u8]> {
if let Some(mut notes) = elf.iter_note_headers(data) {
while let Some(Ok(note)) = notes.next() {
if note.n_type == elf::note::NT_GNU_BUILD_ID {
return Some(note.desc);
}
}
}
if let Some(mut notes) = elf.iter_note_sections(data, Some(".note.gnu.build-id")) {
while let Some(Ok(note)) = notes.next() {
if note.n_type == elf::note::NT_GNU_BUILD_ID {
return Some(note.desc);
}
}
}
None
}
fn create_elf_id(identifier: &[u8], little_endian: bool) -> Option<ObjectId> {
let mut data = [0 as u8; UUID_SIZE];
let len = cmp::min(identifier.len(), UUID_SIZE);
data[0..len].copy_from_slice(&identifier[0..len]);
if little_endian {
data[0..4].reverse(); data[4..6].reverse(); data[6..8].reverse(); }
Uuid::from_bytes(&data).ok().map(ObjectId::from_uuid)
}
pub fn get_elf_id(elf: &elf::Elf, data: &[u8]) -> Option<ObjectId> {
if let Some(identifier) = find_build_id(elf, data) {
return create_elf_id(identifier, elf.little_endian);
}
if let Some(section) = find_elf_section(elf, data, elf::section_header::SHT_PROGBITS, ".text") {
let mut hash = [0; UUID_SIZE];
for i in 0..cmp::min(section.data.len(), PAGE_SIZE) {
hash[i % UUID_SIZE] ^= section.data[i];
}
return create_elf_id(&hash, elf.little_endian);
}
None
}
pub fn get_elf_vmaddr(elf: &elf::Elf) -> Result<u64> {
for phdr in &elf.program_headers {
if phdr.p_type == elf::program_header::PT_LOAD {
return Ok(phdr.p_vaddr);
}
}
Ok(0)
}