diff --git a/src/app.rs b/src/app.rs index b72ea23..3fba8fa 100644 --- a/src/app.rs +++ b/src/app.rs @@ -15,7 +15,7 @@ use notify::{RecursiveMode, Watcher}; use crate::{ jobs::{ - build::{queue_build, BuildResult, BuildStatus}, + objdiff::{queue_build, BuildStatus, ObjDiffResult}, Job, JobResult, JobState, }, views::{ @@ -44,7 +44,7 @@ pub struct ViewState { #[serde(skip)] pub jobs: Vec, #[serde(skip)] - pub build: Option>, + pub build: Option>, #[serde(skip)] pub highlighted_symbol: Option, #[serde(skip)] @@ -68,9 +68,10 @@ pub struct AppConfig { pub selected_wsl_distro: Option, // Split obj pub project_dir: Option, - pub build_asm_dir: Option, - pub build_src_dir: Option, - pub build_obj: Option, + pub target_obj_dir: Option, + pub base_obj_dir: Option, + pub obj_path: Option, + pub build_target: bool, // Whole binary pub left_obj: Option, pub right_obj: Option, @@ -237,11 +238,11 @@ impl eframe::App for App { log::error!("{:?}", err); } } - JobResult::Build(state) => { + JobResult::ObjDiff(state) => { self.view_state.build = Some(state); } JobResult::BinDiff(state) => { - self.view_state.build = Some(Box::new(BuildResult { + self.view_state.build = Some(Box::new(ObjDiffResult { first_status: BuildStatus { success: true, log: "".to_string(), @@ -287,13 +288,13 @@ impl eframe::App for App { } } - if let Some(build_obj) = &config.build_obj { + if let Some(build_obj) = &config.obj_path { if self.modified.load(Ordering::Relaxed) { if !self .view_state .jobs .iter() - .any(|j| j.job_type == Job::Build && j.handle.is_some()) + .any(|j| j.job_type == Job::ObjDiff && j.handle.is_some()) { self.view_state .jobs diff --git a/src/jobs/bindiff.rs b/src/jobs/bindiff.rs index 0cdad49..f6b6c96 100644 --- a/src/jobs/bindiff.rs +++ b/src/jobs/bindiff.rs @@ -5,9 +5,8 @@ use anyhow::{Error, Result}; use crate::{ app::AppConfig, diff::diff_objs, - elf, jobs::{queue_job, update_status, Job, JobResult, JobState, Status}, - obj::ObjInfo, + obj::{elf, ObjInfo}, }; pub struct BinDiffResult { @@ -21,15 +20,15 @@ fn run_build( config: Arc>, ) -> Result> { let config = config.read().map_err(|_| Error::msg("Failed to lock app config"))?.clone(); - let left_path = config.left_obj.as_ref().ok_or_else(|| Error::msg("Missing left obj path"))?; - let right_path = - config.right_obj.as_ref().ok_or_else(|| Error::msg("Missing right obj path"))?; + let target_path = + config.left_obj.as_ref().ok_or_else(|| Error::msg("Missing target obj path"))?; + let base_path = config.right_obj.as_ref().ok_or_else(|| Error::msg("Missing base obj path"))?; - update_status(status, "Loading left obj".to_string(), 0, 3, &cancel)?; - let mut left_obj = elf::read(left_path)?; + update_status(status, "Loading target obj".to_string(), 0, 3, &cancel)?; + let mut left_obj = elf::read(target_path)?; - update_status(status, "Loading right obj".to_string(), 1, 3, &cancel)?; - let mut right_obj = elf::read(right_path)?; + update_status(status, "Loading base obj".to_string(), 1, 3, &cancel)?; + let mut right_obj = elf::read(base_path)?; update_status(status, "Performing diff".to_string(), 2, 3, &cancel)?; diff_objs(&mut left_obj, &mut right_obj)?; diff --git a/src/jobs/mod.rs b/src/jobs/mod.rs index e9af63e..b1081b2 100644 --- a/src/jobs/mod.rs +++ b/src/jobs/mod.rs @@ -9,14 +9,14 @@ use std::{ use anyhow::Result; -use crate::jobs::{bindiff::BinDiffResult, build::BuildResult}; +use crate::jobs::{bindiff::BinDiffResult, objdiff::ObjDiffResult}; pub mod bindiff; -pub mod build; +pub mod objdiff; #[derive(Debug, Eq, PartialEq, Copy, Clone)] pub enum Job { - Build, + ObjDiff, BinDiff, } pub static JOB_ID: AtomicUsize = AtomicUsize::new(0); @@ -38,7 +38,7 @@ pub struct JobStatus { } pub enum JobResult { None, - Build(Box), + ObjDiff(Box), BinDiff(Box), } diff --git a/src/jobs/build.rs b/src/jobs/objdiff.rs similarity index 65% rename from src/jobs/build.rs rename to src/jobs/objdiff.rs index bf93c67..183cffd 100644 --- a/src/jobs/build.rs +++ b/src/jobs/objdiff.rs @@ -10,16 +10,15 @@ use anyhow::{Context, Error, Result}; use crate::{ app::AppConfig, diff::diff_objs, - elf, jobs::{queue_job, update_status, Job, JobResult, JobState, Status}, - obj::ObjInfo, + obj::{elf, ObjInfo}, }; pub struct BuildStatus { pub success: bool, pub log: String, } -pub struct BuildResult { +pub struct ObjDiffResult { pub first_status: BuildStatus, pub second_status: BuildStatus, pub first_obj: Option, @@ -78,58 +77,61 @@ fn run_build( cancel: Receiver<()>, obj_path: String, config: Arc>, -) -> Result> { +) -> Result> { let config = config.read().map_err(|_| Error::msg("Failed to lock app config"))?.clone(); let project_dir = config.project_dir.as_ref().ok_or_else(|| Error::msg("Missing project dir"))?; - let mut asm_path = config - .build_asm_dir + let mut target_path = config + .target_obj_dir .as_ref() - .ok_or_else(|| Error::msg("Missing build asm dir"))? + .ok_or_else(|| Error::msg("Missing target obj dir"))? .to_owned(); - asm_path.push(&obj_path); - let mut src_path = config - .build_src_dir - .as_ref() - .ok_or_else(|| Error::msg("Missing build src dir"))? - .to_owned(); - src_path.push(&obj_path); - let asm_path_rel = - asm_path.strip_prefix(project_dir).context("Failed to create relative asm obj path")?; - let src_path_rel = - src_path.strip_prefix(project_dir).context("Failed to create relative src obj path")?; + target_path.push(&obj_path); + let mut base_path = + config.base_obj_dir.as_ref().ok_or_else(|| Error::msg("Missing base obj dir"))?.to_owned(); + base_path.push(&obj_path); + let target_path_rel = target_path + .strip_prefix(project_dir) + .context("Failed to create relative target obj path")?; + let base_path_rel = + base_path.strip_prefix(project_dir).context("Failed to create relative base obj path")?; - update_status(status, format!("Building asm {}", obj_path), 0, 5, &cancel)?; - let first_status = run_make(project_dir, asm_path_rel, &config); + let total = if config.build_target { 5 } else { 4 }; + let first_status = if config.build_target { + update_status(status, format!("Building target {}", obj_path), 0, total, &cancel)?; + run_make(project_dir, target_path_rel, &config) + } else { + BuildStatus { success: true, log: String::new() } + }; - update_status(status, format!("Building src {}", obj_path), 1, 5, &cancel)?; - let second_status = run_make(project_dir, src_path_rel, &config); + update_status(status, format!("Building base {}", obj_path), 1, total, &cancel)?; + let second_status = run_make(project_dir, base_path_rel, &config); let mut first_obj = if first_status.success { - update_status(status, format!("Loading asm {}", obj_path), 2, 5, &cancel)?; - Some(elf::read(&asm_path)?) + update_status(status, format!("Loading target {}", obj_path), 2, total, &cancel)?; + Some(elf::read(&target_path)?) } else { None }; let mut second_obj = if second_status.success { - update_status(status, format!("Loading src {}", obj_path), 3, 5, &cancel)?; - Some(elf::read(&src_path)?) + update_status(status, format!("Loading base {}", obj_path), 3, total, &cancel)?; + Some(elf::read(&base_path)?) } else { None }; if let (Some(first_obj), Some(second_obj)) = (&mut first_obj, &mut second_obj) { - update_status(status, "Performing diff".to_string(), 4, 5, &cancel)?; + update_status(status, "Performing diff".to_string(), 4, total, &cancel)?; diff_objs(first_obj, second_obj)?; } - update_status(status, "Complete".to_string(), 5, 5, &cancel)?; - Ok(Box::new(BuildResult { first_status, second_status, first_obj, second_obj })) + update_status(status, "Complete".to_string(), total, total, &cancel)?; + Ok(Box::new(ObjDiffResult { first_status, second_status, first_obj, second_obj })) } pub fn queue_build(obj_path: String, config: Arc>) -> JobState { - queue_job(Job::Build, move |status, cancel| { - run_build(status, cancel, obj_path, config).map(JobResult::Build) + queue_job(Job::ObjDiff, move |status, cancel| { + run_build(status, cancel, obj_path, config).map(JobResult::ObjDiff) }) } diff --git a/src/lib.rs b/src/lib.rs index acc522a..0ffed1d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,6 @@ pub use app::App; mod app; mod diff; mod editops; -mod elf; mod jobs; mod obj; mod views; diff --git a/src/elf.rs b/src/obj/elf.rs similarity index 100% rename from src/elf.rs rename to src/obj/elf.rs diff --git a/src/obj.rs b/src/obj/mod.rs similarity index 95% rename from src/obj.rs rename to src/obj/mod.rs index fb8222d..864aeb5 100644 --- a/src/obj.rs +++ b/src/obj/mod.rs @@ -1,3 +1,4 @@ +pub mod elf; pub mod mips; pub mod ppc; @@ -142,9 +143,3 @@ pub struct ObjReloc { pub target: ObjSymbol, pub target_section: Option, } -// #[derive(Debug, Clone)] -// pub struct ObjInsDiff { -// pub kind: ObjInsDiffKind, -// pub left: Option, -// pub right: Option, -// } diff --git a/src/views/config.rs b/src/views/config.rs index 041c446..7ef640f 100644 --- a/src/views/config.rs +++ b/src/views/config.rs @@ -7,7 +7,7 @@ use anyhow::{Context, Result}; use crate::{ app::{AppConfig, DiffKind, ViewState}, - jobs::{bindiff::queue_bindiff, build::queue_build}, + jobs::{bindiff::queue_bindiff, objdiff::queue_build}, }; #[cfg(windows)] @@ -50,12 +50,13 @@ pub fn config_ui(ui: &mut egui::Ui, config: &Arc>, view_state: available_wsl_distros, selected_wsl_distro, project_dir, - project_dir_change, - build_asm_dir, - build_src_dir, - build_obj, + target_obj_dir, + base_obj_dir, + obj_path, + build_target, left_obj, right_obj, + project_dir_change, } = &mut *config_guard; ui.heading("Build config"); @@ -92,9 +93,9 @@ pub fn config_ui(ui: &mut egui::Ui, config: &Arc>, view_state: if let Some(path) = rfd::FileDialog::new().pick_folder() { *project_dir = Some(path); *project_dir_change = true; - *build_asm_dir = None; - *build_src_dir = None; - *build_obj = None; + *target_obj_dir = None; + *base_obj_dir = None; + *obj_path = None; } } if let Some(dir) = project_dir { @@ -104,58 +105,59 @@ pub fn config_ui(ui: &mut egui::Ui, config: &Arc>, view_state: ui.separator(); if let Some(project_dir) = project_dir { - if ui.button("Select asm build dir").clicked() { + if ui.button("Select target build dir").clicked() { if let Some(path) = rfd::FileDialog::new().set_directory(&project_dir).pick_folder() { - *build_asm_dir = Some(path); - *build_obj = None; + *target_obj_dir = Some(path); + *obj_path = None; } } - if let Some(dir) = build_asm_dir { + if let Some(dir) = target_obj_dir { ui.label(dir.to_string_lossy()); } + ui.checkbox(build_target, "Build target"); ui.separator(); - if ui.button("Select src build dir").clicked() { + if ui.button("Select base build dir").clicked() { if let Some(path) = rfd::FileDialog::new().set_directory(&project_dir).pick_folder() { - *build_src_dir = Some(path); - *build_obj = None; + *base_obj_dir = Some(path); + *obj_path = None; } } - if let Some(dir) = build_src_dir { + if let Some(dir) = base_obj_dir { ui.label(dir.to_string_lossy()); } ui.separator(); } - if let Some(build_src_dir) = build_src_dir { + if let Some(base_dir) = base_obj_dir { if ui.button("Select obj").clicked() { if let Some(path) = rfd::FileDialog::new() - .set_directory(&build_src_dir) + .set_directory(&base_dir) .add_filter("Object file", &["o", "elf"]) .pick_file() { let mut new_build_obj: Option = None; - if let Ok(obj_path) = path.strip_prefix(&build_src_dir) { + if let Ok(obj_path) = path.strip_prefix(&base_dir) { new_build_obj = Some(obj_path.display().to_string()); - } else if let Some(build_asm_dir) = build_asm_dir { + } else if let Some(build_asm_dir) = target_obj_dir { if let Ok(obj_path) = path.strip_prefix(&build_asm_dir) { new_build_obj = Some(obj_path.display().to_string()); } } if let Some(new_build_obj) = new_build_obj { - *build_obj = Some(new_build_obj.clone()); + *obj_path = Some(new_build_obj.clone()); view_state.jobs.push(queue_build(new_build_obj, config.clone())); } } } - if let Some(build_obj) = build_obj { - ui.label(&*build_obj); + if let Some(obj) = obj_path { + ui.label(&*obj); if ui.button("Build").clicked() { - view_state.jobs.push(queue_build(build_obj.clone(), config.clone())); + view_state.jobs.push(queue_build(obj.clone(), config.clone())); } } diff --git a/src/views/function_diff.rs b/src/views/function_diff.rs index 18b56ff..90d0d3c 100644 --- a/src/views/function_diff.rs +++ b/src/views/function_diff.rs @@ -324,7 +324,7 @@ pub fn function_diff_ui(ui: &mut egui::Ui, view_state: &mut ViewState) { Color32::WHITE, demangled.as_ref().unwrap_or(selected_symbol), ); - ui.label("Diff asm:"); + ui.label("Diff target:"); ui.separator(); }); }); @@ -342,7 +342,7 @@ pub fn function_diff_ui(ui: &mut egui::Ui, view_state: &mut ViewState) { ); } } - ui.label("Diff src:"); + ui.label("Diff base:"); ui.separator(); }); }); diff --git a/src/views/symbol_diff.rs b/src/views/symbol_diff.rs index 6a65850..3b462df 100644 --- a/src/views/symbol_diff.rs +++ b/src/views/symbol_diff.rs @@ -6,7 +6,7 @@ use egui_extras::{Size, StripBuilder}; use crate::{ app::{View, ViewState}, - jobs::build::BuildStatus, + jobs::objdiff::BuildStatus, obj::{ObjInfo, ObjSymbol, ObjSymbolFlags}, }; @@ -20,6 +20,13 @@ pub fn match_color_for_symbol(symbol: &ObjSymbol) -> Color32 { } } +const FONT_SIZE: f32 = 14.0; +const FONT_ID: FontId = FontId::new(FONT_SIZE, FontFamily::Monospace); + +fn write_text(str: &str, color: Color32, job: &mut LayoutJob) { + job.append(str, 0.0, TextFormat { font_id: FONT_ID, color, ..Default::default() }); +} + fn symbol_ui( ui: &mut Ui, symbol: &ObjSymbol, @@ -34,61 +41,28 @@ fn symbol_ui( if let Some(sym) = highlighted_symbol { selected = sym == &symbol.name; } - let font_id = FontId::new(14.0, FontFamily::Monospace); - job.append("[", 0.0, TextFormat { - font_id: font_id.clone(), - color: Color32::GRAY, - ..Default::default() - }); + write_text("[", Color32::GRAY, &mut job); if symbol.flags.0.contains(ObjSymbolFlags::Common) { - job.append("c", 0.0, TextFormat { - font_id: font_id.clone(), - color: Color32::from_rgb(0, 255, 255), - ..Default::default() - }); + write_text("c", Color32::from_rgb(0, 255, 255), &mut job); } else if symbol.flags.0.contains(ObjSymbolFlags::Global) { - job.append("g", 0.0, TextFormat { - font_id: font_id.clone(), - color: Color32::GREEN, - ..Default::default() - }); + write_text("g", Color32::GREEN, &mut job); } else if symbol.flags.0.contains(ObjSymbolFlags::Local) { - job.append("l", 0.0, TextFormat { - font_id: font_id.clone(), - color: Color32::GRAY, - ..Default::default() - }); + write_text("l", Color32::GRAY, &mut job); } if symbol.flags.0.contains(ObjSymbolFlags::Weak) { - job.append("w", 0.0, TextFormat { - font_id: font_id.clone(), - color: Color32::GRAY, - ..Default::default() - }); + write_text("w", Color32::GRAY, &mut job); } - job.append("] ", 0.0, TextFormat { - font_id: font_id.clone(), - color: Color32::GRAY, - ..Default::default() - }); + write_text("] ", Color32::GRAY, &mut job); if symbol.match_percent > 0.0 { - job.append("(", 0.0, TextFormat { - font_id: font_id.clone(), - color: Color32::GRAY, - ..Default::default() - }); - job.append(&format!("{:.0}%", symbol.match_percent), 0.0, TextFormat { - font_id: font_id.clone(), - color: match_color_for_symbol(symbol), - ..Default::default() - }); - job.append(") ", 0.0, TextFormat { - font_id: font_id.clone(), - color: Color32::GRAY, - ..Default::default() - }); + write_text("(", Color32::GRAY, &mut job); + write_text( + &format!("{:.0}%", symbol.match_percent), + match_color_for_symbol(symbol), + &mut job, + ); + write_text(") ", Color32::GRAY, &mut job); } - job.append(name, 0.0, TextFormat { font_id, color: Color32::WHITE, ..Default::default() }); + write_text(name, Color32::WHITE, &mut job); let response = SelectableLabel::new(selected, job).ui(ui); if response.clicked() { *selected_symbol = Some(symbol.name.clone()); @@ -175,7 +149,7 @@ pub fn symbol_diff_ui(ui: &mut Ui, view_state: &mut ViewState) { Some(egui::TextStyle::Monospace); ui.style_mut().wrap = Some(false); - ui.label("Build asm:"); + ui.label("Build target:"); if result.first_status.success { ui.label("OK"); } else { @@ -190,7 +164,7 @@ pub fn symbol_diff_ui(ui: &mut Ui, view_state: &mut ViewState) { Some(egui::TextStyle::Monospace); ui.style_mut().wrap = Some(false); - ui.label("Build src:"); + ui.label("Build base:"); if result.second_status.success { ui.label("OK"); } else {