diff --git a/Cargo.lock b/Cargo.lock index 51ed96f..0abcff2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1926,9 +1926,10 @@ dependencies = [ [[package]] name = "objdiff" -version = "0.2.0" +version = "0.2.2" dependencies = [ "anyhow", + "bytes", "cfg-if", "console_error_panic_hook", "const_format", @@ -1943,6 +1944,7 @@ dependencies = [ "notify", "object", "path-slash", + "png", "ppc750cl", "rabbitizer", "reqwest", @@ -1958,6 +1960,7 @@ dependencies = [ "twox-hash", "vergen", "winapi", + "winres", ] [[package]] @@ -3520,6 +3523,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "winres" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c" +dependencies = [ + "toml", +] + [[package]] name = "wio" version = "0.2.2" diff --git a/Cargo.toml b/Cargo.toml index 0ae84e3..d479483 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "objdiff" -version = "0.2.1" +version = "0.2.2" edition = "2021" rust-version = "1.62" authors = ["Luke Street "] @@ -18,6 +18,7 @@ strip = "debuginfo" [dependencies] anyhow = "1.0.66" +bytes = "1.3.0" cfg-if = "1.0.0" const_format = "0.2.30" cwdemangle = { git = "https://github.com/encounter/cwdemangle", rev = "286f3d1d29ee2457db89043782725631845c3e4c" } @@ -29,22 +30,26 @@ log = "0.4.17" memmap2 = "0.5.8" notify = "5.0.0" object = { version = "0.30.0", features = ["read_core", "std", "elf"], default-features = false } +png = "0.17.7" ppc750cl = { git = "https://github.com/encounter/ppc750cl", rev = "aa631a33de7882c679afca89350898b87cb3ba3f" } rabbitizer = { git = "https://github.com/encounter/rabbitizer-rs", rev = "10c279b2ef251c62885b1dcdcfe740b0db8e9956" } +reqwest = "0.11.13" rfd = { version = "0.10.0" } # , default-features = false, features = ['xdg-portal'] self_update = "0.32.0" serde = { version = "1", features = ["derive"] } +tempfile = "3.3.0" thiserror = "1.0.37" time = { version = "0.3.17", features = ["formatting", "local-offset"] } toml = "0.5.9" twox-hash = "1.6.3" -tempfile = "3.3.0" -reqwest = "0.11.13" [target.'cfg(windows)'.dependencies] path-slash = "0.2.1" winapi = "0.3.9" +[target.'cfg(windows)'.build-dependencies] +winres = "0.1.12" + [target.'cfg(unix)'.dependencies] exec = "0.3.1" diff --git a/assets/icon.ico b/assets/icon.ico new file mode 100644 index 0000000..27cad1b Binary files /dev/null and b/assets/icon.ico differ diff --git a/assets/icon.png b/assets/icon.png new file mode 100644 index 0000000..8d865d0 Binary files /dev/null and b/assets/icon.png differ diff --git a/assets/icon_64.png b/assets/icon_64.png new file mode 100644 index 0000000..c249a63 Binary files /dev/null and b/assets/icon_64.png differ diff --git a/build.rs b/build.rs index e10776e..1f6705a 100644 --- a/build.rs +++ b/build.rs @@ -1,4 +1,10 @@ use anyhow::Result; use vergen::{vergen, Config}; -fn main() -> Result<()> { vergen(Config::default()) } +fn main() -> Result<()> { + #[cfg(windows)] + { + winres::WindowsResource::new().set_icon("assets/icon.ico").compile()?; + } + vergen(Config::default()) +} diff --git a/src/app.rs b/src/app.rs index c66e30c..3171a31 100644 --- a/src/app.rs +++ b/src/app.rs @@ -79,6 +79,11 @@ impl Default for ViewConfig { } } +pub struct SymbolReference { + pub symbol_name: String, + pub section_index: usize, +} + #[derive(serde::Deserialize, serde::Serialize)] #[serde(default)] pub struct ViewState { @@ -89,7 +94,7 @@ pub struct ViewState { #[serde(skip)] pub highlighted_symbol: Option, #[serde(skip)] - pub selected_symbol: Option, + pub selected_symbol: Option, #[serde(skip)] pub current_view: View, #[serde(skip)] diff --git a/src/main.rs b/src/main.rs index 2ef59b2..0d99c0e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,9 +3,27 @@ use std::{path::PathBuf, rc::Rc, sync::Mutex}; +use anyhow::{Error, Result}; use cfg_if::cfg_if; +use eframe::IconData; use time::UtcOffset; +fn load_icon() -> Result { + use bytes::Buf; + let decoder = png::Decoder::new(include_bytes!("../assets/icon_64.png").reader()); + let mut reader = decoder.read_info()?; + let mut buf = vec![0; reader.output_buffer_size()]; + let info = reader.next_frame(&mut buf)?; + if info.bit_depth != png::BitDepth::Eight { + return Err(Error::msg("Invalid bit depth")); + } + if info.color_type != png::ColorType::Rgba { + return Err(Error::msg("Invalid color type")); + } + buf.truncate(info.buffer_size()); + Ok(IconData { rgba: buf, width: info.width, height: info.height }) +} + // When compiling natively: #[cfg(not(target_arch = "wasm32"))] fn main() { @@ -19,7 +37,15 @@ fn main() { let exec_path: Rc>> = Rc::new(Mutex::new(None)); let exec_path_clone = exec_path.clone(); - let native_options = eframe::NativeOptions::default(); + let mut native_options = eframe::NativeOptions::default(); + match load_icon() { + Ok(data) => { + native_options.icon_data = Some(data); + } + Err(e) => { + log::warn!("Failed to load application icon: {}", e); + } + } // native_options.renderer = eframe::Renderer::Wgpu; eframe::run_native( "objdiff", diff --git a/src/obj/elf.rs b/src/obj/elf.rs index 4e1807a..98d2f0e 100644 --- a/src/obj/elf.rs +++ b/src/obj/elf.rs @@ -9,7 +9,7 @@ use object::{ R_PPC_EMB_SDA21, R_PPC_REL14, R_PPC_REL24, }, Architecture, File, Object, ObjectSection, ObjectSymbol, RelocationKind, RelocationTarget, - SectionKind, Symbol, SymbolKind, SymbolSection, + SectionIndex, SectionKind, Symbol, SymbolKind, SymbolSection, }; use crate::obj::{ @@ -192,9 +192,7 @@ fn relocations_by_section( obj_file: &File<'_>, section: &mut ObjSection, ) -> Result> { - let obj_section = obj_file - .section_by_name(§ion.name) - .ok_or_else(|| anyhow::Error::msg("Failed to locate section"))?; + let obj_section = obj_file.section_by_index(SectionIndex(section.index))?; let mut relocations = Vec::::new(); for (address, reloc) in obj_section.relocations() { let symbol = match reloc.target() { diff --git a/src/views/data_diff.rs b/src/views/data_diff.rs index 8cae0c6..0bd1a1e 100644 --- a/src/views/data_diff.rs +++ b/src/views/data_diff.rs @@ -5,7 +5,7 @@ use egui_extras::{Size, StripBuilder, TableBuilder}; use time::format_description; use crate::{ - app::{View, ViewConfig, ViewState}, + app::{SymbolReference, View, ViewConfig, ViewState}, jobs::Job, obj::{ObjDataDiff, ObjDataDiffKind, ObjInfo, ObjSection}, views::{write_text, COLOR_RED}, @@ -13,8 +13,8 @@ use crate::{ const BYTES_PER_ROW: usize = 16; -fn find_section<'a>(obj: &'a ObjInfo, section_name: &str) -> Option<&'a ObjSection> { - obj.sections.iter().find(|s| s.name == section_name) +fn find_section<'a>(obj: &'a ObjInfo, selected_symbol: &SymbolReference) -> Option<&'a ObjSection> { + obj.sections.get(selected_symbol.section_index) } fn data_row_ui(ui: &mut egui::Ui, address: usize, diffs: &[ObjDataDiff], config: &ViewConfig) { @@ -132,11 +132,11 @@ fn data_table_ui( table: TableBuilder<'_>, left_obj: &ObjInfo, right_obj: &ObjInfo, - section_name: &str, + selected_symbol: &SymbolReference, config: &ViewConfig, ) -> Option<()> { - let left_section = find_section(left_obj, section_name)?; - let right_section = find_section(right_obj, section_name)?; + let left_section = find_section(left_obj, selected_symbol)?; + let right_section = find_section(right_obj, selected_symbol)?; let total_bytes = left_section.data_diff.iter().fold(0usize, |accum, item| accum + item.len); if total_bytes == 0 { @@ -219,7 +219,7 @@ pub fn data_diff_ui(ui: &mut egui::Ui, view_state: &mut ViewState) -> bool { ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace); ui.style_mut().wrap = Some(false); - ui.colored_label(Color32::WHITE, selected_symbol); + ui.colored_label(Color32::WHITE, &selected_symbol.symbol_name); ui.label("Diff target:"); ui.separator(); }); diff --git a/src/views/function_diff.rs b/src/views/function_diff.rs index 3bfb3d8..87de16a 100644 --- a/src/views/function_diff.rs +++ b/src/views/function_diff.rs @@ -7,7 +7,7 @@ use ppc750cl::Argument; use time::format_description; use crate::{ - app::{View, ViewConfig, ViewState}, + app::{SymbolReference, View, ViewConfig, ViewState}, jobs::Job, obj::{ ObjInfo, ObjIns, ObjInsArg, ObjInsArgDiff, ObjInsDiff, ObjInsDiffKind, ObjReloc, @@ -240,9 +240,9 @@ fn ins_context_menu(ui: &mut egui::Ui, ins: &ObjIns) { }); } -fn find_symbol<'a>(obj: &'a ObjInfo, section_name: &str, name: &str) -> Option<&'a ObjSymbol> { - let section = obj.sections.iter().find(|s| s.name == section_name)?; - section.symbols.iter().find(|s| s.name == name) +fn find_symbol<'a>(obj: &'a ObjInfo, selected_symbol: &SymbolReference) -> Option<&'a ObjSymbol> { + let section = obj.sections.get(selected_symbol.section_index)?; + section.symbols.iter().find(|s| s.name == selected_symbol.symbol_name) } fn asm_row_ui(ui: &mut egui::Ui, ins_diff: &ObjInsDiff, symbol: &ObjSymbol, config: &ViewConfig) { @@ -296,11 +296,11 @@ fn asm_table_ui( table: TableBuilder<'_>, left_obj: &ObjInfo, right_obj: &ObjInfo, - fn_name: &str, + selected_symbol: &SymbolReference, config: &ViewConfig, ) -> Option<()> { - let left_symbol = find_symbol(left_obj, ".text", fn_name); - let right_symbol = find_symbol(right_obj, ".text", fn_name); + let left_symbol = find_symbol(left_obj, selected_symbol); + let right_symbol = find_symbol(right_obj, selected_symbol); let instructions_len = left_symbol.or(right_symbol).map(|s| s.instructions.len())?; table.body(|body| { body.rows(config.code_font.size, instructions_len, |row_index, mut row| { @@ -372,7 +372,7 @@ pub fn function_diff_ui(ui: &mut egui::Ui, view_state: &mut ViewState) -> bool { }); strip.strip(|builder| { builder.sizes(Size::remainder(), 2).horizontal(|mut strip| { - let demangled = demangle(selected_symbol, &Default::default()); + let demangled = demangle(&selected_symbol.symbol_name, &Default::default()); strip.cell(|ui| { ui.scope(|ui| { ui.style_mut().override_text_style = @@ -380,7 +380,7 @@ pub fn function_diff_ui(ui: &mut egui::Ui, view_state: &mut ViewState) -> bool { ui.style_mut().wrap = Some(false); ui.colored_label( Color32::WHITE, - demangled.as_ref().unwrap_or(selected_symbol), + demangled.as_ref().unwrap_or(&selected_symbol.symbol_name), ); ui.label("Diff target:"); ui.separator(); @@ -394,7 +394,7 @@ pub fn function_diff_ui(ui: &mut egui::Ui, view_state: &mut ViewState) -> bool { if let Some(match_percent) = result .second_obj .as_ref() - .and_then(|obj| find_symbol(obj, ".text", selected_symbol)) + .and_then(|obj| find_symbol(obj, selected_symbol)) .and_then(|symbol| symbol.match_percent) { ui.colored_label( diff --git a/src/views/symbol_diff.rs b/src/views/symbol_diff.rs index 95a9474..5643f18 100644 --- a/src/views/symbol_diff.rs +++ b/src/views/symbol_diff.rs @@ -4,7 +4,7 @@ use egui::{ use egui_extras::{Size, StripBuilder}; use crate::{ - app::{View, ViewConfig, ViewState}, + app::{SymbolReference, View, ViewConfig, ViewState}, jobs::objdiff::BuildStatus, obj::{ObjInfo, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlags}, views::write_text, @@ -56,9 +56,9 @@ fn symbol_hover_ui(ui: &mut Ui, symbol: &ObjSymbol) { fn symbol_ui( ui: &mut Ui, symbol: &ObjSymbol, - section: Option<&ObjSection>, + section: Option<(usize, &ObjSection)>, highlighted_symbol: &mut Option, - selected_symbol: &mut Option, + selected_symbol: &mut Option, current_view: &mut View, config: &ViewConfig, ) { @@ -97,12 +97,14 @@ fn symbol_ui( .context_menu(|ui| symbol_context_menu_ui(ui, symbol)) .on_hover_ui_at_pointer(|ui| symbol_hover_ui(ui, symbol)); if response.clicked() { - if let Some(section) = section { + if let Some((section_index, section)) = section { if section.kind == ObjSectionKind::Code { - *selected_symbol = Some(symbol.name.clone()); + *selected_symbol = + Some(SymbolReference { symbol_name: symbol.name.clone(), section_index }); *current_view = View::FunctionDiff; } else if section.kind == ObjSectionKind::Data { - *selected_symbol = Some(section.name.clone()); + *selected_symbol = + Some(SymbolReference { symbol_name: section.name.clone(), section_index }); *current_view = View::DataDiff; } } @@ -126,7 +128,7 @@ fn symbol_list_ui( ui: &mut Ui, obj: &ObjInfo, highlighted_symbol: &mut Option, - selected_symbol: &mut Option, + selected_symbol: &mut Option, current_view: &mut View, reverse_function_order: bool, search: &mut String, @@ -156,7 +158,7 @@ fn symbol_list_ui( }); } - for section in &obj.sections { + for (section_index, section) in obj.sections.iter().enumerate() { CollapsingHeader::new(format!("{} ({:x})", section.name, section.size)) .default_open(true) .show(ui, |ui| { @@ -168,7 +170,7 @@ fn symbol_list_ui( symbol_ui( ui, symbol, - Some(section), + Some((section_index, section)), highlighted_symbol, selected_symbol, current_view, @@ -183,7 +185,7 @@ fn symbol_list_ui( symbol_ui( ui, symbol, - Some(section), + Some((section_index, section)), highlighted_symbol, selected_symbol, current_view,