Skip to content

Commit 33c149f

Browse files
committed
Add dropdown to goto offset/address and split left/right
1 parent 8c55754 commit 33c149f

3 files changed

Lines changed: 216 additions & 38 deletions

File tree

objdiff-gui/src/views/diff.rs

Lines changed: 130 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use crate::{
2323
column_layout::{render_header, render_strips, render_table},
2424
data_diff::data_row_ui,
2525
extab_diff::extab_ui,
26-
function_diff::{FunctionDiffContext, asm_col_ui},
26+
function_diff::{FunctionDiffContext, GoToTarget, GoToTargetType, asm_col_ui},
2727
symbol_diff::{
2828
DiffViewAction, DiffViewNavigation, DiffViewState, SymbolDiffContext, SymbolRefByName,
2929
View, match_color_for_symbol, symbol_context_menu_ui, symbol_hover_ui, symbol_list_ui,
@@ -116,25 +116,54 @@ fn get_asm_text(
116116
asm_text
117117
}
118118

119-
fn try_scroll_to_line_number(
120-
scroll_to_line_number: Option<u32>,
119+
fn try_scroll_to_go_to_target(
120+
go_to_target: GoToTarget,
121121
obj: &Object,
122122
diff: &ObjectDiff,
123123
symbol_idx: usize,
124124
) -> Option<DiffViewAction> {
125-
let target_line = scroll_to_line_number?;
126-
let symbol = obj.symbols.get(symbol_idx)?;
127-
let section_index = symbol.section?;
128-
let section = &obj.sections[section_index];
129-
for (ins_idx, ins_row) in diff.symbols[symbol_idx].instruction_rows.iter().enumerate() {
130-
if let Some(ins_ref) = ins_row.ins_ref
131-
&& let Some(current_line) =
132-
section.line_info.range(..=ins_ref.address).last().map(|(_, &b)| b)
133-
&& current_line == target_line
134-
{
135-
return Some(DiffViewAction::ScrollToRow(ins_idx));
125+
match go_to_target {
126+
GoToTarget::None => return None,
127+
GoToTarget::LineNumber(target_line) => {
128+
let symbol = obj.symbols.get(symbol_idx)?;
129+
let section_index = symbol.section?;
130+
let section = &obj.sections[section_index];
131+
for (ins_idx, ins_row) in diff.symbols[symbol_idx].instruction_rows.iter().enumerate() {
132+
if let Some(ins_ref) = ins_row.ins_ref
133+
&& let Some(current_line) =
134+
section.line_info.range(..=ins_ref.address).last().map(|(_, &b)| b)
135+
&& current_line == target_line
136+
{
137+
return Some(DiffViewAction::ScrollToRow(ins_idx));
138+
}
139+
}
136140
}
137-
}
141+
GoToTarget::Address(target_address) => {
142+
let symbol = obj.symbols.get(symbol_idx)?;
143+
let symbol_diff = diff.symbols.get(symbol_idx)?;
144+
for (ins_idx, ins_row) in symbol_diff.instruction_rows.iter().enumerate() {
145+
if let Some(ins_ref) = ins_row.ins_ref
146+
&& target_address == ins_ref.address.saturating_sub(symbol.address)
147+
{
148+
return Some(DiffViewAction::ScrollToRow(ins_idx));
149+
}
150+
}
151+
}
152+
GoToTarget::VirtualAddress(target_virtual_address) => {
153+
let symbol = obj.symbols.get(symbol_idx)?;
154+
let section_index = symbol.section?;
155+
let section = &obj.sections[section_index];
156+
let section_virtual_address = section.virtual_address?;
157+
let target_offset = target_virtual_address.checked_sub(section_virtual_address)?;
158+
for (ins_idx, ins_row) in diff.symbols[symbol_idx].instruction_rows.iter().enumerate() {
159+
if let Some(ins_ref) = ins_row.ins_ref
160+
&& ins_ref.address == target_offset
161+
{
162+
return Some(DiffViewAction::ScrollToRow(ins_idx));
163+
}
164+
}
165+
}
166+
};
138167
None
139168
}
140169

@@ -309,6 +338,44 @@ pub fn diff_view_ui(
309338
{
310339
ret = Some(DiffViewAction::SelectingLeft(symbol_ref.clone()));
311340
}
341+
342+
if state.current_view == View::FunctionDiff {
343+
ui.separator();
344+
345+
let mut goto_line_text = state.function_state.go_to_text_left.clone();
346+
let response = TextEdit::singleline(&mut goto_line_text)
347+
.hint_text("Go to...")
348+
.desired_width(100.0)
349+
.ui(ui);
350+
351+
let mut go_to_target_type_left: GoToTargetType =
352+
state.function_state.go_to_target_type_left;
353+
egui::ComboBox::from_id_salt("go_to_target_type_left")
354+
.selected_text(go_to_target_type_left.to_string())
355+
.show_ui(ui, |ui| {
356+
for go_to_target_type in [
357+
GoToTargetType::LineNumber,
358+
GoToTargetType::Address,
359+
GoToTargetType::VirtualAddress,
360+
] {
361+
let response = ui.selectable_value(
362+
&mut go_to_target_type_left,
363+
go_to_target_type,
364+
go_to_target_type.to_string(),
365+
);
366+
if response.changed() {
367+
ret = Some(DiffViewAction::SetGoToTargetType(
368+
go_to_target_type_left,
369+
false,
370+
));
371+
}
372+
}
373+
});
374+
375+
if response.changed() {
376+
ret = Some(DiffViewAction::SetGoToText(goto_line_text, false));
377+
}
378+
}
312379
});
313380
} else if left_ctx.status.success && !left_ctx.has_symbol() {
314381
ui.horizontal(|ui| {
@@ -480,22 +547,53 @@ pub fn diff_view_ui(
480547
needs_separator = true;
481548
}
482549

483-
if state.current_view == View::FunctionDiff
484-
|| state.current_view == View::DataDiff
485-
{
550+
if state.current_view == View::FunctionDiff {
486551
if needs_separator {
487552
ui.separator();
488553
}
489-
let mut goto_line_text = state.function_state.go_to_line_text.clone();
554+
let mut goto_line_text = state.function_state.go_to_text_right.clone();
490555
let response = TextEdit::singleline(&mut goto_line_text)
491-
.hint_text("Go to line number")
556+
.hint_text("Go to...")
492557
.desired_width(100.0)
493558
.ui(ui);
494559
if hotkeys::consume_go_to_shortcut(ui.ctx()) {
495560
response.request_focus();
496561
}
562+
563+
let mut go_to_target_type_right: GoToTargetType =
564+
state.function_state.go_to_target_type_right;
565+
egui::ComboBox::from_id_salt("go_to_target_type_right")
566+
.selected_text(go_to_target_type_right.to_string())
567+
.show_ui(ui, |ui| {
568+
for go_to_target_type in [
569+
GoToTargetType::LineNumber,
570+
GoToTargetType::Address,
571+
GoToTargetType::VirtualAddress,
572+
] {
573+
let response = ui.selectable_value(
574+
&mut go_to_target_type_right,
575+
go_to_target_type,
576+
go_to_target_type.to_string(),
577+
);
578+
if response.changed() {
579+
ret = Some(DiffViewAction::SetGoToTargetType(
580+
go_to_target_type_right,
581+
true,
582+
));
583+
}
584+
}
585+
});
586+
497587
if response.changed() {
498-
ret = Some(DiffViewAction::SetGoToText(goto_line_text));
588+
ret = Some(DiffViewAction::SetGoToText(goto_line_text, true));
589+
}
590+
}
591+
592+
if state.current_view == View::FunctionDiff
593+
|| state.current_view == View::DataDiff
594+
{
595+
if needs_separator {
596+
ui.separator();
499597
}
500598
if ui
501599
.button("⏴ Prev diff")
@@ -555,11 +653,15 @@ pub fn diff_view_ui(
555653
ui.label("Instruction count mismatch");
556654
return;
557655
}
558-
if let Some(action) = try_scroll_to_line_number(
559-
state.function_state.scroll_to_line_number,
560-
right_obj,
561-
right_diff,
562-
right_symbol_idx,
656+
if let Some(action) = try_scroll_to_go_to_target(
657+
state.function_state.go_to_target,
658+
if state.function_state.go_to_target_is_right { right_obj } else { left_obj },
659+
if state.function_state.go_to_target_is_right { right_diff } else { left_diff },
660+
if state.function_state.go_to_target_is_right {
661+
right_symbol_idx
662+
} else {
663+
left_symbol_idx
664+
},
563665
) {
564666
ret = Some(action);
565667
}
@@ -840,8 +942,8 @@ fn diff_col_ui(
840942
},
841943
);
842944
} else {
843-
if let Some(action) = try_scroll_to_line_number(
844-
state.function_state.scroll_to_line_number,
945+
if let Some(action) = try_scroll_to_go_to_target(
946+
state.function_state.go_to_target,
845947
obj,
846948
diff,
847949
symbol_idx,

objdiff-gui/src/views/function_diff.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,43 @@ use crate::views::{
2020
symbol_diff::DiffViewAction,
2121
};
2222

23+
#[derive(Debug, Default, Copy, Clone)]
24+
pub enum GoToTarget {
25+
#[default]
26+
None,
27+
LineNumber(u32),
28+
Address(u64),
29+
VirtualAddress(u64),
30+
}
31+
32+
#[derive(Debug, Default, Copy, Clone, PartialEq)]
33+
pub enum GoToTargetType {
34+
#[default]
35+
LineNumber,
36+
Address,
37+
VirtualAddress,
38+
}
39+
40+
impl core::fmt::Display for GoToTargetType {
41+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
42+
match self {
43+
GoToTargetType::LineNumber => write!(f, "Line Number"),
44+
GoToTargetType::Address => write!(f, "Address / Offset"),
45+
GoToTargetType::VirtualAddress => write!(f, "Virtual Address"),
46+
}
47+
}
48+
}
49+
2350
#[derive(Default)]
2451
pub struct FunctionViewState {
2552
left_highlight: HighlightKind,
2653
right_highlight: HighlightKind,
27-
pub scroll_to_line_number: Option<u32>,
28-
pub go_to_line_text: String,
54+
pub go_to_target: GoToTarget,
55+
pub go_to_target_is_right: bool,
56+
pub go_to_text_left: String,
57+
pub go_to_target_type_left: GoToTargetType,
58+
pub go_to_text_right: String,
59+
pub go_to_target_type_right: GoToTargetType,
2960
}
3061

3162
impl FunctionViewState {

objdiff-gui/src/views/symbol_diff.rs

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use crate::{
2424
views::{
2525
appearance::Appearance,
2626
diff::{context_menu_items_ui, hover_items_ui},
27-
function_diff::FunctionViewState,
27+
function_diff::{FunctionViewState, GoToTarget, GoToTargetType},
2828
write_text,
2929
},
3030
};
@@ -83,8 +83,12 @@ pub enum DiffViewAction {
8383
SetShowDataFlow(bool),
8484
// Scrolls a row of the function view table into view.
8585
ScrollToRow(usize),
86-
/// Sets the text of the line number jump field and try to scroll that line into view.
87-
SetGoToText(String),
86+
/// Changes the text of the "Go to..." field.
87+
/// The bool is true for right, false for left.
88+
SetGoToText(String, bool),
89+
/// Changes the dropdown next to the "Go to..." field.
90+
/// The bool is true for right, false for left.
91+
SetGoToTargetType(GoToTargetType, bool),
8892
}
8993

9094
#[derive(Debug, Clone, Default, Eq, PartialEq)]
@@ -206,7 +210,7 @@ impl DiffViewState {
206210
// Clear the scroll flags to prevent it from scrolling continuously.
207211
self.symbol_state.autoscroll_to_highlighted_symbols = false;
208212
self.scroll_to_diff_row = None;
209-
self.function_state.scroll_to_line_number = None;
213+
self.function_state.go_to_target = GoToTarget::None;
210214

211215
let Some(action) = action else {
212216
return;
@@ -372,11 +376,22 @@ impl DiffViewState {
372376
DiffViewAction::ScrollToRow(row) => {
373377
self.scroll_to_diff_row = Some(row);
374378
}
375-
DiffViewAction::SetGoToText(text) => {
376-
if let Ok(line_num) = text.trim().parse::<u32>() {
377-
self.function_state.scroll_to_line_number = Some(line_num);
379+
DiffViewAction::SetGoToText(text, is_right) => {
380+
self.function_state.go_to_target_is_right = is_right;
381+
if is_right {
382+
self.function_state.go_to_text_right = text;
383+
} else {
384+
self.function_state.go_to_text_left = text;
378385
}
379-
self.function_state.go_to_line_text = text;
386+
self.resolve_go_to_target(is_right);
387+
}
388+
DiffViewAction::SetGoToTargetType(target_type, is_right) => {
389+
if is_right {
390+
self.function_state.go_to_target_type_right = target_type;
391+
} else {
392+
self.function_state.go_to_target_type_left = target_type;
393+
}
394+
self.resolve_go_to_target(is_right);
380395
}
381396
}
382397
}
@@ -427,6 +442,36 @@ impl DiffViewState {
427442
self.search_regex = search_regex;
428443
}
429444
}
445+
446+
fn resolve_go_to_target(&mut self, is_right: bool) {
447+
let target_type = if is_right {
448+
self.function_state.go_to_target_type_right
449+
} else {
450+
self.function_state.go_to_target_type_left
451+
};
452+
let target_text = if is_right {
453+
&self.function_state.go_to_text_right
454+
} else {
455+
&self.function_state.go_to_text_left
456+
};
457+
match target_type {
458+
GoToTargetType::LineNumber => {
459+
if let Ok(line_num) = target_text.trim().parse::<u32>() {
460+
self.function_state.go_to_target = GoToTarget::LineNumber(line_num)
461+
}
462+
}
463+
GoToTargetType::Address => {
464+
if let Ok(address) = u64::from_str_radix(target_text.trim(), 16) {
465+
self.function_state.go_to_target = GoToTarget::Address(address)
466+
}
467+
}
468+
GoToTargetType::VirtualAddress => {
469+
if let Ok(virtual_address) = u64::from_str_radix(target_text.trim(), 16) {
470+
self.function_state.go_to_target = GoToTarget::VirtualAddress(virtual_address)
471+
}
472+
}
473+
}
474+
}
430475
}
431476

432477
struct ResolvedSymbol<'obj> {

0 commit comments

Comments
 (0)