Deprioritize generated GCC symbols in find_section_symbol

Resolves #115
This commit is contained in:
Luke Street 2024-10-07 19:49:52 -06:00
parent 9596051cb4
commit ab2e84a2c6
1 changed files with 80 additions and 40 deletions

View File

@ -152,16 +152,15 @@ fn symbols_by_section(
arch: &dyn ObjArch, arch: &dyn ObjArch,
obj_file: &File<'_>, obj_file: &File<'_>,
section: &ObjSection, section: &ObjSection,
section_symbols: &[Symbol<'_, '_>],
split_meta: Option<&SplitMeta>, split_meta: Option<&SplitMeta>,
name_counts: &mut HashMap<String, u32>, name_counts: &mut HashMap<String, u32>,
) -> Result<Vec<ObjSymbol>> { ) -> Result<Vec<ObjSymbol>> {
let mut result = Vec::<ObjSymbol>::new(); let mut result = Vec::<ObjSymbol>::new();
for symbol in obj_file.symbols() { for symbol in section_symbols {
if symbol.kind() == SymbolKind::Section { if symbol.kind() == SymbolKind::Section {
continue; continue;
} }
if let Some(index) = symbol.section().index() {
if index.0 == section.orig_index {
if symbol.is_local() && section.kind == ObjSectionKind::Code { if symbol.is_local() && section.kind == ObjSectionKind::Code {
// TODO strip local syms in diff? // TODO strip local syms in diff?
let name = symbol.name().context("Failed to process symbol name")?; let name = symbol.name().context("Failed to process symbol name")?;
@ -169,9 +168,7 @@ fn symbols_by_section(
continue; continue;
} }
} }
result.push(to_obj_symbol(arch, obj_file, &symbol, 0, split_meta)?); result.push(to_obj_symbol(arch, obj_file, symbol, 0, split_meta)?);
}
}
} }
result.sort_by(|a, b| a.address.cmp(&b.address).then(a.size.cmp(&b.size))); result.sort_by(|a, b| a.address.cmp(&b.address).then(a.size.cmp(&b.size)));
let mut iter = result.iter_mut().peekable(); let mut iter = result.iter_mut().peekable();
@ -221,47 +218,71 @@ fn common_symbols(
.collect::<Result<Vec<ObjSymbol>>>() .collect::<Result<Vec<ObjSymbol>>>()
} }
const LOW_PRIORITY_SYMBOLS: &[&str] =
&["__gnu_compiled_c", "__gnu_compiled_cplusplus", "gcc2_compiled."];
fn best_symbol<'r, 'data, 'file>(
symbols: &'r [Symbol<'data, 'file>],
address: u64,
) -> Option<&'r Symbol<'data, 'file>> {
let closest_symbol_index = match symbols.binary_search_by_key(&address, |s| s.address()) {
Ok(index) => Some(index),
Err(index) => index.checked_sub(1),
}?;
let mut best_symbol: Option<&'r Symbol<'data, 'file>> = None;
for symbol in symbols.iter().skip(closest_symbol_index) {
if symbol.address() > address {
break;
}
if symbol.kind() == SymbolKind::Section
|| (symbol.size() > 0 && (symbol.address() + symbol.size()) <= address)
{
continue;
}
// TODO priority ranking with visibility, etc
if let Some(best) = best_symbol {
if LOW_PRIORITY_SYMBOLS.contains(&best.name().unwrap_or_default())
&& !LOW_PRIORITY_SYMBOLS.contains(&symbol.name().unwrap_or_default())
{
best_symbol = Some(symbol);
}
} else {
best_symbol = Some(symbol);
}
}
best_symbol
}
fn find_section_symbol( fn find_section_symbol(
arch: &dyn ObjArch, arch: &dyn ObjArch,
obj_file: &File<'_>, obj_file: &File<'_>,
section_symbols: &[Symbol<'_, '_>],
target: &Symbol<'_, '_>, target: &Symbol<'_, '_>,
address: u64, address: u64,
split_meta: Option<&SplitMeta>, split_meta: Option<&SplitMeta>,
) -> Result<ObjSymbol> { ) -> Result<ObjSymbol> {
if let Some(symbol) = best_symbol(section_symbols, address) {
return to_obj_symbol(
arch,
obj_file,
symbol,
address as i64 - symbol.address() as i64,
split_meta,
);
}
// Fallback to section symbol
let section_index = let section_index =
target.section_index().ok_or_else(|| anyhow::Error::msg("Unknown section index"))?; target.section_index().ok_or_else(|| anyhow::Error::msg("Unknown section index"))?;
let section = obj_file.section_by_index(section_index)?; let section = obj_file.section_by_index(section_index)?;
let mut closest_symbol: Option<Symbol<'_, '_>> = None;
for symbol in obj_file.symbols() {
if !matches!(symbol.section_index(), Some(idx) if idx == section_index) {
continue;
}
if symbol.kind() == SymbolKind::Section || symbol.address() != address {
if symbol.address() < address
&& symbol.size() != 0
&& (closest_symbol.is_none()
|| matches!(&closest_symbol, Some(s) if s.address() <= symbol.address()))
{
closest_symbol = Some(symbol);
}
continue;
}
return to_obj_symbol(arch, obj_file, &symbol, 0, split_meta);
}
let (name, offset) = closest_symbol
.and_then(|s| s.name().map(|n| (n, s.address())).ok())
.or_else(|| section.name().map(|n| (n, section.address())).ok())
.unwrap_or(("<unknown>", 0));
let offset_addr = address - offset;
Ok(ObjSymbol { Ok(ObjSymbol {
name: name.to_string(), name: section.name()?.to_string(),
demangled_name: None, demangled_name: None,
address: offset, address: section.address(),
section_address: address - section.address(), section_address: 0,
size: 0, size: 0,
size_known: false, size_known: false,
flags: Default::default(), flags: Default::default(),
addend: offset_addr as i64, addend: address as i64 - section.address() as i64,
virtual_address: None, virtual_address: None,
original_index: None, original_index: None,
bytes: Vec::new(), bytes: Vec::new(),
@ -272,6 +293,7 @@ fn relocations_by_section(
arch: &dyn ObjArch, arch: &dyn ObjArch,
obj_file: &File<'_>, obj_file: &File<'_>,
section: &ObjSection, section: &ObjSection,
section_symbols: &[Symbol<'_, '_>],
split_meta: Option<&SplitMeta>, split_meta: Option<&SplitMeta>,
) -> Result<Vec<ObjReloc>> { ) -> Result<Vec<ObjReloc>> {
let obj_section = obj_file.section_by_index(SectionIndex(section.orig_index))?; let obj_section = obj_file.section_by_index(SectionIndex(section.orig_index))?;
@ -315,7 +337,14 @@ fn relocations_by_section(
} }
SymbolKind::Section => { SymbolKind::Section => {
ensure!(addend >= 0, "Negative addend in reloc: {addend}"); ensure!(addend >= 0, "Negative addend in reloc: {addend}");
find_section_symbol(arch, obj_file, &symbol, addend as u64, split_meta) find_section_symbol(
arch,
obj_file,
section_symbols,
&symbol,
addend as u64,
split_meta,
)
} }
kind => Err(anyhow!("Unhandled relocation symbol type {kind:?}")), kind => Err(anyhow!("Unhandled relocation symbol type {kind:?}")),
}?; }?;
@ -650,15 +679,26 @@ pub fn parse(data: &[u8], config: &DiffObjConfig) -> Result<ObjInfo> {
let mut sections = filter_sections(&obj_file, split_meta.as_ref())?; let mut sections = filter_sections(&obj_file, split_meta.as_ref())?;
let mut name_counts: HashMap<String, u32> = HashMap::new(); let mut name_counts: HashMap<String, u32> = HashMap::new();
for section in &mut sections { for section in &mut sections {
let mut symbols = obj_file
.symbols()
.filter(|s| s.section_index() == Some(SectionIndex(section.orig_index)))
.collect::<Vec<_>>();
symbols.sort_by_key(|s| s.address());
section.symbols = symbols_by_section( section.symbols = symbols_by_section(
arch.as_ref(), arch.as_ref(),
&obj_file, &obj_file,
section, section,
&symbols,
split_meta.as_ref(), split_meta.as_ref(),
&mut name_counts, &mut name_counts,
)?; )?;
section.relocations = section.relocations = relocations_by_section(
relocations_by_section(arch.as_ref(), &obj_file, section, split_meta.as_ref())?; arch.as_ref(),
&obj_file,
section,
&symbols,
split_meta.as_ref(),
)?;
} }
if config.combine_data_sections { if config.combine_data_sections {
combine_data_sections(&mut sections)?; combine_data_sections(&mut sections)?;