From c071e224f25322f84864dc2d840d37b71a456b1f Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Thu, 9 May 2024 17:21:53 +1000 Subject: [PATCH] read: use SectionIndex/SymbolIndex in low level API Note that many APIs returned unvalidated indices. Validation is performed when they are used to access a table entry. For cases where a 0 index is normal, an Option may be returned. --- crates/examples/src/bin/pecopy.rs | 4 +- crates/examples/src/objdump.rs | 8 ++-- crates/examples/src/readobj/elf.rs | 30 ++++++------- crates/examples/src/readobj/pe.rs | 5 ++- crates/examples/src/readobj/xcoff.rs | 8 ++-- src/build/elf.rs | 41 +++++++++-------- src/read/coff/comdat.rs | 27 +++++++---- src/read/coff/file.rs | 20 +++------ src/read/coff/section.rs | 21 +++++---- src/read/coff/symbol.rs | 65 +++++++++++++++++---------- src/read/elf/comdat.rs | 2 +- src/read/elf/file.rs | 18 ++++++-- src/read/elf/hash.rs | 34 +++++++++----- src/read/elf/relocation.rs | 41 ++++++++++++----- src/read/elf/section.rs | 67 +++++++++++++++++++++------- src/read/elf/symbol.rs | 58 +++++++++++++++--------- src/read/elf/version.rs | 13 ++++-- src/read/macho/file.rs | 16 +++---- src/read/macho/symbol.rs | 41 ++++++++++++----- src/read/mod.rs | 12 +++++ src/read/pe/file.rs | 17 +++---- src/read/xcoff/file.rs | 2 +- src/read/xcoff/symbol.rs | 27 +++++------ 23 files changed, 358 insertions(+), 219 deletions(-) diff --git a/crates/examples/src/bin/pecopy.rs b/crates/examples/src/bin/pecopy.rs index 2001ea99..b8146284 100644 --- a/crates/examples/src/bin/pecopy.rs +++ b/crates/examples/src/bin/pecopy.rs @@ -98,11 +98,11 @@ fn copy_file(in_data: &[u8]) -> Result, Box(w: &mut W, e: &mut E, file: &object::F } for section in file.sections() { - writeln!(w, "{}: {:x?}", section.index().0, section)?; + writeln!(w, "{}: {:x?}", section.index(), section)?; } for comdat in file.comdats() { write!(w, "{:?} Sections:", comdat)?; for section in comdat.sections() { - write!(w, " {}", section.0)?; + write!(w, " {}", section)?; } writeln!(w)?; } @@ -197,7 +197,7 @@ fn dump_parsed_object(w: &mut W, e: &mut E, file: &object::F writeln!(w)?; writeln!(w, "Symbols")?; for symbol in file.symbols() { - writeln!(w, "{}: {:x?}", symbol.index().0, symbol)?; + writeln!(w, "{}: {:x?}", symbol.index(), symbol)?; } for section in file.sections() { @@ -216,7 +216,7 @@ fn dump_parsed_object(w: &mut W, e: &mut E, file: &object::F writeln!(w)?; writeln!(w, "Dynamic symbols")?; for symbol in file.dynamic_symbols() { - writeln!(w, "{}: {:x?}", symbol.index().0, symbol)?; + writeln!(w, "{}: {:x?}", symbol.index(), symbol)?; } if let Some(relocations) = file.dynamic_relocations() { diff --git a/crates/examples/src/readobj/elf.rs b/crates/examples/src/readobj/elf.rs index e21770bd..df16fe38 100644 --- a/crates/examples/src/readobj/elf.rs +++ b/crates/examples/src/readobj/elf.rs @@ -1,7 +1,7 @@ use super::*; use object::elf::*; use object::read::elf::*; -use object::read::{SectionIndex, StringTable}; +use object::read::{SectionIndex, StringTable, SymbolIndex}; pub(super) fn print_elf32(p: &mut Printer<'_>, data: &[u8]) { if let Some(elf) = FileHeader32::::parse(data).print_err(p) { @@ -239,7 +239,7 @@ fn print_section_headers( elf: &Elf, sections: &SectionTable, ) { - for (index, section) in sections.iter().enumerate() { + for (index, section) in sections.enumerate() { let sh_type = section.sh_type(endian); if !p.options.sections && !(p.options.symbols && sh_type == SHT_SYMTAB) @@ -255,7 +255,6 @@ fn print_section_headers( { continue; } - let index = SectionIndex(index); p.group("SectionHeader", |p| { p.field("Index", index.0); p.field_string( @@ -394,10 +393,10 @@ fn print_section_symbols( EM_PARISC => FLAGS_SHN_PARISC, _ => &[], }; - for (index, symbol) in symbols.iter().enumerate() { + for (index, symbol) in symbols.enumerate() { p.group("Symbol", |p| { - p.field("Index", index); - if index == 0 { + p.field("Index", index.0); + if index == SymbolIndex(0) { p.field_hex("Name", symbol.st_name(endian)); } else { p.field_string( @@ -466,7 +465,7 @@ fn print_section_rel( p.group("Relocation", |p| { p.field_hex("Offset", relocation.r_offset(endian).into()); p.field_enum("Type", relocation.r_type(endian), proc); - let sym = relocation.r_sym(endian); + let sym = relocation.symbol(endian); print_rel_symbol(p, endian, symbols, sym); }); } @@ -497,7 +496,7 @@ fn print_section_rela( relocation.r_type(endian, elf.is_mips64el(endian)), proc, ); - let sym = relocation.r_sym(endian, elf.is_mips64el(endian)); + let sym = relocation.symbol(endian, elf.is_mips64el(endian)); print_rel_symbol(p, endian, symbols, sym); let addend = relocation.r_addend(endian).into() as u64; if addend != 0 { @@ -512,19 +511,19 @@ fn print_rel_symbol( p: &mut Printer<'_>, endian: Elf::Endian, symbols: Option>, - sym: u32, + index: Option, ) { - if sym == 0 { - p.field_hex("Symbol", sym); + let Some(index) = index else { + p.field_hex("Symbol", 0); return; - } + }; let name = symbols.and_then(|symbols| { symbols - .symbol(sym as usize) + .symbol(index) .and_then(|symbol| symbol.name(endian, symbols.strings())) .print_err(p) }); - p.field_string_option("Symbol", sym, name); + p.field_string_option("Symbol", index.0, name); } fn rel_flag_type(endian: Elf::Endian, elf: &Elf) -> &'static [Flag] { @@ -760,7 +759,7 @@ fn print_hash( if let Ok(Some((hash_table, link))) = section.hash(endian, data) { if let Ok(symbols) = _sections.symbol_table_by_index(endian, data, link) { if let Ok(versions) = _sections.versions(endian, data) { - for (index, symbol) in symbols.symbols().iter().enumerate() { + for (index, symbol) in symbols.symbols().enumerate() { let name = symbols.symbol_name(endian, symbol).unwrap(); if name.is_empty() { continue; @@ -802,7 +801,6 @@ fn print_gnu_hash( if let Ok(versions) = _sections.versions(endian, data) { for (index, symbol) in symbols .symbols() - .iter() .enumerate() .skip(hash_table.symbol_base() as usize) { diff --git a/crates/examples/src/readobj/pe.rs b/crates/examples/src/readobj/pe.rs index 97ee305a..4ac9733e 100644 --- a/crates/examples/src/readobj/pe.rs +++ b/crates/examples/src/readobj/pe.rs @@ -3,6 +3,7 @@ use object::pe::*; use object::read::coff::ImageSymbol as _; use object::read::coff::*; use object::read::pe::*; +use object::read::{SectionIndex, SymbolIndex}; use object::LittleEndian as LE; use object::{Bytes, U32Bytes, U64Bytes}; @@ -643,7 +644,7 @@ fn print_relocations<'data, Coff: CoffHeader>( let index = relocation.symbol_table_index.get(LE); let name = symbols.and_then(|symbols| { symbols - .symbol(index as usize) + .symbol(SymbolIndex(index as usize)) .and_then(|symbol| symbol.name(symbols.strings())) .print_err(p) }); @@ -714,7 +715,7 @@ fn print_symbols<'data, Coff: CoffHeader>( } else { let section_name = sections.and_then(|sections| { sections - .section(section as usize) + .section(SectionIndex(section as usize)) .and_then(|section| section.name(symbols.strings())) .print_err(p) }); diff --git a/crates/examples/src/readobj/xcoff.rs b/crates/examples/src/readobj/xcoff.rs index 1a9cde00..68b7a1cc 100644 --- a/crates/examples/src/readobj/xcoff.rs +++ b/crates/examples/src/readobj/xcoff.rs @@ -1,6 +1,6 @@ use super::*; use object::read::xcoff::*; -use object::read::SectionIndex; +use object::read::{SectionIndex, SymbolIndex}; use object::xcoff::*; pub(super) fn print_xcoff32(p: &mut Printer<'_>, data: &[u8]) { @@ -129,7 +129,7 @@ fn print_sections<'data, Xcoff: FileHeader>( let index = relocation.r_symndx(); let name = symbols.and_then(|symbols| { symbols - .symbol(index as usize) + .symbol(SymbolIndex(index as usize)) .and_then(|symbol| symbol.name(symbols.strings())) .print_err(p) }); @@ -188,7 +188,7 @@ fn print_symbols<'data, Xcoff: FileHeader>( p.field("NumberOfAuxSymbols", numaux); if symbol.has_aux_file() { for i in 1..=numaux { - if let Some(aux_file) = symbols.aux_file(index.0, i).print_err(p) { + if let Some(aux_file) = symbols.aux_file(index, i).print_err(p) { p.group("FileAux", |p| { p.field("Index", index.0 + i); let name = aux_file.fname(symbols.strings()); @@ -206,7 +206,7 @@ fn print_symbols<'data, Xcoff: FileHeader>( } } if symbol.has_aux_csect() { - if let Some(aux_csect) = symbols.aux_csect(index.0, numaux).print_err(p) { + if let Some(aux_csect) = symbols.aux_csect(index, numaux).print_err(p) { p.group("CsectAux", |p| { p.field("Index", index.0 + numaux); p.field_hex("SectionLength", aux_csect.x_scnlen()); diff --git a/src/build/elf.rs b/src/build/elf.rs index 2f1b2698..06b01f90 100644 --- a/src/build/elf.rs +++ b/src/build/elf.rs @@ -116,7 +116,7 @@ impl<'data> Builder<'data> { let header = Elf::parse(data)?; let endian = header.endian()?; let is_mips64el = header.is_mips64el(endian); - let shstrndx = header.shstrndx(endian, data)? as usize; + let section_strings_index = header.section_strings_index(endian, data)?; let segments = header.program_headers(endian, data)?; let sections = header.sections(endian, data)?; let symbols = sections.symbols(endian, data, elf::SHT_SYMTAB)?; @@ -179,8 +179,8 @@ impl<'data> Builder<'data> { builder.load_align = 1; } - for (index, section) in sections.iter().enumerate().skip(1) { - let id = SectionId(index - 1); + for (index, section) in sections.enumerate().skip(1) { + let id = SectionId(index.0 - 1); let relocations = if let Some((rels, link)) = section.rel(endian, data)? { Self::read_relocations( index, @@ -222,7 +222,7 @@ impl<'data> Builder<'data> { | elf::SHT_PREINIT_ARRAY => SectionData::Data(section.data(endian, data)?.into()), elf::SHT_REL | elf::SHT_RELA => relocations, elf::SHT_SYMTAB => { - if index == symbols.section().0 { + if index == symbols.section() { SectionData::Symbol } else { return Err(Error(format!( @@ -232,7 +232,7 @@ impl<'data> Builder<'data> { } } elf::SHT_SYMTAB_SHNDX => { - if index == symbols.shndx_section().0 { + if index == symbols.shndx_section() { SectionData::SymbolSectionIndex } else { return Err(Error(format!( @@ -242,7 +242,7 @@ impl<'data> Builder<'data> { } } elf::SHT_DYNSYM => { - if index == dynamic_symbols.section().0 { + if index == dynamic_symbols.section() { SectionData::DynamicSymbol } else { return Err(Error(format!( @@ -252,11 +252,11 @@ impl<'data> Builder<'data> { } } elf::SHT_STRTAB => { - if index == symbols.string_section().0 { + if index == symbols.string_section() { SectionData::String - } else if index == dynamic_symbols.string_section().0 { + } else if index == dynamic_symbols.string_section() { SectionData::DynamicString - } else if index == shstrndx { + } else if index == section_strings_index { SectionData::SectionString } else { return Err(Error(format!( @@ -372,7 +372,7 @@ impl<'data> Builder<'data> { #[allow(clippy::too_many_arguments)] fn read_relocations( - index: usize, + index: read::SectionIndex, endian: Elf::Endian, is_mips64el: bool, section: &'data Elf::SectionHeader, @@ -427,7 +427,7 @@ impl<'data> Builder<'data> { } fn read_relocations_impl( - index: usize, + index: read::SectionIndex, endian: Elf::Endian, is_mips64el: bool, rels: &'data [Rel], @@ -440,17 +440,16 @@ impl<'data> Builder<'data> { let mut relocations = Vec::new(); for rel in rels { let rel = (*rel).into(); - let r_sym = rel.r_sym(endian, is_mips64el); - let symbol = if r_sym == 0 { - None - } else { - if r_sym as usize >= symbols_len { + let symbol = if let Some(symbol) = rel.symbol(endian, is_mips64el) { + if symbol.0 >= symbols_len { return Err(Error(format!( "Invalid symbol index {} in relocation section at index {}", - r_sym, index, + symbol, index, ))); } - Some(SymbolId(r_sym as usize - 1)) + Some(SymbolId(symbol.0 - 1)) + } else { + None }; relocations.push(Relocation { r_offset: rel.r_offset(endian).into(), @@ -523,8 +522,8 @@ impl<'data> Builder<'data> { Elf: FileHeader, R: ReadRef<'data>, { - for (index, symbol) in symbols.iter().enumerate().skip(1) { - let id = SymbolId(index - 1); + for (index, symbol) in symbols.enumerate().skip(1) { + let id = SymbolId(index.0 - 1); let section = if let Some(section_index) = symbols.symbol_section(endian, symbol, index)? { let section_id = section_index.0.wrapping_sub(1); @@ -553,7 +552,7 @@ impl<'data> Builder<'data> { } fn read_attributes( - index: usize, + index: read::SectionIndex, attributes: read::elf::AttributesSection<'data, Elf>, sections_len: usize, symbols_len: usize, diff --git a/src/read/coff/comdat.rs b/src/read/coff/comdat.rs index 6378547a..464d2388 100644 --- a/src/read/coff/comdat.rs +++ b/src/read/coff/comdat.rs @@ -20,8 +20,17 @@ pub struct CoffComdatIterator< R: ReadRef<'data> = &'data [u8], Coff: CoffHeader = pe::ImageFileHeader, > { - pub(super) file: &'file CoffFile<'data, R, Coff>, - pub(super) index: usize, + file: &'file CoffFile<'data, R, Coff>, + index: SymbolIndex, +} + +impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> CoffComdatIterator<'data, 'file, R, Coff> { + pub(crate) fn new(file: &'file CoffFile<'data, R, Coff>) -> Self { + CoffComdatIterator { + file, + index: SymbolIndex(0), + } + } } impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> Iterator @@ -33,7 +42,7 @@ impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> Iterator loop { let index = self.index; let symbol = self.file.common.symbols.symbol(index).ok()?; - self.index += 1 + symbol.number_of_aux_symbols() as usize; + self.index.0 += 1 + symbol.number_of_aux_symbols() as usize; if let Some(comdat) = CoffComdat::parse(self.file, symbol, index) { return Some(comdat); } @@ -67,7 +76,7 @@ impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> CoffComdat<'data, 'file, fn parse( file: &'file CoffFile<'data, R, Coff>, section_symbol: &'data Coff::ImageSymbol, - index: usize, + index: SymbolIndex, ) -> Option> { // Must be a section symbol. if !section_symbol.has_aux_section() { @@ -86,7 +95,7 @@ impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> CoffComdat<'data, 'file, let mut symbol = section_symbol; let section_number = section_symbol.section_number(); loop { - symbol_index += 1 + symbol.number_of_aux_symbols() as usize; + symbol_index.0 += 1 + symbol.number_of_aux_symbols() as usize; symbol = file.common.symbols.symbol(symbol_index).ok()?; if section_number == symbol.section_number() { break; @@ -95,7 +104,7 @@ impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> CoffComdat<'data, 'file, Some(CoffComdat { file, - symbol_index: SymbolIndex(symbol_index), + symbol_index, symbol, selection, }) @@ -149,7 +158,7 @@ impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> ObjectComdat<'data> CoffComdatSectionIterator { file: self.file, section_number: self.symbol.section_number(), - index: 0, + index: SymbolIndex(0), } } } @@ -168,7 +177,7 @@ pub struct CoffComdatSectionIterator< > { file: &'file CoffFile<'data, R, Coff>, section_number: i32, - index: usize, + index: SymbolIndex, } impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> Iterator @@ -182,7 +191,7 @@ impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> Iterator loop { let index = self.index; let symbol = self.file.common.symbols.symbol(index).ok()?; - self.index += 1 + symbol.number_of_aux_symbols() as usize; + self.index.0 += 1 + symbol.number_of_aux_symbols() as usize; // Must be a section symbol. if !symbol.has_aux_section() { diff --git a/src/read/coff/file.rs b/src/read/coff/file.rs index 379f4efe..525c11d3 100644 --- a/src/read/coff/file.rs +++ b/src/read/coff/file.rs @@ -149,7 +149,7 @@ where } fn section_by_index(&self, index: SectionIndex) -> Result> { - let section = self.common.sections.section(index.0)?; + let section = self.common.sections.section(index)?; Ok(CoffSection { file: self, index, @@ -165,14 +165,11 @@ where } fn comdats(&self) -> CoffComdatIterator<'data, '_, R, Coff> { - CoffComdatIterator { - file: self, - index: 0, - } + CoffComdatIterator::new(self) } fn symbol_by_index(&self, index: SymbolIndex) -> Result> { - let symbol = self.common.symbols.symbol(index.0)?; + let symbol = self.common.symbols.symbol(index)?; Ok(CoffSymbol { file: &self.common, index, @@ -181,10 +178,7 @@ where } fn symbols(&self) -> CoffSymbolIterator<'data, '_, R, Coff> { - CoffSymbolIterator { - file: &self.common, - index: 0, - } + CoffSymbolIterator::new(&self.common) } #[inline] @@ -193,11 +187,7 @@ where } fn dynamic_symbols(&self) -> CoffSymbolIterator<'data, '_, R, Coff> { - CoffSymbolIterator { - file: &self.common, - // Hack: don't return any. - index: self.common.symbols.len(), - } + CoffSymbolIterator::empty(&self.common) } #[inline] diff --git a/src/read/coff/section.rs b/src/read/coff/section.rs index c0a648f0..28b5e2e7 100644 --- a/src/read/coff/section.rs +++ b/src/read/coff/section.rs @@ -38,12 +38,20 @@ impl<'data> SectionTable<'data> { /// Iterate over the section headers. /// - /// Warning: sections indices start at 1. + /// Warning: section indices start at 1. #[inline] pub fn iter(&self) -> slice::Iter<'data, pe::ImageSectionHeader> { self.sections.iter() } + /// Iterate over the section headers and their indices. + pub fn enumerate(&self) -> impl Iterator { + self.sections + .iter() + .enumerate() + .map(|(i, section)| (SectionIndex(i + 1), section)) + } + /// Return true if the section table is empty. #[inline] pub fn is_empty(&self) -> bool { @@ -59,9 +67,9 @@ impl<'data> SectionTable<'data> { /// Return the section header at the given index. /// /// The index is 1-based. - pub fn section(&self, index: usize) -> read::Result<&'data pe::ImageSectionHeader> { + pub fn section(&self, index: SectionIndex) -> read::Result<&'data pe::ImageSectionHeader> { self.sections - .get(index.wrapping_sub(1)) + .get(index.0.wrapping_sub(1)) .read_error("Invalid COFF/PE section index") } @@ -74,12 +82,9 @@ impl<'data> SectionTable<'data> { &self, strings: StringTable<'data, R>, name: &[u8], - ) -> Option<(usize, &'data pe::ImageSectionHeader)> { - self.sections - .iter() - .enumerate() + ) -> Option<(SectionIndex, &'data pe::ImageSectionHeader)> { + self.enumerate() .find(|(_, section)| section.name(strings) == Ok(name)) - .map(|(index, section)| (index + 1, section)) } /// Compute the maximum file offset used by sections. diff --git a/src/read/coff/symbol.rs b/src/read/coff/symbol.rs index 55f23a63..bca1fe51 100644 --- a/src/read/coff/symbol.rs +++ b/src/read/coff/symbol.rs @@ -92,13 +92,13 @@ impl<'data, R: ReadRef<'data>, Coff: CoffHeader> SymbolTable<'data, R, Coff> { pub fn iter<'table>(&'table self) -> SymbolIterator<'data, 'table, R, Coff> { SymbolIterator { symbols: self, - index: 0, + index: SymbolIndex(0), } } /// Return the symbol table entry at the given index. #[inline] - pub fn symbol(&self, index: usize) -> Result<&'data Coff::ImageSymbol> { + pub fn symbol(&self, index: SymbolIndex) -> Result<&'data Coff::ImageSymbol> { self.get::(index, 0) } @@ -106,7 +106,7 @@ impl<'data, R: ReadRef<'data>, Coff: CoffHeader> SymbolTable<'data, R, Coff> { /// /// Note that the index is of the symbol, not the first auxiliary record. #[inline] - pub fn aux_function(&self, index: usize) -> Result<&'data pe::ImageAuxSymbolFunction> { + pub fn aux_function(&self, index: SymbolIndex) -> Result<&'data pe::ImageAuxSymbolFunction> { self.get::(index, 1) } @@ -114,15 +114,16 @@ impl<'data, R: ReadRef<'data>, Coff: CoffHeader> SymbolTable<'data, R, Coff> { /// /// Note that the index is of the symbol, not the first auxiliary record. #[inline] - pub fn aux_section(&self, index: usize) -> Result<&'data pe::ImageAuxSymbolSection> { + pub fn aux_section(&self, index: SymbolIndex) -> Result<&'data pe::ImageAuxSymbolSection> { self.get::(index, 1) } /// Return the auxiliary file name for the symbol table entry at the given index. /// /// Note that the index is of the symbol, not the first auxiliary record. - pub fn aux_file_name(&self, index: usize, aux_count: u8) -> Result<&'data [u8]> { + pub fn aux_file_name(&self, index: SymbolIndex, aux_count: u8) -> Result<&'data [u8]> { let entries = index + .0 .checked_add(1) .and_then(|x| Some(x..x.checked_add(aux_count.into())?)) .and_then(|x| self.symbols.get(x)) @@ -136,8 +137,9 @@ impl<'data, R: ReadRef<'data>, Coff: CoffHeader> SymbolTable<'data, R, Coff> { } /// Return the symbol table entry or auxiliary record at the given index and offset. - pub fn get(&self, index: usize, offset: usize) -> Result<&'data T> { + pub fn get(&self, index: SymbolIndex, offset: usize) -> Result<&'data T> { let bytes = index + .0 .checked_add(offset) .and_then(|x| self.symbols.get(x)) .read_error("Invalid COFF symbol index")?; @@ -174,18 +176,18 @@ where Coff: CoffHeader, { symbols: &'table SymbolTable<'data, R, Coff>, - index: usize, + index: SymbolIndex, } impl<'data, 'table, R: ReadRef<'data>, Coff: CoffHeader> Iterator for SymbolIterator<'data, 'table, R, Coff> { - type Item = (usize, &'data Coff::ImageSymbol); + type Item = (SymbolIndex, &'data Coff::ImageSymbol); fn next(&mut self) -> Option { let index = self.index; let symbol = self.symbols.symbol(index).ok()?; - self.index += 1 + symbol.number_of_aux_symbols() as usize; + self.index.0 += 1 + symbol.number_of_aux_symbols() as usize; Some((index, symbol)) } } @@ -217,14 +219,11 @@ impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> ObjectSymbolTable<'data> type SymbolIterator = CoffSymbolIterator<'data, 'file, R, Coff>; fn symbols(&self) -> Self::SymbolIterator { - CoffSymbolIterator { - file: self.file, - index: 0, - } + CoffSymbolIterator::new(self.file) } fn symbol_by_index(&self, index: SymbolIndex) -> Result { - let symbol = self.file.symbols.symbol(index.0)?; + let symbol = self.file.symbols.symbol(index)?; Ok(CoffSymbol { file: self.file, index, @@ -244,8 +243,28 @@ where R: ReadRef<'data>, Coff: CoffHeader, { - pub(crate) file: &'file CoffCommon<'data, R, Coff>, - pub(crate) index: usize, + file: &'file CoffCommon<'data, R, Coff>, + index: SymbolIndex, +} + +impl<'data, 'file, R, Coff> CoffSymbolIterator<'data, 'file, R, Coff> +where + R: ReadRef<'data>, + Coff: CoffHeader, +{ + pub(crate) fn new(file: &'file CoffCommon<'data, R, Coff>) -> Self { + Self { + file, + index: SymbolIndex(0), + } + } + + pub(crate) fn empty(file: &'file CoffCommon<'data, R, Coff>) -> Self { + Self { + file, + index: SymbolIndex(file.symbols.len()), + } + } } impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> fmt::Debug @@ -264,10 +283,10 @@ impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> Iterator fn next(&mut self) -> Option { let index = self.index; let symbol = self.file.symbols.symbol(index).ok()?; - self.index += 1 + symbol.number_of_aux_symbols() as usize; + self.index.0 += 1 + symbol.number_of_aux_symbols() as usize; Some(CoffSymbol { file: self.file, - index: SymbolIndex(index), + index, symbol, }) } @@ -324,7 +343,7 @@ impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> ObjectSymbol<'data> if self.symbol.has_aux_file_name() { self.file .symbols - .aux_file_name(self.index.0, self.symbol.number_of_aux_symbols()) + .aux_file_name(self.index, self.symbol.number_of_aux_symbols()) } else { self.symbol.name(self.file.symbols.strings()) } @@ -361,7 +380,7 @@ impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> ObjectSymbol<'data> pe::IMAGE_SYM_CLASS_STATIC => { // Section symbols may duplicate the size from the section table. if self.symbol.has_aux_section() { - if let Ok(aux) = self.file.symbols.aux_section(self.index.0) { + if let Ok(aux) = self.file.symbols.aux_section(self.index) { u64::from(aux.length.get(LE)) } else { 0 @@ -377,7 +396,7 @@ impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> ObjectSymbol<'data> u64::from(self.symbol.value()) } else if self.symbol.has_aux_function() { // Function symbols may have a size. - if let Ok(aux) = self.file.symbols.aux_function(self.index.0) { + if let Ok(aux) = self.file.symbols.aux_function(self.index) { u64::from(aux.total_size.get(LE)) } else { 0 @@ -491,7 +510,7 @@ impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> ObjectSymbol<'data> fn flags(&self) -> SymbolFlags { if self.symbol.has_aux_section() { - if let Ok(aux) = self.file.symbols.aux_section(self.index.0) { + if let Ok(aux) = self.file.symbols.aux_section(self.index) { let number = if Coff::is_type_bigobj() { u32::from(aux.number.get(LE)) | (u32::from(aux.high_number.get(LE)) << 16) } else { @@ -548,7 +567,7 @@ pub trait ImageSymbol: Debug + Pod { /// /// This takes into account the image base and the section address. fn address(&self, image_base: u64, sections: &SectionTable<'_>) -> Result { - let section_number = self.section_number() as usize; + let section_number = SectionIndex(self.section_number() as usize); let section = sections.section(section_number)?; let virtual_address = u64::from(section.virtual_address.get(LE)); let value = u64::from(self.value()); diff --git a/src/read/elf/comdat.rs b/src/read/elf/comdat.rs index bc42bf3b..cfeb04fc 100644 --- a/src/read/elf/comdat.rs +++ b/src/read/elf/comdat.rs @@ -134,7 +134,7 @@ where fn name_bytes(&self) -> read::Result<&'data [u8]> { // FIXME: check sh_link - let index = self.section.sh_info(self.file.endian) as usize; + let index = self.symbol(); let symbol = self.file.symbols.symbol(index)?; symbol.name(self.file.endian, self.file.symbols.strings()) } diff --git a/src/read/elf/file.rs b/src/read/elf/file.rs index 2e417d33..55b51bf5 100644 --- a/src/read/elf/file.rs +++ b/src/read/elf/file.rs @@ -286,7 +286,7 @@ where } fn symbol_by_index(&self, index: SymbolIndex) -> read::Result> { - let symbol = self.symbols.symbol(index.0)?; + let symbol = self.symbols.symbol(index)?; Ok(ElfSymbol { endian: self.endian, symbols: &self.symbols, @@ -702,6 +702,18 @@ pub trait FileHeader: Debug + Pod { .read_error("Invalid ELF section header offset/size/alignment") } + /// Get the section index of the section header string table. + /// + /// Returns `Err` for invalid values (including if the index is 0). + fn section_strings_index<'data, R: ReadRef<'data>>( + &self, + endian: Self::Endian, + data: R, + ) -> read::Result { + self.shstrndx(endian, data) + .map(|index| SectionIndex(index as usize)) + } + /// Return the string table for the section headers. fn section_strings<'data, R: ReadRef<'data>>( &self, @@ -712,8 +724,8 @@ pub trait FileHeader: Debug + Pod { if sections.is_empty() { return Ok(StringTable::default()); } - let index = self.shstrndx(endian, data)? as usize; - let shstrtab = sections.get(index).read_error("Invalid ELF e_shstrndx")?; + let index = self.section_strings_index(endian, data)?; + let shstrtab = sections.get(index.0).read_error("Invalid ELF e_shstrndx")?; let strings = if let Some((shstrtab_offset, shstrtab_size)) = shstrtab.file_range(endian) { let shstrtab_end = shstrtab_offset .checked_add(shstrtab_size) diff --git a/src/read/elf/hash.rs b/src/read/elf/hash.rs index 62aa1c07..bbc7ae93 100644 --- a/src/read/elf/hash.rs +++ b/src/read/elf/hash.rs @@ -2,7 +2,7 @@ use core::mem; use crate::elf; use crate::endian::{U32, U64}; -use crate::read::{ReadError, ReadRef, Result}; +use crate::read::{ReadError, ReadRef, Result, SymbolIndex}; use super::{FileHeader, Sym, SymbolTable, Version, VersionTable}; @@ -41,6 +41,14 @@ impl<'data, Elf: FileHeader> HashTable<'data, Elf> { self.chains.len() as u32 } + fn bucket(&self, endian: Elf::Endian, hash: u32) -> SymbolIndex { + SymbolIndex(self.buckets[(hash as usize) % self.buckets.len()].get(endian) as usize) + } + + fn chain(&self, endian: Elf::Endian, index: SymbolIndex) -> SymbolIndex { + SymbolIndex(self.chains[index.0].get(endian) as usize) + } + /// Use the hash table to find the symbol table entry with the given name, hash and version. pub fn find>( &self, @@ -50,13 +58,13 @@ impl<'data, Elf: FileHeader> HashTable<'data, Elf> { version: Option<&Version<'_>>, symbols: &SymbolTable<'data, Elf, R>, versions: &VersionTable<'data, Elf>, - ) -> Option<(usize, &'data Elf::Sym)> { + ) -> Option<(SymbolIndex, &'data Elf::Sym)> { // Get the chain start from the bucket for this hash. - let mut index = self.buckets[(hash as usize) % self.buckets.len()].get(endian) as usize; + let mut index = self.bucket(endian, hash); // Avoid infinite loop. let mut i = 0; let strings = symbols.strings(); - while index != 0 && i < self.chains.len() { + while index != SymbolIndex(0) && i < self.chains.len() { if let Ok(symbol) = symbols.symbol(index) { if symbol.name(endian, strings) == Ok(name) && versions.matches(endian, index, version) @@ -64,7 +72,7 @@ impl<'data, Elf: FileHeader> HashTable<'data, Elf> { return Some((index, symbol)); } } - index = self.chains.get(index)?.get(endian) as usize; + index = self.chain(endian, index); i += 1; } None @@ -158,6 +166,10 @@ impl<'data, Elf: FileHeader> GnuHashTable<'data, Elf> { None } + fn bucket(&self, endian: Elf::Endian, hash: u32) -> SymbolIndex { + SymbolIndex(self.buckets[(hash as usize) % self.buckets.len()].get(endian) as usize) + } + /// Use the hash table to find the symbol table entry with the given name, hash, and version. pub fn find>( &self, @@ -167,7 +179,7 @@ impl<'data, Elf: FileHeader> GnuHashTable<'data, Elf> { version: Option<&Version<'_>>, symbols: &SymbolTable<'data, Elf, R>, versions: &VersionTable<'data, Elf>, - ) -> Option<(usize, &'data Elf::Sym)> { + ) -> Option<(SymbolIndex, &'data Elf::Sym)> { let word_bits = mem::size_of::() as u32 * 8; // Test against bloom filter. @@ -194,17 +206,17 @@ impl<'data, Elf: FileHeader> GnuHashTable<'data, Elf> { } // Get the chain start from the bucket for this hash. - let mut index = self.buckets[(hash as usize) % self.buckets.len()].get(endian) as usize; - if index == 0 { + let mut index = self.bucket(endian, hash); + if index == SymbolIndex(0) { return None; } // Test symbols in the chain. let strings = symbols.strings(); - let symbols = symbols.symbols().get(index..)?; + let symbols = symbols.symbols().get(index.0..)?; let values = self .values - .get(index.checked_sub(self.symbol_base as usize)?..)?; + .get(index.0.checked_sub(self.symbol_base as usize)?..)?; for (symbol, value) in symbols.iter().zip(values.iter()) { let value = value.get(endian); if value | 1 == hash | 1 { @@ -217,7 +229,7 @@ impl<'data, Elf: FileHeader> GnuHashTable<'data, Elf> { if value & 1 != 0 { break; } - index += 1; + index.0 += 1; } None } diff --git a/src/read/elf/relocation.rs b/src/read/elf/relocation.rs index 036e7a33..a0ae7bfe 100644 --- a/src/read/elf/relocation.rs +++ b/src/read/elf/relocation.rs @@ -34,13 +34,13 @@ impl RelocationSections { if sh_type == elf::SHT_REL || sh_type == elf::SHT_RELA { // The symbol indices used in relocations must be for the symbol table // we are expecting to use. - let sh_link = SectionIndex(section.sh_link(endian) as usize); + let sh_link = section.link(endian); if sh_link != symbol_section { continue; } - let sh_info = SectionIndex(section.sh_info(endian) as usize); - if sh_info.0 == 0 { + let sh_info = section.info_link(endian); + if sh_info == SectionIndex(0) { // Skip dynamic relocations. continue; } @@ -143,8 +143,7 @@ where let section = self.file.sections.section(self.section_index).ok()?; self.section_index.0 += 1; - let sh_link = SectionIndex(section.sh_link(endian) as usize); - if sh_link != self.file.dynamic_symbols.section() { + if section.link(endian) != self.file.dynamic_symbols.section() { continue; } @@ -481,11 +480,9 @@ fn parse_relocation( }, _ => (RelocationKind::Unknown, 0), }; - let sym = reloc.r_sym(endian, is_mips64el) as usize; - let target = if sym == 0 { - RelocationTarget::Absolute - } else { - RelocationTarget::Symbol(SymbolIndex(sym)) + let target = match reloc.symbol(endian, is_mips64el) { + None => RelocationTarget::Absolute, + Some(symbol) => RelocationTarget::Symbol(symbol), }; Relocation { kind, @@ -509,6 +506,18 @@ pub trait Rel: Debug + Pod + Clone { fn r_info(&self, endian: Self::Endian) -> Self::Word; fn r_sym(&self, endian: Self::Endian) -> u32; fn r_type(&self, endian: Self::Endian) -> u32; + + /// Get the symbol index referenced by the relocation. + /// + /// Returns `None` for the null symbol index. + fn symbol(&self, endian: Self::Endian) -> Option { + let sym = self.r_sym(endian); + if sym == 0 { + None + } else { + Some(SymbolIndex(sym as usize)) + } + } } impl Rel for elf::Rel32 { @@ -575,6 +584,18 @@ pub trait Rela: Debug + Pod + Clone { fn r_addend(&self, endian: Self::Endian) -> Self::Sword; fn r_sym(&self, endian: Self::Endian, is_mips64el: bool) -> u32; fn r_type(&self, endian: Self::Endian, is_mips64el: bool) -> u32; + + /// Get the symbol index referenced by the relocation. + /// + /// Returns `None` for the null symbol index. + fn symbol(&self, endian: Self::Endian, is_mips64el: bool) -> Option { + let sym = self.r_sym(endian, is_mips64el); + if sym == 0 { + None + } else { + Some(SymbolIndex(sym as usize)) + } + } } impl Rela for elf::Rela32 { diff --git a/src/read/elf/section.rs b/src/read/elf/section.rs index 44a25132..dba63870 100644 --- a/src/read/elf/section.rs +++ b/src/read/elf/section.rs @@ -37,11 +37,24 @@ impl<'data, Elf: FileHeader, R: ReadRef<'data>> SectionTable<'data, Elf, R> { } /// Iterate over the section headers. + /// + /// This includes the null section at index 0, which you will usually need to skip. #[inline] pub fn iter(&self) -> slice::Iter<'data, Elf::SectionHeader> { self.sections.iter() } + /// Iterate over the section headers and their indices. + /// + /// This includes the null section at index 0, which you will usually need to skip. + #[inline] + pub fn enumerate(&self) -> impl Iterator { + self.sections + .iter() + .enumerate() + .map(|(i, section)| (SectionIndex(i), section)) + } + /// Return true if the section table is empty. #[inline] pub fn is_empty(&self) -> bool { @@ -58,7 +71,7 @@ impl<'data, Elf: FileHeader, R: ReadRef<'data>> SectionTable<'data, Elf, R> { /// /// Returns an error for the null section at index 0. pub fn section(&self, index: SectionIndex) -> read::Result<&'data Elf::SectionHeader> { - if index.0 == 0 { + if index == SectionIndex(0) { return Err(read::Error("Invalid ELF section index")); } self.sections @@ -442,6 +455,7 @@ impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ElfSection<'data, 'file, let Some(relocation_section) = self.elf_relocation_section()? else { return Ok(&[]); }; + // The linked symbol table was already checked when self.file.relocations was created. let Some((rel, _)) = relocation_section.rel(self.file.endian, self.file.data)? else { return Ok(&[]); }; @@ -456,6 +470,7 @@ impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ElfSection<'data, 'file, let Some(relocation_section) = self.elf_relocation_section()? else { return Ok(&[]); }; + // The linked symbol table was already checked when self.file.relocations was created. let Some((rela, _)) = relocation_section.rela(self.file.endian, self.file.data)? else { return Ok(&[]); }; @@ -715,6 +730,26 @@ pub trait SectionHeader: Debug + Pod { .read_error("Invalid ELF section name offset") } + /// Get the `sh_link` field as a section index. + /// + /// This may return a null section index, and does not check for validity. + fn link(&self, endian: Self::Endian) -> SectionIndex { + SectionIndex(self.sh_link(endian) as usize) + } + + /// Return true if the `SHF_INFO_LINK` flag is set. + fn has_info_link(&self, endian: Self::Endian) -> bool { + self.sh_flags(endian).into() & u64::from(elf::SHF_INFO_LINK) != 0 + } + + /// Get the `sh_info` field as a section index. + /// + /// This does not check the `SHF_INFO_LINK` flag. + /// This may return a null section index, and does not check for validity. + fn info_link(&self, endian: Self::Endian) -> SectionIndex { + SectionIndex(self.sh_info(endian) as usize) + } + /// Return the offset and size of the section in the file. /// /// Returns `None` for sections that have no data in the file. @@ -817,8 +852,7 @@ pub trait SectionHeader: Debug + Pod { let rel = self .data_as_array(endian, data) .read_error("Invalid ELF relocation section offset or size")?; - let link = SectionIndex(self.sh_link(endian) as usize); - Ok(Some((rel, link))) + Ok(Some((rel, self.link(endian)))) } /// Return the `Elf::Rela` entries in the section. @@ -838,8 +872,7 @@ pub trait SectionHeader: Debug + Pod { let rela = self .data_as_array(endian, data) .read_error("Invalid ELF relocation section offset or size")?; - let link = SectionIndex(self.sh_link(endian) as usize); - Ok(Some((rela, link))) + Ok(Some((rela, self.link(endian)))) } /// Return entries in a dynamic section. @@ -859,8 +892,7 @@ pub trait SectionHeader: Debug + Pod { let dynamic = self .data_as_array(endian, data) .read_error("Invalid ELF dynamic section offset or size")?; - let link = SectionIndex(self.sh_link(endian) as usize); - Ok(Some((dynamic, link))) + Ok(Some((dynamic, self.link(endian)))) } /// Return a note iterator for the section data. @@ -943,8 +975,7 @@ pub trait SectionHeader: Debug + Pod { .data(endian, data) .read_error("Invalid ELF hash section offset or size")?; let hash = HashTable::parse(endian, data)?; - let link = SectionIndex(self.sh_link(endian) as usize); - Ok(Some((hash, link))) + Ok(Some((hash, self.link(endian)))) } /// Return the header of a GNU hash section. @@ -986,8 +1017,7 @@ pub trait SectionHeader: Debug + Pod { .data(endian, data) .read_error("Invalid ELF GNU hash section offset or size")?; let hash = GnuHashTable::parse(endian, data)?; - let link = SectionIndex(self.sh_link(endian) as usize); - Ok(Some((hash, link))) + Ok(Some((hash, self.link(endian)))) } /// Return the contents of a `SHT_GNU_VERSYM` section. @@ -1007,8 +1037,7 @@ pub trait SectionHeader: Debug + Pod { let versym = self .data_as_array(endian, data) .read_error("Invalid ELF GNU versym section offset or size")?; - let link = SectionIndex(self.sh_link(endian) as usize); - Ok(Some((versym, link))) + Ok(Some((versym, self.link(endian)))) } /// Return an iterator for the entries of a `SHT_GNU_VERDEF` section. @@ -1028,8 +1057,10 @@ pub trait SectionHeader: Debug + Pod { let verdef = self .data(endian, data) .read_error("Invalid ELF GNU verdef section offset or size")?; - let link = SectionIndex(self.sh_link(endian) as usize); - Ok(Some((VerdefIterator::new(endian, verdef), link))) + Ok(Some(( + VerdefIterator::new(endian, verdef), + self.link(endian), + ))) } /// Return an iterator for the entries of a `SHT_GNU_VERNEED` section. @@ -1049,8 +1080,10 @@ pub trait SectionHeader: Debug + Pod { let verneed = self .data(endian, data) .read_error("Invalid ELF GNU verneed section offset or size")?; - let link = SectionIndex(self.sh_link(endian) as usize); - Ok(Some((VerneedIterator::new(endian, verneed), link))) + Ok(Some(( + VerneedIterator::new(endian, verneed), + self.link(endian), + ))) } /// Return the contents of a `SHT_GNU_ATTRIBUTES` section. diff --git a/src/read/elf/symbol.rs b/src/read/elf/symbol.rs index 4dbf823a..a0066abe 100644 --- a/src/read/elf/symbol.rs +++ b/src/read/elf/symbol.rs @@ -70,9 +70,7 @@ impl<'data, Elf: FileHeader, R: ReadRef<'data>> SymbolTable<'data, Elf, R> { let mut shndx_section = SectionIndex(0); let mut shndx = &[][..]; for (i, s) in sections.iter().enumerate() { - if s.sh_type(endian) == elf::SHT_SYMTAB_SHNDX - && s.sh_link(endian) as usize == section_index.0 - { + if s.sh_type(endian) == elf::SHT_SYMTAB_SHNDX && s.link(endian) == section_index { shndx_section = SectionIndex(i); shndx = s .data_as_array(endian, data) @@ -121,11 +119,24 @@ impl<'data, Elf: FileHeader, R: ReadRef<'data>> SymbolTable<'data, Elf, R> { } /// Iterate over the symbols. + /// + /// This includes the null symbol at index 0, which you will usually need to skip. #[inline] pub fn iter(&self) -> slice::Iter<'data, Elf::Sym> { self.symbols.iter() } + /// Iterate over the symbols and their indices. + /// + /// This includes the null symbol at index 0, which you will usually need to skip. + #[inline] + pub fn enumerate(&self) -> impl Iterator { + self.symbols + .iter() + .enumerate() + .map(|(i, sym)| (SymbolIndex(i), sym)) + } + /// Return true if the symbol table is empty. #[inline] pub fn is_empty(&self) -> bool { @@ -141,19 +152,19 @@ impl<'data, Elf: FileHeader, R: ReadRef<'data>> SymbolTable<'data, Elf, R> { /// Get the symbol at the given index. /// /// Returns an error for null entry at index 0. - pub fn symbol(&self, index: usize) -> read::Result<&'data Elf::Sym> { - if index == 0 { + pub fn symbol(&self, index: SymbolIndex) -> read::Result<&'data Elf::Sym> { + if index == SymbolIndex(0) { return Err(read::Error("Invalid ELF symbol index")); } self.symbols - .get(index) + .get(index.0) .read_error("Invalid ELF symbol index") } /// Return the extended section index for the given symbol if present. #[inline] - pub fn shndx(&self, endian: Elf::Endian, index: usize) -> Option { - self.shndx.get(index).map(|x| x.get(endian)) + pub fn shndx(&self, endian: Elf::Endian, index: SymbolIndex) -> Option { + self.shndx.get(index.0).map(|x| x.get(endian)) } /// Return the section index for the given symbol. @@ -163,14 +174,20 @@ impl<'data, Elf: FileHeader, R: ReadRef<'data>> SymbolTable<'data, Elf, R> { &self, endian: Elf::Endian, symbol: &Elf::Sym, - index: usize, + index: SymbolIndex, ) -> read::Result> { match symbol.st_shndx(endian) { elf::SHN_UNDEF => Ok(None), - elf::SHN_XINDEX => self - .shndx(endian, index) - .read_error("Missing ELF symbol extended index") - .map(|index| Some(SectionIndex(index as usize))), + elf::SHN_XINDEX => { + let shndx = self + .shndx(endian, index) + .read_error("Missing ELF symbol extended index")?; + if shndx == 0 { + Ok(None) + } else { + Ok(Some(SectionIndex(shndx as usize))) + } + } shndx if shndx < elf::SHN_LORESERVE => Ok(Some(SectionIndex(shndx.into()))), _ => Ok(None), } @@ -234,7 +251,7 @@ impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ObjectSymbolTable<'data> } fn symbol_by_index(&self, index: SymbolIndex) -> read::Result { - let symbol = self.symbols.symbol(index.0)?; + let symbol = self.symbols.symbol(index)?; Ok(ElfSymbol { endian: self.endian, symbols: self.symbols, @@ -259,7 +276,7 @@ where { endian: Elf::Endian, symbols: &'file SymbolTable<'data, Elf, R>, - index: usize, + index: SymbolIndex, } impl<'data, 'file, Elf, R> ElfSymbolIterator<'data, 'file, Elf, R> @@ -271,7 +288,7 @@ where ElfSymbolIterator { endian, symbols, - index: 1, + index: SymbolIndex(1), } } } @@ -291,12 +308,12 @@ impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> Iterator fn next(&mut self) -> Option { let index = self.index; - let symbol = self.symbols.symbols.get(index)?; - self.index += 1; + let symbol = self.symbols.symbols.get(index.0)?; + self.index.0 += 1; Some(ElfSymbol { endian: self.endian, symbols: self.symbols, - index: SymbolIndex(index), + index, symbol, }) } @@ -400,7 +417,8 @@ impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ObjectSymbol<'data> } } elf::SHN_COMMON => SymbolSection::Common, - elf::SHN_XINDEX => match self.symbols.shndx(self.endian, self.index.0) { + elf::SHN_XINDEX => match self.symbols.shndx(self.endian, self.index) { + Some(0) => SymbolSection::None, Some(index) => SymbolSection::Section(SectionIndex(index as usize)), None => SymbolSection::Unknown, }, diff --git a/src/read/elf/version.rs b/src/read/elf/version.rs index 28eeed0a..ae3f005b 100644 --- a/src/read/elf/version.rs +++ b/src/read/elf/version.rs @@ -1,6 +1,6 @@ use alloc::vec::Vec; -use crate::read::{Bytes, ReadError, ReadRef, Result, StringTable}; +use crate::read::{Bytes, ReadError, ReadRef, Result, StringTable, SymbolIndex}; use crate::{elf, endian}; use super::FileHeader; @@ -161,8 +161,8 @@ impl<'data, Elf: FileHeader> VersionTable<'data, Elf> { } /// Return version index for a given symbol index. - pub fn version_index(&self, endian: Elf::Endian, index: usize) -> VersionIndex { - let version_index = match self.symbols.get(index) { + pub fn version_index(&self, endian: Elf::Endian, index: SymbolIndex) -> VersionIndex { + let version_index = match self.symbols.get(index.0) { Some(x) => x.0.get(endian), // Ideally this would be VER_NDX_LOCAL for undefined symbols, // but currently there are no checks that need this distinction. @@ -191,7 +191,12 @@ impl<'data, Elf: FileHeader> VersionTable<'data, Elf> { /// Returns false for any error. /// /// Note: this function hasn't been fully tested and is likely to be incomplete. - pub fn matches(&self, endian: Elf::Endian, index: usize, need: Option<&Version<'_>>) -> bool { + pub fn matches( + &self, + endian: Elf::Endian, + index: SymbolIndex, + need: Option<&Version<'_>>, + ) -> bool { let version_index = self.version_index(endian, index); let def = match self.version(version_index) { Ok(def) => def, diff --git a/src/read/macho/file.rs b/src/read/macho/file.rs index 18a04b63..9c62f71c 100644 --- a/src/read/macho/file.rs +++ b/src/read/macho/file.rs @@ -335,15 +335,12 @@ where } fn symbol_by_index(&self, index: SymbolIndex) -> Result> { - let nlist = self.symbols.symbol(index.0)?; + let nlist = self.symbols.symbol(index)?; MachOSymbol::new(self, index, nlist).read_error("Unsupported Mach-O symbol index") } fn symbols(&self) -> MachOSymbolIterator<'data, '_, Mach, R> { - MachOSymbolIterator { - file: self, - index: 0, - } + MachOSymbolIterator::new(self) } #[inline] @@ -352,10 +349,7 @@ where } fn dynamic_symbols(&self) -> MachOSymbolIterator<'data, '_, Mach, R> { - MachOSymbolIterator { - file: self, - index: self.symbols.len(), - } + MachOSymbolIterator::empty(self) } #[inline] @@ -393,7 +387,7 @@ where let index = dysymtab.iundefsym.get(self.endian) as usize; let number = dysymtab.nundefsym.get(self.endian) as usize; for i in index..(index.wrapping_add(number)) { - let symbol = self.symbols.symbol(i)?; + let symbol = self.symbols.symbol(SymbolIndex(i))?; let name = symbol.name(self.endian, self.symbols.strings())?; let library = if twolevel { libraries @@ -429,7 +423,7 @@ where let index = dysymtab.iextdefsym.get(self.endian) as usize; let number = dysymtab.nextdefsym.get(self.endian) as usize; for i in index..(index.wrapping_add(number)) { - let symbol = self.symbols.symbol(i)?; + let symbol = self.symbols.symbol(SymbolIndex(i))?; let name = symbol.name(self.endian, self.symbols.strings())?; let address = symbol.n_value(self.endian).into(); exports.push(Export { diff --git a/src/read/macho/symbol.rs b/src/read/macho/symbol.rs index 8fe64f66..5a18650d 100644 --- a/src/read/macho/symbol.rs +++ b/src/read/macho/symbol.rs @@ -68,9 +68,9 @@ impl<'data, Mach: MachHeader, R: ReadRef<'data>> SymbolTable<'data, Mach, R> { } /// Return the symbol at the given index. - pub fn symbol(&self, index: usize) -> Result<&'data Mach::Nlist> { + pub fn symbol(&self, index: SymbolIndex) -> Result<&'data Mach::Nlist> { self.symbols - .get(index) + .get(index.0) .read_error("Invalid Mach-O symbol index") } @@ -178,14 +178,11 @@ where type SymbolIterator = MachOSymbolIterator<'data, 'file, Mach, R>; fn symbols(&self) -> Self::SymbolIterator { - MachOSymbolIterator { - file: self.file, - index: 0, - } + MachOSymbolIterator::new(self.file) } fn symbol_by_index(&self, index: SymbolIndex) -> Result { - let nlist = self.file.symbols.symbol(index.0)?; + let nlist = self.file.symbols.symbol(index)?; MachOSymbol::new(self.file, index, nlist).read_error("Unsupported Mach-O symbol index") } } @@ -203,8 +200,28 @@ where Mach: MachHeader, R: ReadRef<'data>, { - pub(super) file: &'file MachOFile<'data, Mach, R>, - pub(super) index: usize, + file: &'file MachOFile<'data, Mach, R>, + index: SymbolIndex, +} + +impl<'data, 'file, Mach, R> MachOSymbolIterator<'data, 'file, Mach, R> +where + Mach: MachHeader, + R: ReadRef<'data>, +{ + pub(super) fn new(file: &'file MachOFile<'data, Mach, R>) -> Self { + MachOSymbolIterator { + file, + index: SymbolIndex(0), + } + } + + pub(super) fn empty(file: &'file MachOFile<'data, Mach, R>) -> Self { + MachOSymbolIterator { + file, + index: SymbolIndex(file.symbols.len()), + } + } } impl<'data, 'file, Mach, R> fmt::Debug for MachOSymbolIterator<'data, 'file, Mach, R> @@ -227,9 +244,9 @@ where fn next(&mut self) -> Option { loop { let index = self.index; - let nlist = self.file.symbols.symbols.get(index)?; - self.index += 1; - if let Some(symbol) = MachOSymbol::new(self.file, SymbolIndex(index), nlist) { + let nlist = self.file.symbols.symbols.get(index.0)?; + self.index.0 += 1; + if let Some(symbol) = MachOSymbol::new(self.file, index, nlist) { return Some(symbol); } } diff --git a/src/read/mod.rs b/src/read/mod.rs index 31077fe1..b9c717d5 100644 --- a/src/read/mod.rs +++ b/src/read/mod.rs @@ -379,10 +379,22 @@ pub enum ObjectKind { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct SectionIndex(pub usize); +impl fmt::Display for SectionIndex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + /// The index used to identify a symbol in a symbol table. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct SymbolIndex(pub usize); +impl fmt::Display for SymbolIndex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + /// The section where an [`ObjectSymbol`] is defined. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[non_exhaustive] diff --git a/src/read/pe/file.rs b/src/read/pe/file.rs index 2e9d4462..ec9d9e6c 100644 --- a/src/read/pe/file.rs +++ b/src/read/pe/file.rs @@ -209,13 +209,13 @@ where .section_by_name(self.common.symbols.strings(), section_name) .map(|(index, section)| PeSection { file: self, - index: SectionIndex(index), + index, section, }) } fn section_by_index(&self, index: SectionIndex) -> Result> { - let section = self.common.sections.section(index.0)?; + let section = self.common.sections.section(index)?; Ok(PeSection { file: self, index, @@ -235,7 +235,7 @@ where } fn symbol_by_index(&self, index: SymbolIndex) -> Result> { - let symbol = self.common.symbols.symbol(index.0)?; + let symbol = self.common.symbols.symbol(index)?; Ok(CoffSymbol { file: &self.common, index, @@ -244,10 +244,7 @@ where } fn symbols(&self) -> CoffSymbolIterator<'data, '_, R> { - CoffSymbolIterator { - file: &self.common, - index: 0, - } + CoffSymbolIterator::new(&self.common) } fn symbol_table(&self) -> Option> { @@ -255,11 +252,7 @@ where } fn dynamic_symbols(&self) -> CoffSymbolIterator<'data, '_, R> { - CoffSymbolIterator { - file: &self.common, - // Hack: don't return any. - index: self.common.symbols.len(), - } + CoffSymbolIterator::empty(&self.common) } fn dynamic_symbol_table(&self) -> Option> { diff --git a/src/read/xcoff/file.rs b/src/read/xcoff/file.rs index f4f22133..6d8de8dd 100644 --- a/src/read/xcoff/file.rs +++ b/src/read/xcoff/file.rs @@ -193,7 +193,7 @@ where } fn symbol_by_index(&self, index: SymbolIndex) -> Result> { - let symbol = self.symbols.symbol(index.0)?; + let symbol = self.symbols.symbol(index)?; Ok(XcoffSymbol { symbols: &self.symbols, index, diff --git a/src/read/xcoff/symbol.rs b/src/read/xcoff/symbol.rs index 9cdc844f..6e8c0c61 100644 --- a/src/read/xcoff/symbol.rs +++ b/src/read/xcoff/symbol.rs @@ -107,8 +107,9 @@ where } /// Return the symbol entry at the given index and offset. - pub fn get(&self, index: usize, offset: usize) -> Result<&'data T> { + pub fn get(&self, index: SymbolIndex, offset: usize) -> Result<&'data T> { let entry = index + .0 .checked_add(offset) .and_then(|x| self.symbols.get(x)) .read_error("Invalid XCOFF symbol index")?; @@ -119,7 +120,7 @@ where /// Get the symbol at the given index. /// /// This does not check if the symbol is null, but does check if the index is in bounds. - fn symbol_unchecked(&self, index: usize) -> Result<&'data Xcoff::Symbol> { + fn symbol_unchecked(&self, index: SymbolIndex) -> Result<&'data Xcoff::Symbol> { self.get::(index, 0) } @@ -127,7 +128,7 @@ where /// /// Returns an error for null symbols and out of bounds indices. /// Note that this is unable to check whether the index is an auxiliary symbol. - pub fn symbol(&self, index: usize) -> Result<&'data Xcoff::Symbol> { + pub fn symbol(&self, index: SymbolIndex) -> Result<&'data Xcoff::Symbol> { let symbol = self.symbol_unchecked(index)?; if symbol.is_null() { return Err(Error("Invalid XCOFF symbol index")); @@ -136,7 +137,7 @@ where } /// Return a file auxiliary symbol. - pub fn aux_file(&self, index: usize, offset: usize) -> Result<&'data Xcoff::FileAux> { + pub fn aux_file(&self, index: SymbolIndex, offset: usize) -> Result<&'data Xcoff::FileAux> { debug_assert!(self.symbol(index)?.has_aux_file()); let aux_file = self.get::(index, offset)?; if let Some(aux_type) = aux_file.x_auxtype() { @@ -148,7 +149,7 @@ where } /// Return the csect auxiliary symbol. - pub fn aux_csect(&self, index: usize, offset: usize) -> Result<&'data Xcoff::CsectAux> { + pub fn aux_csect(&self, index: SymbolIndex, offset: usize) -> Result<&'data Xcoff::CsectAux> { debug_assert!(self.symbol(index)?.has_aux_csect()); let aux_csect = self.get::(index, offset)?; if let Some(aux_type) = aux_csect.x_auxtype() { @@ -194,11 +195,11 @@ impl<'data, 'table, Xcoff: FileHeader, R: ReadRef<'data>> Iterator fn next(&mut self) -> Option { loop { - let index = self.index; + let index = SymbolIndex(self.index); let symbol = self.symbols.symbol_unchecked(index).ok()?; self.index += 1 + symbol.n_numaux() as usize; if !symbol.is_null() { - return Some((SymbolIndex(index), symbol)); + return Some((index, symbol)); } } } @@ -241,7 +242,7 @@ impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> ObjectSymbolTable<'data } fn symbol_by_index(&self, index: SymbolIndex) -> read::Result { - let symbol = self.symbols.symbol(index.0)?; + let symbol = self.symbols.symbol(index)?; Ok(XcoffSymbol { file: self.file, symbols: self.symbols, @@ -347,7 +348,7 @@ impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> ObjectSymbol<'data> if self.symbol.has_aux_file() { // By convention the file name is in the first auxiliary entry. self.symbols - .aux_file(self.index.0, 1)? + .aux_file(self.index, 1)? .fname(self.symbols.strings) } else { self.symbol.name(self.symbols.strings) @@ -384,7 +385,7 @@ impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> ObjectSymbol<'data> if let Ok(aux_csect) = self .file .symbols - .aux_csect(self.index.0, self.symbol.n_numaux() as usize) + .aux_csect(self.index, self.symbol.n_numaux() as usize) { let sym_type = aux_csect.sym_type(); if sym_type == xcoff::XTY_SD || sym_type == xcoff::XTY_CM { @@ -400,7 +401,7 @@ impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> ObjectSymbol<'data> if let Ok(aux_csect) = self .file .symbols - .aux_csect(self.index.0, self.symbol.n_numaux() as usize) + .aux_csect(self.index, self.symbol.n_numaux() as usize) { let sym_type = aux_csect.sym_type(); if sym_type == xcoff::XTY_SD || sym_type == xcoff::XTY_CM { @@ -454,7 +455,7 @@ impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> ObjectSymbol<'data> if self.symbol.has_aux_csect() { if let Ok(aux_csect) = self .symbols - .aux_csect(self.index.0, self.symbol.n_numaux() as usize) + .aux_csect(self.index, self.symbol.n_numaux() as usize) { let sym_type = aux_csect.sym_type(); sym_type == xcoff::XTY_SD || sym_type == xcoff::XTY_LD || sym_type == xcoff::XTY_CM @@ -516,7 +517,7 @@ impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> ObjectSymbol<'data> if let Ok(aux_csect) = self .file .symbols - .aux_csect(self.index.0, self.symbol.n_numaux() as usize) + .aux_csect(self.index, self.symbol.n_numaux() as usize) { x_smtyp = aux_csect.x_smtyp(); x_smclas = aux_csect.x_smclas();