Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose dynamic symbols in ELF files #421

Merged
merged 1 commit into from
Aug 24, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 55 additions & 26 deletions symbolic-debuginfo/src/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ use std::io::Cursor;

use flate2::{Decompress, FlushDecompress};
use goblin::elf::compression_header::{CompressionHeader, ELFCOMPRESS_ZLIB};
use goblin::elf::SectionHeader;
use goblin::elf64::sym::SymIterator;
use goblin::strtab::Strtab;
use goblin::{container::Ctx, elf, strtab};
use thiserror::Error;

Expand Down Expand Up @@ -214,14 +217,16 @@ impl<'data> ElfObject<'data> {

/// Determines whether this object exposes a public symbol table.
pub fn has_symbols(&self) -> bool {
!self.elf.syms.is_empty()
!self.elf.syms.is_empty() || !self.elf.dynsyms.is_empty()
}

/// Returns an iterator over symbols in the public symbol table.
pub fn symbols(&self) -> ElfSymbolIterator<'data, '_> {
ElfSymbolIterator {
symbols: self.elf.syms.iter(),
strtab: &self.elf.strtab,
dynamic_symbols: self.elf.dynsyms.iter(),
dynamic_strtab: &self.elf.dynstrtab,
sections: &self.elf.section_headers,
load_addr: self.load_address(),
}
Expand Down Expand Up @@ -542,6 +547,8 @@ impl<'data> Dwarf<'data> for ElfObject<'data> {
pub struct ElfSymbolIterator<'data, 'object> {
symbols: elf::sym::SymIterator<'data>,
strtab: &'object strtab::Strtab<'data>,
dynamic_symbols: elf::sym::SymIterator<'data>,
dynamic_strtab: &'object strtab::Strtab<'data>,
sections: &'object [elf::SectionHeader],
load_addr: u64,
}
Expand All @@ -550,37 +557,59 @@ impl<'data, 'object> Iterator for ElfSymbolIterator<'data, 'object> {
type Item = Symbol<'data>;

fn next(&mut self) -> Option<Self::Item> {
for symbol in &mut self.symbols {
// Only check for function symbols.
if symbol.st_type() != elf::sym::STT_FUNC {
continue;
}
fn get_symbols<'data>(
symbols: &mut SymIterator,
strtab: &Strtab<'data>,
load_addr: u64,
sections: &[SectionHeader],
) -> Option<Symbol<'data>> {
for symbol in symbols {
// Only check for function symbols.
if symbol.st_type() != elf::sym::STT_FUNC {
continue;
}

// Sanity check of the symbol address. Since we only intend to iterate over function
// symbols, they need to be mapped after the image's load address.
if symbol.st_value < self.load_addr {
continue;
}
// Sanity check of the symbol address. Since we only intend to iterate over function
// symbols, they need to be mapped after the image's load address.
if symbol.st_value < load_addr {
continue;
}

let section = match symbol.st_shndx {
self::SHN_UNDEF => None,
index => self.sections.get(index),
};
let section = match symbol.st_shndx {
self::SHN_UNDEF => None,
index => sections.get(index),
};

// We are only interested in symbols pointing into sections with executable flag.
if !section.map_or(false, |header| header.is_executable()) {
continue;
}
// We are only interested in symbols pointing into sections with executable flag.
if !section.map_or(false, |header| header.is_executable()) {
continue;
}

let name = self.strtab.get_at(symbol.st_name).map(Cow::Borrowed);
let name = strtab.get_at(symbol.st_name).map(Cow::Borrowed);

return Some(Symbol {
name,
address: symbol.st_value - self.load_addr,
size: symbol.st_size,
});
return Some(Symbol {
name,
address: symbol.st_value - load_addr,
size: symbol.st_size,
});
}

None
}

None
get_symbols(
&mut self.symbols,
self.strtab,
self.load_addr,
self.sections,
)
.or_else(|| {
get_symbols(
&mut self.dynamic_symbols,
self.dynamic_strtab,
self.load_addr,
self.sections,
)
})
}
}