mirror of https://github.com/encounter/objdiff.git
Cleanup & move extab code into ppc arch
This commit is contained in:
parent
c7e6394628
commit
dcf209aac5
|
@ -41,6 +41,10 @@ pub trait ObjArch: Send + Sync {
|
||||||
fn display_reloc(&self, flags: RelocationFlags) -> Cow<'static, str>;
|
fn display_reloc(&self, flags: RelocationFlags) -> Cow<'static, str>;
|
||||||
|
|
||||||
fn symbol_address(&self, symbol: &Symbol) -> u64 { symbol.address() }
|
fn symbol_address(&self, symbol: &Symbol) -> u64 { symbol.address() }
|
||||||
|
|
||||||
|
// Downcast methods
|
||||||
|
#[cfg(feature = "ppc")]
|
||||||
|
fn ppc(&self) -> Option<&ppc::ObjArchPpc> { None }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ProcessCodeResult {
|
pub struct ProcessCodeResult {
|
||||||
|
@ -48,7 +52,7 @@ pub struct ProcessCodeResult {
|
||||||
pub insts: Vec<ObjIns>,
|
pub insts: Vec<ObjIns>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_arch(object: &object::File) -> Result<Box<dyn ObjArch>> {
|
pub fn new_arch(object: &File) -> Result<Box<dyn ObjArch>> {
|
||||||
Ok(match object.architecture() {
|
Ok(match object.architecture() {
|
||||||
#[cfg(feature = "ppc")]
|
#[cfg(feature = "ppc")]
|
||||||
Architecture::PowerPc => Box::new(ppc::ObjArchPpc::new(object)?),
|
Architecture::PowerPc => Box::new(ppc::ObjArchPpc::new(object)?),
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
use std::{borrow::Cow, collections::BTreeMap};
|
use std::{borrow::Cow, collections::BTreeMap};
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, ensure, Result};
|
||||||
use object::{elf, File, Relocation, RelocationFlags};
|
use cwextab::{decode_extab, ExceptionTableData};
|
||||||
|
use object::{
|
||||||
|
elf, File, Object, ObjectSection, ObjectSymbol, Relocation, RelocationFlags, RelocationTarget,
|
||||||
|
Symbol, SymbolKind,
|
||||||
|
};
|
||||||
use ppc750cl::{Argument, InsIter, GPR};
|
use ppc750cl::{Argument, InsIter, GPR};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{ObjArch, ProcessCodeResult},
|
arch::{ObjArch, ProcessCodeResult},
|
||||||
diff::DiffObjConfig,
|
diff::DiffObjConfig,
|
||||||
obj::{ObjIns, ObjInsArg, ObjInsArgValue, ObjReloc, ObjSection},
|
obj::{ObjIns, ObjInsArg, ObjInsArgValue, ObjReloc, ObjSection, ObjSymbol},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Relative relocation, can be Simm, Offset or BranchDest
|
// Relative relocation, can be Simm, Offset or BranchDest
|
||||||
|
@ -22,10 +26,13 @@ fn is_rel_abs_arg(arg: &Argument) -> bool {
|
||||||
|
|
||||||
fn is_offset_arg(arg: &Argument) -> bool { matches!(arg, Argument::Offset(_)) }
|
fn is_offset_arg(arg: &Argument) -> bool { matches!(arg, Argument::Offset(_)) }
|
||||||
|
|
||||||
pub struct ObjArchPpc {}
|
pub struct ObjArchPpc {
|
||||||
|
/// Exception info
|
||||||
|
pub extab: Option<BTreeMap<usize, ExceptionInfo>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl ObjArchPpc {
|
impl ObjArchPpc {
|
||||||
pub fn new(_file: &File) -> Result<Self> { Ok(Self {}) }
|
pub fn new(file: &File) -> Result<Self> { Ok(Self { extab: decode_exception_info(file)? }) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjArch for ObjArchPpc {
|
impl ObjArch for ObjArchPpc {
|
||||||
|
@ -178,6 +185,14 @@ impl ObjArch for ObjArchPpc {
|
||||||
_ => Cow::Owned(format!("<{flags:?}>")),
|
_ => Cow::Owned(format!("<{flags:?}>")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ppc(&self) -> Option<&ObjArchPpc> { Some(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjArchPpc {
|
||||||
|
pub fn extab_for_symbol(&self, symbol: &ObjSymbol) -> Option<&ExceptionInfo> {
|
||||||
|
symbol.original_index.and_then(|i| self.extab.as_ref()?.get(&i))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_reloc(args: &mut Vec<ObjInsArg>, reloc: &ObjReloc) -> Result<()> {
|
fn push_reloc(args: &mut Vec<ObjInsArg>, reloc: &ObjReloc) -> Result<()> {
|
||||||
|
@ -208,3 +223,128 @@ fn push_reloc(args: &mut Vec<ObjInsArg>, reloc: &ObjReloc) -> Result<()> {
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ExtabSymbolRef {
|
||||||
|
pub original_index: usize,
|
||||||
|
pub name: String,
|
||||||
|
pub demangled_name: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ExceptionInfo {
|
||||||
|
pub eti_symbol: ExtabSymbolRef,
|
||||||
|
pub etb_symbol: ExtabSymbolRef,
|
||||||
|
pub data: ExceptionTableData,
|
||||||
|
pub dtors: Vec<ExtabSymbolRef>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_exception_info(file: &File<'_>) -> Result<Option<BTreeMap<usize, ExceptionInfo>>> {
|
||||||
|
let Some(extab_section) = file.section_by_name("extab") else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
let Some(extabindex_section) = file.section_by_name("extabindex") else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut result = BTreeMap::new();
|
||||||
|
let extab_relocations = extab_section.relocations().collect::<BTreeMap<u64, Relocation>>();
|
||||||
|
let extabindex_relocations =
|
||||||
|
extabindex_section.relocations().collect::<BTreeMap<u64, Relocation>>();
|
||||||
|
|
||||||
|
for extabindex in file.symbols().filter(|symbol| {
|
||||||
|
symbol.section_index() == Some(extabindex_section.index())
|
||||||
|
&& symbol.kind() == SymbolKind::Data
|
||||||
|
}) {
|
||||||
|
if extabindex.size() != 12 {
|
||||||
|
log::warn!("Invalid extabindex entry size {}", extabindex.size());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each extabindex entry has two relocations:
|
||||||
|
// - 0x0: The function that the exception table is for
|
||||||
|
// - 0x8: The relevant entry in extab section
|
||||||
|
let Some(extab_func_reloc) = extabindex_relocations.get(&extabindex.address()) else {
|
||||||
|
log::warn!("Failed to find function relocation for extabindex entry");
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let Some(extab_reloc) = extabindex_relocations.get(&(extabindex.address() + 8)) else {
|
||||||
|
log::warn!("Failed to find extab relocation for extabindex entry");
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Resolve the function and extab symbols
|
||||||
|
let Some(extab_func) = relocation_symbol(file, extab_func_reloc)? else {
|
||||||
|
log::warn!("Failed to find function symbol for extabindex entry");
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let extab_func_name = extab_func.name()?;
|
||||||
|
let Some(extab) = relocation_symbol(file, extab_reloc)? else {
|
||||||
|
log::warn!("Failed to find extab symbol for extabindex entry");
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let extab_start_addr = extab.address() - extab_section.address();
|
||||||
|
let extab_end_addr = extab_start_addr + extab.size();
|
||||||
|
|
||||||
|
// All relocations in the extab section are dtors
|
||||||
|
let mut dtors: Vec<ExtabSymbolRef> = vec![];
|
||||||
|
for (_, reloc) in extab_relocations.range(extab_start_addr..extab_end_addr) {
|
||||||
|
let Some(symbol) = relocation_symbol(file, reloc)? else {
|
||||||
|
log::warn!("Failed to find symbol for extab relocation");
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
dtors.push(make_symbol_ref(&symbol)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the extab data
|
||||||
|
let Some(extab_data) = extab_section.data_range(extab_start_addr, extab.size())? else {
|
||||||
|
log::warn!("Failed to get extab data for function {}", extab_func_name);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let data = match decode_extab(extab_data) {
|
||||||
|
Some(decoded_data) => decoded_data,
|
||||||
|
None => {
|
||||||
|
log::warn!("Exception table decoding failed for function {}", extab_func_name);
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Add the new entry to the list
|
||||||
|
result.insert(extab_func.index().0, ExceptionInfo {
|
||||||
|
eti_symbol: make_symbol_ref(&extabindex)?,
|
||||||
|
etb_symbol: make_symbol_ref(&extab)?,
|
||||||
|
data,
|
||||||
|
dtors,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Some(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn relocation_symbol<'data, 'file>(
|
||||||
|
file: &'file File<'data>,
|
||||||
|
relocation: &Relocation,
|
||||||
|
) -> Result<Option<Symbol<'data, 'file>>> {
|
||||||
|
let addend = relocation.addend();
|
||||||
|
match relocation.target() {
|
||||||
|
RelocationTarget::Symbol(idx) => {
|
||||||
|
ensure!(addend == 0, "Symbol relocations must have zero addend");
|
||||||
|
Ok(Some(file.symbol_by_index(idx)?))
|
||||||
|
}
|
||||||
|
RelocationTarget::Section(idx) => {
|
||||||
|
ensure!(addend >= 0, "Section relocations must have non-negative addend");
|
||||||
|
let addend = addend as u64;
|
||||||
|
Ok(file
|
||||||
|
.symbols()
|
||||||
|
.find(|symbol| symbol.section_index() == Some(idx) && symbol.address() == addend))
|
||||||
|
}
|
||||||
|
target => bail!("Unsupported relocation target: {target:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_symbol_ref(symbol: &Symbol) -> Result<ExtabSymbolRef> {
|
||||||
|
let name = symbol.name()?.to_string();
|
||||||
|
let demangled_name = cwdemangle::demangle(&name, &cwdemangle::DemangleOptions::default());
|
||||||
|
Ok(ExtabSymbolRef { original_index: symbol.index().0, name, demangled_name })
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ pub mod split_meta;
|
||||||
|
|
||||||
use std::{borrow::Cow, collections::BTreeMap, fmt, path::PathBuf};
|
use std::{borrow::Cow, collections::BTreeMap, fmt, path::PathBuf};
|
||||||
|
|
||||||
use cwextab::*;
|
|
||||||
use filetime::FileTime;
|
use filetime::FileTime;
|
||||||
use flagset::{flags, FlagSet};
|
use flagset::{flags, FlagSet};
|
||||||
use object::RelocationFlags;
|
use object::RelocationFlags;
|
||||||
|
@ -24,6 +23,9 @@ flags! {
|
||||||
Weak,
|
Weak,
|
||||||
Common,
|
Common,
|
||||||
Hidden,
|
Hidden,
|
||||||
|
/// Has extra data associated with the symbol
|
||||||
|
/// (e.g. exception table entry)
|
||||||
|
HasExtra,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Debug, Copy, Clone, Default)]
|
#[derive(Debug, Copy, Clone, Default)]
|
||||||
|
@ -114,9 +116,6 @@ pub struct ObjIns {
|
||||||
pub struct ObjSymbol {
|
pub struct ObjSymbol {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub demangled_name: Option<String>,
|
pub demangled_name: Option<String>,
|
||||||
pub has_extab: bool,
|
|
||||||
pub extab_name: Option<String>,
|
|
||||||
pub extabindex_name: Option<String>,
|
|
||||||
pub address: u64,
|
pub address: u64,
|
||||||
pub section_address: u64,
|
pub section_address: u64,
|
||||||
pub size: u64,
|
pub size: u64,
|
||||||
|
@ -125,13 +124,8 @@ pub struct ObjSymbol {
|
||||||
pub addend: i64,
|
pub addend: i64,
|
||||||
/// Original virtual address (from .note.split section)
|
/// Original virtual address (from .note.split section)
|
||||||
pub virtual_address: Option<u64>,
|
pub virtual_address: Option<u64>,
|
||||||
}
|
/// Original index in object symbol table
|
||||||
|
pub original_index: Option<usize>,
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ObjExtab {
|
|
||||||
pub func: ObjSymbol,
|
|
||||||
pub data: ExceptionTableData,
|
|
||||||
pub dtors: Vec<ObjSymbol>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ObjInfo {
|
pub struct ObjInfo {
|
||||||
|
@ -141,8 +135,6 @@ pub struct ObjInfo {
|
||||||
pub sections: Vec<ObjSection>,
|
pub sections: Vec<ObjSection>,
|
||||||
/// Common BSS symbols
|
/// Common BSS symbols
|
||||||
pub common: Vec<ObjSymbol>,
|
pub common: Vec<ObjSymbol>,
|
||||||
/// Exception tables
|
|
||||||
pub extab: Option<Vec<ObjExtab>>,
|
|
||||||
/// Split object metadata (.note.split section)
|
/// Split object metadata (.note.split section)
|
||||||
pub split_meta: Option<SplitMeta>,
|
pub split_meta: Option<SplitMeta>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
use std::{collections::HashSet, fs, io::Cursor, mem::size_of, path::Path};
|
use std::{collections::HashSet, fs, io::Cursor, mem::size_of, path::Path};
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, ensure, Context, Result};
|
use anyhow::{anyhow, bail, ensure, Context, Result};
|
||||||
use cwextab::decode_extab;
|
|
||||||
use filetime::FileTime;
|
use filetime::FileTime;
|
||||||
use flagset::Flags;
|
use flagset::Flags;
|
||||||
use object::{
|
use object::{
|
||||||
endian::LittleEndian as LE,
|
endian::LittleEndian as LE,
|
||||||
pe::{ImageAuxSymbolFunctionBeginEnd, ImageLinenumber},
|
pe::{ImageAuxSymbolFunctionBeginEnd, ImageLinenumber},
|
||||||
read::coff::{CoffFile, CoffHeader, ImageSymbol},
|
read::coff::{CoffFile, CoffHeader, ImageSymbol},
|
||||||
Architecture, BinaryFormat, File, Object, ObjectSection, ObjectSymbol, RelocationTarget,
|
BinaryFormat, File, Object, ObjectSection, ObjectSymbol, RelocationTarget, SectionIndex,
|
||||||
SectionIndex, SectionKind, Symbol, SymbolIndex, SymbolKind, SymbolScope, SymbolSection,
|
SectionKind, Symbol, SymbolIndex, SymbolKind, SymbolScope, SymbolSection,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -17,8 +16,7 @@ use crate::{
|
||||||
diff::DiffObjConfig,
|
diff::DiffObjConfig,
|
||||||
obj::{
|
obj::{
|
||||||
split_meta::{SplitMeta, SPLITMETA_SECTION},
|
split_meta::{SplitMeta, SPLITMETA_SECTION},
|
||||||
ObjExtab, ObjInfo, ObjReloc, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlagSet,
|
ObjInfo, ObjReloc, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlagSet, ObjSymbolFlags,
|
||||||
ObjSymbolFlags,
|
|
||||||
},
|
},
|
||||||
util::{read_u16, read_u32},
|
util::{read_u16, read_u32},
|
||||||
};
|
};
|
||||||
|
@ -60,6 +58,13 @@ fn to_obj_symbol(
|
||||||
if obj_file.format() == BinaryFormat::Elf && symbol.scope() == SymbolScope::Linkage {
|
if obj_file.format() == BinaryFormat::Elf && symbol.scope() == SymbolScope::Linkage {
|
||||||
flags = ObjSymbolFlagSet(flags.0 | ObjSymbolFlags::Hidden);
|
flags = ObjSymbolFlagSet(flags.0 | ObjSymbolFlags::Hidden);
|
||||||
}
|
}
|
||||||
|
if arch
|
||||||
|
.ppc()
|
||||||
|
.and_then(|a| a.extab.as_ref())
|
||||||
|
.map_or(false, |e| e.contains_key(&symbol.index().0))
|
||||||
|
{
|
||||||
|
flags = ObjSymbolFlagSet(flags.0 | ObjSymbolFlags::HasExtra);
|
||||||
|
}
|
||||||
let address = arch.symbol_address(symbol);
|
let address = arch.symbol_address(symbol);
|
||||||
let section_address = if let Some(section) =
|
let section_address = if let Some(section) =
|
||||||
symbol.section_index().and_then(|idx| obj_file.section_by_index(idx).ok())
|
symbol.section_index().and_then(|idx| obj_file.section_by_index(idx).ok())
|
||||||
|
@ -76,9 +81,6 @@ fn to_obj_symbol(
|
||||||
Ok(ObjSymbol {
|
Ok(ObjSymbol {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
demangled_name,
|
demangled_name,
|
||||||
has_extab: false,
|
|
||||||
extab_name: None,
|
|
||||||
extabindex_name: None,
|
|
||||||
address,
|
address,
|
||||||
section_address,
|
section_address,
|
||||||
size: symbol.size(),
|
size: symbol.size(),
|
||||||
|
@ -86,6 +88,7 @@ fn to_obj_symbol(
|
||||||
flags,
|
flags,
|
||||||
addend,
|
addend,
|
||||||
virtual_address,
|
virtual_address,
|
||||||
|
original_index: Some(symbol.index().0),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,9 +171,6 @@ fn symbols_by_section(
|
||||||
result.push(ObjSymbol {
|
result.push(ObjSymbol {
|
||||||
name: format!("[{}]", section.name),
|
name: format!("[{}]", section.name),
|
||||||
demangled_name: None,
|
demangled_name: None,
|
||||||
has_extab: false,
|
|
||||||
extab_name: None,
|
|
||||||
extabindex_name: None,
|
|
||||||
address: 0,
|
address: 0,
|
||||||
section_address: 0,
|
section_address: 0,
|
||||||
size: section.size,
|
size: section.size,
|
||||||
|
@ -178,6 +178,7 @@ fn symbols_by_section(
|
||||||
flags: Default::default(),
|
flags: Default::default(),
|
||||||
addend: 0,
|
addend: 0,
|
||||||
virtual_address: None,
|
virtual_address: None,
|
||||||
|
original_index: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Ok(result)
|
Ok(result)
|
||||||
|
@ -195,111 +196,6 @@ fn common_symbols(
|
||||||
.collect::<Result<Vec<ObjSymbol>>>()
|
.collect::<Result<Vec<ObjSymbol>>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn section_by_name<'a>(sections: &'a mut [ObjSection], name: &str) -> Option<&'a mut ObjSection> {
|
|
||||||
sections.iter_mut().find(|section| section.name == name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn exception_tables(
|
|
||||||
sections: &mut [ObjSection],
|
|
||||||
obj_file: &File<'_>,
|
|
||||||
) -> Result<Option<Vec<ObjExtab>>> {
|
|
||||||
//PowerPC only
|
|
||||||
if obj_file.architecture() != Architecture::PowerPc {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Find the extab/extabindex sections
|
|
||||||
let extab_section = match section_by_name(sections, "extab") {
|
|
||||||
Some(section) => section.clone(),
|
|
||||||
None => {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let extabindex_section = match section_by_name(sections, "extabindex") {
|
|
||||||
Some(section) => section.clone(),
|
|
||||||
None => {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let text_section = match section_by_name(sections, ".text") {
|
|
||||||
Some(section) => section,
|
|
||||||
None => bail!(".text section is somehow missing, this should not happen"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut result: Vec<ObjExtab> = vec![];
|
|
||||||
let extab_symbol_count = extab_section.symbols.len();
|
|
||||||
let extabindex_symbol_count = extabindex_section.symbols.len();
|
|
||||||
let extab_reloc_count = extab_section.relocations.len();
|
|
||||||
let table_count = extab_symbol_count;
|
|
||||||
let mut extab_reloc_index: usize = 0;
|
|
||||||
|
|
||||||
//Make sure that the number of symbols in the extab/extabindex section matches. If not, exit early
|
|
||||||
if extab_symbol_count != extabindex_symbol_count {
|
|
||||||
bail!("Extab/Extabindex symbol counts do not match");
|
|
||||||
}
|
|
||||||
|
|
||||||
//Convert the extab/extabindex section data
|
|
||||||
|
|
||||||
//Go through each extabindex entry
|
|
||||||
for i in 0..table_count {
|
|
||||||
let extabindex = &extabindex_section.symbols[i];
|
|
||||||
|
|
||||||
/* Get the function symbol and extab symbol from the extabindex relocations array. Each extabindex
|
|
||||||
entry has two relocations (the first for the function, the second for the extab entry) */
|
|
||||||
let extab_func = extabindex_section.relocations[i * 2].target.clone();
|
|
||||||
let extab = &extabindex_section.relocations[(i * 2) + 1].target;
|
|
||||||
|
|
||||||
let extab_start_addr = extab.address;
|
|
||||||
let extab_end_addr = extab_start_addr + extab.size;
|
|
||||||
|
|
||||||
//Find the function in the text section, and set the has extab flag
|
|
||||||
for i in 0..text_section.symbols.len() {
|
|
||||||
let func = &mut text_section.symbols[i];
|
|
||||||
if func.name == extab_func.name {
|
|
||||||
func.has_extab = true;
|
|
||||||
func.extab_name = Some(extab.name.clone());
|
|
||||||
func.extabindex_name = Some(extabindex.name.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Iterate through the list of extab relocations, continuing until we hit a relocation
|
|
||||||
that isn't within the current extab symbol. Get the target dtor function symbol from
|
|
||||||
each relocation used, and add them to the list. */
|
|
||||||
let mut dtors: Vec<ObjSymbol> = vec![];
|
|
||||||
|
|
||||||
while extab_reloc_index < extab_reloc_count {
|
|
||||||
let extab_reloc = &extab_section.relocations[extab_reloc_index];
|
|
||||||
//If the current entry is past the current extab table, stop here
|
|
||||||
if extab_reloc.address >= extab_end_addr {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Otherwise, the current relocation is used by the current table
|
|
||||||
dtors.push(extab_reloc.target.clone());
|
|
||||||
//Go to the next entry
|
|
||||||
extab_reloc_index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Decode the extab data
|
|
||||||
let start_index = extab_start_addr as usize;
|
|
||||||
let end_index = extab_end_addr as usize;
|
|
||||||
let extab_data = extab_section.data[start_index..end_index].try_into().unwrap();
|
|
||||||
let data = match decode_extab(extab_data) {
|
|
||||||
Some(decoded_data) => decoded_data,
|
|
||||||
None => {
|
|
||||||
log::warn!("Exception table decoding failed for function {}", extab_func.name);
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//Add the new entry to the list
|
|
||||||
let entry = ObjExtab { func: extab_func, data, dtors };
|
|
||||||
result.push(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Some(result))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_section_symbol(
|
fn find_section_symbol(
|
||||||
arch: &dyn ObjArch,
|
arch: &dyn ObjArch,
|
||||||
obj_file: &File<'_>,
|
obj_file: &File<'_>,
|
||||||
|
@ -335,9 +231,6 @@ fn find_section_symbol(
|
||||||
Ok(ObjSymbol {
|
Ok(ObjSymbol {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
demangled_name: None,
|
demangled_name: None,
|
||||||
has_extab: false,
|
|
||||||
extab_name: None,
|
|
||||||
extabindex_name: None,
|
|
||||||
address: offset,
|
address: offset,
|
||||||
section_address: address - section.address(),
|
section_address: address - section.address(),
|
||||||
size: 0,
|
size: 0,
|
||||||
|
@ -345,6 +238,7 @@ fn find_section_symbol(
|
||||||
flags: Default::default(),
|
flags: Default::default(),
|
||||||
addend: offset_addr as i64,
|
addend: offset_addr as i64,
|
||||||
virtual_address: None,
|
virtual_address: None,
|
||||||
|
original_index: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -615,9 +509,6 @@ fn update_combined_symbol(symbol: ObjSymbol, address_change: i64) -> Result<ObjS
|
||||||
Ok(ObjSymbol {
|
Ok(ObjSymbol {
|
||||||
name: symbol.name,
|
name: symbol.name,
|
||||||
demangled_name: symbol.demangled_name,
|
demangled_name: symbol.demangled_name,
|
||||||
has_extab: symbol.has_extab,
|
|
||||||
extab_name: symbol.extab_name,
|
|
||||||
extabindex_name: symbol.extabindex_name,
|
|
||||||
address: (symbol.address as i64 + address_change).try_into()?,
|
address: (symbol.address as i64 + address_change).try_into()?,
|
||||||
section_address: (symbol.section_address as i64 + address_change).try_into()?,
|
section_address: (symbol.section_address as i64 + address_change).try_into()?,
|
||||||
size: symbol.size,
|
size: symbol.size,
|
||||||
|
@ -629,6 +520,7 @@ fn update_combined_symbol(symbol: ObjSymbol, address_change: i64) -> Result<ObjS
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
|
original_index: symbol.original_index,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -740,8 +632,7 @@ pub fn parse(data: &[u8], config: &DiffObjConfig) -> Result<ObjInfo> {
|
||||||
}
|
}
|
||||||
line_info(&obj_file, &mut sections, data)?;
|
line_info(&obj_file, &mut sections, data)?;
|
||||||
let common = common_symbols(arch.as_ref(), &obj_file, split_meta.as_ref())?;
|
let common = common_symbols(arch.as_ref(), &obj_file, split_meta.as_ref())?;
|
||||||
let extab = exception_tables(&mut sections, &obj_file)?;
|
Ok(ObjInfo { arch, path: None, timestamp: None, sections, common, split_meta })
|
||||||
Ok(ObjInfo { arch, path: None, timestamp: None, sections, common, extab, split_meta })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_function(obj_path: &Path, symbol_name: &str) -> Result<bool> {
|
pub fn has_function(obj_path: &Path, symbol_name: &str) -> Result<bool> {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#![warn(clippy::all, rust_2018_idioms)]
|
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
mod app;
|
mod app;
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
use egui::{Align, Layout, ScrollArea, Ui, Vec2};
|
use egui::{Align, Layout, ScrollArea, Ui, Vec2};
|
||||||
use egui_extras::{Size, StripBuilder};
|
use egui_extras::{Size, StripBuilder};
|
||||||
use objdiff_core::{
|
use objdiff_core::{
|
||||||
|
arch::ppc::ExceptionInfo,
|
||||||
diff::ObjDiff,
|
diff::ObjDiff,
|
||||||
obj::{ObjExtab, ObjInfo, ObjSymbol, SymbolRef},
|
obj::{ObjInfo, ObjSymbol, SymbolRef},
|
||||||
};
|
};
|
||||||
use time::format_description;
|
use time::format_description;
|
||||||
|
|
||||||
|
@ -22,7 +23,7 @@ fn find_symbol(obj: &ObjInfo, selected_symbol: &SymbolRefByName) -> Option<Symbo
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_extab(extab: &ObjExtab) -> String {
|
fn decode_extab(extab: &ExceptionInfo) -> String {
|
||||||
let mut text = String::from("");
|
let mut text = String::from("");
|
||||||
|
|
||||||
let mut dtor_names: Vec<&str> = vec![];
|
let mut dtor_names: Vec<&str> = vec![];
|
||||||
|
@ -42,18 +43,8 @@ fn decode_extab(extab: &ObjExtab) -> String {
|
||||||
text
|
text
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_extab_entry(obj: &ObjInfo, symbol: &ObjSymbol) -> Option<ObjExtab> {
|
fn find_extab_entry<'a>(obj: &'a ObjInfo, symbol: &ObjSymbol) -> Option<&'a ExceptionInfo> {
|
||||||
if let Some(extab_array) = &obj.extab {
|
obj.arch.ppc().and_then(|ppc| ppc.extab_for_symbol(symbol))
|
||||||
for extab_entry in extab_array {
|
|
||||||
if extab_entry.func.name == symbol.name {
|
|
||||||
return Some(extab_entry.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extab_text_ui(
|
fn extab_text_ui(
|
||||||
|
@ -65,7 +56,7 @@ fn extab_text_ui(
|
||||||
let (_section, symbol) = obj.0.section_symbol(symbol_ref);
|
let (_section, symbol) = obj.0.section_symbol(symbol_ref);
|
||||||
|
|
||||||
if let Some(extab_entry) = find_extab_entry(&obj.0, symbol) {
|
if let Some(extab_entry) = find_extab_entry(&obj.0, symbol) {
|
||||||
let text = decode_extab(&extab_entry);
|
let text = decode_extab(extab_entry);
|
||||||
ui.colored_label(appearance.replace_color, &text);
|
ui.colored_label(appearance.replace_color, &text);
|
||||||
return Some(());
|
return Some(());
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ use egui::{
|
||||||
};
|
};
|
||||||
use egui_extras::{Size, StripBuilder};
|
use egui_extras::{Size, StripBuilder};
|
||||||
use objdiff_core::{
|
use objdiff_core::{
|
||||||
|
arch::ObjArch,
|
||||||
diff::{ObjDiff, ObjSymbolDiff},
|
diff::{ObjDiff, ObjSymbolDiff},
|
||||||
obj::{ObjInfo, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlags, SymbolRef},
|
obj::{ObjInfo, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlags, SymbolRef},
|
||||||
};
|
};
|
||||||
|
@ -60,7 +61,6 @@ pub struct SymbolViewState {
|
||||||
pub reverse_fn_order: bool,
|
pub reverse_fn_order: bool,
|
||||||
pub disable_reverse_fn_order: bool,
|
pub disable_reverse_fn_order: bool,
|
||||||
pub show_hidden_symbols: bool,
|
pub show_hidden_symbols: bool,
|
||||||
pub queue_extab_decode: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiffViewState {
|
impl DiffViewState {
|
||||||
|
@ -138,9 +138,11 @@ pub fn match_color_for_symbol(match_percent: f32, appearance: &Appearance) -> Co
|
||||||
fn symbol_context_menu_ui(
|
fn symbol_context_menu_ui(
|
||||||
ui: &mut Ui,
|
ui: &mut Ui,
|
||||||
state: &mut SymbolViewState,
|
state: &mut SymbolViewState,
|
||||||
|
arch: &dyn ObjArch,
|
||||||
symbol: &ObjSymbol,
|
symbol: &ObjSymbol,
|
||||||
section: Option<&ObjSection>,
|
section: Option<&ObjSection>,
|
||||||
) {
|
) -> Option<View> {
|
||||||
|
let mut ret = None;
|
||||||
ui.scope(|ui| {
|
ui.scope(|ui| {
|
||||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||||
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
||||||
|
@ -162,20 +164,22 @@ fn symbol_context_menu_ui(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(section) = section {
|
if let Some(section) = section {
|
||||||
if symbol.has_extab && ui.button("Decode exception table").clicked() {
|
let has_extab = arch.ppc().and_then(|ppc| ppc.extab_for_symbol(symbol)).is_some();
|
||||||
state.queue_extab_decode = true;
|
if has_extab && ui.button("Decode exception table").clicked() {
|
||||||
state.selected_symbol = Some(SymbolRefByName {
|
state.selected_symbol = Some(SymbolRefByName {
|
||||||
symbol_name: symbol.name.clone(),
|
symbol_name: symbol.name.clone(),
|
||||||
demangled_symbol_name: symbol.demangled_name.clone(),
|
demangled_symbol_name: symbol.demangled_name.clone(),
|
||||||
section_name: section.name.clone(),
|
section_name: section.name.clone(),
|
||||||
});
|
});
|
||||||
|
ret = Some(View::ExtabDiff);
|
||||||
ui.close_menu();
|
ui.close_menu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
fn symbol_hover_ui(ui: &mut Ui, symbol: &ObjSymbol, appearance: &Appearance) {
|
fn symbol_hover_ui(ui: &mut Ui, arch: &dyn ObjArch, symbol: &ObjSymbol, appearance: &Appearance) {
|
||||||
ui.scope(|ui| {
|
ui.scope(|ui| {
|
||||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||||
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
||||||
|
@ -193,26 +197,24 @@ fn symbol_hover_ui(ui: &mut Ui, symbol: &ObjSymbol, appearance: &Appearance) {
|
||||||
if let Some(address) = symbol.virtual_address {
|
if let Some(address) = symbol.virtual_address {
|
||||||
ui.colored_label(appearance.replace_color, format!("Virtual address: {:#x}", address));
|
ui.colored_label(appearance.replace_color, format!("Virtual address: {:#x}", address));
|
||||||
}
|
}
|
||||||
if symbol.has_extab {
|
if let Some(extab) = arch.ppc().and_then(|ppc| ppc.extab_for_symbol(symbol)) {
|
||||||
if let (Some(extab_name), Some(extabindex_name)) =
|
ui.colored_label(
|
||||||
(&symbol.extab_name, &symbol.extabindex_name)
|
appearance.highlight_color,
|
||||||
{
|
format!("extab symbol: {}", &extab.etb_symbol.name),
|
||||||
ui.colored_label(
|
);
|
||||||
appearance.highlight_color,
|
ui.colored_label(
|
||||||
format!("Extab Symbol: {}", extab_name),
|
appearance.highlight_color,
|
||||||
);
|
format!("extabindex symbol: {}", &extab.eti_symbol.name),
|
||||||
ui.colored_label(
|
);
|
||||||
appearance.highlight_color,
|
|
||||||
format!("Extabindex Symbol: {}", extabindex_name),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn symbol_ui(
|
fn symbol_ui(
|
||||||
ui: &mut Ui,
|
ui: &mut Ui,
|
||||||
|
arch: &dyn ObjArch,
|
||||||
symbol: &ObjSymbol,
|
symbol: &ObjSymbol,
|
||||||
symbol_diff: &ObjSymbolDiff,
|
symbol_diff: &ObjSymbolDiff,
|
||||||
section: Option<&ObjSection>,
|
section: Option<&ObjSection>,
|
||||||
|
@ -245,6 +247,9 @@ fn symbol_ui(
|
||||||
if symbol.flags.0.contains(ObjSymbolFlags::Weak) {
|
if symbol.flags.0.contains(ObjSymbolFlags::Weak) {
|
||||||
write_text("w", appearance.text_color, &mut job, appearance.code_font.clone());
|
write_text("w", appearance.text_color, &mut job, appearance.code_font.clone());
|
||||||
}
|
}
|
||||||
|
if symbol.flags.0.contains(ObjSymbolFlags::HasExtra) {
|
||||||
|
write_text("e", appearance.text_color, &mut job, appearance.code_font.clone());
|
||||||
|
}
|
||||||
if symbol.flags.0.contains(ObjSymbolFlags::Hidden) {
|
if symbol.flags.0.contains(ObjSymbolFlags::Hidden) {
|
||||||
write_text(
|
write_text(
|
||||||
"h",
|
"h",
|
||||||
|
@ -268,8 +273,10 @@ fn symbol_ui(
|
||||||
write_text(name, appearance.highlight_color, &mut job, appearance.code_font.clone());
|
write_text(name, appearance.highlight_color, &mut job, appearance.code_font.clone());
|
||||||
let response = SelectableLabel::new(selected, job)
|
let response = SelectableLabel::new(selected, job)
|
||||||
.ui(ui)
|
.ui(ui)
|
||||||
.on_hover_ui_at_pointer(|ui| symbol_hover_ui(ui, symbol, appearance));
|
.on_hover_ui_at_pointer(|ui| symbol_hover_ui(ui, arch, symbol, appearance));
|
||||||
response.context_menu(|ui| symbol_context_menu_ui(ui, state, symbol, section));
|
response.context_menu(|ui| {
|
||||||
|
ret = ret.or(symbol_context_menu_ui(ui, state, arch, symbol, section));
|
||||||
|
});
|
||||||
if response.clicked() {
|
if response.clicked() {
|
||||||
if let Some(section) = section {
|
if let Some(section) = section {
|
||||||
if section.kind == ObjSectionKind::Code {
|
if section.kind == ObjSectionKind::Code {
|
||||||
|
@ -299,13 +306,6 @@ fn symbol_ui(
|
||||||
(None, None)
|
(None, None)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//If the decode extab context menu option was clicked, switch to the extab view
|
|
||||||
if state.queue_extab_decode {
|
|
||||||
ret = Some(View::ExtabDiff);
|
|
||||||
state.queue_extab_decode = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,6 +328,7 @@ fn symbol_list_ui(
|
||||||
left: bool,
|
left: bool,
|
||||||
) -> Option<View> {
|
) -> Option<View> {
|
||||||
let mut ret = None;
|
let mut ret = None;
|
||||||
|
let arch = obj.0.arch.as_ref();
|
||||||
ScrollArea::both().auto_shrink([false, false]).show(ui, |ui| {
|
ScrollArea::both().auto_shrink([false, false]).show(ui, |ui| {
|
||||||
ui.scope(|ui| {
|
ui.scope(|ui| {
|
||||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||||
|
@ -341,6 +342,7 @@ fn symbol_list_ui(
|
||||||
}
|
}
|
||||||
ret = ret.or(symbol_ui(
|
ret = ret.or(symbol_ui(
|
||||||
ui,
|
ui,
|
||||||
|
arch,
|
||||||
symbol,
|
symbol,
|
||||||
symbol_diff,
|
symbol_diff,
|
||||||
None,
|
None,
|
||||||
|
@ -391,6 +393,7 @@ fn symbol_list_ui(
|
||||||
}
|
}
|
||||||
ret = ret.or(symbol_ui(
|
ret = ret.or(symbol_ui(
|
||||||
ui,
|
ui,
|
||||||
|
arch,
|
||||||
symbol,
|
symbol,
|
||||||
symbol_diff,
|
symbol_diff,
|
||||||
Some(section),
|
Some(section),
|
||||||
|
@ -408,6 +411,7 @@ fn symbol_list_ui(
|
||||||
}
|
}
|
||||||
ret = ret.or(symbol_ui(
|
ret = ret.or(symbol_ui(
|
||||||
ui,
|
ui,
|
||||||
|
arch,
|
||||||
symbol,
|
symbol,
|
||||||
symbol_diff,
|
symbol_diff,
|
||||||
Some(section),
|
Some(section),
|
||||||
|
|
Loading…
Reference in New Issue