Skip to content

Commit 3224be2

Browse files
committed
Rework function diff view (fixes #12)
1 parent 1e44f73 commit 3224be2

File tree

10 files changed

+183
-45
lines changed

10 files changed

+183
-45
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ rfd = { version = "0.10.0" } # , default-features = false, features = ['xdg-port
2626
egui_extras = "0.19.0"
2727
ppc750cl = { git = "https://github.com/terorie/ppc750cl" }
2828
rabbitizer = { git = "https://github.com/encounter/rabbitizer-rs", rev = "10c279b2ef251c62885b1dcdcfe740b0db8e9956" }
29+
time = { version = "0.3.14", features = ["formatting", "local-offset"] }
2930

3031
[target.'cfg(windows)'.dependencies]
3132
path-slash = "0.2.0"

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ A tool for decompilation projects.
77

88
Currently supports:
99
- PowerPC 750CL (GameCube & Wii)
10+
- MIPS (Nintendo 64)
1011

1112
**WARNING:** Very early & unstable.
1213

src/app.rs

Lines changed: 64 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use std::{
1212
use eframe::Frame;
1313
use egui::Widget;
1414
use notify::{RecursiveMode, Watcher};
15+
use time::{OffsetDateTime, UtcOffset};
1516

1617
use crate::{
1718
jobs::{
@@ -38,7 +39,14 @@ pub enum DiffKind {
3839
WholeBinary,
3940
}
4041

41-
#[derive(Default, serde::Deserialize, serde::Serialize)]
42+
#[derive(Default, Clone)]
43+
pub struct DiffConfig {
44+
// TODO
45+
// pub stripped_symbols: Vec<String>,
46+
// pub mapped_symbols: HashMap<String, String>,
47+
}
48+
49+
#[derive(serde::Deserialize, serde::Serialize)]
4250
#[serde(default)]
4351
pub struct ViewState {
4452
#[serde(skip)]
@@ -53,11 +61,35 @@ pub struct ViewState {
5361
pub current_view: View,
5462
#[serde(skip)]
5563
pub show_config: bool,
64+
#[serde(skip)]
65+
pub diff_config: DiffConfig,
66+
#[serde(skip)]
67+
pub search: String,
68+
#[serde(skip)]
69+
pub utc_offset: UtcOffset,
5670
// Config
5771
pub diff_kind: DiffKind,
5872
pub reverse_fn_order: bool,
5973
}
6074

75+
impl Default for ViewState {
76+
fn default() -> Self {
77+
Self {
78+
jobs: vec![],
79+
build: None,
80+
highlighted_symbol: None,
81+
selected_symbol: None,
82+
current_view: Default::default(),
83+
show_config: false,
84+
diff_config: Default::default(),
85+
search: Default::default(),
86+
utc_offset: UtcOffset::UTC,
87+
diff_kind: Default::default(),
88+
reverse_fn_order: false,
89+
}
90+
}
91+
}
92+
6193
#[derive(Default, Clone, serde::Deserialize, serde::Serialize)]
6294
#[serde(default)]
6395
pub struct AppConfig {
@@ -107,7 +139,7 @@ const CONFIG_KEY: &str = "app_config";
107139

108140
impl App {
109141
/// Called once before the first frame.
110-
pub fn new(cc: &eframe::CreationContext<'_>) -> Self {
142+
pub fn new(cc: &eframe::CreationContext<'_>, utc_offset: UtcOffset) -> Self {
111143
// This is also where you can customized the look at feel of egui using
112144
// `cc.egui_ctx.set_visuals` and `cc.egui_ctx.set_fonts`.
113145

@@ -120,6 +152,7 @@ impl App {
120152
config.project_dir_change = true;
121153
}
122154
app.config = Arc::new(RwLock::new(config));
155+
app.view_state.utc_offset = utc_offset;
123156
app
124157
} else {
125158
Self::default()
@@ -149,16 +182,20 @@ impl eframe::App for App {
149182
if view_state.current_view == View::FunctionDiff
150183
&& matches!(&view_state.build, Some(b) if b.first_status.success && b.second_status.success)
151184
{
152-
egui::SidePanel::left("side_panel").show(ctx, |ui| {
153-
if ui.button("Back").clicked() {
154-
view_state.current_view = View::SymbolDiff;
155-
}
156-
ui.separator();
157-
jobs_ui(ui, view_state);
158-
});
185+
// egui::SidePanel::left("side_panel").show(ctx, |ui| {
186+
// if ui.button("Back").clicked() {
187+
// view_state.current_view = View::SymbolDiff;
188+
// }
189+
// ui.separator();
190+
// jobs_ui(ui, view_state);
191+
// });
159192

160193
egui::CentralPanel::default().show(ctx, |ui| {
161-
function_diff_ui(ui, view_state);
194+
if function_diff_ui(ui, view_state) {
195+
view_state
196+
.jobs
197+
.push(queue_build(config.clone(), view_state.diff_config.clone()));
198+
}
162199
});
163200
} else {
164201
egui::SidePanel::left("side_panel").show(ctx, |ui| {
@@ -253,6 +290,7 @@ impl eframe::App for App {
253290
},
254291
first_obj: Some(state.first_obj),
255292
second_obj: Some(state.second_obj),
293+
time: OffsetDateTime::now_utc(),
256294
}));
257295
}
258296
}
@@ -267,7 +305,10 @@ impl eframe::App for App {
267305
let mut i = 0;
268306
while i < self.view_state.jobs.len() {
269307
let job = &self.view_state.jobs[i];
270-
if job.should_remove && job.handle.is_none() {
308+
if job.should_remove
309+
&& job.handle.is_none()
310+
&& job.status.read().unwrap().error.is_none()
311+
{
271312
self.view_state.jobs.remove(i);
272313
} else {
273314
i += 1;
@@ -288,20 +329,19 @@ impl eframe::App for App {
288329
}
289330
}
290331

291-
if let Some(build_obj) = &config.obj_path {
292-
if self.modified.load(Ordering::Relaxed) {
293-
if !self
294-
.view_state
295-
.jobs
296-
.iter()
297-
.any(|j| j.job_type == Job::ObjDiff && j.handle.is_some())
298-
{
299-
self.view_state
300-
.jobs
301-
.push(queue_build(build_obj.clone(), self.config.clone()));
302-
}
303-
self.modified.store(false, Ordering::Relaxed);
332+
if config.obj_path.is_some() && self.modified.load(Ordering::Relaxed) {
333+
if !self
334+
.view_state
335+
.jobs
336+
.iter()
337+
.any(|j| j.job_type == Job::ObjDiff && j.handle.is_some())
338+
{
339+
self.view_state.jobs.push(queue_build(
340+
self.config.clone(),
341+
self.view_state.diff_config.clone(),
342+
));
304343
}
344+
self.modified.store(false, Ordering::Relaxed);
305345
}
306346
}
307347
}

src/diff.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::collections::BTreeMap;
33
use anyhow::Result;
44

55
use crate::{
6+
app::DiffConfig,
67
editops::{editops_find, LevEditType},
78
obj::{
89
mips, ppc, ObjArchitecture, ObjInfo, ObjInsArg, ObjInsArgDiff, ObjInsBranchFrom,
@@ -336,7 +337,7 @@ fn find_symbol<'a>(symbols: &'a mut [ObjSymbol], name: &str) -> Option<&'a mut O
336337
symbols.iter_mut().find(|s| s.name == name)
337338
}
338339

339-
pub fn diff_objs(left: &mut ObjInfo, right: &mut ObjInfo) -> Result<()> {
340+
pub fn diff_objs(left: &mut ObjInfo, right: &mut ObjInfo, _diff_config: &DiffConfig) -> Result<()> {
340341
for left_section in &mut left.sections {
341342
if let Some(right_section) = find_section(right, &left_section.name) {
342343
for left_symbol in &mut left_section.symbols {

src/jobs/bindiff.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::sync::{mpsc::Receiver, Arc, RwLock};
33
use anyhow::{Error, Result};
44

55
use crate::{
6-
app::AppConfig,
6+
app::{AppConfig, DiffConfig},
77
diff::diff_objs,
88
jobs::{queue_job, update_status, Job, JobResult, JobState, Status},
99
obj::{elf, ObjInfo},
@@ -31,7 +31,7 @@ fn run_build(
3131
let mut right_obj = elf::read(base_path)?;
3232

3333
update_status(status, "Performing diff".to_string(), 2, 3, &cancel)?;
34-
diff_objs(&mut left_obj, &mut right_obj)?;
34+
diff_objs(&mut left_obj, &mut right_obj, &DiffConfig::default() /* TODO */)?;
3535

3636
update_status(status, "Complete".to_string(), 3, 3, &cancel)?;
3737
Ok(Box::new(BinDiffResult { first_obj: left_obj, second_obj: right_obj }))

src/jobs/objdiff.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ use std::{
66
};
77

88
use anyhow::{Context, Error, Result};
9+
use time::OffsetDateTime;
910

1011
use crate::{
11-
app::AppConfig,
12+
app::{AppConfig, DiffConfig},
1213
diff::diff_objs,
1314
jobs::{queue_job, update_status, Job, JobResult, JobState, Status},
1415
obj::{elf, ObjInfo},
@@ -23,6 +24,7 @@ pub struct ObjDiffResult {
2324
pub second_status: BuildStatus,
2425
pub first_obj: Option<ObjInfo>,
2526
pub second_obj: Option<ObjInfo>,
27+
pub time: OffsetDateTime,
2628
}
2729

2830
fn run_make(cwd: &Path, arg: &Path, config: &AppConfig) -> BuildStatus {
@@ -75,21 +77,22 @@ fn run_make(cwd: &Path, arg: &Path, config: &AppConfig) -> BuildStatus {
7577
fn run_build(
7678
status: &Status,
7779
cancel: Receiver<()>,
78-
obj_path: String,
7980
config: Arc<RwLock<AppConfig>>,
81+
diff_config: DiffConfig,
8082
) -> Result<Box<ObjDiffResult>> {
8183
let config = config.read().map_err(|_| Error::msg("Failed to lock app config"))?.clone();
84+
let obj_path = config.obj_path.as_ref().ok_or_else(|| Error::msg("Missing obj path"))?;
8285
let project_dir =
8386
config.project_dir.as_ref().ok_or_else(|| Error::msg("Missing project dir"))?;
8487
let mut target_path = config
8588
.target_obj_dir
8689
.as_ref()
8790
.ok_or_else(|| Error::msg("Missing target obj dir"))?
8891
.to_owned();
89-
target_path.push(&obj_path);
92+
target_path.push(obj_path);
9093
let mut base_path =
9194
config.base_obj_dir.as_ref().ok_or_else(|| Error::msg("Missing base obj dir"))?.to_owned();
92-
base_path.push(&obj_path);
95+
base_path.push(obj_path);
9396
let target_path_rel = target_path
9497
.strip_prefix(project_dir)
9598
.context("Failed to create relative target obj path")?;
@@ -107,6 +110,8 @@ fn run_build(
107110
update_status(status, format!("Building base {}", obj_path), 1, total, &cancel)?;
108111
let second_status = run_make(project_dir, base_path_rel, &config);
109112

113+
let time = OffsetDateTime::now_utc();
114+
110115
let mut first_obj = if first_status.success {
111116
update_status(status, format!("Loading target {}", obj_path), 2, total, &cancel)?;
112117
Some(elf::read(&target_path)?)
@@ -123,15 +128,15 @@ fn run_build(
123128

124129
if let (Some(first_obj), Some(second_obj)) = (&mut first_obj, &mut second_obj) {
125130
update_status(status, "Performing diff".to_string(), 4, total, &cancel)?;
126-
diff_objs(first_obj, second_obj)?;
131+
diff_objs(first_obj, second_obj, &diff_config)?;
127132
}
128133

129134
update_status(status, "Complete".to_string(), total, total, &cancel)?;
130-
Ok(Box::new(ObjDiffResult { first_status, second_status, first_obj, second_obj }))
135+
Ok(Box::new(ObjDiffResult { first_status, second_status, first_obj, second_obj, time }))
131136
}
132137

133-
pub fn queue_build(obj_path: String, config: Arc<RwLock<AppConfig>>) -> JobState {
138+
pub fn queue_build(config: Arc<RwLock<AppConfig>>, diff_config: DiffConfig) -> JobState {
134139
queue_job(Job::ObjDiff, move |status, cancel| {
135-
run_build(status, cancel, obj_path, config).map(JobResult::ObjDiff)
140+
run_build(status, cancel, config, diff_config).map(JobResult::ObjDiff)
136141
})
137142
}

src/main.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,26 @@
11
#![warn(clippy::all, rust_2018_idioms)]
22
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
33

4+
use time::UtcOffset;
5+
46
// When compiling natively:
57
#[cfg(not(target_arch = "wasm32"))]
68
fn main() {
79
// Log to stdout (if you run with `RUST_LOG=debug`).
810
tracing_subscriber::fmt::init();
911

12+
// Because localtime_r is unsound in multithreaded apps,
13+
// we must call this before initializing eframe.
14+
// https://github.com/time-rs/time/issues/293
15+
let utc_offset = UtcOffset::current_local_offset().unwrap();
16+
1017
let native_options = eframe::NativeOptions::default();
1118
// native_options.renderer = eframe::Renderer::Wgpu;
12-
eframe::run_native("objdiff", native_options, Box::new(|cc| Box::new(objdiff::App::new(cc))));
19+
eframe::run_native(
20+
"objdiff",
21+
native_options,
22+
Box::new(move |cc| Box::new(objdiff::App::new(cc, utc_offset))),
23+
);
1324
}
1425

1526
// when compiling to web using trunk.

src/views/config.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,19 @@ pub fn config_ui(ui: &mut egui::Ui, config: &Arc<RwLock<AppConfig>>, view_state:
149149
}
150150
}
151151
if let Some(new_build_obj) = new_build_obj {
152-
*obj_path = Some(new_build_obj.clone());
153-
view_state.jobs.push(queue_build(new_build_obj, config.clone()));
152+
*obj_path = Some(new_build_obj);
153+
view_state
154+
.jobs
155+
.push(queue_build(config.clone(), view_state.diff_config.clone()));
154156
}
155157
}
156158
}
157159
if let Some(obj) = obj_path {
158160
ui.label(&*obj);
159161
if ui.button("Build").clicked() {
160-
view_state.jobs.push(queue_build(obj.clone(), config.clone()));
162+
view_state
163+
.jobs
164+
.push(queue_build(config.clone(), view_state.diff_config.clone()));
161165
}
162166
}
163167

0 commit comments

Comments
 (0)