mirror of https://github.com/encounter/objdiff.git
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
This commit is contained in:
parent
9f71ce9fea
commit
75b0e7d9e5
|
@ -22,3 +22,4 @@ android.keystore
|
|||
*.frag
|
||||
*.vert
|
||||
*.metal
|
||||
.vscode/launch.json
|
||||
|
|
|
@ -970,6 +970,15 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2e06f9bce634a3c898eb1e5cb949ff63133cbb218af93cc9b38b31d6f3ea285"
|
||||
|
||||
[[package]]
|
||||
name = "cwextab"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a92e840be31d11ead5f357b8fc503133d3657845d0ccf539afcc7d1212fad226"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "d3d12"
|
||||
version = "0.19.0"
|
||||
|
@ -2815,6 +2824,7 @@ dependencies = [
|
|||
"byteorder",
|
||||
"cpp_demangle",
|
||||
"cwdemangle",
|
||||
"cwextab",
|
||||
"filetime",
|
||||
"flagset",
|
||||
"gimli 0.29.0",
|
||||
|
@ -2846,6 +2856,7 @@ dependencies = [
|
|||
"console_error_panic_hook",
|
||||
"const_format",
|
||||
"cwdemangle",
|
||||
"cwextab",
|
||||
"dirs",
|
||||
"eframe",
|
||||
"egui",
|
||||
|
|
|
@ -17,7 +17,7 @@ any-arch = [] # Implicit, used to check if any arch is enabled
|
|||
config = ["globset", "semver", "serde_json", "serde_yaml"]
|
||||
dwarf = ["gimli"]
|
||||
mips = ["any-arch", "rabbitizer"]
|
||||
ppc = ["any-arch", "cwdemangle", "ppc750cl"]
|
||||
ppc = ["any-arch", "cwdemangle", "cwextab", "ppc750cl"]
|
||||
x86 = ["any-arch", "cpp_demangle", "iced-x86", "msvc-demangler"]
|
||||
arm = ["any-arch", "cpp_demangle", "unarm", "arm-attr"]
|
||||
|
||||
|
@ -45,6 +45,7 @@ gimli = { version = "0.29.0", default-features = false, features = ["read-all"],
|
|||
|
||||
# ppc
|
||||
cwdemangle = { version = "1.0.0", optional = true }
|
||||
cwextab = { version = "0.2.3", optional = true }
|
||||
ppc750cl = { git = "https://github.com/encounter/ppc750cl", rev = "6cbd7d888c7082c2c860f66cbb9848d633f753ed", optional = true }
|
||||
|
||||
# mips
|
||||
|
|
|
@ -3,6 +3,7 @@ pub mod split_meta;
|
|||
|
||||
use std::{borrow::Cow, collections::BTreeMap, fmt, path::PathBuf};
|
||||
|
||||
use cwextab::*;
|
||||
use filetime::FileTime;
|
||||
use flagset::{flags, FlagSet};
|
||||
use object::RelocationFlags;
|
||||
|
@ -113,6 +114,9 @@ pub struct ObjIns {
|
|||
pub struct ObjSymbol {
|
||||
pub name: String,
|
||||
pub demangled_name: Option<String>,
|
||||
pub has_extab: bool,
|
||||
pub extab_name: Option<String>,
|
||||
pub extabindex_name: Option<String>,
|
||||
pub address: u64,
|
||||
pub section_address: u64,
|
||||
pub size: u64,
|
||||
|
@ -123,6 +127,13 @@ pub struct ObjSymbol {
|
|||
pub virtual_address: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ObjExtab {
|
||||
pub func: ObjSymbol,
|
||||
pub data: ExceptionTableData,
|
||||
pub dtors: Vec<ObjSymbol>,
|
||||
}
|
||||
|
||||
pub struct ObjInfo {
|
||||
pub arch: Box<dyn ObjArch>,
|
||||
pub path: PathBuf,
|
||||
|
@ -130,6 +141,8 @@ pub struct ObjInfo {
|
|||
pub sections: Vec<ObjSection>,
|
||||
/// Common BSS symbols
|
||||
pub common: Vec<ObjSymbol>,
|
||||
/// Exception tables
|
||||
pub extab: Option<Vec<ObjExtab>>,
|
||||
/// Split object metadata (.note.split section)
|
||||
pub split_meta: Option<SplitMeta>,
|
||||
}
|
||||
|
|
|
@ -2,11 +2,12 @@ use std::{collections::HashSet, fs, io::Cursor, path::Path};
|
|||
|
||||
use anyhow::{anyhow, bail, ensure, Context, Result};
|
||||
use byteorder::{BigEndian, ReadBytesExt};
|
||||
use cwextab::decode_extab;
|
||||
use filetime::FileTime;
|
||||
use flagset::Flags;
|
||||
use object::{
|
||||
BinaryFormat, File, Object, ObjectSection, ObjectSymbol, RelocationTarget, SectionIndex,
|
||||
SectionKind, Symbol, SymbolKind, SymbolScope, SymbolSection,
|
||||
Architecture, BinaryFormat, File, Object, ObjectSection, ObjectSymbol, RelocationTarget,
|
||||
SectionIndex, SectionKind, Symbol, SymbolKind, SymbolScope, SymbolSection,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
@ -14,7 +15,8 @@ use crate::{
|
|||
diff::DiffObjConfig,
|
||||
obj::{
|
||||
split_meta::{SplitMeta, SPLITMETA_SECTION},
|
||||
ObjInfo, ObjReloc, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlagSet, ObjSymbolFlags,
|
||||
ObjExtab, ObjInfo, ObjReloc, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlagSet,
|
||||
ObjSymbolFlags,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -71,6 +73,9 @@ fn to_obj_symbol(
|
|||
Ok(ObjSymbol {
|
||||
name: name.to_string(),
|
||||
demangled_name,
|
||||
has_extab: false,
|
||||
extab_name: None,
|
||||
extabindex_name: None,
|
||||
address,
|
||||
section_address,
|
||||
size: symbol.size(),
|
||||
|
@ -170,6 +175,111 @@ fn common_symbols(
|
|||
.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(
|
||||
arch: &dyn ObjArch,
|
||||
obj_file: &File<'_>,
|
||||
|
@ -205,6 +315,9 @@ fn find_section_symbol(
|
|||
Ok(ObjSymbol {
|
||||
name: name.to_string(),
|
||||
demangled_name: None,
|
||||
has_extab: false,
|
||||
extab_name: None,
|
||||
extabindex_name: None,
|
||||
address: offset,
|
||||
section_address: address - section.address(),
|
||||
size: 0,
|
||||
|
@ -367,6 +480,9 @@ fn update_combined_symbol(symbol: ObjSymbol, address_change: i64) -> Result<ObjS
|
|||
Ok(ObjSymbol {
|
||||
name: symbol.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()?,
|
||||
section_address: (symbol.section_address as i64 + address_change).try_into()?,
|
||||
size: symbol.size,
|
||||
|
@ -482,7 +598,8 @@ pub fn read(obj_path: &Path, config: &DiffObjConfig) -> Result<ObjInfo> {
|
|||
}
|
||||
line_info(&obj_file, &mut sections)?;
|
||||
let common = common_symbols(arch.as_ref(), &obj_file, split_meta.as_ref())?;
|
||||
Ok(ObjInfo { arch, path: obj_path.to_owned(), timestamp, sections, common, split_meta })
|
||||
let extab = exception_tables(&mut sections, &obj_file)?;
|
||||
Ok(ObjInfo { arch, path: obj_path.to_owned(), timestamp, sections, common, extab, split_meta })
|
||||
}
|
||||
|
||||
pub fn has_function(obj_path: &Path, symbol_name: &str) -> Result<bool> {
|
||||
|
|
|
@ -30,6 +30,7 @@ cfg-if = "1.0.0"
|
|||
const_format = "0.2.32"
|
||||
cwdemangle = "1.0.0"
|
||||
rlwinmdec = "1.0.1"
|
||||
cwextab = "0.2.3"
|
||||
dirs = "5.0.1"
|
||||
egui = "0.27.2"
|
||||
egui_extras = "0.27.2"
|
||||
|
|
|
@ -35,6 +35,7 @@ use crate::{
|
|||
data_diff::data_diff_ui,
|
||||
debug::debug_window,
|
||||
demangle::{demangle_window, DemangleViewState},
|
||||
extab_diff::extab_diff_ui,
|
||||
frame_history::FrameHistory,
|
||||
function_diff::function_diff_ui,
|
||||
graphics::{graphics_window, GraphicsConfig, GraphicsViewState},
|
||||
|
@ -591,6 +592,10 @@ impl eframe::App for App {
|
|||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
data_diff_ui(ui, diff_state, appearance);
|
||||
});
|
||||
} else if diff_state.current_view == View::ExtabDiff && build_success {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
extab_diff_ui(ui, diff_state, appearance);
|
||||
});
|
||||
} else {
|
||||
egui::SidePanel::left("side_panel").show(ctx, |ui| {
|
||||
egui::ScrollArea::both().show(ui, |ui| {
|
||||
|
|
|
@ -0,0 +1,218 @@
|
|||
use egui::{text::LayoutJob, Align, Layout, ScrollArea, Ui, Vec2};
|
||||
use egui_extras::{Size, StripBuilder};
|
||||
use objdiff_core::{
|
||||
diff::ObjDiff,
|
||||
obj::{ObjExtab, ObjInfo, ObjSymbol, SymbolRef},
|
||||
};
|
||||
use time::format_description;
|
||||
|
||||
use crate::views::{
|
||||
appearance::Appearance,
|
||||
symbol_diff::{match_color_for_symbol, DiffViewState, SymbolRefByName, View},
|
||||
};
|
||||
|
||||
fn find_symbol(obj: &ObjInfo, selected_symbol: &SymbolRefByName) -> Option<SymbolRef> {
|
||||
for (section_idx, section) in obj.sections.iter().enumerate() {
|
||||
for (symbol_idx, symbol) in section.symbols.iter().enumerate() {
|
||||
if symbol.name == selected_symbol.symbol_name {
|
||||
return Some(SymbolRef { section_idx, symbol_idx });
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn decode_extab(extab: &ObjExtab) -> String {
|
||||
let mut text = String::from("");
|
||||
|
||||
let mut dtor_names: Vec<&str> = vec![];
|
||||
for dtor in &extab.dtors {
|
||||
//For each function name, use the demangled name by default,
|
||||
//and if not available fallback to the original name
|
||||
let name = match &dtor.demangled_name {
|
||||
Some(demangled_name) => demangled_name,
|
||||
None => &dtor.name,
|
||||
};
|
||||
dtor_names.push(name.as_str());
|
||||
}
|
||||
if let Some(decoded) = extab.data.to_string(&dtor_names) {
|
||||
text += decoded.as_str();
|
||||
}
|
||||
|
||||
text
|
||||
}
|
||||
|
||||
fn find_extab_entry(obj: &ObjInfo, symbol: &ObjSymbol) -> Option<ObjExtab> {
|
||||
if let Some(extab_array) = &obj.extab {
|
||||
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(
|
||||
ui: &mut Ui,
|
||||
obj: &(ObjInfo, ObjDiff),
|
||||
symbol_ref: SymbolRef,
|
||||
appearance: &Appearance,
|
||||
) -> Option<()> {
|
||||
let (_section, symbol) = obj.0.section_symbol(symbol_ref);
|
||||
|
||||
if let Some(extab_entry) = find_extab_entry(&obj.0, symbol) {
|
||||
let text = decode_extab(&extab_entry);
|
||||
ui.colored_label(appearance.replace_color, &text);
|
||||
return Some(());
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn extab_ui(
|
||||
ui: &mut Ui,
|
||||
obj: Option<&(ObjInfo, ObjDiff)>,
|
||||
selected_symbol: &SymbolRefByName,
|
||||
appearance: &Appearance,
|
||||
_left: bool,
|
||||
) {
|
||||
ScrollArea::both().auto_shrink([false, false]).show(ui, |ui| {
|
||||
ui.scope(|ui| {
|
||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||
ui.style_mut().wrap = Some(false);
|
||||
|
||||
let symbol = obj.and_then(|(obj, _)| find_symbol(obj, selected_symbol));
|
||||
|
||||
if let (Some(object), Some(symbol_ref)) = (obj, symbol) {
|
||||
extab_text_ui(ui, object, symbol_ref, appearance);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn extab_diff_ui(ui: &mut egui::Ui, state: &mut DiffViewState, appearance: &Appearance) {
|
||||
let (Some(result), Some(selected_symbol)) = (&state.build, &state.symbol_state.selected_symbol)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
// Header
|
||||
let available_width = ui.available_width();
|
||||
let column_width = available_width / 2.0;
|
||||
ui.allocate_ui_with_layout(
|
||||
Vec2 { x: available_width, y: 100.0 },
|
||||
Layout::left_to_right(Align::Min),
|
||||
|ui| {
|
||||
// Left column
|
||||
ui.allocate_ui_with_layout(
|
||||
Vec2 { x: column_width, y: 100.0 },
|
||||
Layout::top_down(Align::Min),
|
||||
|ui| {
|
||||
ui.set_width(column_width);
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("⏴ Back").clicked() {
|
||||
state.current_view = View::SymbolDiff;
|
||||
}
|
||||
});
|
||||
|
||||
let name = selected_symbol
|
||||
.demangled_symbol_name
|
||||
.as_deref()
|
||||
.unwrap_or(&selected_symbol.symbol_name);
|
||||
let mut job = LayoutJob::simple(
|
||||
name.to_string(),
|
||||
appearance.code_font.clone(),
|
||||
appearance.highlight_color,
|
||||
column_width,
|
||||
);
|
||||
job.wrap.break_anywhere = true;
|
||||
job.wrap.max_rows = 1;
|
||||
ui.label(job);
|
||||
|
||||
ui.scope(|ui| {
|
||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||
ui.label("Diff target:");
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
// Right column
|
||||
ui.allocate_ui_with_layout(
|
||||
Vec2 { x: column_width, y: 100.0 },
|
||||
Layout::top_down(Align::Min),
|
||||
|ui| {
|
||||
ui.set_width(column_width);
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
if ui
|
||||
.add_enabled(!state.build_running, egui::Button::new("Build"))
|
||||
.clicked()
|
||||
{
|
||||
state.queue_build = true;
|
||||
}
|
||||
ui.scope(|ui| {
|
||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||
ui.style_mut().wrap = Some(false);
|
||||
if state.build_running {
|
||||
ui.colored_label(appearance.replace_color, "Building…");
|
||||
} else {
|
||||
ui.label("Last built:");
|
||||
let format =
|
||||
format_description::parse("[hour]:[minute]:[second]").unwrap();
|
||||
ui.label(
|
||||
result
|
||||
.time
|
||||
.to_offset(appearance.utc_offset)
|
||||
.format(&format)
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ui.scope(|ui| {
|
||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||
if let Some(match_percent) = result
|
||||
.second_obj
|
||||
.as_ref()
|
||||
.and_then(|(obj, diff)| {
|
||||
find_symbol(obj, selected_symbol).map(|sref| {
|
||||
&diff.sections[sref.section_idx].symbols[sref.symbol_idx]
|
||||
})
|
||||
})
|
||||
.and_then(|symbol| symbol.match_percent)
|
||||
{
|
||||
ui.colored_label(
|
||||
match_color_for_symbol(match_percent, appearance),
|
||||
&format!("{match_percent:.0}%"),
|
||||
);
|
||||
} else {
|
||||
ui.colored_label(appearance.replace_color, "Missing");
|
||||
}
|
||||
ui.label("Diff base:");
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
ui.separator();
|
||||
|
||||
// Table
|
||||
StripBuilder::new(ui).size(Size::remainder()).vertical(|mut strip| {
|
||||
strip.strip(|builder| {
|
||||
builder.sizes(Size::remainder(), 2).horizontal(|mut strip| {
|
||||
strip.cell(|ui| {
|
||||
extab_ui(ui, result.first_obj.as_ref(), selected_symbol, appearance, true);
|
||||
});
|
||||
strip.cell(|ui| {
|
||||
extab_ui(ui, result.second_obj.as_ref(), selected_symbol, appearance, false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -5,6 +5,7 @@ pub(crate) mod config;
|
|||
pub(crate) mod data_diff;
|
||||
pub(crate) mod debug;
|
||||
pub(crate) mod demangle;
|
||||
pub(crate) mod extab_diff;
|
||||
pub(crate) mod file;
|
||||
pub(crate) mod frame_history;
|
||||
pub(crate) mod function_diff;
|
||||
|
|
|
@ -33,6 +33,7 @@ pub enum View {
|
|||
SymbolDiff,
|
||||
FunctionDiff,
|
||||
DataDiff,
|
||||
ExtabDiff,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -57,6 +58,7 @@ pub struct SymbolViewState {
|
|||
pub reverse_fn_order: bool,
|
||||
pub disable_reverse_fn_order: bool,
|
||||
pub show_hidden_symbols: bool,
|
||||
pub queue_extab_decode: bool,
|
||||
}
|
||||
|
||||
impl DiffViewState {
|
||||
|
@ -131,7 +133,12 @@ pub fn match_color_for_symbol(match_percent: f32, appearance: &Appearance) -> Co
|
|||
}
|
||||
}
|
||||
|
||||
fn symbol_context_menu_ui(ui: &mut Ui, symbol: &ObjSymbol) {
|
||||
fn symbol_context_menu_ui(
|
||||
ui: &mut Ui,
|
||||
state: &mut SymbolViewState,
|
||||
symbol: &ObjSymbol,
|
||||
section: Option<&ObjSection>,
|
||||
) {
|
||||
ui.scope(|ui| {
|
||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||
ui.style_mut().wrap = Some(false);
|
||||
|
@ -152,6 +159,17 @@ fn symbol_context_menu_ui(ui: &mut Ui, symbol: &ObjSymbol) {
|
|||
ui.close_menu();
|
||||
}
|
||||
}
|
||||
if let Some(section) = section {
|
||||
if symbol.has_extab && ui.button("Decode exception table").clicked() {
|
||||
state.queue_extab_decode = true;
|
||||
state.selected_symbol = Some(SymbolRefByName {
|
||||
symbol_name: symbol.name.clone(),
|
||||
demangled_symbol_name: symbol.demangled_name.clone(),
|
||||
section_name: section.name.clone(),
|
||||
});
|
||||
ui.close_menu();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -173,6 +191,20 @@ fn symbol_hover_ui(ui: &mut Ui, symbol: &ObjSymbol, appearance: &Appearance) {
|
|||
if let Some(address) = symbol.virtual_address {
|
||||
ui.colored_label(appearance.replace_color, format!("Virtual address: {:#x}", address));
|
||||
}
|
||||
if symbol.has_extab {
|
||||
if let (Some(extab_name), Some(extabindex_name)) =
|
||||
(&symbol.extab_name, &symbol.extabindex_name)
|
||||
{
|
||||
ui.colored_label(
|
||||
appearance.highlight_color,
|
||||
format!("Extab Symbol: {}", extab_name),
|
||||
);
|
||||
ui.colored_label(
|
||||
appearance.highlight_color,
|
||||
format!("Extabindex Symbol: {}", extabindex_name),
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -228,7 +260,7 @@ fn symbol_ui(
|
|||
let response = SelectableLabel::new(selected, job)
|
||||
.ui(ui)
|
||||
.on_hover_ui_at_pointer(|ui| symbol_hover_ui(ui, symbol, appearance));
|
||||
response.context_menu(|ui| symbol_context_menu_ui(ui, symbol));
|
||||
response.context_menu(|ui| symbol_context_menu_ui(ui, state, symbol, section));
|
||||
if response.clicked() {
|
||||
if let Some(section) = section {
|
||||
if section.kind == ObjSectionKind::Code {
|
||||
|
@ -258,6 +290,13 @@ fn symbol_ui(
|
|||
(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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue