Skip to content

Commit 75b0e7d

Browse files
Exception table diff view (#82)
* Basic integration * Implement basic right click option Needs lotsa work * nothing to worry about * Convert extab diff to separate view * Make clippy and fmt shut up * Make clippy fmt shut up for real this time * Print extab/extabindex symbol names in extab view * I hate fmt * Basic integration * Implement basic right click option Needs lotsa work * nothing to worry about * Convert extab diff to separate view * Make clippy and fmt shut up * Make clippy fmt shut up for real this time * Print extab/extabindex symbol names in extab view * I hate fmt * Fix scroll position not being maintained from extab view * Silly me * Add rlwinm decoder window * Remove extra files * Create Cargo.lock * Show extab symbol names in hover window * Appease fmt * Update symbol_diff.rs * Update symbol_diff.rs * Get extab symbol from extabindex relocations instead * Update Cargo.lock * Update Cargo.lock
1 parent 9f71ce9 commit 75b0e7d

File tree

10 files changed

+414
-7
lines changed

10 files changed

+414
-7
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ android.keystore
2222
*.frag
2323
*.vert
2424
*.metal
25+
.vscode/launch.json

Cargo.lock

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

objdiff-core/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ any-arch = [] # Implicit, used to check if any arch is enabled
1717
config = ["globset", "semver", "serde_json", "serde_yaml"]
1818
dwarf = ["gimli"]
1919
mips = ["any-arch", "rabbitizer"]
20-
ppc = ["any-arch", "cwdemangle", "ppc750cl"]
20+
ppc = ["any-arch", "cwdemangle", "cwextab", "ppc750cl"]
2121
x86 = ["any-arch", "cpp_demangle", "iced-x86", "msvc-demangler"]
2222
arm = ["any-arch", "cpp_demangle", "unarm", "arm-attr"]
2323

@@ -45,6 +45,7 @@ gimli = { version = "0.29.0", default-features = false, features = ["read-all"],
4545

4646
# ppc
4747
cwdemangle = { version = "1.0.0", optional = true }
48+
cwextab = { version = "0.2.3", optional = true }
4849
ppc750cl = { git = "https://github.com/encounter/ppc750cl", rev = "6cbd7d888c7082c2c860f66cbb9848d633f753ed", optional = true }
4950

5051
# mips

objdiff-core/src/obj/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pub mod split_meta;
33

44
use std::{borrow::Cow, collections::BTreeMap, fmt, path::PathBuf};
55

6+
use cwextab::*;
67
use filetime::FileTime;
78
use flagset::{flags, FlagSet};
89
use object::RelocationFlags;
@@ -113,6 +114,9 @@ pub struct ObjIns {
113114
pub struct ObjSymbol {
114115
pub name: String,
115116
pub demangled_name: Option<String>,
117+
pub has_extab: bool,
118+
pub extab_name: Option<String>,
119+
pub extabindex_name: Option<String>,
116120
pub address: u64,
117121
pub section_address: u64,
118122
pub size: u64,
@@ -123,13 +127,22 @@ pub struct ObjSymbol {
123127
pub virtual_address: Option<u64>,
124128
}
125129

130+
#[derive(Debug, Clone)]
131+
pub struct ObjExtab {
132+
pub func: ObjSymbol,
133+
pub data: ExceptionTableData,
134+
pub dtors: Vec<ObjSymbol>,
135+
}
136+
126137
pub struct ObjInfo {
127138
pub arch: Box<dyn ObjArch>,
128139
pub path: PathBuf,
129140
pub timestamp: FileTime,
130141
pub sections: Vec<ObjSection>,
131142
/// Common BSS symbols
132143
pub common: Vec<ObjSymbol>,
144+
/// Exception tables
145+
pub extab: Option<Vec<ObjExtab>>,
133146
/// Split object metadata (.note.split section)
134147
pub split_meta: Option<SplitMeta>,
135148
}

objdiff-core/src/obj/read.rs

Lines changed: 121 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,21 @@ use std::{collections::HashSet, fs, io::Cursor, path::Path};
22

33
use anyhow::{anyhow, bail, ensure, Context, Result};
44
use byteorder::{BigEndian, ReadBytesExt};
5+
use cwextab::decode_extab;
56
use filetime::FileTime;
67
use flagset::Flags;
78
use object::{
8-
BinaryFormat, File, Object, ObjectSection, ObjectSymbol, RelocationTarget, SectionIndex,
9-
SectionKind, Symbol, SymbolKind, SymbolScope, SymbolSection,
9+
Architecture, BinaryFormat, File, Object, ObjectSection, ObjectSymbol, RelocationTarget,
10+
SectionIndex, SectionKind, Symbol, SymbolKind, SymbolScope, SymbolSection,
1011
};
1112

1213
use crate::{
1314
arch::{new_arch, ObjArch},
1415
diff::DiffObjConfig,
1516
obj::{
1617
split_meta::{SplitMeta, SPLITMETA_SECTION},
17-
ObjInfo, ObjReloc, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlagSet, ObjSymbolFlags,
18+
ObjExtab, ObjInfo, ObjReloc, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlagSet,
19+
ObjSymbolFlags,
1820
},
1921
};
2022

@@ -71,6 +73,9 @@ fn to_obj_symbol(
7173
Ok(ObjSymbol {
7274
name: name.to_string(),
7375
demangled_name,
76+
has_extab: false,
77+
extab_name: None,
78+
extabindex_name: None,
7479
address,
7580
section_address,
7681
size: symbol.size(),
@@ -170,6 +175,111 @@ fn common_symbols(
170175
.collect::<Result<Vec<ObjSymbol>>>()
171176
}
172177

178+
fn section_by_name<'a>(sections: &'a mut [ObjSection], name: &str) -> Option<&'a mut ObjSection> {
179+
sections.iter_mut().find(|section| section.name == name)
180+
}
181+
182+
fn exception_tables(
183+
sections: &mut [ObjSection],
184+
obj_file: &File<'_>,
185+
) -> Result<Option<Vec<ObjExtab>>> {
186+
//PowerPC only
187+
if obj_file.architecture() != Architecture::PowerPc {
188+
return Ok(None);
189+
}
190+
191+
//Find the extab/extabindex sections
192+
let extab_section = match section_by_name(sections, "extab") {
193+
Some(section) => section.clone(),
194+
None => {
195+
return Ok(None);
196+
}
197+
};
198+
let extabindex_section = match section_by_name(sections, "extabindex") {
199+
Some(section) => section.clone(),
200+
None => {
201+
return Ok(None);
202+
}
203+
};
204+
let text_section = match section_by_name(sections, ".text") {
205+
Some(section) => section,
206+
None => bail!(".text section is somehow missing, this should not happen"),
207+
};
208+
209+
let mut result: Vec<ObjExtab> = vec![];
210+
let extab_symbol_count = extab_section.symbols.len();
211+
let extabindex_symbol_count = extabindex_section.symbols.len();
212+
let extab_reloc_count = extab_section.relocations.len();
213+
let table_count = extab_symbol_count;
214+
let mut extab_reloc_index: usize = 0;
215+
216+
//Make sure that the number of symbols in the extab/extabindex section matches. If not, exit early
217+
if extab_symbol_count != extabindex_symbol_count {
218+
bail!("Extab/Extabindex symbol counts do not match");
219+
}
220+
221+
//Convert the extab/extabindex section data
222+
223+
//Go through each extabindex entry
224+
for i in 0..table_count {
225+
let extabindex = &extabindex_section.symbols[i];
226+
227+
/* Get the function symbol and extab symbol from the extabindex relocations array. Each extabindex
228+
entry has two relocations (the first for the function, the second for the extab entry) */
229+
let extab_func = extabindex_section.relocations[i * 2].target.clone();
230+
let extab = &extabindex_section.relocations[(i * 2) + 1].target;
231+
232+
let extab_start_addr = extab.address;
233+
let extab_end_addr = extab_start_addr + extab.size;
234+
235+
//Find the function in the text section, and set the has extab flag
236+
for i in 0..text_section.symbols.len() {
237+
let func = &mut text_section.symbols[i];
238+
if func.name == extab_func.name {
239+
func.has_extab = true;
240+
func.extab_name = Some(extab.name.clone());
241+
func.extabindex_name = Some(extabindex.name.clone());
242+
}
243+
}
244+
245+
/* Iterate through the list of extab relocations, continuing until we hit a relocation
246+
that isn't within the current extab symbol. Get the target dtor function symbol from
247+
each relocation used, and add them to the list. */
248+
let mut dtors: Vec<ObjSymbol> = vec![];
249+
250+
while extab_reloc_index < extab_reloc_count {
251+
let extab_reloc = &extab_section.relocations[extab_reloc_index];
252+
//If the current entry is past the current extab table, stop here
253+
if extab_reloc.address >= extab_end_addr {
254+
break;
255+
}
256+
257+
//Otherwise, the current relocation is used by the current table
258+
dtors.push(extab_reloc.target.clone());
259+
//Go to the next entry
260+
extab_reloc_index += 1;
261+
}
262+
263+
//Decode the extab data
264+
let start_index = extab_start_addr as usize;
265+
let end_index = extab_end_addr as usize;
266+
let extab_data = extab_section.data[start_index..end_index].try_into().unwrap();
267+
let data = match decode_extab(extab_data) {
268+
Some(decoded_data) => decoded_data,
269+
None => {
270+
log::warn!("Exception table decoding failed for function {}", extab_func.name);
271+
return Ok(None);
272+
}
273+
};
274+
275+
//Add the new entry to the list
276+
let entry = ObjExtab { func: extab_func, data, dtors };
277+
result.push(entry);
278+
}
279+
280+
Ok(Some(result))
281+
}
282+
173283
fn find_section_symbol(
174284
arch: &dyn ObjArch,
175285
obj_file: &File<'_>,
@@ -205,6 +315,9 @@ fn find_section_symbol(
205315
Ok(ObjSymbol {
206316
name: name.to_string(),
207317
demangled_name: None,
318+
has_extab: false,
319+
extab_name: None,
320+
extabindex_name: None,
208321
address: offset,
209322
section_address: address - section.address(),
210323
size: 0,
@@ -367,6 +480,9 @@ fn update_combined_symbol(symbol: ObjSymbol, address_change: i64) -> Result<ObjS
367480
Ok(ObjSymbol {
368481
name: symbol.name,
369482
demangled_name: symbol.demangled_name,
483+
has_extab: symbol.has_extab,
484+
extab_name: symbol.extab_name,
485+
extabindex_name: symbol.extabindex_name,
370486
address: (symbol.address as i64 + address_change).try_into()?,
371487
section_address: (symbol.section_address as i64 + address_change).try_into()?,
372488
size: symbol.size,
@@ -482,7 +598,8 @@ pub fn read(obj_path: &Path, config: &DiffObjConfig) -> Result<ObjInfo> {
482598
}
483599
line_info(&obj_file, &mut sections)?;
484600
let common = common_symbols(arch.as_ref(), &obj_file, split_meta.as_ref())?;
485-
Ok(ObjInfo { arch, path: obj_path.to_owned(), timestamp, sections, common, split_meta })
601+
let extab = exception_tables(&mut sections, &obj_file)?;
602+
Ok(ObjInfo { arch, path: obj_path.to_owned(), timestamp, sections, common, extab, split_meta })
486603
}
487604

488605
pub fn has_function(obj_path: &Path, symbol_name: &str) -> Result<bool> {

objdiff-gui/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ cfg-if = "1.0.0"
3030
const_format = "0.2.32"
3131
cwdemangle = "1.0.0"
3232
rlwinmdec = "1.0.1"
33+
cwextab = "0.2.3"
3334
dirs = "5.0.1"
3435
egui = "0.27.2"
3536
egui_extras = "0.27.2"

objdiff-gui/src/app.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use crate::{
3535
data_diff::data_diff_ui,
3636
debug::debug_window,
3737
demangle::{demangle_window, DemangleViewState},
38+
extab_diff::extab_diff_ui,
3839
frame_history::FrameHistory,
3940
function_diff::function_diff_ui,
4041
graphics::{graphics_window, GraphicsConfig, GraphicsViewState},
@@ -591,6 +592,10 @@ impl eframe::App for App {
591592
egui::CentralPanel::default().show(ctx, |ui| {
592593
data_diff_ui(ui, diff_state, appearance);
593594
});
595+
} else if diff_state.current_view == View::ExtabDiff && build_success {
596+
egui::CentralPanel::default().show(ctx, |ui| {
597+
extab_diff_ui(ui, diff_state, appearance);
598+
});
594599
} else {
595600
egui::SidePanel::left("side_panel").show(ctx, |ui| {
596601
egui::ScrollArea::both().show(ui, |ui| {

0 commit comments

Comments
 (0)