Navigation Menu

Skip to content

Commit

Permalink
Replace Symbol with a trait
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
philipc committed Sep 21, 2020
1 parent f727066 commit 4299e27
Show file tree
Hide file tree
Showing 23 changed files with 1,515 additions and 689 deletions.
11 changes: 7 additions & 4 deletions 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};

Expand Down Expand Up @@ -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, &section_kinds);
}
println!();

println!("Dynamic symbols:");
for (_, symbol) in file.dynamic_symbols() {
for symbol in file.dynamic_symbols() {
print_symbol(&symbol, &section_kinds);
}
}
}

fn print_symbol(symbol: &Symbol<'_>, section_kinds: &HashMap<SectionIndex, SectionKind>) {
fn print_symbol(symbol: &Symbol<'_, '_>, section_kinds: &HashMap<SectionIndex, SectionKind>) {
if let SymbolKind::Section | SymbolKind::File = symbol.kind() {
return;
}
Expand Down
8 changes: 4 additions & 4 deletions examples/objcopy.rs
Expand Up @@ -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() {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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() {
Expand Down
6 changes: 3 additions & 3 deletions 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() {
Expand Down Expand Up @@ -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() {
Expand Down
193 changes: 186 additions & 7 deletions src/read/any.rs
Expand Up @@ -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.
Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -292,8 +295,10 @@ where
}
}

fn symbol_by_index(&self, index: SymbolIndex) -> Result<Symbol<'data>> {
with_inner!(self.inner, FileInternal, |x| x.symbol_by_index(index))
fn symbol_by_index(&'file self, index: SymbolIndex) -> Result<Symbol<'data, 'file>> {
map_inner_option!(self.inner, FileInternal, SymbolInternal, |x| x
.symbol_by_index(index))
.map(|inner| Symbol { inner })
}

fn symbols(&'file self) -> SymbolIterator<'data, 'file> {
Expand All @@ -303,14 +308,26 @@ where
}
}

fn symbol_table(&'file self) -> Option<SymbolTable<'data, 'file>> {
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
.dynamic_symbols()),
}
}

fn symbol_map(&self) -> SymbolMap<'data> {
fn dynamic_symbol_table(&'file self) -> Option<SymbolTable<'data, 'file>> {
map_inner_option!(self.inner, FileInternal, SymbolTableInternal, |x| x
.dynamic_symbol_table())
.map(|inner| SymbolTable { inner })
}

fn symbol_map(&self) -> SymbolMap<SymbolMapName<'data>> {
with_inner!(self.inner, FileInternal, |x| x.symbol_map())
}

Expand Down Expand Up @@ -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<Self::Symbol> {
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>
Expand Down Expand Up @@ -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<Self::Item> {
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("<invalid>"))
.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<SectionIndex> {
with_inner!(self.inner, SymbolInternal, |x| x.flags())
}
}

Expand Down
32 changes: 26 additions & 6 deletions src/read/coff/comdat.rs
Expand Up @@ -22,7 +22,12 @@ impl<'data, 'file> Iterator for CoffComdatIterator<'data, 'file> {
fn next(&mut self) -> Option<Self::Item> {
loop {
let index = self.index;
let symbol = self.file.symbols.get::<pe::ImageSymbol>(index)?;
let symbol = self
.file
.common
.symbols
.get::<pe::ImageSymbol>(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);
Expand Down Expand Up @@ -59,7 +64,11 @@ impl<'data, 'file> CoffComdat<'data, 'file> {
}

// Auxiliary record must have a non-associative selection.
let aux = file.symbols.get::<pe::ImageAuxSymbolSection>(index + 1)?;
let aux = file
.common
.symbols
.get::<pe::ImageAuxSymbolSection>(index + 1)
.ok()?;
let selection = aux.selection;
if selection == 0 || selection == pe::IMAGE_COMDAT_SELECT_ASSOCIATIVE {
return None;
Expand All @@ -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::<pe::ImageSymbol>(symbol_index)?;
symbol = file
.common
.symbols
.get::<pe::ImageSymbol>(symbol_index)
.ok()?;
if section_number == symbol.section_number.get(LE) {
break;
}
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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::<pe::ImageSymbol>(index)?;
let symbol = self
.file
.common
.symbols
.get::<pe::ImageSymbol>(index)
.ok()?;
self.index += 1 + symbol.number_of_aux_symbols as usize;

// Must be a section symbol.
Expand All @@ -163,8 +181,10 @@ impl<'data, 'file> Iterator for CoffComdatSectionIterator<'data, 'file> {

let aux = self
.file
.common
.symbols
.get::<pe::ImageAuxSymbolSection>(index + 1)?;
.get::<pe::ImageAuxSymbolSection>(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 {
Expand Down

0 comments on commit 4299e27

Please sign in to comment.