Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions objdiff-gui/src/hotkeys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,9 @@ const NEXT_DIFF_SHORTCUT: KeyboardShortcut = KeyboardShortcut::new(Modifiers::CT
pub fn consume_next_diff_shortcut(ctx: &Context) -> bool {
ctx.input_mut(|i| i.consume_shortcut(&NEXT_DIFF_SHORTCUT))
}

const GO_TO_SHORTCUT: KeyboardShortcut = KeyboardShortcut::new(Modifiers::CTRL, Key::G);

pub fn consume_go_to_shortcut(ctx: &Context) -> bool {
ctx.input_mut(|i| i.consume_shortcut(&GO_TO_SHORTCUT))
}
153 changes: 152 additions & 1 deletion objdiff-gui/src/views/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::{
column_layout::{render_header, render_strips, render_table},
data_diff::data_row_ui,
extab_diff::extab_ui,
function_diff::{FunctionDiffContext, asm_col_ui},
function_diff::{FunctionDiffContext, GoToTarget, GoToTargetType, asm_col_ui},
symbol_diff::{
DiffViewAction, DiffViewNavigation, DiffViewState, SymbolDiffContext, SymbolRefByName,
View, match_color_for_symbol, symbol_context_menu_ui, symbol_hover_ui, symbol_list_ui,
Expand Down Expand Up @@ -116,6 +116,57 @@ fn get_asm_text(
asm_text
}

fn try_scroll_to_go_to_target(
go_to_target: GoToTarget,
obj: &Object,
diff: &ObjectDiff,
symbol_idx: usize,
) -> Option<DiffViewAction> {
match go_to_target {
GoToTarget::None => return None,
GoToTarget::LineNumber(target_line) => {
let symbol = obj.symbols.get(symbol_idx)?;
let section_index = symbol.section?;
let section = &obj.sections[section_index];
for (ins_idx, ins_row) in diff.symbols[symbol_idx].instruction_rows.iter().enumerate() {
if let Some(ins_ref) = ins_row.ins_ref
&& let Some(current_line) =
section.line_info.range(..=ins_ref.address).last().map(|(_, &b)| b)
&& current_line == target_line
{
return Some(DiffViewAction::ScrollToRow(ins_idx));
}
}
}
GoToTarget::Address(target_address) => {
let symbol = obj.symbols.get(symbol_idx)?;
let symbol_diff = diff.symbols.get(symbol_idx)?;
for (ins_idx, ins_row) in symbol_diff.instruction_rows.iter().enumerate() {
if let Some(ins_ref) = ins_row.ins_ref
&& target_address == ins_ref.address.saturating_sub(symbol.address)
{
return Some(DiffViewAction::ScrollToRow(ins_idx));
}
}
}
GoToTarget::VirtualAddress(target_virtual_address) => {
let symbol = obj.symbols.get(symbol_idx)?;
let section_index = symbol.section?;
let section = &obj.sections[section_index];
let section_virtual_address = section.virtual_address?;
let target_offset = target_virtual_address.checked_sub(section_virtual_address)?;
for (ins_idx, ins_row) in diff.symbols[symbol_idx].instruction_rows.iter().enumerate() {
if let Some(ins_ref) = ins_row.ins_ref
&& ins_ref.address == target_offset
{
return Some(DiffViewAction::ScrollToRow(ins_idx));
}
}
}
};
None
}

#[must_use]
pub fn diff_view_ui(
ui: &mut Ui,
Expand Down Expand Up @@ -287,6 +338,44 @@ pub fn diff_view_ui(
{
ret = Some(DiffViewAction::SelectingLeft(symbol_ref.clone()));
}

if state.current_view == View::FunctionDiff {
ui.separator();

let mut goto_line_text = state.function_state.go_to_text_left.clone();
let response = TextEdit::singleline(&mut goto_line_text)
.hint_text("Go to...")
.desired_width(100.0)
.ui(ui);

let mut go_to_target_type_left: GoToTargetType =
state.function_state.go_to_target_type_left;
egui::ComboBox::from_id_salt("go_to_target_type_left")
.selected_text(go_to_target_type_left.to_string())
.show_ui(ui, |ui| {
for go_to_target_type in [
GoToTargetType::LineNumber,
GoToTargetType::Address,
GoToTargetType::VirtualAddress,
] {
let response = ui.selectable_value(
&mut go_to_target_type_left,
go_to_target_type,
go_to_target_type.to_string(),
);
if response.changed() {
ret = Some(DiffViewAction::SetGoToTargetType(
go_to_target_type_left,
false,
));
}
}
});

if response.changed() {
ret = Some(DiffViewAction::SetGoToText(goto_line_text, false));
}
}
});
} else if left_ctx.status.success && !left_ctx.has_symbol() {
ui.horizontal(|ui| {
Expand Down Expand Up @@ -458,6 +547,48 @@ pub fn diff_view_ui(
needs_separator = true;
}

if state.current_view == View::FunctionDiff {
if needs_separator {
ui.separator();
}
let mut goto_line_text = state.function_state.go_to_text_right.clone();
let response = TextEdit::singleline(&mut goto_line_text)
.hint_text("Go to...")
.desired_width(100.0)
.ui(ui);
if hotkeys::consume_go_to_shortcut(ui.ctx()) {
response.request_focus();
}

let mut go_to_target_type_right: GoToTargetType =
state.function_state.go_to_target_type_right;
egui::ComboBox::from_id_salt("go_to_target_type_right")
.selected_text(go_to_target_type_right.to_string())
.show_ui(ui, |ui| {
for go_to_target_type in [
GoToTargetType::LineNumber,
GoToTargetType::Address,
GoToTargetType::VirtualAddress,
] {
let response = ui.selectable_value(
&mut go_to_target_type_right,
go_to_target_type,
go_to_target_type.to_string(),
);
if response.changed() {
ret = Some(DiffViewAction::SetGoToTargetType(
go_to_target_type_right,
true,
));
}
}
});

if response.changed() {
ret = Some(DiffViewAction::SetGoToText(goto_line_text, true));
}
}

if state.current_view == View::FunctionDiff
|| state.current_view == View::DataDiff
{
Expand Down Expand Up @@ -522,6 +653,18 @@ pub fn diff_view_ui(
ui.label("Instruction count mismatch");
return;
}
if let Some(action) = try_scroll_to_go_to_target(
state.function_state.go_to_target,
if state.function_state.go_to_target_is_right { right_obj } else { left_obj },
if state.function_state.go_to_target_is_right { right_diff } else { left_diff },
if state.function_state.go_to_target_is_right {
right_symbol_idx
} else {
left_symbol_idx
},
) {
ret = Some(action);
}
let instructions_len = left_symbol_diff.instruction_rows.len();
let mut min_row = None;
let mut max_row = None;
Expand Down Expand Up @@ -799,6 +942,14 @@ fn diff_col_ui(
},
);
} else {
if let Some(action) = try_scroll_to_go_to_target(
state.function_state.go_to_target,
obj,
diff,
symbol_idx,
) {
ret = Some(action);
}
render_table(
ui,
available_width / 2.0,
Expand Down
33 changes: 33 additions & 0 deletions objdiff-gui/src/views/function_diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,43 @@ use crate::views::{
symbol_diff::DiffViewAction,
};

#[derive(Debug, Default, Copy, Clone)]
pub enum GoToTarget {
#[default]
None,
LineNumber(u32),
Address(u64),
VirtualAddress(u64),
}

#[derive(Debug, Default, Copy, Clone, PartialEq)]
pub enum GoToTargetType {
#[default]
LineNumber,
Address,
VirtualAddress,
}

impl core::fmt::Display for GoToTargetType {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
GoToTargetType::LineNumber => write!(f, "Line Number"),
GoToTargetType::Address => write!(f, "Address / Offset"),
GoToTargetType::VirtualAddress => write!(f, "Virtual Address"),
}
}
}

#[derive(Default)]
pub struct FunctionViewState {
left_highlight: HighlightKind,
right_highlight: HighlightKind,
pub go_to_target: GoToTarget,
pub go_to_target_is_right: bool,
pub go_to_text_left: String,
pub go_to_target_type_left: GoToTargetType,
pub go_to_text_right: String,
pub go_to_target_type_right: GoToTargetType,
}

impl FunctionViewState {
Expand Down
56 changes: 55 additions & 1 deletion objdiff-gui/src/views/symbol_diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::{
views::{
appearance::Appearance,
diff::{context_menu_items_ui, hover_items_ui},
function_diff::FunctionViewState,
function_diff::{FunctionViewState, GoToTarget, GoToTargetType},
write_text,
},
};
Expand Down Expand Up @@ -83,6 +83,12 @@ pub enum DiffViewAction {
SetShowDataFlow(bool),
// Scrolls a row of the function view table into view.
ScrollToRow(usize),
/// Changes the text of the "Go to..." field.
/// The bool is true for right, false for left.
SetGoToText(String, bool),
/// Changes the dropdown next to the "Go to..." field.
/// The bool is true for right, false for left.
SetGoToTargetType(GoToTargetType, bool),
}

#[derive(Debug, Clone, Default, Eq, PartialEq)]
Expand Down Expand Up @@ -204,6 +210,7 @@ impl DiffViewState {
// Clear the scroll flags to prevent it from scrolling continuously.
self.symbol_state.autoscroll_to_highlighted_symbols = false;
self.scroll_to_diff_row = None;
self.function_state.go_to_target = GoToTarget::None;

let Some(action) = action else {
return;
Expand Down Expand Up @@ -369,6 +376,23 @@ impl DiffViewState {
DiffViewAction::ScrollToRow(row) => {
self.scroll_to_diff_row = Some(row);
}
DiffViewAction::SetGoToText(text, is_right) => {
self.function_state.go_to_target_is_right = is_right;
if is_right {
self.function_state.go_to_text_right = text;
} else {
self.function_state.go_to_text_left = text;
}
self.resolve_go_to_target(is_right);
}
DiffViewAction::SetGoToTargetType(target_type, is_right) => {
if is_right {
self.function_state.go_to_target_type_right = target_type;
} else {
self.function_state.go_to_target_type_left = target_type;
}
self.resolve_go_to_target(is_right);
}
}
}

Expand Down Expand Up @@ -418,6 +442,36 @@ impl DiffViewState {
self.search_regex = search_regex;
}
}

fn resolve_go_to_target(&mut self, is_right: bool) {
let target_type = if is_right {
self.function_state.go_to_target_type_right
} else {
self.function_state.go_to_target_type_left
};
let target_text = if is_right {
&self.function_state.go_to_text_right
} else {
&self.function_state.go_to_text_left
};
match target_type {
GoToTargetType::LineNumber => {
if let Ok(line_num) = target_text.trim().parse::<u32>() {
self.function_state.go_to_target = GoToTarget::LineNumber(line_num)
}
}
GoToTargetType::Address => {
if let Ok(address) = u64::from_str_radix(target_text.trim(), 16) {
self.function_state.go_to_target = GoToTarget::Address(address)
}
}
GoToTargetType::VirtualAddress => {
if let Ok(virtual_address) = u64::from_str_radix(target_text.trim(), 16) {
self.function_state.go_to_target = GoToTarget::VirtualAddress(virtual_address)
}
}
}
}
}

struct ResolvedSymbol<'obj> {
Expand Down