use super::ElfParser;
use crate::section;
impl ElfParser {
pub(super) fn parse_elf64_sections<'a>(
&'a self,
b: &'a [u8],
shdrs: section::Elf64SectionHeaderTable,
section_name_string_table: §ion::ElfStringTable,
encoding: u8,
) -> nom::IResult<&'a [u8], section::Elf64Sections> {
let mut sections = Vec::with_capacity(shdrs.len());
for (i, shdr) in shdrs.into_iter().enumerate() {
log::debug!("trying to parse sections[{}]({})", i, shdr.section_type);
let (_b, sct) =
self.parse_elf64_section(b, shdr, section_name_string_table, encoding)?;
sections.push(sct);
}
Ok((b, sections))
}
fn parse_elf64_section<'a>(
&'a self,
b: &'a [u8],
shdr: section::Elf64SectionHeader,
section_name_string_table: §ion::ElfStringTable,
encoding: u8,
) -> nom::IResult<&'a [u8], section::Elf64Section> {
let (_b, data) = self.parse_elf64_section_data(b, &shdr, encoding)?;
let name = if shdr.section_type == section::SectionHeaderType::Null {
String::new()
} else {
section_name_string_table
.find_by_index(shdr.name as usize)
.unwrap()
.value
.clone()
};
let sct = section::Elf64Section {
name,
data,
header: shdr,
};
Ok((b, sct))
}
fn parse_elf64_section_data<'a>(
&'a self,
b: &'a [u8],
shdr: §ion::Elf64SectionHeader,
encoding: u8,
) -> nom::IResult<&'a [u8], section::Elf64SectionData> {
if shdr.section_type == section::SectionHeaderType::NoBits {
return Ok((b, section::Elf64SectionData::Raw { bytes: Vec::new() }));
}
let start = shdr.offset as usize;
let end = shdr.offset as usize + shdr.size as usize;
match shdr.section_type {
section::SectionHeaderType::StrTab => Ok((
b,
section::Elf64SectionData::StringTable {
table: section::ElfStringTable::from(b[start..end].to_vec()),
},
)),
section::SectionHeaderType::SymTab => {
self.parse_raw_elf64_symbol_table(b, shdr, encoding)
}
_ => {
if shdr.section_type == section::SectionHeaderType::NoBits {
return Ok((b, section::Elf64SectionData::Raw { bytes: Vec::new() }));
}
Ok((
b,
section::Elf64SectionData::Raw {
bytes: b[start..end].to_vec(),
},
))
}
}
}
pub(super) fn parse_raw_elf64_symbol_table<'a>(
&'a self,
b: &'a [u8],
shdr: §ion::Elf64SectionHeader,
encoding: u8,
) -> nom::IResult<&'a [u8], section::Elf64SectionData> {
let entries = shdr.size / shdr.entsize;
let mut symbols = Vec::with_capacity(entries as usize);
for i in 0..entries {
let start = shdr.offset + (shdr.entsize * i);
let end = shdr.offset + (shdr.entsize * i + 1);
let (_, raw_sym) =
self.parse_raw_elf64_symbol(&b[start as usize..end as usize], encoding)?;
symbols.push(raw_sym);
}
Ok((b, section::Elf64SectionData::RawSymbolTable { symbols }))
}
fn parse_raw_elf64_symbol<'a>(
&'a self,
b: &'a [u8],
encoding: u8,
) -> nom::IResult<&'a [u8], section::RawElf64Symbol> {
let (b, st_name) = self.parse_elf64_word(encoding, b)?;
let (b, st_info) = nom::number::complete::u8(b)?;
let (b, st_other) = nom::number::complete::u8(b)?;
let (b, st_shndx) = self.parse_elf64_section_index(encoding, b)?;
let (b, st_size) = self.parse_elf64_xword(encoding, b)?;
let sym = section::RawElf64Symbol {
st_name,
st_info,
st_other,
st_shndx,
st_size,
};
Ok((b, sym))
}
pub(super) fn parse_raw_elf64_sections<'a>(
&'a self,
b: &'a [u8],
shdrs: §ion::RawElf64SectionHeaderTable,
) -> nom::IResult<&'a [u8], section::RawElf64Sections> {
let sections = shdrs
.iter()
.map(|shdr| {
if shdr.sh_type == section::ELF_SECTION_HEADER_TYPE_NOBITS {
return Vec::new();
}
let start = shdr.sh_offset as usize;
let end = shdr.sh_offset as usize + shdr.sh_size as usize;
b[start..end].to_vec()
})
.collect();
Ok((b, sections))
}
pub(super) fn parse_raw_elf64_section_header_table<'a>(
&'a self,
b: &'a [u8],
encoding: u8,
shoff: usize,
shnum: usize,
) -> nom::IResult<&'a [u8], section::RawElf64SectionHeaderTable> {
let mut shdrs = vec![section::RawElf64SectionHeader::default(); shnum];
for (i, shdr) in shdrs.iter_mut().enumerate().take(shnum) {
log::debug!("trying to parse SHT[{}]", i);
let start = shoff + (std::mem::size_of::<section::RawElf64SectionHeader>() * i);
let (_b, v) = self.parse_raw_elf64_section_header(&b[start..], encoding)?;
*shdr = v;
}
let end = shoff + (std::mem::size_of::<section::RawElf64SectionHeader>() * shnum);
Ok((&b[end..], section::RawElf64SectionHeaderTable::new(shdrs)))
}
fn parse_raw_elf64_section_header<'a>(
&'a self,
b: &'a [u8],
encoding: u8,
) -> nom::IResult<&'a [u8], section::RawElf64SectionHeader> {
let (b, sh_name) = self.parse_elf64_word(encoding, b)?;
let (b, sh_type) = self.parse_elf64_word(encoding, b)?;
let (b, sh_flags) = self.parse_elf64_xword(encoding, b)?;
let (b, sh_addr) = self.parse_elf64_address(encoding, b)?;
let (b, sh_offset) = self.parse_elf64_offset(encoding, b)?;
let (b, sh_size) = self.parse_elf64_xword(encoding, b)?;
let (b, sh_link) = self.parse_elf64_word(encoding, b)?;
let (b, sh_info) = self.parse_elf64_word(encoding, b)?;
let (b, sh_addralign) = self.parse_elf64_xword(encoding, b)?;
let (b, sh_entsize) = self.parse_elf64_xword(encoding, b)?;
let shdr = section::RawElf64SectionHeaderBuilder::default()
.name(sh_name)
.section_type(sh_type)
.flags(sh_flags)
.addr(sh_addr)
.offset(sh_offset)
.size(sh_size)
.link(sh_link)
.info(sh_info)
.addralign(sh_addralign)
.entsize(sh_entsize)
.build();
Ok((b, shdr))
}
}
#[cfg(test)]
mod tests {
use crate::{header, parser::ElfParserConfig, section};
#[test]
fn test_parse_raw_elf64_section_header() {
let input = vec![
0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
let p = ElfParserConfig::new().build();
let result = p.parse_raw_elf64_section_header(&input, header::ELF_IDENT_DATA_2LSB);
assert!(result.is_ok());
let (b, shdr) = result.unwrap();
assert!(b.is_empty());
assert_eq!(0xb, shdr.sh_name);
assert_eq!(0x1, shdr.sh_type);
assert_eq!(section::ELF_SECTION_HEADER_FLAG_ALLOC, shdr.sh_flags);
assert_eq!(0x318, shdr.sh_addr);
assert_eq!(0x318, shdr.sh_offset);
assert_eq!(0x1c, shdr.sh_size);
assert_eq!(0, shdr.sh_link);
assert_eq!(0, shdr.sh_info);
assert_eq!(0x1, shdr.sh_addralign);
assert_eq!(0, shdr.sh_entsize);
}
}