read/pe: add SectionTable

Also fix section indices to be 1-based.
This commit is contained in:
Philip Craig
2020-04-30 16:09:34 +10:00
parent ff2abb979c
commit dfed15dedf
5 changed files with 85 additions and 26 deletions
+4 -10
View File
@@ -12,14 +12,14 @@ use crate::read::{
use super::{
parse_symbol, CoffSection, CoffSectionIterator, CoffSegment, CoffSegmentIterator,
CoffSymbolIterator, SymbolTable,
CoffSymbolIterator, SectionTable, SymbolTable,
};
/// A COFF object file.
#[derive(Debug)]
pub struct CoffFile<'data> {
pub(super) header: &'data pe::ImageFileHeader,
pub(super) sections: &'data [pe::ImageSectionHeader],
pub(super) sections: SectionTable<'data>,
// TODO: ImageSymbolExBytes
pub(super) symbols: SymbolTable<'data>,
pub(super) data: Bytes<'data>,
@@ -37,10 +37,7 @@ impl<'data> CoffFile<'data> {
// Skip over the optional header and get the section headers.
tail.skip(header.size_of_optional_header.get(LE) as usize)
.read_error("Invalid COFF optional header size")?;
let sections = tail
.read_slice(header.number_of_sections.get(LE) as usize)
.read_error("Invalid COFF section headers")?;
let sections = SectionTable::parse(header, tail)?;
let symbols = SymbolTable::parse(header, data)?;
// TODO: maybe validate that the machine is known?
@@ -96,10 +93,7 @@ where
}
fn section_by_index(&'file self, index: SectionIndex) -> Result<CoffSection<'data, 'file>> {
let section = self
.sections
.get(index.0)
.read_error("Invalid COFF section index")?;
let section = self.sections.section(index.0)?;
Ok(CoffSection {
file: self,
index,
+64
View File
@@ -13,6 +13,70 @@ use crate::read::{
use super::{CoffFile, CoffRelocationIterator};
/// The table of section headers in a COFF or PE file.
#[derive(Debug, Default, Clone, Copy)]
pub struct SectionTable<'data> {
sections: &'data [pe::ImageSectionHeader],
}
impl<'data> SectionTable<'data> {
/// Parse the section table.
///
/// `data` must be the data following the optional header.
pub fn parse(header: &pe::ImageFileHeader, mut data: Bytes<'data>) -> Result<Self> {
let sections = data
.read_slice(header.number_of_sections.get(LE) as usize)
.read_error("Invalid COFF/PE section headers")?;
Ok(SectionTable { sections })
}
/// Iterate over the section headers.
///
/// Warning: sections indices start at 1.
#[inline]
pub fn iter(&self) -> slice::Iter<'data, pe::ImageSectionHeader> {
self.sections.iter()
}
/// Return true if the section table is empty.
#[inline]
pub fn is_empty(&self) -> bool {
self.sections.is_empty()
}
/// The number of section headers.
#[inline]
pub fn len(&self) -> usize {
self.sections.len()
}
/// Return the section header at the given index.
///
/// The index is 1-based.
pub fn section(&self, index: usize) -> read::Result<&'data pe::ImageSectionHeader> {
self.sections
.get(index.wrapping_sub(1))
.read_error("Invalid COFF/PE section index")
}
/// Return the section header with the given name.
///
/// The returned index is 1-based.
///
/// Ignores sections with invalid names.
pub fn section_by_name(
&self,
strings: StringTable<'data>,
name: &[u8],
) -> Option<(usize, &'data pe::ImageSectionHeader)> {
self.sections
.iter()
.enumerate()
.find(|(_, section)| section.name(strings) == Ok(name))
.map(|(index, section)| (index + 1, section))
}
}
/// An iterator over the loadable sections of a `CoffFile`.
#[derive(Debug)]
pub struct CoffSegmentIterator<'data, 'file>
+14 -15
View File
@@ -8,11 +8,10 @@ use crate::pe;
use crate::pod::{Bytes, Pod};
use crate::read::coff::{parse_symbol, CoffSymbolIterator, SymbolTable};
use crate::read::{
self, Error, FileFlags, Object, ObjectSection, ReadError, Result, SectionIndex, Symbol,
SymbolIndex, SymbolMap,
self, Error, FileFlags, Object, ReadError, Result, SectionIndex, Symbol, SymbolIndex, SymbolMap,
};
use super::{PeSection, PeSectionIterator, PeSegment, PeSegmentIterator};
use super::{PeSection, PeSectionIterator, PeSegment, PeSegmentIterator, SectionTable};
/// A PE32 (32-bit) image file.
pub type PeFile32<'data> = PeFile<'data, pe::ImageNtHeaders32>;
@@ -25,7 +24,7 @@ pub struct PeFile<'data, Pe: ImageNtHeaders> {
pub(super) dos_header: &'data pe::ImageDosHeader,
pub(super) nt_headers: &'data Pe,
pub(super) data_directories: &'data [pe::ImageDataDirectory],
pub(super) sections: &'data [pe::ImageSectionHeader],
pub(super) sections: SectionTable<'data>,
pub(super) symbols: SymbolTable<'data>,
pub(super) data: Bytes<'data>,
}
@@ -91,11 +90,9 @@ impl<'data, Pe: ImageNtHeaders> PeFile<'data, Pe> {
.read_error("Invalid PE number of RVA and sizes")?;
// Section headers are after the optional header.
let sections = nt_tail
.read_slice(nt_headers.file_header().number_of_sections.get(LE) as usize)
.read_error("Invalid PE section headers")?;
let symbols = SymbolTable::parse(&nt_headers.file_header(), data)?;
let sections = SectionTable::parse(nt_headers.file_header(), nt_tail)?;
// Symbols are at an offset specified in the file header.
let symbols = SymbolTable::parse(nt_headers.file_header(), data)?;
Ok(PeFile {
dos_header,
@@ -153,15 +150,17 @@ where
}
fn section_by_name(&'file self, section_name: &str) -> Option<PeSection<'data, 'file, Pe>> {
self.sections()
.find(|section| section.name() == Ok(section_name))
self.sections
.section_by_name(self.symbols.strings, section_name.as_bytes())
.map(|(index, section)| PeSection {
file: self,
index: SectionIndex(index),
section,
})
}
fn section_by_index(&'file self, index: SectionIndex) -> Result<PeSection<'data, 'file, Pe>> {
let section = self
.sections
.get(index.0)
.read_error("Invalid PE section index")?;
let section = self.sections.section(index.0)?;
Ok(PeSection {
file: self,
index,
+2
View File
@@ -12,3 +12,5 @@ pub use file::*;
mod section;
pub use section::*;
pub use super::coff::SectionTable;
+1 -1
View File
@@ -134,7 +134,7 @@ impl<'data, 'file, Pe: ImageNtHeaders> Iterator for PeSectionIterator<'data, 'fi
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(index, section)| PeSection {
file: self.file,
index: SectionIndex(index),
index: SectionIndex(index + 1),
section,
})
}