pelf 0.1.5

A library for parsing/generating/analyzing ELF
Documentation
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: &section::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: &section::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: &section::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: &section::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: &section::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, // sh_name
            0x01, 0x00, 0x00, 0x00, // sh_type
            0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sh_flags
            0x18, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sh_addr
            0x18, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sh_offset
            0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sh_size
            0x00, 0x00, 0x00, 0x00, // sh_link
            0x00, 0x00, 0x00, 0x00, // sh_info
            0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sh_addralign
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sh_entsize
        ];

        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);
    }
}