From 4299e27e3c26d32d9c3282e76705d43f15469636 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Mon, 21 Sep 2020 13:36:01 +1000 Subject: [PATCH] Replace `Symbol` with a trait This allows users to only store the parts of the symbol that they are interested in. For example, the user may want to only store the symbol index and retrieve specific details from the symbol table only as needed. `Object::symbol_map` now returns a map containing only symbol names and addresses, which is the most common use case. `SymbolMap` can be constructed with custom symbol entries if other information is required. This method also uses the dynamic symbol table if there are no debugging symbols. Also fixes COFF/PE symbols to give the correct address. Previously they weren't including the image base address and the section address. --- examples/nm.rs | 11 +- examples/objcopy.rs | 8 +- examples/objdump.rs | 6 +- src/read/any.rs | 193 ++++++++++++++++- src/read/coff/comdat.rs | 32 ++- src/read/coff/file.rs | 72 ++++--- src/read/coff/section.rs | 4 +- src/read/coff/symbol.rs | 423 +++++++++++++++++++++++++++---------- src/read/elf/file.rs | 57 ++--- src/read/elf/symbol.rs | 287 +++++++++++++++++++------ src/read/macho/file.rs | 71 ++----- src/read/macho/symbol.rs | 281 +++++++++++++++++------- src/read/mod.rs | 165 +++++---------- src/read/pe/file.rs | 64 +++--- src/read/pe/section.rs | 4 +- src/read/traits.rs | 148 ++++++++++--- src/read/wasm.rs | 194 +++++++++++++---- tests/round_trip/bss.rs | 30 +-- tests/round_trip/comdat.rs | 24 ++- tests/round_trip/common.rs | 36 ++-- tests/round_trip/elf.rs | 6 +- tests/round_trip/mod.rs | 47 +++-- tests/round_trip/tls.rs | 41 ++-- 23 files changed, 1515 insertions(+), 689 deletions(-) diff --git a/examples/nm.rs b/examples/nm.rs index 67a1d31b..6c35737d 100644 --- a/examples/nm.rs +++ b/examples/nm.rs @@ -1,4 +1,7 @@ -use object::{Object, ObjectSection, SectionIndex, SectionKind, Symbol, SymbolKind, SymbolSection}; +use object::{ + Object, ObjectSection, ObjectSymbol, SectionIndex, SectionKind, Symbol, SymbolKind, + SymbolSection, +}; use std::collections::HashMap; use std::{env, fs, process}; @@ -40,19 +43,19 @@ fn main() { let section_kinds = file.sections().map(|s| (s.index(), s.kind())).collect(); println!("Debugging symbols:"); - for (_, symbol) in file.symbols() { + for symbol in file.symbols() { print_symbol(&symbol, §ion_kinds); } println!(); println!("Dynamic symbols:"); - for (_, symbol) in file.dynamic_symbols() { + for symbol in file.dynamic_symbols() { print_symbol(&symbol, §ion_kinds); } } } -fn print_symbol(symbol: &Symbol<'_>, section_kinds: &HashMap) { +fn print_symbol(symbol: &Symbol<'_, '_>, section_kinds: &HashMap) { if let SymbolKind::Section | SymbolKind::File = symbol.kind() { return; } diff --git a/examples/objcopy.rs b/examples/objcopy.rs index 9175f611..8d2c1140 100644 --- a/examples/objcopy.rs +++ b/examples/objcopy.rs @@ -2,8 +2,8 @@ use std::collections::HashMap; use std::{env, fs, process}; use object::{ - write, Object, ObjectComdat, ObjectSection, RelocationTarget, SectionKind, SymbolFlags, - SymbolKind, SymbolSection, + write, Object, ObjectComdat, ObjectSection, ObjectSymbol, RelocationTarget, SectionKind, + SymbolFlags, SymbolKind, SymbolSection, }; fn main() { @@ -73,7 +73,7 @@ fn main() { } let mut out_symbols = HashMap::new(); - for (symbol_index, in_symbol) in in_object.symbols() { + for in_symbol in in_object.symbols() { if in_symbol.kind() == SymbolKind::Null { continue; } @@ -123,7 +123,7 @@ fn main() { flags, }; let symbol_id = out_object.add_symbol(out_symbol); - out_symbols.insert(symbol_index, symbol_id); + out_symbols.insert(in_symbol.index(), symbol_id); } for in_section in in_object.sections() { diff --git a/examples/objdump.rs b/examples/objdump.rs index c9e2c0cd..4bcfe43b 100644 --- a/examples/objdump.rs +++ b/examples/objdump.rs @@ -1,4 +1,4 @@ -use object::{Object, ObjectComdat, ObjectSection}; +use object::{Object, ObjectComdat, ObjectSection, ObjectSymbol}; use std::{env, fs, process}; fn main() { @@ -72,8 +72,8 @@ fn main() { println!(); } - for (index, symbol) in file.symbols() { - println!("{}: {:?}", index.0, symbol); + for symbol in file.symbols() { + println!("{}: {:?}", symbol.index().0, symbol); } for section in file.sections() { diff --git a/src/read/any.rs b/src/read/any.rs index 0dfe6171..8d4ad54f 100644 --- a/src/read/any.rs +++ b/src/read/any.rs @@ -12,8 +12,9 @@ use crate::read::pe; use crate::read::wasm; use crate::read::{ self, Architecture, BinaryFormat, ComdatKind, CompressedData, Error, FileFlags, Object, - ObjectComdat, ObjectSection, ObjectSegment, Relocation, Result, SectionFlags, SectionIndex, - SectionKind, Symbol, SymbolIndex, SymbolMap, + ObjectComdat, ObjectSection, ObjectSegment, ObjectSymbol, ObjectSymbolTable, Relocation, + Result, SectionFlags, SectionIndex, SectionKind, SymbolFlags, SymbolIndex, SymbolKind, + SymbolMap, SymbolMapName, SymbolScope, SymbolSection, }; /// Evaluate an expression on the contents of a file format enum. @@ -245,7 +246,9 @@ where type SectionIterator = SectionIterator<'data, 'file>; type Comdat = Comdat<'data, 'file>; type ComdatIterator = ComdatIterator<'data, 'file>; + type Symbol = Symbol<'data, 'file>; type SymbolIterator = SymbolIterator<'data, 'file>; + type SymbolTable = SymbolTable<'data, 'file>; fn architecture(&self) -> Architecture { with_inner!(self.inner, FileInternal, |x| x.architecture()) @@ -292,8 +295,10 @@ where } } - fn symbol_by_index(&self, index: SymbolIndex) -> Result> { - with_inner!(self.inner, FileInternal, |x| x.symbol_by_index(index)) + fn symbol_by_index(&'file self, index: SymbolIndex) -> Result> { + map_inner_option!(self.inner, FileInternal, SymbolInternal, |x| x + .symbol_by_index(index)) + .map(|inner| Symbol { inner }) } fn symbols(&'file self) -> SymbolIterator<'data, 'file> { @@ -303,6 +308,12 @@ where } } + fn symbol_table(&'file self) -> Option> { + map_inner_option!(self.inner, FileInternal, SymbolTableInternal, |x| x + .symbol_table()) + .map(|inner| SymbolTable { inner }) + } + fn dynamic_symbols(&'file self) -> SymbolIterator<'data, 'file> { SymbolIterator { inner: map_inner!(self.inner, FileInternal, SymbolIteratorInternal, |x| x @@ -310,7 +321,13 @@ where } } - fn symbol_map(&self) -> SymbolMap<'data> { + fn dynamic_symbol_table(&'file self) -> Option> { + map_inner_option!(self.inner, FileInternal, SymbolTableInternal, |x| x + .dynamic_symbol_table()) + .map(|inner| SymbolTable { inner }) + } + + fn symbol_map(&self) -> SymbolMap> { with_inner!(self.inner, FileInternal, |x| x.symbol_map()) } @@ -775,6 +792,62 @@ impl<'data, 'file> Iterator for ComdatSectionIterator<'data, 'file> { } } +/// A symbol table. +#[derive(Debug)] +pub struct SymbolTable<'data, 'file> +where + 'data: 'file, +{ + inner: SymbolTableInternal<'data, 'file>, +} + +#[derive(Debug)] +enum SymbolTableInternal<'data, 'file> +where + 'data: 'file, +{ + #[cfg(feature = "coff")] + Coff(coff::CoffSymbolTable<'data, 'file>), + #[cfg(feature = "elf")] + Elf32(elf::ElfSymbolTable32<'data, 'file>), + #[cfg(feature = "elf")] + Elf64(elf::ElfSymbolTable64<'data, 'file>), + #[cfg(feature = "macho")] + MachO32(macho::MachOSymbolTable32<'data, 'file>), + #[cfg(feature = "macho")] + MachO64(macho::MachOSymbolTable64<'data, 'file>), + #[cfg(feature = "pe")] + Pe32(coff::CoffSymbolTable<'data, 'file>), + #[cfg(feature = "pe")] + Pe64(coff::CoffSymbolTable<'data, 'file>), + #[cfg(feature = "wasm")] + Wasm(wasm::WasmSymbolTable<'data, 'file>), +} + +impl<'data, 'file> read::private::Sealed for SymbolTable<'data, 'file> {} + +impl<'data, 'file> ObjectSymbolTable<'data> for SymbolTable<'data, 'file> { + type Symbol = Symbol<'data, 'file>; + type SymbolIterator = SymbolIterator<'data, 'file>; + + fn symbols(&self) -> Self::SymbolIterator { + SymbolIterator { + inner: map_inner!( + self.inner, + SymbolTableInternal, + SymbolIteratorInternal, + |x| x.symbols() + ), + } + } + + fn symbol_by_index(&self, index: SymbolIndex) -> Result { + map_inner_option!(self.inner, SymbolTableInternal, SymbolInternal, |x| x + .symbol_by_index(index)) + .map(|inner| Symbol { inner }) + } +} + /// An iterator over symbol table entries. #[derive(Debug)] pub struct SymbolIterator<'data, 'file> @@ -808,10 +881,116 @@ where } impl<'data, 'file> Iterator for SymbolIterator<'data, 'file> { - type Item = (SymbolIndex, Symbol<'data>); + type Item = Symbol<'data, 'file>; fn next(&mut self) -> Option { - with_inner_mut!(self.inner, SymbolIteratorInternal, |x| x.next()) + next_inner!(self.inner, SymbolIteratorInternal, SymbolInternal) + .map(|inner| Symbol { inner }) + } +} + +/// A symbol table entry. +pub struct Symbol<'data, 'file> +where + 'data: 'file, +{ + inner: SymbolInternal<'data, 'file>, +} + +enum SymbolInternal<'data, 'file> +where + 'data: 'file, +{ + #[cfg(feature = "coff")] + Coff(coff::CoffSymbol<'data, 'file>), + #[cfg(feature = "elf")] + Elf32(elf::ElfSymbol32<'data, 'file>), + #[cfg(feature = "elf")] + Elf64(elf::ElfSymbol64<'data, 'file>), + #[cfg(feature = "macho")] + MachO32(macho::MachOSymbol32<'data, 'file>), + #[cfg(feature = "macho")] + MachO64(macho::MachOSymbol64<'data, 'file>), + #[cfg(feature = "pe")] + Pe32(coff::CoffSymbol<'data, 'file>), + #[cfg(feature = "pe")] + Pe64(coff::CoffSymbol<'data, 'file>), + #[cfg(feature = "wasm")] + Wasm(wasm::WasmSymbol<'data, 'file>), +} + +impl<'data, 'file> fmt::Debug for Symbol<'data, 'file> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Symbol") + .field("name", &self.name().unwrap_or("")) + .field("address", &self.address()) + .field("size", &self.size()) + .field("kind", &self.kind()) + .field("section", &self.section()) + .field("scope", &self.scope()) + .field("weak", &self.is_weak()) + .field("flags", &self.flags()) + .finish() + } +} + +impl<'data, 'file> read::private::Sealed for Symbol<'data, 'file> {} + +impl<'data, 'file> ObjectSymbol<'data> for Symbol<'data, 'file> { + fn index(&self) -> SymbolIndex { + with_inner!(self.inner, SymbolInternal, |x| x.index()) + } + + fn name(&self) -> Result<&'data str> { + with_inner!(self.inner, SymbolInternal, |x| x.name()) + } + + fn address(&self) -> u64 { + with_inner!(self.inner, SymbolInternal, |x| x.address()) + } + + fn size(&self) -> u64 { + with_inner!(self.inner, SymbolInternal, |x| x.size()) + } + + fn kind(&self) -> SymbolKind { + with_inner!(self.inner, SymbolInternal, |x| x.kind()) + } + + fn section(&self) -> SymbolSection { + with_inner!(self.inner, SymbolInternal, |x| x.section()) + } + + fn is_undefined(&self) -> bool { + with_inner!(self.inner, SymbolInternal, |x| x.is_undefined()) + } + + fn is_definition(&self) -> bool { + with_inner!(self.inner, SymbolInternal, |x| x.is_definition()) + } + + fn is_common(&self) -> bool { + with_inner!(self.inner, SymbolInternal, |x| x.is_common()) + } + + fn is_weak(&self) -> bool { + with_inner!(self.inner, SymbolInternal, |x| x.is_weak()) + } + + fn scope(&self) -> SymbolScope { + with_inner!(self.inner, SymbolInternal, |x| x.scope()) + } + + fn is_global(&self) -> bool { + with_inner!(self.inner, SymbolInternal, |x| x.is_global()) + } + + fn is_local(&self) -> bool { + with_inner!(self.inner, SymbolInternal, |x| x.is_local()) + } + + fn flags(&self) -> SymbolFlags { + with_inner!(self.inner, SymbolInternal, |x| x.flags()) } } diff --git a/src/read/coff/comdat.rs b/src/read/coff/comdat.rs index 9edd80f8..46dad0a0 100644 --- a/src/read/coff/comdat.rs +++ b/src/read/coff/comdat.rs @@ -22,7 +22,12 @@ impl<'data, 'file> Iterator for CoffComdatIterator<'data, 'file> { fn next(&mut self) -> Option { loop { let index = self.index; - let symbol = self.file.symbols.get::(index)?; + let symbol = self + .file + .common + .symbols + .get::(index) + .ok()?; self.index += 1 + symbol.number_of_aux_symbols as usize; if let Some(comdat) = CoffComdat::parse(self.file, symbol, index) { return Some(comdat); @@ -59,7 +64,11 @@ impl<'data, 'file> CoffComdat<'data, 'file> { } // Auxiliary record must have a non-associative selection. - let aux = file.symbols.get::(index + 1)?; + let aux = file + .common + .symbols + .get::(index + 1) + .ok()?; let selection = aux.selection; if selection == 0 || selection == pe::IMAGE_COMDAT_SELECT_ASSOCIATIVE { return None; @@ -71,7 +80,11 @@ impl<'data, 'file> CoffComdat<'data, 'file> { let section_number = section_symbol.section_number.get(LE); loop { symbol_index += 1 + symbol.number_of_aux_symbols as usize; - symbol = file.symbols.get::(symbol_index)?; + symbol = file + .common + .symbols + .get::(symbol_index) + .ok()?; if section_number == symbol.section_number.get(LE) { break; } @@ -112,7 +125,7 @@ impl<'data, 'file> ObjectComdat<'data> for CoffComdat<'data, 'file> { #[inline] fn name(&self) -> Result<&str> { // Find the name of first symbol referring to the section. - let name = self.symbol.name(self.file.symbols.strings())?; + let name = self.symbol.name(self.file.common.symbols.strings())?; str::from_utf8(name) .ok() .read_error("Non UTF-8 COFF COMDAT name") @@ -147,7 +160,12 @@ impl<'data, 'file> Iterator for CoffComdatSectionIterator<'data, 'file> { // TODO: it seems gcc doesn't use associated symbols for this loop { let index = self.index; - let symbol = self.file.symbols.get::(index)?; + let symbol = self + .file + .common + .symbols + .get::(index) + .ok()?; self.index += 1 + symbol.number_of_aux_symbols as usize; // Must be a section symbol. @@ -163,8 +181,10 @@ impl<'data, 'file> Iterator for CoffComdatSectionIterator<'data, 'file> { let aux = self .file + .common .symbols - .get::(index + 1)?; + .get::(index + 1) + .ok()?; if aux.selection == pe::IMAGE_COMDAT_SELECT_ASSOCIATIVE { // TODO: use high_number for bigobj if aux.number.get(LE) == self.section_number { diff --git a/src/read/coff/file.rs b/src/read/coff/file.rs index da258896..ee05e2a7 100644 --- a/src/read/coff/file.rs +++ b/src/read/coff/file.rs @@ -1,24 +1,31 @@ -use alloc::vec::Vec; use core::str; use crate::read::{ - self, Architecture, FileFlags, Object, ObjectSection, ReadError, Result, SectionIndex, Symbol, - SymbolIndex, SymbolMap, + self, Architecture, FileFlags, Object, ObjectSection, ReadError, Result, SectionIndex, + SymbolIndex, }; use crate::{pe, Bytes, LittleEndian as LE}; use super::{ - parse_symbol, CoffComdat, CoffComdatIterator, CoffSection, CoffSectionIterator, CoffSegment, - CoffSegmentIterator, CoffSymbolIterator, SectionTable, SymbolTable, + CoffComdat, CoffComdatIterator, CoffSection, CoffSectionIterator, CoffSegment, + CoffSegmentIterator, CoffSymbol, CoffSymbolIterator, CoffSymbolTable, SectionTable, + SymbolTable, }; +/// The common parts of `PeFile` and `CoffFile`. +#[derive(Debug)] +pub(crate) struct CoffCommon<'data> { + pub(crate) sections: SectionTable<'data>, + // TODO: ImageSymbolExBytes + pub(crate) symbols: SymbolTable<'data>, + pub(crate) image_base: u64, +} + /// A COFF object file. #[derive(Debug)] pub struct CoffFile<'data> { pub(super) header: &'data pe::ImageFileHeader, - pub(super) sections: SectionTable<'data>, - // TODO: ImageSymbolExBytes - pub(super) symbols: SymbolTable<'data>, + pub(super) common: CoffCommon<'data>, pub(super) data: Bytes<'data>, } @@ -32,8 +39,11 @@ impl<'data> CoffFile<'data> { Ok(CoffFile { header, - sections, - symbols, + common: CoffCommon { + sections, + symbols, + image_base: 0, + }, data, }) } @@ -51,7 +61,9 @@ where type SectionIterator = CoffSectionIterator<'data, 'file>; type Comdat = CoffComdat<'data, 'file>; type ComdatIterator = CoffComdatIterator<'data, 'file>; + type Symbol = CoffSymbol<'data, 'file>; type SymbolIterator = CoffSymbolIterator<'data, 'file>; + type SymbolTable = CoffSymbolTable<'data, 'file>; fn architecture(&self) -> Architecture { match self.header.machine.get(LE) { @@ -75,7 +87,7 @@ where fn segments(&'file self) -> CoffSegmentIterator<'data, 'file> { CoffSegmentIterator { file: self, - iter: self.sections.iter(), + iter: self.common.sections.iter(), } } @@ -85,7 +97,7 @@ where } fn section_by_index(&'file self, index: SectionIndex) -> Result> { - let section = self.sections.section(index.0)?; + let section = self.common.sections.section(index.0)?; Ok(CoffSection { file: self, index, @@ -96,7 +108,7 @@ where fn sections(&'file self) -> CoffSectionIterator<'data, 'file> { CoffSectionIterator { file: self, - iter: self.sections.iter().enumerate(), + iter: self.common.sections.iter().enumerate(), } } @@ -107,38 +119,36 @@ where } } - fn symbol_by_index(&self, index: SymbolIndex) -> Result> { - let symbol = self - .symbols - .get(index.0) - .read_error("Invalid COFF symbol index")?; - Ok(parse_symbol(&self.symbols, index.0, symbol)) + fn symbol_by_index(&'file self, index: SymbolIndex) -> Result> { + let symbol = self.common.symbols.symbol(index.0)?; + Ok(CoffSymbol { + file: &self.common, + index, + symbol, + }) } fn symbols(&'file self) -> CoffSymbolIterator<'data, 'file> { CoffSymbolIterator { - symbols: &self.symbols, + file: &self.common, index: 0, } } + fn symbol_table(&'file self) -> Option> { + Some(CoffSymbolTable { file: &self.common }) + } + fn dynamic_symbols(&'file self) -> CoffSymbolIterator<'data, 'file> { CoffSymbolIterator { - symbols: &self.symbols, + file: &self.common, // Hack: don't return any. - index: self.symbols.len(), + index: self.common.symbols.len(), } } - fn symbol_map(&self) -> SymbolMap<'data> { - // TODO: untested - let mut symbols: Vec<_> = self - .symbols() - .map(|(_, s)| s) - .filter(SymbolMap::filter) - .collect(); - symbols.sort_by_key(|x| x.address); - SymbolMap { symbols } + fn dynamic_symbol_table(&'file self) -> Option> { + None } fn has_debug_symbols(&self) -> bool { diff --git a/src/read/coff/section.rs b/src/read/coff/section.rs index bad7a709..bd1c0e38 100644 --- a/src/read/coff/section.rs +++ b/src/read/coff/section.rs @@ -153,7 +153,7 @@ impl<'data, 'file> ObjectSegment<'data> for CoffSegment<'data, 'file> { #[inline] fn name(&self) -> Result> { - let name = self.section.name(self.file.symbols.strings())?; + let name = self.section.name(self.file.common.symbols.strings())?; Ok(Some( str::from_utf8(name) .ok() @@ -255,7 +255,7 @@ impl<'data, 'file> ObjectSection<'data> for CoffSection<'data, 'file> { #[inline] fn name(&self) -> Result<&str> { - let name = self.section.name(self.file.symbols.strings())?; + let name = self.section.name(self.file.common.symbols.strings())?; str::from_utf8(name) .ok() .read_error("Non UTF-8 COFF section name") diff --git a/src/read/coff/symbol.rs b/src/read/coff/symbol.rs index 2d5b883b..411b0be2 100644 --- a/src/read/coff/symbol.rs +++ b/src/read/coff/symbol.rs @@ -1,14 +1,16 @@ use alloc::fmt; +use alloc::vec::Vec; use core::convert::TryInto; use core::str; +use super::{CoffCommon, SectionTable}; use crate::endian::{LittleEndian as LE, U32Bytes}; use crate::pe; use crate::pod::{Bytes, Pod}; use crate::read::util::StringTable; use crate::read::{ - ReadError, Result, SectionIndex, Symbol, SymbolFlags, SymbolIndex, SymbolKind, SymbolScope, - SymbolSection, + self, ObjectSymbol, ObjectSymbolTable, ReadError, Result, SectionIndex, SymbolFlags, + SymbolIndex, SymbolKind, SymbolMap, SymbolMapEntry, SymbolScope, SymbolSection, }; /// A table of symbol entries in a COFF or PE file. @@ -72,14 +74,38 @@ impl<'data> SymbolTable<'data> { /// Return the symbol table entry at the given index. #[inline] - pub fn symbol(&self, index: usize) -> Option<&'data pe::ImageSymbol> { + pub fn symbol(&self, index: usize) -> Result<&'data pe::ImageSymbol> { self.get::(index) } /// Return the symbol table entry or auxiliary record at the given index. - pub fn get(&self, index: usize) -> Option<&'data T> { - let bytes = self.symbols.get(index)?; - Bytes(&bytes.0[..]).read().ok() + pub fn get(&self, index: usize) -> Result<&'data T> { + let bytes = self + .symbols + .get(index) + .read_error("Invalid COFF symbol index")?; + Bytes(&bytes.0[..]) + .read() + .read_error("Invalid COFF symbol data") + } + + /// Construct a map from addresses to a user-defined map entry. + pub fn map Option>( + &self, + f: F, + ) -> SymbolMap { + let mut symbols = Vec::with_capacity(self.symbols.len()); + let mut i = 0; + while let Ok(symbol) = self.symbol(i) { + i += 1 + symbol.number_of_aux_symbols as usize; + if !symbol.is_definition() { + continue; + } + if let Some(entry) = f(symbol) { + symbols.push(entry); + } + } + SymbolMap::new(symbols) } } @@ -102,6 +128,69 @@ impl pe::ImageSymbol { }) } } + + /// Return the symbol address. + /// + /// This takes into account the image base and the section address. + pub fn address(&self, image_base: u64, sections: &SectionTable) -> Result { + let section_number = self.section_number.get(LE) as usize; + let section = sections.section(section_number)?; + let virtual_address = u64::from(section.virtual_address.get(LE)); + let value = u64::from(self.value.get(LE)); + Ok(image_base + virtual_address + value) + } + + /// Return true if the symbol is a definition of a function or data object. + pub fn is_definition(&self) -> bool { + let section_number = self.section_number.get(LE); + if section_number == pe::IMAGE_SYM_UNDEFINED { + return false; + } + match self.storage_class { + pe::IMAGE_SYM_CLASS_STATIC => { + if self.value.get(LE) == 0 && self.number_of_aux_symbols > 0 { + // This is a section symbol. + false + } else { + true + } + } + pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => true, + _ => false, + } + } +} + +/// A symbol table of a `CoffFile`. +#[derive(Debug, Clone, Copy)] +pub struct CoffSymbolTable<'data, 'file> +where + 'data: 'file, +{ + pub(crate) file: &'file CoffCommon<'data>, +} + +impl<'data, 'file> read::private::Sealed for CoffSymbolTable<'data, 'file> {} + +impl<'data, 'file> ObjectSymbolTable<'data> for CoffSymbolTable<'data, 'file> { + type Symbol = CoffSymbol<'data, 'file>; + type SymbolIterator = CoffSymbolIterator<'data, 'file>; + + fn symbols(&self) -> Self::SymbolIterator { + CoffSymbolIterator { + file: self.file, + index: 0, + } + } + + fn symbol_by_index(&self, index: SymbolIndex) -> Result { + let symbol = self.file.symbols.symbol(index.0)?; + Ok(CoffSymbol { + file: self.file, + index, + symbol, + }) + } } /// An iterator over the symbols of a `CoffFile`. @@ -109,7 +198,7 @@ pub struct CoffSymbolIterator<'data, 'file> where 'data: 'file, { - pub(crate) symbols: &'file SymbolTable<'data>, + pub(crate) file: &'file CoffCommon<'data>, pub(crate) index: usize, } @@ -120,135 +209,245 @@ impl<'data, 'file> fmt::Debug for CoffSymbolIterator<'data, 'file> { } impl<'data, 'file> Iterator for CoffSymbolIterator<'data, 'file> { - type Item = (SymbolIndex, Symbol<'data>); + type Item = CoffSymbol<'data, 'file>; fn next(&mut self) -> Option { let index = self.index; - let symbol = self.symbols.get::(index)?; + let symbol = self.file.symbols.symbol(index).ok()?; self.index += 1 + symbol.number_of_aux_symbols as usize; - Some(( - SymbolIndex(index), - parse_symbol(self.symbols, index, symbol), - )) + Some(CoffSymbol { + file: self.file, + index: SymbolIndex(index), + symbol, + }) } } -pub(crate) fn parse_symbol<'data>( - symbols: &SymbolTable<'data>, - index: usize, - symbol: &'data pe::ImageSymbol, -) -> Symbol<'data> { - let value = symbol.value.get(LE); - let section_number = symbol.section_number.get(LE); - - let name = if symbol.storage_class == pe::IMAGE_SYM_CLASS_FILE { - // The file name is in the following auxiliary symbol. - if symbol.number_of_aux_symbols > 0 { - symbols.symbols.get(index + 1).map(|s| { +/// A symbol of a `CoffFile`. +#[derive(Debug, Clone, Copy)] +pub struct CoffSymbol<'data, 'file> +where + 'data: 'file, +{ + pub(crate) file: &'file CoffCommon<'data>, + pub(crate) index: SymbolIndex, + pub(crate) symbol: &'data pe::ImageSymbol, +} + +impl<'data, 'file> read::private::Sealed for CoffSymbol<'data, 'file> {} + +impl<'data, 'file> ObjectSymbol<'data> for CoffSymbol<'data, 'file> { + #[inline] + fn index(&self) -> SymbolIndex { + self.index + } + + fn name(&self) -> read::Result<&'data str> { + let name = if self.symbol.storage_class == pe::IMAGE_SYM_CLASS_FILE { + // The file name is in the following auxiliary symbol. + if self.symbol.number_of_aux_symbols > 0 { + let s = self + .file + .symbols + .get::(self.index.0 + 1)?; // The name is padded with nulls. match s.0.iter().position(|&x| x == 0) { Some(end) => &s.0[..end], None => &s.0[..], } - }) + } else { + &[][..] + } } else { - None - } - } else { - symbol.name(symbols.strings()).ok() - }; - let name = name.and_then(|s| str::from_utf8(s).ok()); - - let derived_kind = if symbol.derived_type() == pe::IMAGE_SYM_DTYPE_FUNCTION { - SymbolKind::Text - } else { - SymbolKind::Data - }; - let mut flags = SymbolFlags::None; - // FIXME: symbol.value is a section offset for non-absolute symbols, not an address - let (kind, address, size) = match symbol.storage_class { - pe::IMAGE_SYM_CLASS_STATIC => { - if value == 0 && symbol.number_of_aux_symbols > 0 { - let mut size = 0; - if let Some(aux) = symbols.get::(index + 1) { - size = u64::from(aux.length.get(LE)); - // TODO: use high_number for bigobj - let number = aux.number.get(LE) as usize; - flags = SymbolFlags::CoffSection { - selection: aux.selection, - associative_section: if number == 0 { - None - } else { - Some(SectionIndex(number)) - }, - }; + self.symbol.name(self.file.symbols.strings())? + }; + str::from_utf8(name) + .ok() + .read_error("Non UTF-8 COFF symbol name") + } + + #[inline] + fn address(&self) -> u64 { + // Only return an address for storage classes that we know use an address. + match self.symbol.storage_class { + pe::IMAGE_SYM_CLASS_STATIC + | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL + | pe::IMAGE_SYM_CLASS_LABEL => {} + pe::IMAGE_SYM_CLASS_EXTERNAL => { + if self.symbol.section_number.get(LE) == pe::IMAGE_SYM_UNDEFINED { + // Undefined or common data, neither of which have an address. + return 0; } - (SymbolKind::Section, 0, size) - } else { - (derived_kind, u64::from(value), 0) } + _ => return 0, } - pe::IMAGE_SYM_CLASS_EXTERNAL => { - if section_number == pe::IMAGE_SYM_UNDEFINED { - // Common data: symbol.value is the size. - (derived_kind, 0, u64::from(value)) - } else if symbol.derived_type() == pe::IMAGE_SYM_DTYPE_FUNCTION - && symbol.number_of_aux_symbols > 0 - { - let mut size = 0; - if let Some(aux) = symbols.get::(index + 1) { - size = u64::from(aux.total_size.get(LE)); + self.symbol + .address(self.file.image_base, &self.file.sections) + .unwrap_or(0) + } + + #[inline] + fn size(&self) -> u64 { + match self.symbol.storage_class { + pe::IMAGE_SYM_CLASS_STATIC => { + // Section symbols may duplicate the size from the section table. + if self.symbol.value.get(LE) == 0 && self.symbol.number_of_aux_symbols > 0 { + if let Ok(aux) = self + .file + .symbols + .get::(self.index.0 + 1) + { + u64::from(aux.length.get(LE)) + } else { + 0 + } + } else { + 0 + } + } + pe::IMAGE_SYM_CLASS_EXTERNAL => { + if self.symbol.section_number.get(LE) == pe::IMAGE_SYM_UNDEFINED { + // For undefined symbols, symbol.value is 0 and the size is 0. + // For common data, symbol.value is the size. + u64::from(self.symbol.value.get(LE)) + } else if self.symbol.derived_type() == pe::IMAGE_SYM_DTYPE_FUNCTION + && self.symbol.number_of_aux_symbols > 0 + { + // Function symbols may have a size. + if let Ok(aux) = self + .file + .symbols + .get::(self.index.0 + 1) + { + u64::from(aux.total_size.get(LE)) + } else { + 0 + } + } else { + 0 } - (derived_kind, u64::from(value), size) - } else { - (derived_kind, u64::from(value), 0) } + // Most symbols don't have sizes. + _ => 0, } - pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => (derived_kind, u64::from(value), 0), - pe::IMAGE_SYM_CLASS_SECTION => (SymbolKind::Section, 0, 0), - pe::IMAGE_SYM_CLASS_FILE => (SymbolKind::File, 0, 0), - pe::IMAGE_SYM_CLASS_LABEL => (SymbolKind::Label, u64::from(value), 0), - _ => { - // No address because symbol.value could mean anything. - (SymbolKind::Unknown, 0, 0) + } + + fn kind(&self) -> SymbolKind { + let derived_kind = if self.symbol.derived_type() == pe::IMAGE_SYM_DTYPE_FUNCTION { + SymbolKind::Text + } else { + SymbolKind::Data + }; + match self.symbol.storage_class { + pe::IMAGE_SYM_CLASS_STATIC => { + if self.symbol.value.get(LE) == 0 && self.symbol.number_of_aux_symbols > 0 { + SymbolKind::Section + } else { + derived_kind + } + } + pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => derived_kind, + pe::IMAGE_SYM_CLASS_SECTION => SymbolKind::Section, + pe::IMAGE_SYM_CLASS_FILE => SymbolKind::File, + pe::IMAGE_SYM_CLASS_LABEL => SymbolKind::Label, + _ => SymbolKind::Unknown, } - }; - let section = match section_number { - pe::IMAGE_SYM_UNDEFINED => { - if symbol.storage_class == pe::IMAGE_SYM_CLASS_EXTERNAL && value != 0 { - SymbolSection::Common - } else { - SymbolSection::Undefined + } + + fn section(&self) -> SymbolSection { + match self.symbol.section_number.get(LE) { + pe::IMAGE_SYM_UNDEFINED => { + if self.symbol.storage_class == pe::IMAGE_SYM_CLASS_EXTERNAL + && self.symbol.value.get(LE) == 0 + { + SymbolSection::Undefined + } else { + SymbolSection::Common + } } + pe::IMAGE_SYM_ABSOLUTE => SymbolSection::Absolute, + pe::IMAGE_SYM_DEBUG => { + if self.symbol.storage_class == pe::IMAGE_SYM_CLASS_FILE { + SymbolSection::None + } else { + SymbolSection::Unknown + } + } + index if index > 0 => SymbolSection::Section(SectionIndex(index as usize)), + _ => SymbolSection::Unknown, } - pe::IMAGE_SYM_ABSOLUTE => SymbolSection::Absolute, - pe::IMAGE_SYM_DEBUG => { - if symbol.storage_class == pe::IMAGE_SYM_CLASS_FILE { - SymbolSection::None - } else { - SymbolSection::Unknown + } + + #[inline] + fn is_undefined(&self) -> bool { + self.symbol.storage_class == pe::IMAGE_SYM_CLASS_EXTERNAL + && self.symbol.section_number.get(LE) == pe::IMAGE_SYM_UNDEFINED + && self.symbol.value.get(LE) == 0 + } + + #[inline] + fn is_definition(&self) -> bool { + self.symbol.is_definition() + } + + #[inline] + fn is_common(&self) -> bool { + self.symbol.storage_class == pe::IMAGE_SYM_CLASS_EXTERNAL + && self.symbol.section_number.get(LE) == pe::IMAGE_SYM_UNDEFINED + && self.symbol.value.get(LE) != 0 + } + + #[inline] + fn is_weak(&self) -> bool { + self.symbol.storage_class == pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL + } + + #[inline] + fn scope(&self) -> SymbolScope { + match self.symbol.storage_class { + pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => { + // TODO: determine if symbol is exported + SymbolScope::Linkage } + _ => SymbolScope::Compilation, } - index if index > 0 => SymbolSection::Section(SectionIndex(index as usize)), - _ => SymbolSection::Unknown, - }; - let weak = symbol.storage_class == pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL; - let scope = match symbol.storage_class { - _ if section == SymbolSection::Undefined => SymbolScope::Unknown, - pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => { - // TODO: determine if symbol is exported - SymbolScope::Linkage + } + + #[inline] + fn is_global(&self) -> bool { + match self.symbol.storage_class { + pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => true, + _ => false, + } + } + + #[inline] + fn is_local(&self) -> bool { + !self.is_global() + } + + fn flags(&self) -> SymbolFlags { + if self.symbol.storage_class == pe::IMAGE_SYM_CLASS_STATIC + && self.symbol.value.get(LE) == 0 + && self.symbol.number_of_aux_symbols > 0 + { + if let Ok(aux) = self + .file + .symbols + .get::(self.index.0 + 1) + { + // TODO: use high_number for bigobj + let number = aux.number.get(LE) as usize; + return SymbolFlags::CoffSection { + selection: aux.selection, + associative_section: if number == 0 { + None + } else { + Some(SectionIndex(number)) + }, + }; + } } - _ => SymbolScope::Compilation, - }; - Symbol { - name, - address, - size, - kind, - section, - weak, - scope, - flags, + SymbolFlags::None } } diff --git a/src/read/elf/file.rs b/src/read/elf/file.rs index c8ee1b8f..6ccddc85 100644 --- a/src/read/elf/file.rs +++ b/src/read/elf/file.rs @@ -1,17 +1,16 @@ -use alloc::vec::Vec; use core::fmt::Debug; use core::{mem, str}; use crate::read::{ self, util, Architecture, Error, FileFlags, Object, ReadError, SectionIndex, StringTable, - Symbol, SymbolIndex, SymbolMap, + SymbolIndex, }; use crate::{elf, endian, Bytes, Endian, Endianness, Pod, U32}; use super::{ - parse_symbol, CompressionHeader, ElfComdat, ElfComdatIterator, ElfSection, ElfSectionIterator, - ElfSegment, ElfSegmentIterator, ElfSymbolIterator, NoteHeader, ProgramHeader, Rela, - RelocationSections, SectionHeader, SectionTable, Sym, SymbolTable, + CompressionHeader, ElfComdat, ElfComdatIterator, ElfSection, ElfSectionIterator, ElfSegment, + ElfSegmentIterator, ElfSymbol, ElfSymbolIterator, ElfSymbolTable, NoteHeader, ProgramHeader, + Rela, RelocationSections, SectionHeader, SectionTable, Sym, SymbolTable, }; /// A 32-bit ELF object file. @@ -106,7 +105,9 @@ where type SectionIterator = ElfSectionIterator<'data, 'file, Elf>; type Comdat = ElfComdat<'data, 'file, Elf>; type ComdatIterator = ElfComdatIterator<'data, 'file, Elf>; + type Symbol = ElfSymbol<'data, 'file, Elf>; type SymbolIterator = ElfSymbolIterator<'data, 'file, Elf>; + type SymbolTable = ElfSymbolTable<'data, 'file, Elf>; fn architecture(&self) -> Architecture { match self.header.e_machine(self.endian) { @@ -176,43 +177,47 @@ where } } - fn symbol_by_index(&self, index: SymbolIndex) -> read::Result> { + fn symbol_by_index( + &'file self, + index: SymbolIndex, + ) -> read::Result> { let symbol = self.symbols.symbol(index.0)?; - let shndx = self.symbols.shndx(index.0); - let name = symbol.name(self.endian, self.symbols.strings()).ok(); - Ok(parse_symbol::( - self.endian, - index.0, + Ok(ElfSymbol { + endian: self.endian, + symbols: &self.symbols, + index, symbol, - name, - shndx, - )) + }) } fn symbols(&'file self) -> ElfSymbolIterator<'data, 'file, Elf> { ElfSymbolIterator { - file: self, - symbols: self.symbols, + endian: self.endian, + symbols: &self.symbols, index: 0, } } + fn symbol_table(&'file self) -> Option> { + Some(ElfSymbolTable { + endian: self.endian, + symbols: &self.symbols, + }) + } + fn dynamic_symbols(&'file self) -> ElfSymbolIterator<'data, 'file, Elf> { ElfSymbolIterator { - file: self, - symbols: self.dynamic_symbols, + endian: self.endian, + symbols: &self.dynamic_symbols, index: 0, } } - fn symbol_map(&self) -> SymbolMap<'data> { - let mut symbols: Vec<_> = self - .symbols() - .map(|(_, s)| s) - .filter(SymbolMap::filter) - .collect(); - symbols.sort_by_key(|x| x.address); - SymbolMap { symbols } + fn dynamic_symbol_table(&'file self) -> Option> { + Some(ElfSymbolTable { + endian: self.endian, + symbols: &self.dynamic_symbols, + }) } fn has_debug_symbols(&self) -> bool { diff --git a/src/read/elf/symbol.rs b/src/read/elf/symbol.rs index 990dd6df..16acbae1 100644 --- a/src/read/elf/symbol.rs +++ b/src/read/elf/symbol.rs @@ -1,4 +1,5 @@ use alloc::fmt; +use alloc::vec::Vec; use core::fmt::Debug; use core::slice; use core::str; @@ -8,11 +9,11 @@ use crate::endian::{self, Endianness}; use crate::pod::{Bytes, Pod}; use crate::read::util::StringTable; use crate::read::{ - self, ReadError, SectionIndex, Symbol, SymbolFlags, SymbolIndex, SymbolKind, SymbolScope, - SymbolSection, + self, ObjectSymbol, ObjectSymbolTable, ReadError, SectionIndex, SymbolFlags, SymbolIndex, + SymbolKind, SymbolMap, SymbolMapEntry, SymbolScope, SymbolSection, }; -use super::{ElfFile, FileHeader, SectionHeader, SectionTable}; +use super::{FileHeader, SectionHeader, SectionTable}; /// A table of symbol entries in an ELF file. /// @@ -111,6 +112,12 @@ impl<'data, Elf: FileHeader> SymbolTable<'data, Elf> { self.symbols.is_empty() } + /// The number of symbols. + #[inline] + pub fn len(&self) -> usize { + self.symbols.len() + } + /// Return the symbol at the given index. pub fn symbol(&self, index: usize) -> read::Result<&'data Elf::Sym> { self.symbols @@ -123,6 +130,67 @@ impl<'data, Elf: FileHeader> SymbolTable<'data, Elf> { pub fn shndx(&self, index: usize) -> Option { self.shndx.get(index).cloned() } + + /// Construct a map from addresses to a user-defined map entry. + pub fn map Option>( + &self, + endian: Elf::Endian, + f: F, + ) -> SymbolMap { + let mut symbols = Vec::with_capacity(self.symbols.len()); + for symbol in self.symbols { + if !symbol.is_definition(endian) { + continue; + } + if let Some(entry) = f(symbol) { + symbols.push(entry); + } + } + SymbolMap::new(symbols) + } +} + +/// A symbol table of an `ElfFile32`. +pub type ElfSymbolTable32<'data, 'file, Endian = Endianness> = + ElfSymbolTable<'data, 'file, elf::FileHeader32>; +/// A symbol table of an `ElfFile32`. +pub type ElfSymbolTable64<'data, 'file, Endian = Endianness> = + ElfSymbolTable<'data, 'file, elf::FileHeader64>; + +/// A symbol table of an `ElfFile`. +#[derive(Debug, Clone, Copy)] +pub struct ElfSymbolTable<'data, 'file, Elf> +where + 'data: 'file, + Elf: FileHeader, +{ + pub(super) endian: Elf::Endian, + pub(super) symbols: &'file SymbolTable<'data, Elf>, +} + +impl<'data, 'file, Elf: FileHeader> read::private::Sealed for ElfSymbolTable<'data, 'file, Elf> {} + +impl<'data, 'file, Elf: FileHeader> ObjectSymbolTable<'data> for ElfSymbolTable<'data, 'file, Elf> { + type Symbol = ElfSymbol<'data, 'file, Elf>; + type SymbolIterator = ElfSymbolIterator<'data, 'file, Elf>; + + fn symbols(&self) -> Self::SymbolIterator { + ElfSymbolIterator { + endian: self.endian, + symbols: self.symbols, + index: 0, + } + } + + fn symbol_by_index(&self, index: SymbolIndex) -> read::Result { + let symbol = self.symbols.symbol(index.0)?; + Ok(ElfSymbol { + endian: self.endian, + symbols: self.symbols, + index, + symbol, + }) + } } /// An iterator over the symbols of an `ElfFile32`. @@ -138,8 +206,8 @@ where 'data: 'file, Elf: FileHeader, { - pub(super) file: &'file ElfFile<'data, Elf>, - pub(super) symbols: SymbolTable<'data, Elf>, + pub(super) endian: Elf::Endian, + pub(super) symbols: &'file SymbolTable<'data, Elf>, pub(super) index: usize, } @@ -150,82 +218,154 @@ impl<'data, 'file, Elf: FileHeader> fmt::Debug for ElfSymbolIterator<'data, 'fil } impl<'data, 'file, Elf: FileHeader> Iterator for ElfSymbolIterator<'data, 'file, Elf> { - type Item = (SymbolIndex, Symbol<'data>); + type Item = ElfSymbol<'data, 'file, Elf>; fn next(&mut self) -> Option { let index = self.index; - let shndx = self.symbols.shndx(index); - self.symbols.symbols.get(index).map(|symbol| { - self.index += 1; - let name = symbol.name(self.file.endian, self.symbols.strings()).ok(); - ( - SymbolIndex(index), - parse_symbol::(self.file.endian, index, symbol, name, shndx), - ) + let symbol = self.symbols.symbols.get(index)?; + self.index += 1; + Some(ElfSymbol { + endian: self.endian, + symbols: self.symbols, + index: SymbolIndex(index), + symbol, }) } } -pub(super) fn parse_symbol<'data, Elf: FileHeader>( - endian: Elf::Endian, - index: usize, - symbol: &Elf::Sym, - name: Option<&'data [u8]>, - shndx: Option, -) -> Symbol<'data> { - let name = name.and_then(|s| str::from_utf8(s).ok()); - let kind = match symbol.st_type() { - elf::STT_NOTYPE if index == 0 => SymbolKind::Null, - elf::STT_OBJECT | elf::STT_COMMON => SymbolKind::Data, - elf::STT_FUNC => SymbolKind::Text, - elf::STT_SECTION => SymbolKind::Section, - elf::STT_FILE => SymbolKind::File, - elf::STT_TLS => SymbolKind::Tls, - _ => SymbolKind::Unknown, - }; - let section = match symbol.st_shndx(endian) { - elf::SHN_UNDEF => SymbolSection::Undefined, - elf::SHN_ABS => { - if kind == SymbolKind::File { - SymbolSection::None - } else { - SymbolSection::Absolute +/// A symbol of an `ElfFile32`. +pub type ElfSymbol32<'data, 'file, Endian = Endianness> = + ElfSymbol<'data, 'file, elf::FileHeader32>; +/// A symbol of an `ElfFile64`. +pub type ElfSymbol64<'data, 'file, Endian = Endianness> = + ElfSymbol<'data, 'file, elf::FileHeader64>; + +/// A symbol of an `ElfFile`. +#[derive(Debug, Clone, Copy)] +pub struct ElfSymbol<'data, 'file, Elf> +where + 'data: 'file, + Elf: FileHeader, +{ + pub(super) endian: Elf::Endian, + pub(super) symbols: &'file SymbolTable<'data, Elf>, + pub(super) index: SymbolIndex, + pub(super) symbol: &'data Elf::Sym, +} + +impl<'data, 'file, Elf: FileHeader> read::private::Sealed for ElfSymbol<'data, 'file, Elf> {} + +impl<'data, 'file, Elf: FileHeader> ObjectSymbol<'data> for ElfSymbol<'data, 'file, Elf> { + #[inline] + fn index(&self) -> SymbolIndex { + self.index + } + + fn name(&self) -> read::Result<&'data str> { + let name = self.symbol.name(self.endian, self.symbols.strings())?; + str::from_utf8(name) + .ok() + .read_error("Non UTF-8 ELF symbol name") + } + + #[inline] + fn address(&self) -> u64 { + self.symbol.st_value(self.endian).into() + } + + #[inline] + fn size(&self) -> u64 { + self.symbol.st_size(self.endian).into() + } + + fn kind(&self) -> SymbolKind { + match self.symbol.st_type() { + elf::STT_NOTYPE if self.index.0 == 0 => SymbolKind::Null, + elf::STT_OBJECT | elf::STT_COMMON => SymbolKind::Data, + elf::STT_FUNC => SymbolKind::Text, + elf::STT_SECTION => SymbolKind::Section, + elf::STT_FILE => SymbolKind::File, + elf::STT_TLS => SymbolKind::Tls, + _ => SymbolKind::Unknown, + } + } + + fn section(&self) -> SymbolSection { + match self.symbol.st_shndx(self.endian) { + elf::SHN_UNDEF => SymbolSection::Undefined, + elf::SHN_ABS => { + if self.symbol.st_type() == elf::STT_FILE { + SymbolSection::None + } else { + SymbolSection::Absolute + } + } + elf::SHN_COMMON => SymbolSection::Common, + elf::SHN_XINDEX => match self.symbols.shndx(self.index.0) { + Some(index) => SymbolSection::Section(SectionIndex(index as usize)), + None => SymbolSection::Unknown, + }, + index if index < elf::SHN_LORESERVE => { + SymbolSection::Section(SectionIndex(index as usize)) } + _ => SymbolSection::Unknown, } - elf::SHN_COMMON => SymbolSection::Common, - elf::SHN_XINDEX => match shndx { - Some(index) => SymbolSection::Section(SectionIndex(index as usize)), - None => SymbolSection::Unknown, - }, - index if index < elf::SHN_LORESERVE => SymbolSection::Section(SectionIndex(index as usize)), - _ => SymbolSection::Unknown, - }; - let weak = symbol.st_bind() == elf::STB_WEAK; - let scope = match symbol.st_bind() { - _ if section == SymbolSection::Undefined => SymbolScope::Unknown, - elf::STB_LOCAL => SymbolScope::Compilation, - elf::STB_GLOBAL | elf::STB_WEAK => { - if symbol.st_visibility() == elf::STV_HIDDEN { - SymbolScope::Linkage - } else { - SymbolScope::Dynamic + } + + #[inline] + fn is_undefined(&self) -> bool { + self.symbol.st_shndx(self.endian) == elf::SHN_UNDEF + } + + #[inline] + fn is_definition(&self) -> bool { + self.symbol.is_definition(self.endian) + } + + #[inline] + fn is_common(&self) -> bool { + self.symbol.st_shndx(self.endian) == elf::SHN_COMMON + } + + #[inline] + fn is_weak(&self) -> bool { + self.symbol.st_bind() == elf::STB_WEAK + } + + fn scope(&self) -> SymbolScope { + if self.symbol.st_shndx(self.endian) == elf::SHN_UNDEF { + SymbolScope::Unknown + } else { + match self.symbol.st_bind() { + elf::STB_LOCAL => SymbolScope::Compilation, + elf::STB_GLOBAL | elf::STB_WEAK => { + if self.symbol.st_visibility() == elf::STV_HIDDEN { + SymbolScope::Linkage + } else { + SymbolScope::Dynamic + } + } + _ => SymbolScope::Unknown, } } - _ => SymbolScope::Unknown, - }; - let flags = SymbolFlags::Elf { - st_info: symbol.st_info(), - st_other: symbol.st_other(), - }; - Symbol { - name, - address: symbol.st_value(endian).into(), - size: symbol.st_size(endian).into(), - kind, - section, - weak, - scope, - flags, + } + + #[inline] + fn is_global(&self) -> bool { + self.symbol.st_bind() != elf::STB_LOCAL + } + + #[inline] + fn is_local(&self) -> bool { + self.symbol.st_bind() == elf::STB_LOCAL + } + + #[inline] + fn flags(&self) -> SymbolFlags { + SymbolFlags::Elf { + st_info: self.symbol.st_info(), + st_other: self.symbol.st_other(), + } } } @@ -255,6 +395,13 @@ pub trait Sym: Debug + Pod { .get(self.st_name(endian)) .read_error("Invalid ELF symbol name offset") } + + /// Return true if the symbol is a definition of a function or data object. + fn is_definition(&self, endian: Self::Endian) -> bool { + let st_type = self.st_type(); + (st_type == elf::STT_NOTYPE || st_type == elf::STT_FUNC || st_type == elf::STT_OBJECT) + && self.st_shndx(endian) != elf::SHN_UNDEF + } } impl Sym for elf::Sym32 { diff --git a/src/read/macho/file.rs b/src/read/macho/file.rs index b7ca1121..d88c08da 100644 --- a/src/read/macho/file.rs +++ b/src/read/macho/file.rs @@ -4,15 +4,14 @@ use core::{mem, str}; use crate::read::{ self, Architecture, ComdatKind, Error, FileFlags, Object, ObjectComdat, ObjectSection, - ReadError, Result, SectionIndex, Symbol, SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, - SymbolScope, SymbolSection, + ReadError, Result, SectionIndex, SymbolIndex, }; use crate::{endian, macho, BigEndian, Bytes, Endian, Endianness, Pod}; use super::{ - parse_symbol, MachOLoadCommandIterator, MachOSection, MachOSectionInternal, - MachOSectionIterator, MachOSegment, MachOSegmentIterator, MachOSymbolIterator, Nlist, Section, - Segment, SymbolTable, + MachOLoadCommandIterator, MachOSection, MachOSectionInternal, MachOSectionIterator, + MachOSegment, MachOSegmentIterator, MachOSymbol, MachOSymbolIterator, MachOSymbolTable, Nlist, + Section, Segment, SymbolTable, }; /// A 32-bit Mach-O object file. @@ -91,7 +90,9 @@ where type SectionIterator = MachOSectionIterator<'data, 'file, Mach>; type Comdat = MachOComdat<'data, 'file, Mach>; type ComdatIterator = MachOComdatIterator<'data, 'file, Mach>; + type Symbol = MachOSymbol<'data, 'file, Mach>; type SymbolIterator = MachOSymbolIterator<'data, 'file, Mach>; + type SymbolTable = MachOSymbolTable<'data, 'file, Mach>; fn architecture(&self) -> Architecture { match self.header.cputype(self.endian) { @@ -169,67 +170,31 @@ where MachOComdatIterator { file: self } } - fn symbol_by_index(&self, index: SymbolIndex) -> Result> { + fn symbol_by_index(&'file self, index: SymbolIndex) -> Result> { let nlist = self.symbols.symbol(index.0)?; - parse_symbol(self, nlist, self.symbols.strings()) - .read_error("Unsupported Mach-O symbol index") + MachOSymbol::new(self, index, nlist).read_error("Unsupported Mach-O symbol index") } fn symbols(&'file self) -> MachOSymbolIterator<'data, 'file, Mach> { MachOSymbolIterator { file: self, - symbols: self.symbols, index: 0, } } - fn dynamic_symbols(&'file self) -> MachOSymbolIterator<'data, 'file, Mach> { - // The LC_DYSYMTAB command contains indices into the same symbol - // table as the LC_SYMTAB command, so return all of them. - self.symbols() - } - - fn symbol_map(&self) -> SymbolMap<'data> { - let mut symbols: Vec<_> = self.symbols().map(|(_, s)| s).collect(); - - // Add symbols for the end of each section. - for section in self.sections() { - symbols.push(Symbol { - name: None, - address: section.address() + section.size(), - size: 0, - kind: SymbolKind::Section, - section: SymbolSection::Undefined, - weak: false, - scope: SymbolScope::Compilation, - flags: SymbolFlags::None, - }); - } + fn symbol_table(&'file self) -> Option> { + Some(MachOSymbolTable { file: self }) + } - // Calculate symbol sizes by sorting and finding the next symbol. - symbols.sort_by(|a, b| { - a.address.cmp(&b.address).then_with(|| { - // Place the end of section symbols last. - (a.kind == SymbolKind::Section).cmp(&(b.kind == SymbolKind::Section)) - }) - }); - - for i in 0..symbols.len() { - let (before, after) = symbols.split_at_mut(i + 1); - let symbol = &mut before[i]; - if symbol.kind != SymbolKind::Section { - if let Some(next) = after - .iter() - .skip_while(|x| x.kind != SymbolKind::Section && x.address == symbol.address) - .next() - { - symbol.size = next.address - symbol.address; - } - } + fn dynamic_symbols(&'file self) -> MachOSymbolIterator<'data, 'file, Mach> { + MachOSymbolIterator { + file: self, + index: self.symbols.len(), } + } - symbols.retain(SymbolMap::filter); - SymbolMap { symbols } + fn dynamic_symbol_table(&'file self) -> Option> { + None } fn has_debug_symbols(&self) -> bool { diff --git a/src/read/macho/symbol.rs b/src/read/macho/symbol.rs index e2d3c33d..27e8d863 100644 --- a/src/read/macho/symbol.rs +++ b/src/read/macho/symbol.rs @@ -1,3 +1,4 @@ +use alloc::vec::Vec; use core::fmt::Debug; use core::{fmt, slice, str}; @@ -6,8 +7,8 @@ use crate::macho; use crate::pod::Pod; use crate::read::util::StringTable; use crate::read::{ - ReadError, Result, SectionIndex, SectionKind, Symbol, SymbolFlags, SymbolIndex, SymbolKind, - SymbolScope, SymbolSection, + self, ObjectSymbol, ObjectSymbolTable, ReadError, Result, SectionIndex, SectionKind, + SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, SymbolMapEntry, SymbolScope, SymbolSection, }; use super::{MachHeader, MachOFile}; @@ -54,12 +55,72 @@ impl<'data, Mach: MachHeader> SymbolTable<'data, Mach> { self.symbols.is_empty() } + /// The number of symbols. + #[inline] + pub fn len(&self) -> usize { + self.symbols.len() + } + /// Return the symbol at the given index. pub fn symbol(&self, index: usize) -> Result<&'data Mach::Nlist> { self.symbols .get(index) .read_error("Invalid Mach-O symbol index") } + + /// Construct a map from addresses to a user-defined map entry. + pub fn map Option>( + &self, + f: F, + ) -> SymbolMap { + let mut symbols = Vec::with_capacity(self.symbols.len()); + for nlist in self.symbols { + if !nlist.is_definition() { + continue; + } + if let Some(entry) = f(nlist) { + symbols.push(entry); + } + } + SymbolMap::new(symbols) + } +} + +/// An iterator over the symbols of a `MachOFile32`. +pub type MachOSymbolTable32<'data, 'file, Endian = Endianness> = + MachOSymbolTable<'data, 'file, macho::MachHeader32>; +/// An iterator over the symbols of a `MachOFile64`. +pub type MachOSymbolTable64<'data, 'file, Endian = Endianness> = + MachOSymbolTable<'data, 'file, macho::MachHeader64>; + +/// A symbol table of a `MachOFile`. +#[derive(Debug, Clone, Copy)] +pub struct MachOSymbolTable<'data, 'file, Mach: MachHeader> { + pub(super) file: &'file MachOFile<'data, Mach>, +} + +impl<'data, 'file, Mach: MachHeader> read::private::Sealed + for MachOSymbolTable<'data, 'file, Mach> +{ +} + +impl<'data, 'file, Mach: MachHeader> ObjectSymbolTable<'data> + for MachOSymbolTable<'data, 'file, Mach> +{ + type Symbol = MachOSymbol<'data, 'file, Mach>; + type SymbolIterator = MachOSymbolIterator<'data, 'file, Mach>; + + fn symbols(&self) -> Self::SymbolIterator { + MachOSymbolIterator { + file: self.file, + index: 0, + } + } + + fn symbol_by_index(&self, index: SymbolIndex) -> Result { + let nlist = self.file.symbols.symbol(index.0)?; + MachOSymbol::new(self.file, index, nlist).read_error("Unsupported Mach-O symbol index") + } } /// An iterator over the symbols of a `MachOFile32`. @@ -72,7 +133,6 @@ pub type MachOSymbolIterator64<'data, 'file, Endian = Endianness> = /// An iterator over the symbols of a `MachOFile`. pub struct MachOSymbolIterator<'data, 'file, Mach: MachHeader> { pub(super) file: &'file MachOFile<'data, Mach>, - pub(super) symbols: SymbolTable<'data, Mach>, pub(super) index: usize, } @@ -83,86 +143,159 @@ impl<'data, 'file, Mach: MachHeader> fmt::Debug for MachOSymbolIterator<'data, ' } impl<'data, 'file, Mach: MachHeader> Iterator for MachOSymbolIterator<'data, 'file, Mach> { - type Item = (SymbolIndex, Symbol<'data>); + type Item = MachOSymbol<'data, 'file, Mach>; fn next(&mut self) -> Option { loop { let index = self.index; - let nlist = self.symbols.symbols.get(index)?; + let nlist = self.file.symbols.symbols.get(index)?; self.index += 1; - if let Some(symbol) = parse_symbol(self.file, nlist, self.symbols.strings) { - return Some((SymbolIndex(index), symbol)); + if let Some(symbol) = MachOSymbol::new(self.file, SymbolIndex(index), nlist) { + return Some(symbol); } } } } -pub(super) fn parse_symbol<'data, Mach: MachHeader>( - file: &MachOFile<'data, Mach>, - nlist: &Mach::Nlist, - strings: StringTable<'data>, -) -> Option> { - let endian = file.endian; - let name = nlist - .name(endian, strings) - .ok() - .and_then(|s| str::from_utf8(s).ok()); - let n_type = nlist.n_type(); - let n_desc = nlist.n_desc(endian); - if n_type & macho::N_STAB != 0 { - return None; - } - let section = match n_type & macho::N_TYPE { - macho::N_UNDF => SymbolSection::Undefined, - macho::N_ABS => SymbolSection::Absolute, - macho::N_SECT => { - let n_sect = nlist.n_sect(); - if n_sect != 0 { - SymbolSection::Section(SectionIndex(n_sect as usize)) - } else { - SymbolSection::Unknown - } +/// A symbol of a `MachOFile32`. +pub type MachOSymbol32<'data, 'file, Endian = Endianness> = + MachOSymbol<'data, 'file, macho::MachHeader32>; +/// A symbol of a `MachOFile64`. +pub type MachOSymbol64<'data, 'file, Endian = Endianness> = + MachOSymbol<'data, 'file, macho::MachHeader64>; + +/// A symbol of a `MachOFile`. +#[derive(Debug, Clone, Copy)] +pub struct MachOSymbol<'data, 'file, Mach: MachHeader> { + file: &'file MachOFile<'data, Mach>, + index: SymbolIndex, + nlist: &'data Mach::Nlist, +} + +impl<'data, 'file, Mach: MachHeader> MachOSymbol<'data, 'file, Mach> { + pub(super) fn new( + file: &'file MachOFile<'data, Mach>, + index: SymbolIndex, + nlist: &'data Mach::Nlist, + ) -> Option { + if nlist.n_type() & macho::N_STAB != 0 { + return None; } - _ => SymbolSection::Unknown, - }; - let kind = section - .index() - .and_then(|index| file.section_internal(index).ok()) - .map(|section| match section.kind { - SectionKind::Text => SymbolKind::Text, - SectionKind::Data - | SectionKind::ReadOnlyData - | SectionKind::ReadOnlyString - | SectionKind::UninitializedData - | SectionKind::Common => SymbolKind::Data, - SectionKind::Tls | SectionKind::UninitializedTls | SectionKind::TlsVariables => { - SymbolKind::Tls + Some(MachOSymbol { file, index, nlist }) + } +} + +impl<'data, 'file, Mach: MachHeader> read::private::Sealed for MachOSymbol<'data, 'file, Mach> {} + +impl<'data, 'file, Mach: MachHeader> ObjectSymbol<'data> for MachOSymbol<'data, 'file, Mach> { + #[inline] + fn index(&self) -> SymbolIndex { + self.index + } + + fn name(&self) -> Result<&'data str> { + let name = self + .nlist + .name(self.file.endian, self.file.symbols.strings)?; + str::from_utf8(name) + .ok() + .read_error("Non UTF-8 Mach-O symbol name") + } + + #[inline] + fn address(&self) -> u64 { + self.nlist.n_value(self.file.endian).into() + } + + #[inline] + fn size(&self) -> u64 { + 0 + } + + fn kind(&self) -> SymbolKind { + self.section() + .index() + .and_then(|index| self.file.section_internal(index).ok()) + .map(|section| match section.kind { + SectionKind::Text => SymbolKind::Text, + SectionKind::Data + | SectionKind::ReadOnlyData + | SectionKind::ReadOnlyString + | SectionKind::UninitializedData + | SectionKind::Common => SymbolKind::Data, + SectionKind::Tls | SectionKind::UninitializedTls | SectionKind::TlsVariables => { + SymbolKind::Tls + } + _ => SymbolKind::Unknown, + }) + .unwrap_or(SymbolKind::Unknown) + } + + fn section(&self) -> SymbolSection { + match self.nlist.n_type() & macho::N_TYPE { + macho::N_UNDF => SymbolSection::Undefined, + macho::N_ABS => SymbolSection::Absolute, + macho::N_SECT => { + let n_sect = self.nlist.n_sect(); + if n_sect != 0 { + SymbolSection::Section(SectionIndex(n_sect as usize)) + } else { + SymbolSection::Unknown + } } - _ => SymbolKind::Unknown, - }) - .unwrap_or(SymbolKind::Unknown); - let weak = n_desc & (macho::N_WEAK_REF | macho::N_WEAK_DEF) != 0; - let scope = if section == SymbolSection::Undefined { - SymbolScope::Unknown - } else if n_type & macho::N_EXT == 0 { - SymbolScope::Compilation - } else if n_type & macho::N_PEXT != 0 { - SymbolScope::Linkage - } else { - SymbolScope::Dynamic - }; - let flags = SymbolFlags::MachO { n_desc }; - Some(Symbol { - name, - address: nlist.n_value(endian).into(), - // Only calculated for symbol maps - size: 0, - kind, - section, - weak, - scope, - flags, - }) + _ => SymbolSection::Unknown, + } + } + + #[inline] + fn is_undefined(&self) -> bool { + self.nlist.n_type() & macho::N_TYPE == macho::N_UNDF + } + + #[inline] + fn is_definition(&self) -> bool { + self.nlist.is_definition() + } + + #[inline] + fn is_common(&self) -> bool { + // Mach-O common symbols are based on section, not symbol + false + } + + #[inline] + fn is_weak(&self) -> bool { + self.nlist.n_desc(self.file.endian) & (macho::N_WEAK_REF | macho::N_WEAK_DEF) != 0 + } + + fn scope(&self) -> SymbolScope { + let n_type = self.nlist.n_type(); + if n_type & macho::N_TYPE == macho::N_UNDF { + SymbolScope::Unknown + } else if n_type & macho::N_EXT == 0 { + SymbolScope::Compilation + } else if n_type & macho::N_PEXT != 0 { + SymbolScope::Linkage + } else { + SymbolScope::Dynamic + } + } + + #[inline] + fn is_global(&self) -> bool { + self.scope() != SymbolScope::Compilation + } + + #[inline] + fn is_local(&self) -> bool { + self.scope() == SymbolScope::Compilation + } + + #[inline] + fn flags(&self) -> SymbolFlags { + let n_desc = self.nlist.n_desc(self.file.endian); + SymbolFlags::MachO { n_desc } + } } /// A trait for generic access to `Nlist32` and `Nlist64`. @@ -187,8 +320,10 @@ pub trait Nlist: Debug + Pod { .read_error("Invalid Mach-O symbol name offset") } - fn is_undefined(&self) -> bool { - self.n_type() & macho::N_TYPE == macho::N_UNDF + /// Return true if the symbol is a definition of a function or data object. + fn is_definition(&self) -> bool { + let n_type = self.n_type(); + n_type & macho::N_STAB == 0 && n_type & macho::N_TYPE != macho::N_UNDF } } diff --git a/src/read/mod.rs b/src/read/mod.rs index f223c504..e9cd07dd 100644 --- a/src/read/mod.rs +++ b/src/read/mod.rs @@ -2,7 +2,7 @@ use alloc::borrow::Cow; use alloc::vec::Vec; -use core::{cmp, fmt, result}; +use core::{fmt, result}; use crate::common::*; use crate::Bytes; @@ -145,147 +145,76 @@ impl SymbolSection { } } -/// A symbol table entry. -#[derive(Clone, Debug)] -pub struct Symbol<'data> { - name: Option<&'data str>, - address: u64, - size: u64, - kind: SymbolKind, - section: SymbolSection, - weak: bool, - scope: SymbolScope, - flags: SymbolFlags, +/// An entry in a `SymbolMap`. +pub trait SymbolMapEntry { + /// The symbol address. + fn address(&self) -> u64; } -impl<'data> Symbol<'data> { - /// Return the kind of this symbol. - #[inline] - pub fn kind(&self) -> SymbolKind { - self.kind - } - - /// Returns the section where the symbol is defined. - #[inline] - pub fn section(&self) -> SymbolSection { - self.section - } - - /// Returns the section index for the section containing this symbol. - /// - /// May return `None` if the symbol is not defined in a section. - #[inline] - pub fn section_index(&self) -> Option { - self.section.index() - } - - /// Return true if the symbol is undefined. - #[inline] - pub fn is_undefined(&self) -> bool { - self.section == SymbolSection::Undefined - } - - /// Return true if the symbol is common data. - /// - /// Note: does not check for `SymbolSection::Section` with `SectionKind::Common`. - #[inline] - fn is_common(&self) -> bool { - self.section == SymbolSection::Common - } - - /// Return true if the symbol is weak. - #[inline] - pub fn is_weak(&self) -> bool { - self.weak - } +/// A map from addresses to symbols. +#[derive(Debug)] +pub struct SymbolMap { + symbols: Vec, +} - /// Return true if the symbol visible outside of the compilation unit. +impl SymbolMap { + /// Construct a new symbol map. /// - /// This treats `SymbolScope::Unknown` as global. - #[inline] - pub fn is_global(&self) -> bool { - !self.is_local() + /// This function will sort the symbols by address. + pub fn new(mut symbols: Vec) -> Self { + symbols.sort_unstable_by_key(|s| s.address()); + SymbolMap { symbols } } - /// Return true if the symbol is only visible within the compilation unit. - #[inline] - pub fn is_local(&self) -> bool { - self.scope == SymbolScope::Compilation + /// Get the symbol before the given address. + pub fn get(&self, address: u64) -> Option<&T> { + let index = match self + .symbols + .binary_search_by_key(&address, |symbol| symbol.address()) + { + Ok(index) => index, + Err(index) => index.checked_sub(1)?, + }; + self.symbols.get(index) } - /// Returns the symbol scope. + /// Get all symbols in the map. #[inline] - pub fn scope(&self) -> SymbolScope { - self.scope + pub fn symbols(&self) -> &[T] { + &self.symbols } +} - /// Symbol flags that are specific to each file format. - #[inline] - pub fn flags(&self) -> SymbolFlags { - self.flags - } +/// A `SymbolMap` entry for symbol names. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct SymbolMapName<'data> { + address: u64, + name: &'data str, +} - /// The name of the symbol. - #[inline] - pub fn name(&self) -> Option<&'data str> { - self.name +impl<'data> SymbolMapName<'data> { + /// Construct a `SymbolMapName`. + pub fn new(address: u64, name: &'data str) -> Self { + SymbolMapName { address, name } } - /// The address of the symbol. May be zero if the address is unknown. + /// The symbol address. #[inline] pub fn address(&self) -> u64 { self.address } - /// The size of the symbol. May be zero if the size is unknown. + /// The symbol name. #[inline] - pub fn size(&self) -> u64 { - self.size + pub fn name(&self) -> &'data str { + self.name } } -/// A map from addresses to symbols. -#[derive(Debug)] -pub struct SymbolMap<'data> { - symbols: Vec>, -} - -impl<'data> SymbolMap<'data> { - /// Get the symbol containing the given address. - pub fn get(&self, address: u64) -> Option<&Symbol<'data>> { - self.symbols - .binary_search_by(|symbol| { - if address < symbol.address { - cmp::Ordering::Greater - } else if address < symbol.address + symbol.size { - cmp::Ordering::Equal - } else { - cmp::Ordering::Less - } - }) - .ok() - .and_then(|index| self.symbols.get(index)) - } - - /// Get all symbols in the map. +impl<'data> SymbolMapEntry for SymbolMapName<'data> { #[inline] - pub fn symbols(&self) -> &[Symbol<'data>] { - &self.symbols - } - - /// Return true for symbols that should be included in the map. - fn filter(symbol: &Symbol<'_>) -> bool { - match symbol.kind() { - SymbolKind::Unknown | SymbolKind::Text | SymbolKind::Data => {} - SymbolKind::Null - | SymbolKind::Section - | SymbolKind::File - | SymbolKind::Label - | SymbolKind::Tls => { - return false; - } - } - !symbol.is_undefined() && !symbol.is_common() && symbol.size() > 0 + fn address(&self) -> u64 { + self.address } } diff --git a/src/read/pe/file.rs b/src/read/pe/file.rs index ae82c465..426e5001 100644 --- a/src/read/pe/file.rs +++ b/src/read/pe/file.rs @@ -1,11 +1,10 @@ -use alloc::vec::Vec; use core::fmt::Debug; use core::{mem, str}; -use crate::read::coff::{parse_symbol, CoffSymbolIterator, SymbolTable}; +use crate::read::coff::{CoffCommon, CoffSymbol, CoffSymbolIterator, CoffSymbolTable, SymbolTable}; use crate::read::{ self, Architecture, ComdatKind, Error, FileFlags, Object, ObjectComdat, ReadError, Result, - SectionIndex, Symbol, SymbolIndex, SymbolMap, + SectionIndex, SymbolIndex, }; use crate::{pe, Bytes, LittleEndian as LE, Pod}; @@ -22,8 +21,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: SectionTable<'data>, - pub(super) symbols: SymbolTable<'data>, + pub(super) common: CoffCommon<'data>, pub(super) data: Bytes<'data>, } @@ -49,13 +47,17 @@ impl<'data, Pe: ImageNtHeaders> PeFile<'data, Pe> { let (nt_headers, data_directories, nt_tail) = dos_header.nt_headers::(data)?; let sections = nt_headers.sections(nt_tail)?; let symbols = nt_headers.symbols(data)?; + let image_base = u64::from(nt_headers.optional_header().image_base()); Ok(PeFile { dos_header, nt_headers, data_directories, - sections, - symbols, + common: CoffCommon { + sections, + symbols, + image_base, + }, data, }) } @@ -78,7 +80,9 @@ where type SectionIterator = PeSectionIterator<'data, 'file, Pe>; type Comdat = PeComdat<'data, 'file, Pe>; type ComdatIterator = PeComdatIterator<'data, 'file, Pe>; + type Symbol = CoffSymbol<'data, 'file>; type SymbolIterator = CoffSymbolIterator<'data, 'file>; + type SymbolTable = CoffSymbolTable<'data, 'file>; fn architecture(&self) -> Architecture { match self.nt_headers.file_header().machine.get(LE) { @@ -103,13 +107,14 @@ where fn segments(&'file self) -> PeSegmentIterator<'data, 'file, Pe> { PeSegmentIterator { file: self, - iter: self.sections.iter(), + iter: self.common.sections.iter(), } } fn section_by_name(&'file self, section_name: &str) -> Option> { - self.sections - .section_by_name(self.symbols.strings(), section_name.as_bytes()) + self.common + .sections + .section_by_name(self.common.symbols.strings(), section_name.as_bytes()) .map(|(index, section)| PeSection { file: self, index: SectionIndex(index), @@ -118,7 +123,7 @@ where } fn section_by_index(&'file self, index: SectionIndex) -> Result> { - let section = self.sections.section(index.0)?; + let section = self.common.sections.section(index.0)?; Ok(PeSection { file: self, index, @@ -129,7 +134,7 @@ where fn sections(&'file self) -> PeSectionIterator<'data, 'file, Pe> { PeSectionIterator { file: self, - iter: self.sections.iter().enumerate(), + iter: self.common.sections.iter().enumerate(), } } @@ -137,39 +142,36 @@ where PeComdatIterator { file: self } } - fn symbol_by_index(&self, index: SymbolIndex) -> Result> { - let symbol = self - .symbols - .get(index.0) - .read_error("Invalid PE symbol index")?; - Ok(parse_symbol(&self.symbols, index.0, symbol)) + fn symbol_by_index(&'file self, index: SymbolIndex) -> Result> { + let symbol = self.common.symbols.symbol(index.0)?; + Ok(CoffSymbol { + file: &self.common, + index, + symbol, + }) } fn symbols(&'file self) -> CoffSymbolIterator<'data, 'file> { CoffSymbolIterator { - symbols: &self.symbols, + file: &self.common, index: 0, } } + fn symbol_table(&'file self) -> Option> { + Some(CoffSymbolTable { file: &self.common }) + } + fn dynamic_symbols(&'file self) -> CoffSymbolIterator<'data, 'file> { - // TODO: return exports/imports CoffSymbolIterator { - symbols: &self.symbols, + file: &self.common, // Hack: don't return any. - index: self.symbols.len(), + index: self.common.symbols.len(), } } - fn symbol_map(&self) -> SymbolMap<'data> { - // TODO: untested - let mut symbols: Vec<_> = self - .symbols() - .map(|(_, s)| s) - .filter(SymbolMap::filter) - .collect(); - symbols.sort_by_key(|x| x.address); - SymbolMap { symbols } + fn dynamic_symbol_table(&'file self) -> Option> { + None } fn has_debug_symbols(&self) -> bool { diff --git a/src/read/pe/section.rs b/src/read/pe/section.rs index 086c3721..82e2d1c2 100644 --- a/src/read/pe/section.rs +++ b/src/read/pe/section.rs @@ -101,7 +101,7 @@ impl<'data, 'file, Pe: ImageNtHeaders> ObjectSegment<'data> for PeSegment<'data, #[inline] fn name(&self) -> Result> { - let name = self.section.name(self.file.symbols.strings())?; + let name = self.section.name(self.file.common.symbols.strings())?; Ok(Some( str::from_utf8(name) .ok() @@ -218,7 +218,7 @@ impl<'data, 'file, Pe: ImageNtHeaders> ObjectSection<'data> for PeSection<'data, #[inline] fn name(&self) -> Result<&str> { - let name = self.section.name(self.file.symbols.strings())?; + let name = self.section.name(self.file.common.symbols.strings())?; str::from_utf8(name) .ok() .read_error("Non UTF-8 PE section name") diff --git a/src/read/traits.rs b/src/read/traits.rs index 93fcdd1e..fa9083b3 100644 --- a/src/read/traits.rs +++ b/src/read/traits.rs @@ -1,13 +1,15 @@ use alloc::borrow::Cow; +use alloc::vec::Vec; use crate::read::{ self, Architecture, ComdatKind, CompressedData, FileFlags, Relocation, Result, SectionFlags, - SectionIndex, SectionKind, Symbol, SymbolIndex, SymbolMap, + SectionIndex, SectionKind, SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, SymbolMapName, + SymbolScope, SymbolSection, }; use crate::Endianness; /// An object file. -pub trait Object<'data, 'file>: read::private::Sealed { +pub trait Object<'data: 'file, 'file>: read::private::Sealed { /// A segment in the object file. type Segment: ObjectSegment<'data>; @@ -26,8 +28,18 @@ pub trait Object<'data, 'file>: read::private::Sealed { /// An iterator over the COMDAT section groups in the object file. type ComdatIterator: Iterator; - /// An iterator over the symbols in the object file. - type SymbolIterator: Iterator)>; + /// A symbol in the object file. + type Symbol: ObjectSymbol<'data>; + + /// An iterator over symbols in the object file. + type SymbolIterator: Iterator; + + /// A symbol table in the object file. + type SymbolTable: ObjectSymbolTable< + 'data, + Symbol = Self::Symbol, + SymbolIterator = Self::SymbolIterator, + >; /// Get the architecture type of the file. fn architecture(&self) -> Architecture; @@ -85,49 +97,47 @@ pub trait Object<'data, 'file>: read::private::Sealed { /// Get an iterator over the COMDAT section groups in the file. fn comdats(&'file self) -> Self::ComdatIterator; + /// Get the symbol table, if any. + fn symbol_table(&'file self) -> Option; + /// Get the debugging symbol at the given index. /// /// The meaning of the index depends on the object file. /// /// Returns an error if the index is invalid. - fn symbol_by_index(&self, index: SymbolIndex) -> Result>; + fn symbol_by_index(&'file self, index: SymbolIndex) -> Result; /// Get an iterator over the debugging symbols in the file. /// /// This may skip over symbols that are malformed or unsupported. fn symbols(&'file self) -> Self::SymbolIterator; - /// Get the data for the given symbol. - /// - /// This may iterate over segments. - /// - /// Returns `Ok(None)` for undefined symbols or if the data could not be found. - fn symbol_data(&'file self, symbol: &Symbol<'data>) -> Result> { - if symbol.is_undefined() { - return Ok(None); - } - let address = symbol.address(); - let size = symbol.size(); - if let Some(index) = symbol.section_index() { - let section = self.section_by_index(index)?; - section.data_range(address, size) - } else { - for segment in self.segments() { - if let Some(data) = segment.data_range(address, size)? { - return Ok(Some(data)); - } - } - Ok(None) - } - } + /// Get the dynamic linking symbol table, if any. + fn dynamic_symbol_table(&'file self) -> Option; /// Get an iterator over the dynamic linking symbols in the file. /// /// This may skip over symbols that are malformed or unsupported. fn dynamic_symbols(&'file self) -> Self::SymbolIterator; - /// Construct a map from addresses to symbols. - fn symbol_map(&self) -> SymbolMap<'data>; + /// Construct a map from addresses to symbol names. + /// + /// The map will only contain defined text and data symbols. + /// The dynamic symbol table will only be used if there are no debugging symbols. + fn symbol_map(&'file self) -> SymbolMap> { + let mut symbols = Vec::new(); + if let Some(table) = self.symbol_table().or_else(|| self.dynamic_symbol_table()) { + for symbol in table.symbols() { + if !symbol.is_definition() { + continue; + } + if let Ok(name) = symbol.name() { + symbols.push(SymbolMapName::new(symbol.address(), name)); + } + } + } + SymbolMap::new(symbols) + } /// Return true if the file contains debug information sections, false if not. fn has_debug_symbols(&self) -> bool; @@ -272,3 +282,81 @@ pub trait ObjectComdat<'data>: read::private::Sealed { /// Get the sections in this section group. fn sections(&self) -> Self::SectionIterator; } + +/// A symbol table. +pub trait ObjectSymbolTable<'data>: read::private::Sealed { + /// A symbol table entry. + type Symbol: ObjectSymbol<'data>; + + /// An iterator over the symbols in a symbol table. + type SymbolIterator: Iterator; + + /// Get an iterator over the symbols in the table. + /// + /// This may skip over symbols that are malformed or unsupported. + fn symbols(&self) -> Self::SymbolIterator; + + /// Get the symbol at the given index. + /// + /// The meaning of the index depends on the object file. + /// + /// Returns an error if the index is invalid. + fn symbol_by_index(&self, index: SymbolIndex) -> Result; +} + +/// A symbol table entry. +pub trait ObjectSymbol<'data>: read::private::Sealed { + /// The index of the symbol. + fn index(&self) -> SymbolIndex; + + /// The name of the symbol. + fn name(&self) -> Result<&'data str>; + + /// The address of the symbol. May be zero if the address is unknown. + fn address(&self) -> u64; + + /// The size of the symbol. May be zero if the size is unknown. + fn size(&self) -> u64; + + /// Return the kind of this symbol. + fn kind(&self) -> SymbolKind; + + /// Returns the section where the symbol is defined. + fn section(&self) -> SymbolSection; + + /// Returns the section index for the section containing this symbol. + /// + /// May return `None` if the symbol is not defined in a section. + fn section_index(&self) -> Option { + self.section().index() + } + + /// Return true if the symbol is undefined. + fn is_undefined(&self) -> bool; + + /// Return true if the symbol is a definition of a function or data object + /// that has a known address. + fn is_definition(&self) -> bool; + + /// Return true if the symbol is common data. + /// + /// Note: does not check for `SymbolSection::Section` with `SectionKind::Common`. + fn is_common(&self) -> bool; + + /// Return true if the symbol is weak. + fn is_weak(&self) -> bool; + + /// Returns the symbol scope. + fn scope(&self) -> SymbolScope; + + /// Return true if the symbol visible outside of the compilation unit. + /// + /// This treats `SymbolScope::Unknown` as global. + fn is_global(&self) -> bool; + + /// Return true if the symbol is only visible within the compilation unit. + fn is_local(&self) -> bool; + + /// Symbol flags that are specific to each file format. + fn flags(&self) -> SymbolFlags; +} diff --git a/src/read/wasm.rs b/src/read/wasm.rs index cf7bfd97..66877883 100644 --- a/src/read/wasm.rs +++ b/src/read/wasm.rs @@ -11,8 +11,8 @@ use wasmparser as wp; use crate::read::{ self, Architecture, ComdatKind, CompressedData, Error, FileFlags, Object, ObjectComdat, - ObjectSection, ObjectSegment, ReadError, Relocation, Result, SectionFlags, SectionIndex, - SectionKind, Symbol, SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, SymbolScope, + ObjectSection, ObjectSegment, ObjectSymbol, ObjectSymbolTable, ReadError, Relocation, Result, + SectionFlags, SectionIndex, SectionKind, SymbolFlags, SymbolIndex, SymbolKind, SymbolScope, SymbolSection, }; @@ -42,7 +42,7 @@ pub struct WasmFile<'data> { // Whether the file has DWARF information. has_debug_symbols: bool, // Symbols collected from imports, exports, code and name sections. - symbols: Vec>, + symbols: Vec>, // Address of the function body for the entry point. entry: u64, } @@ -67,15 +67,13 @@ impl<'data> WasmFile<'data> { let mut file = WasmFile::default(); - let mut main_file_symbol = Some(Symbol { - name: None, + let mut main_file_symbol = Some(WasmSymbolInternal { + name: "", address: 0, size: 0, kind: SymbolKind::File, section: SymbolSection::None, - weak: false, scope: SymbolScope::Compilation, - flags: SymbolFlags::None, }); let mut imported_funcs_count = 0; @@ -94,20 +92,18 @@ impl<'data> WasmFile<'data> { .read_error("Couldn't read header of the import section")? { let import = import.read_error("Couldn't read an import item")?; - let module_name = Some(import.module); + let module_name = import.module; - if last_module_name != module_name { - file.symbols.push(Symbol { + if last_module_name != Some(module_name) { + file.symbols.push(WasmSymbolInternal { name: module_name, address: 0, size: 0, kind: SymbolKind::File, section: SymbolSection::None, - weak: false, scope: SymbolScope::Dynamic, - flags: SymbolFlags::None, }); - last_module_name = module_name; + last_module_name = Some(module_name); } let kind = match import.ty { @@ -120,15 +116,13 @@ impl<'data> WasmFile<'data> { | wp::ImportSectionEntryType::Global(_) => SymbolKind::Data, }; - file.symbols.push(Symbol { - name: Some(import.field), + file.symbols.push(WasmSymbolInternal { + name: import.field, address: 0, size: 0, kind, section: SymbolSection::Undefined, - weak: false, scope: SymbolScope::Dynamic, - flags: SymbolFlags::None, }); } } @@ -177,15 +171,13 @@ impl<'data> WasmFile<'data> { | wp::ExternalKind::Global => (SymbolKind::Data, SECTION_DATA), }; - file.symbols.push(Symbol { - name: Some(export.field), + file.symbols.push(WasmSymbolInternal { + name: export.field, address: 0, size: 0, kind, section: SymbolSection::Section(SectionIndex(section_idx)), - weak: false, scope: SymbolScope::Dynamic, - flags: SymbolFlags::None, }); } } @@ -223,15 +215,13 @@ impl<'data> WasmFile<'data> { *local_func_kind = LocalFunctionKind::Local { symbol_id: file.symbols.len() as u32, }; - file.symbols.push(Symbol { - section: SymbolSection::Section(SectionIndex(SECTION_CODE)), + file.symbols.push(WasmSymbolInternal { + name: "", address, size, kind: SymbolKind::Text, - name: None, - weak: false, + section: SymbolSection::Section(SectionIndex(SECTION_CODE)), scope: SymbolScope::Compilation, - flags: SymbolFlags::None, }); } LocalFunctionKind::Exported { symbol_ids } => { @@ -271,7 +261,7 @@ impl<'data> WasmFile<'data> { if let LocalFunctionKind::Local { symbol_id } = local_func_kinds[local_index as usize] { - file.symbols[symbol_id as usize].name = Some(naming.name); + file.symbols[symbol_id as usize].name = naming.name; } } } @@ -305,7 +295,9 @@ where type SectionIterator = WasmSectionIterator<'data, 'file>; type Comdat = WasmComdat<'data, 'file>; type ComdatIterator = WasmComdatIterator<'data, 'file>; + type Symbol = WasmSymbol<'data, 'file>; type SymbolIterator = WasmSymbolIterator<'data, 'file>; + type SymbolTable = WasmSymbolTable<'data, 'file>; #[inline] fn architecture(&self) -> Architecture { @@ -358,11 +350,12 @@ where } #[inline] - fn symbol_by_index(&self, index: SymbolIndex) -> Result> { - self.symbols + fn symbol_by_index(&'file self, index: SymbolIndex) -> Result> { + let symbol = self + .symbols .get(index.0) - .cloned() - .read_error("Invalid Wasm symbol index") + .read_error("Invalid Wasm symbol index")?; + Ok(WasmSymbol { index, symbol }) } fn symbols(&'file self) -> Self::SymbolIterator { @@ -371,16 +364,20 @@ where } } + fn symbol_table(&'file self) -> Option> { + Some(WasmSymbolTable { + symbols: &self.symbols, + }) + } + fn dynamic_symbols(&'file self) -> Self::SymbolIterator { WasmSymbolIterator { symbols: [].iter().enumerate(), } } - fn symbol_map(&self) -> SymbolMap<'data> { - SymbolMap { - symbols: self.symbols.clone(), - } + fn dynamic_symbol_table(&'file self) -> Option> { + None } fn has_debug_symbols(&self) -> bool { @@ -646,18 +643,139 @@ impl<'data, 'file> Iterator for WasmComdatSectionIterator<'data, 'file> { } } +/// A symbol table of a `WasmFile`. +#[derive(Debug)] +pub struct WasmSymbolTable<'data, 'file> { + symbols: &'file [WasmSymbolInternal<'data>], +} + +impl<'data, 'file> read::private::Sealed for WasmSymbolTable<'data, 'file> {} + +impl<'data, 'file> ObjectSymbolTable<'data> for WasmSymbolTable<'data, 'file> { + type Symbol = WasmSymbol<'data, 'file>; + type SymbolIterator = WasmSymbolIterator<'data, 'file>; + + fn symbols(&self) -> Self::SymbolIterator { + WasmSymbolIterator { + symbols: self.symbols.iter().enumerate(), + } + } + + fn symbol_by_index(&self, index: SymbolIndex) -> Result { + let symbol = self + .symbols + .get(index.0) + .read_error("Invalid Wasm symbol index")?; + Ok(WasmSymbol { index, symbol }) + } +} + /// An iterator over the symbols of a `WasmFile`. #[derive(Debug)] pub struct WasmSymbolIterator<'data, 'file> { - symbols: core::iter::Enumerate>>, + symbols: core::iter::Enumerate>>, } impl<'data, 'file> Iterator for WasmSymbolIterator<'data, 'file> { - type Item = (SymbolIndex, Symbol<'data>); + type Item = WasmSymbol<'data, 'file>; fn next(&mut self) -> Option { let (index, symbol) = self.symbols.next()?; - Some((SymbolIndex(index), symbol.clone())) + Some(WasmSymbol { + index: SymbolIndex(index), + symbol, + }) + } +} + +/// A symbol of a `WasmFile`. +#[derive(Clone, Copy, Debug)] +pub struct WasmSymbol<'data, 'file> { + index: SymbolIndex, + symbol: &'file WasmSymbolInternal<'data>, +} + +#[derive(Clone, Debug)] +struct WasmSymbolInternal<'data> { + name: &'data str, + address: u64, + size: u64, + kind: SymbolKind, + section: SymbolSection, + scope: SymbolScope, +} + +impl<'data, 'file> read::private::Sealed for WasmSymbol<'data, 'file> {} + +impl<'data, 'file> ObjectSymbol<'data> for WasmSymbol<'data, 'file> { + #[inline] + fn index(&self) -> SymbolIndex { + self.index + } + + #[inline] + fn name(&self) -> read::Result<&'data str> { + Ok(self.symbol.name) + } + + #[inline] + fn address(&self) -> u64 { + self.symbol.address + } + + #[inline] + fn size(&self) -> u64 { + self.symbol.size + } + + #[inline] + fn kind(&self) -> SymbolKind { + self.symbol.kind + } + + #[inline] + fn section(&self) -> SymbolSection { + self.symbol.section + } + + #[inline] + fn is_undefined(&self) -> bool { + self.symbol.section == SymbolSection::Undefined + } + + #[inline] + fn is_definition(&self) -> bool { + self.symbol.kind == SymbolKind::Text && self.symbol.section != SymbolSection::Undefined + } + + #[inline] + fn is_common(&self) -> bool { + self.symbol.section == SymbolSection::Common + } + + #[inline] + fn is_weak(&self) -> bool { + false + } + + #[inline] + fn scope(&self) -> SymbolScope { + self.symbol.scope + } + + #[inline] + fn is_global(&self) -> bool { + self.symbol.scope != SymbolScope::Compilation + } + + #[inline] + fn is_local(&self) -> bool { + self.symbol.scope == SymbolScope::Compilation + } + + #[inline] + fn flags(&self) -> SymbolFlags { + SymbolFlags::None } } diff --git a/tests/round_trip/bss.rs b/tests/round_trip/bss.rs index 6339379e..b297221d 100644 --- a/tests/round_trip/bss.rs +++ b/tests/round_trip/bss.rs @@ -1,6 +1,6 @@ #![cfg(all(feature = "read", feature = "write"))] -use object::read::{Object, ObjectSection}; +use object::read::{Object, ObjectSection, ObjectSymbol}; use object::{read, write}; use object::{ Architecture, BinaryFormat, Endianness, SectionKind, SymbolFlags, SymbolKind, SymbolScope, @@ -63,9 +63,9 @@ fn coff_x86_64_bss() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("v1")); + assert_eq!(symbol.name(), Ok("v1")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section_index(), Some(bss_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -73,9 +73,9 @@ fn coff_x86_64_bss() { assert_eq!(symbol.is_undefined(), false); assert_eq!(symbol.address(), 0); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("v2")); + assert_eq!(symbol.name(), Ok("v2")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section_index(), Some(bss_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -145,13 +145,13 @@ fn elf_x86_64_bss() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("")); + assert_eq!(symbol.name(), Ok("")); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("v1")); + assert_eq!(symbol.name(), Ok("v1")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section_index(), Some(bss_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -160,9 +160,9 @@ fn elf_x86_64_bss() { assert_eq!(symbol.address(), 0); assert_eq!(symbol.size(), 18); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("v2")); + assert_eq!(symbol.name(), Ok("v2")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section_index(), Some(bss_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -236,9 +236,9 @@ fn macho_x86_64_bss() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("_v1")); + assert_eq!(symbol.name(), Ok("_v1")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section_index(), Some(bss_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -246,9 +246,9 @@ fn macho_x86_64_bss() { assert_eq!(symbol.is_undefined(), false); assert_eq!(symbol.address(), 0); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("_v2")); + assert_eq!(symbol.name(), Ok("_v2")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section_index(), Some(bss_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); diff --git a/tests/round_trip/comdat.rs b/tests/round_trip/comdat.rs index d34587e7..eb8a1e0f 100644 --- a/tests/round_trip/comdat.rs +++ b/tests/round_trip/comdat.rs @@ -1,7 +1,7 @@ #![cfg(all(feature = "read", feature = "write"))] use object::pe; -use object::read::{Object, ObjectComdat, ObjectSection}; +use object::read::{Object, ObjectComdat, ObjectSection, ObjectSymbol}; use object::{read, write}; use object::{ Architecture, BinaryFormat, ComdatKind, Endianness, SectionKind, SymbolFlags, SymbolKind, @@ -65,9 +65,9 @@ fn coff_x86_64_comdat() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some(".text$s1")); + assert_eq!(symbol.name(), Ok(".text$s1")); assert_eq!(symbol.kind(), SymbolKind::Section); assert_eq!( symbol.section(), @@ -81,9 +81,9 @@ fn coff_x86_64_comdat() { } ); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some(".data$s1")); + assert_eq!(symbol.name(), Ok(".data$s1")); assert_eq!(symbol.kind(), SymbolKind::Section); assert_eq!( symbol.section(), @@ -97,9 +97,10 @@ fn coff_x86_64_comdat() { } ); - let (symbol_index, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); + let symbol_index = symbol.index(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("s1")); + assert_eq!(symbol.name(), Ok("s1")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!( symbol.section(), @@ -189,13 +190,14 @@ fn elf_x86_64_common() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("")); + assert_eq!(symbol.name(), Ok("")); - let (symbol_index, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); + let symbol_index = symbol.index(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("s1")); + assert_eq!(symbol.name(), Ok("s1")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!( symbol.section(), diff --git a/tests/round_trip/common.rs b/tests/round_trip/common.rs index c63c7f48..a9238699 100644 --- a/tests/round_trip/common.rs +++ b/tests/round_trip/common.rs @@ -1,6 +1,6 @@ #![cfg(all(feature = "read", feature = "write"))] -use object::read::{Object, ObjectSection}; +use object::read::{Object, ObjectSection, ObjectSymbol}; use object::{read, write}; use object::{ Architecture, BinaryFormat, Endianness, SectionKind, SymbolFlags, SymbolKind, SymbolScope, @@ -58,9 +58,9 @@ fn coff_x86_64_common() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("v1")); + assert_eq!(symbol.name(), Ok("v1")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section(), read::SymbolSection::Common); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -69,9 +69,9 @@ fn coff_x86_64_common() { assert_eq!(symbol.address(), 0); assert_eq!(symbol.size(), 4); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("v2")); + assert_eq!(symbol.name(), Ok("v2")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section(), read::SymbolSection::Common); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -80,12 +80,12 @@ fn coff_x86_64_common() { assert_eq!(symbol.address(), 0); assert_eq!(symbol.size(), 8); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("v3")); + assert_eq!(symbol.name(), Ok("v3")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section(), read::SymbolSection::Undefined); - assert_eq!(symbol.scope(), SymbolScope::Unknown); + assert_eq!(symbol.scope(), SymbolScope::Linkage); assert_eq!(symbol.is_weak(), false); assert_eq!(symbol.is_undefined(), true); assert_eq!(symbol.address(), 0); @@ -134,13 +134,13 @@ fn elf_x86_64_common() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("")); + assert_eq!(symbol.name(), Ok("")); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("v1")); + assert_eq!(symbol.name(), Ok("v1")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section(), read::SymbolSection::Common); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -149,9 +149,9 @@ fn elf_x86_64_common() { assert_eq!(symbol.address(), 0); assert_eq!(symbol.size(), 4); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("v2")); + assert_eq!(symbol.name(), Ok("v2")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section(), read::SymbolSection::Common); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -223,9 +223,9 @@ fn macho_x86_64_common() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("_v1")); + assert_eq!(symbol.name(), Ok("_v1")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section_index(), Some(common_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -233,9 +233,9 @@ fn macho_x86_64_common() { assert_eq!(symbol.is_undefined(), false); assert_eq!(symbol.address(), 0); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("_v2")); + assert_eq!(symbol.name(), Ok("_v2")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section_index(), Some(common_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); diff --git a/tests/round_trip/elf.rs b/tests/round_trip/elf.rs index 12b21369..b5bb11ca 100644 --- a/tests/round_trip/elf.rs +++ b/tests/round_trip/elf.rs @@ -1,5 +1,5 @@ use object::read::elf::{FileHeader, SectionHeader}; -use object::read::Object; +use object::read::{Object, ObjectSymbol}; use object::{ elf, read, write, Architecture, BinaryFormat, Bytes, Endianness, LittleEndian, SectionIndex, SectionKind, SymbolFlags, SymbolKind, SymbolScope, SymbolSection, U32, @@ -34,10 +34,10 @@ fn symtab_shndx() { assert_eq!(object.format(), BinaryFormat::Elf); assert_eq!(object.architecture(), Architecture::X86_64); - for (index, symbol) in object.symbols().skip(1) { + for symbol in object.symbols().skip(1) { assert_eq!( symbol.section(), - SymbolSection::Section(SectionIndex(index.0)) + SymbolSection::Section(SectionIndex(symbol.index().0)) ); } } diff --git a/tests/round_trip/mod.rs b/tests/round_trip/mod.rs index df308b9b..cf82b81c 100644 --- a/tests/round_trip/mod.rs +++ b/tests/round_trip/mod.rs @@ -1,6 +1,6 @@ #![cfg(all(feature = "read", feature = "write"))] -use object::read::{Object, ObjectSection}; +use object::read::{Object, ObjectSection, ObjectSymbol}; use object::{read, write}; use object::{ Architecture, BinaryFormat, Endianness, RelocationEncoding, RelocationKind, SectionKind, @@ -69,18 +69,19 @@ fn coff_x86_64() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("file.c")); + assert_eq!(symbol.name(), Ok("file.c")); assert_eq!(symbol.address(), 0); assert_eq!(symbol.kind(), SymbolKind::File); assert_eq!(symbol.section(), SymbolSection::None); assert_eq!(symbol.scope(), SymbolScope::Compilation); assert_eq!(symbol.is_weak(), false); - let (func1_symbol, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("func1")); + let func1_symbol = symbol.index(); + assert_eq!(symbol.name(), Ok("func1")); assert_eq!(symbol.address(), func1_offset); assert_eq!(symbol.kind(), SymbolKind::Text); assert_eq!(symbol.section_index(), Some(text_index)); @@ -101,6 +102,12 @@ fn coff_x86_64() { read::RelocationTarget::Symbol(func1_symbol) ); assert_eq!(relocation.addend(), 0); + + let map = object.symbol_map(); + let symbol = map.get(func1_offset + 1).unwrap(); + assert_eq!(symbol.address(), func1_offset); + assert_eq!(symbol.name(), "func1"); + assert_eq!(map.get(func1_offset - 1), None); } #[test] @@ -166,9 +173,9 @@ fn elf_x86_64() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("")); + assert_eq!(symbol.name(), Ok("")); assert_eq!(symbol.address(), 0); assert_eq!(symbol.kind(), SymbolKind::Null); assert_eq!(symbol.section_index(), None); @@ -176,18 +183,19 @@ fn elf_x86_64() { assert_eq!(symbol.is_weak(), false); assert_eq!(symbol.is_undefined(), true); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("file.c")); + assert_eq!(symbol.name(), Ok("file.c")); assert_eq!(symbol.address(), 0); assert_eq!(symbol.kind(), SymbolKind::File); assert_eq!(symbol.section(), SymbolSection::None); assert_eq!(symbol.scope(), SymbolScope::Compilation); assert_eq!(symbol.is_weak(), false); - let (func1_symbol, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("func1")); + let func1_symbol = symbol.index(); + assert_eq!(symbol.name(), Ok("func1")); assert_eq!(symbol.address(), func1_offset); assert_eq!(symbol.kind(), SymbolKind::Text); assert_eq!(symbol.section_index(), Some(text_index)); @@ -208,6 +216,12 @@ fn elf_x86_64() { read::RelocationTarget::Symbol(func1_symbol) ); assert_eq!(relocation.addend(), 0); + + let map = object.symbol_map(); + let symbol = map.get(func1_offset + 1).unwrap(); + assert_eq!(symbol.address(), func1_offset); + assert_eq!(symbol.name(), "func1"); + assert_eq!(map.get(func1_offset - 1), None); } #[test] @@ -283,9 +297,10 @@ fn macho_x86_64() { let mut symbols = object.symbols(); - let (func1_symbol, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("_func1")); + let func1_symbol = symbol.index(); + assert_eq!(symbol.name(), Ok("_func1")); assert_eq!(symbol.address(), func1_offset); assert_eq!(symbol.kind(), SymbolKind::Text); assert_eq!(symbol.section_index(), Some(text_index)); @@ -318,4 +333,10 @@ fn macho_x86_64() { read::RelocationTarget::Symbol(func1_symbol) ); assert_eq!(relocation.addend(), -4); + + let map = object.symbol_map(); + let symbol = map.get(func1_offset + 1).unwrap(); + assert_eq!(symbol.address(), func1_offset); + assert_eq!(symbol.name(), "_func1"); + assert_eq!(map.get(func1_offset - 1), None); } diff --git a/tests/round_trip/tls.rs b/tests/round_trip/tls.rs index 6d577658..7a438b45 100644 --- a/tests/round_trip/tls.rs +++ b/tests/round_trip/tls.rs @@ -1,6 +1,6 @@ #![cfg(all(feature = "read", feature = "write"))] -use object::read::{Object, ObjectSection}; +use object::read::{Object, ObjectSection, ObjectSymbol}; use object::{read, write}; use object::{ Architecture, BinaryFormat, Endianness, RelocationEncoding, RelocationKind, SectionKind, @@ -45,9 +45,9 @@ fn coff_x86_64_tls() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("tls1")); + assert_eq!(symbol.name(), Ok("tls1")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section_index(), Some(tls_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -118,13 +118,13 @@ fn elf_x86_64_tls() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("")); + assert_eq!(symbol.name(), Ok("")); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("tls1")); + assert_eq!(symbol.name(), Ok("tls1")); assert_eq!(symbol.kind(), SymbolKind::Tls); assert_eq!(symbol.section_index(), Some(tdata_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -132,9 +132,9 @@ fn elf_x86_64_tls() { assert_eq!(symbol.is_undefined(), false); assert_eq!(symbol.size(), 30); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("tls2")); + assert_eq!(symbol.name(), Ok("tls2")); assert_eq!(symbol.kind(), SymbolKind::Tls); assert_eq!(symbol.section_index(), Some(tbss_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -216,45 +216,48 @@ fn macho_x86_64_tls() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("_tls1")); + assert_eq!(symbol.name(), Ok("_tls1")); assert_eq!(symbol.kind(), SymbolKind::Tls); assert_eq!(symbol.section_index(), Some(thread_vars_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); assert_eq!(symbol.is_weak(), false); assert_eq!(symbol.is_undefined(), false); - let (tls1_init_symbol, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("_tls1$tlv$init")); + let tls1_init_symbol = symbol.index(); + assert_eq!(symbol.name(), Ok("_tls1$tlv$init")); assert_eq!(symbol.kind(), SymbolKind::Tls); assert_eq!(symbol.section_index(), Some(thread_data_index)); assert_eq!(symbol.scope(), SymbolScope::Compilation); assert_eq!(symbol.is_weak(), false); assert_eq!(symbol.is_undefined(), false); - let (tlv_bootstrap_symbol, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("__tlv_bootstrap")); + let tlv_bootstrap_symbol = symbol.index(); + assert_eq!(symbol.name(), Ok("__tlv_bootstrap")); assert_eq!(symbol.kind(), SymbolKind::Unknown); assert_eq!(symbol.section_index(), None); assert_eq!(symbol.scope(), SymbolScope::Unknown); assert_eq!(symbol.is_weak(), false); assert_eq!(symbol.is_undefined(), true); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("_tls2")); + assert_eq!(symbol.name(), Ok("_tls2")); assert_eq!(symbol.kind(), SymbolKind::Tls); assert_eq!(symbol.section_index(), Some(thread_vars_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); assert_eq!(symbol.is_weak(), false); assert_eq!(symbol.is_undefined(), false); - let (tls2_init_symbol, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("_tls2$tlv$init")); + let tls2_init_symbol = symbol.index(); + assert_eq!(symbol.name(), Ok("_tls2$tlv$init")); assert_eq!(symbol.kind(), SymbolKind::Tls); assert_eq!(symbol.section_index(), Some(thread_bss_index)); assert_eq!(symbol.scope(), SymbolScope::Compilation);