mirror of
https://github.com/encounter/objdiff.git
synced 2025-12-17 17:05:29 +00:00
Compare commits
7 Commits
v2.0.0-bet
...
v2.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
| 2cc10b0d06 | |||
| 8091941448 | |||
| de74dfdba7 | |||
| 177bd5e895 | |||
| e1ccee1e73 | |||
| 952b6a63c3 | |||
|
|
09cc9952df |
6
Cargo.lock
generated
6
Cargo.lock
generated
@@ -2798,7 +2798,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-cli"
|
||||
version = "2.0.0-beta.1"
|
||||
version = "2.0.0-beta.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argp",
|
||||
@@ -2817,7 +2817,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-core"
|
||||
version = "2.0.0-beta.1"
|
||||
version = "2.0.0-beta.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arm-attr",
|
||||
@@ -2848,7 +2848,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-gui"
|
||||
version = "2.0.0-beta.1"
|
||||
version = "2.0.0-beta.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "objdiff-cli"
|
||||
version = "2.0.0-beta.1"
|
||||
version = "2.0.0-beta.2"
|
||||
edition = "2021"
|
||||
rust-version = "1.70"
|
||||
authors = ["Luke Street <luke@street.dev>"]
|
||||
|
||||
@@ -750,8 +750,11 @@ impl FunctionDiffUi {
|
||||
base_color = COLOR_ROTATION[diff.idx % COLOR_ROTATION.len()]
|
||||
}
|
||||
}
|
||||
DiffText::BranchDest(addr) => {
|
||||
DiffText::BranchDest(addr, diff) => {
|
||||
label_text = format!("{addr:x}");
|
||||
if let Some(diff) = diff {
|
||||
base_color = COLOR_ROTATION[diff.idx % COLOR_ROTATION.len()]
|
||||
}
|
||||
}
|
||||
DiffText::Symbol(sym) => {
|
||||
let name = sym.demangled_name.as_ref().unwrap_or(&sym.name);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "objdiff-core"
|
||||
version = "2.0.0-beta.1"
|
||||
version = "2.0.0-beta.2"
|
||||
edition = "2021"
|
||||
rust-version = "1.70"
|
||||
authors = ["Luke Street <luke@street.dev>"]
|
||||
|
||||
@@ -227,6 +227,7 @@ impl ObjArch for ObjArchArm {
|
||||
|
||||
fn implcit_addend(
|
||||
&self,
|
||||
_file: &File<'_>,
|
||||
section: &ObjSection,
|
||||
address: u64,
|
||||
reloc: &Relocation,
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use std::{borrow::Cow, collections::BTreeMap, sync::Mutex};
|
||||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use object::{elf, Endian, Endianness, File, FileFlags, Object, Relocation, RelocationFlags};
|
||||
use object::{
|
||||
elf, Endian, Endianness, File, FileFlags, Object, ObjectSection, ObjectSymbol, Relocation,
|
||||
RelocationFlags, RelocationTarget,
|
||||
};
|
||||
use rabbitizer::{config, Abi, InstrCategory, Instruction, OperandType};
|
||||
|
||||
use crate::{
|
||||
@@ -22,6 +25,7 @@ pub struct ObjArchMips {
|
||||
pub endianness: Endianness,
|
||||
pub abi: Abi,
|
||||
pub instr_category: InstrCategory,
|
||||
pub ri_gp_value: i32,
|
||||
}
|
||||
|
||||
const EF_MIPS_ABI: u32 = 0x0000F000;
|
||||
@@ -56,7 +60,19 @@ impl ObjArchMips {
|
||||
}
|
||||
_ => bail!("Unsupported MIPS file flags"),
|
||||
}
|
||||
Ok(Self { endianness: object.endianness(), abi, instr_category })
|
||||
|
||||
// Parse the ri_gp_value stored in .reginfo to be able to correctly
|
||||
// calculate R_MIPS_GPREL16 relocations later. The value is stored
|
||||
// 0x14 bytes into .reginfo (on 32 bit platforms)
|
||||
let ri_gp_value = object
|
||||
.section_by_name(".reginfo")
|
||||
.and_then(|section| section.data().ok())
|
||||
.and_then(|data| data.get(0x14..0x18))
|
||||
.and_then(|s| s.try_into().ok())
|
||||
.map(|bytes| object.endianness().read_i32_bytes(bytes))
|
||||
.unwrap_or(0);
|
||||
|
||||
Ok(Self { endianness: object.endianness(), abi, instr_category, ri_gp_value })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,6 +195,7 @@ impl ObjArch for ObjArchMips {
|
||||
|
||||
fn implcit_addend(
|
||||
&self,
|
||||
file: &File<'_>,
|
||||
section: &ObjSection,
|
||||
address: u64,
|
||||
reloc: &Relocation,
|
||||
@@ -191,9 +208,22 @@ impl ObjArch for ObjArchMips {
|
||||
((addend & 0x0000FFFF) << 16) as i32 as i64
|
||||
}
|
||||
RelocationFlags::Elf {
|
||||
r_type:
|
||||
elf::R_MIPS_LO16 | elf::R_MIPS_GOT16 | elf::R_MIPS_CALL16 | elf::R_MIPS_GPREL16,
|
||||
r_type: elf::R_MIPS_LO16 | elf::R_MIPS_GOT16 | elf::R_MIPS_CALL16,
|
||||
} => (addend & 0x0000FFFF) as i16 as i64,
|
||||
RelocationFlags::Elf { r_type: elf::R_MIPS_GPREL16 } => {
|
||||
let RelocationTarget::Symbol(idx) = reloc.target() else {
|
||||
bail!("Unsupported R_MIPS_GPREL16 relocation against a non-symbol");
|
||||
};
|
||||
let sym = file.symbol_by_index(idx)?;
|
||||
|
||||
// if the symbol we are relocating against is in a local section we need to add
|
||||
// the ri_gp_value from .reginfo to the addend.
|
||||
if sym.section().index().is_some() {
|
||||
((addend & 0x0000FFFF) as i16 as i64) + self.ri_gp_value as i64
|
||||
} else {
|
||||
(addend & 0x0000FFFF) as i16 as i64
|
||||
}
|
||||
}
|
||||
RelocationFlags::Elf { r_type: elf::R_MIPS_26 } => ((addend & 0x03FFFFFF) << 2) as i64,
|
||||
flags => bail!("Unsupported MIPS implicit relocation {flags:?}"),
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::{borrow::Cow, collections::BTreeMap};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use object::{Architecture, Object, ObjectSymbol, Relocation, RelocationFlags, Symbol};
|
||||
use object::{Architecture, File, Object, ObjectSymbol, Relocation, RelocationFlags, Symbol};
|
||||
|
||||
use crate::{
|
||||
diff::DiffObjConfig,
|
||||
@@ -28,8 +28,13 @@ pub trait ObjArch: Send + Sync {
|
||||
config: &DiffObjConfig,
|
||||
) -> Result<ProcessCodeResult>;
|
||||
|
||||
fn implcit_addend(&self, section: &ObjSection, address: u64, reloc: &Relocation)
|
||||
-> Result<i64>;
|
||||
fn implcit_addend(
|
||||
&self,
|
||||
file: &File<'_>,
|
||||
section: &ObjSection,
|
||||
address: u64,
|
||||
reloc: &Relocation,
|
||||
) -> Result<i64>;
|
||||
|
||||
fn demangle(&self, _name: &str) -> Option<String> { None }
|
||||
|
||||
|
||||
@@ -150,6 +150,7 @@ impl ObjArch for ObjArchPpc {
|
||||
|
||||
fn implcit_addend(
|
||||
&self,
|
||||
_file: &File<'_>,
|
||||
_section: &ObjSection,
|
||||
address: u64,
|
||||
reloc: &Relocation,
|
||||
|
||||
@@ -128,6 +128,7 @@ impl ObjArch for ObjArchX86 {
|
||||
|
||||
fn implcit_addend(
|
||||
&self,
|
||||
_file: &File<'_>,
|
||||
section: &ObjSection,
|
||||
address: u64,
|
||||
reloc: &Relocation,
|
||||
|
||||
@@ -54,6 +54,7 @@ pub fn diff_data_section(
|
||||
let right_data = &right.data[..right_max as usize];
|
||||
let ops =
|
||||
capture_diff_slices_deadline(Algorithm::Patience, left_data, right_data, Some(deadline));
|
||||
let match_percent = get_diff_ratio(&ops, left_data.len(), right_data.len()) * 100.0;
|
||||
|
||||
let mut left_diff = Vec::<ObjDataDiff>::new();
|
||||
let mut right_diff = Vec::<ObjDataDiff>::new();
|
||||
@@ -127,6 +128,13 @@ pub fn diff_data_section(
|
||||
diff_generic_section(left, right, left_section_diff, right_section_diff)?;
|
||||
left_section_diff.data_diff = left_diff;
|
||||
right_section_diff.data_diff = right_diff;
|
||||
// Use the highest match percent between two options:
|
||||
// - Left symbols matching right symbols by name
|
||||
// - Diff of the data itself
|
||||
if left_section_diff.match_percent.unwrap_or(-1.0) < match_percent {
|
||||
left_section_diff.match_percent = Some(match_percent);
|
||||
right_section_diff.match_percent = Some(match_percent);
|
||||
}
|
||||
Ok((left_section_diff, right_section_diff))
|
||||
}
|
||||
|
||||
@@ -191,3 +199,35 @@ pub fn diff_generic_section(
|
||||
ObjSectionDiff { symbols: vec![], data_diff: vec![], match_percent: Some(match_percent) },
|
||||
))
|
||||
}
|
||||
|
||||
/// Compare the addresses and sizes of each symbol in the BSS sections.
|
||||
pub fn diff_bss_section(
|
||||
left: &ObjSection,
|
||||
right: &ObjSection,
|
||||
left_diff: &ObjSectionDiff,
|
||||
right_diff: &ObjSectionDiff,
|
||||
) -> Result<(ObjSectionDiff, ObjSectionDiff)> {
|
||||
let deadline = Instant::now() + Duration::from_secs(5);
|
||||
let left_sizes = left.symbols.iter().map(|s| (s.section_address, s.size)).collect::<Vec<_>>();
|
||||
let right_sizes = right.symbols.iter().map(|s| (s.section_address, s.size)).collect::<Vec<_>>();
|
||||
let ops = capture_diff_slices_deadline(
|
||||
Algorithm::Patience,
|
||||
&left_sizes,
|
||||
&right_sizes,
|
||||
Some(deadline),
|
||||
);
|
||||
let mut match_percent = get_diff_ratio(&ops, left_sizes.len(), right_sizes.len()) * 100.0;
|
||||
|
||||
// Use the highest match percent between two options:
|
||||
// - Left symbols matching right symbols by name
|
||||
// - Diff of the addresses and sizes of each symbol
|
||||
let (generic_diff, _) = diff_generic_section(left, right, left_diff, right_diff)?;
|
||||
if generic_diff.match_percent.unwrap_or(-1.0) > match_percent {
|
||||
match_percent = generic_diff.match_percent.unwrap();
|
||||
}
|
||||
|
||||
Ok((
|
||||
ObjSectionDiff { symbols: vec![], data_diff: vec![], match_percent: Some(match_percent) },
|
||||
ObjSectionDiff { symbols: vec![], data_diff: vec![], match_percent: Some(match_percent) },
|
||||
))
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ pub enum DiffText<'a> {
|
||||
/// Instruction argument
|
||||
Argument(&'a ObjInsArgValue, Option<&'a ObjInsArgDiff>),
|
||||
/// Branch destination
|
||||
BranchDest(u64),
|
||||
BranchDest(u64, Option<&'a ObjInsArgDiff>),
|
||||
/// Symbol name
|
||||
Symbol(&'a ObjSymbol),
|
||||
/// Number of spaces
|
||||
@@ -62,12 +62,12 @@ pub fn display_diff<E>(
|
||||
if i == 0 {
|
||||
cb(DiffText::Spacing(1))?;
|
||||
}
|
||||
let diff = ins_diff.arg_diff.get(i).and_then(|o| o.as_ref());
|
||||
match arg {
|
||||
ObjInsArg::PlainText(s) => {
|
||||
cb(DiffText::Basic(s))?;
|
||||
}
|
||||
ObjInsArg::Arg(v) => {
|
||||
let diff = ins_diff.arg_diff.get(i).and_then(|o| o.as_ref());
|
||||
cb(DiffText::Argument(v, diff))?;
|
||||
}
|
||||
ObjInsArg::Reloc => {
|
||||
@@ -75,7 +75,7 @@ pub fn display_diff<E>(
|
||||
}
|
||||
ObjInsArg::BranchDest(dest) => {
|
||||
if let Some(dest) = dest.checked_sub(base_addr) {
|
||||
cb(DiffText::BranchDest(dest))?;
|
||||
cb(DiffText::BranchDest(dest, diff))?;
|
||||
} else {
|
||||
cb(DiffText::Basic("<unknown>"))?;
|
||||
}
|
||||
@@ -107,7 +107,9 @@ impl PartialEq<DiffText<'_>> for HighlightKind {
|
||||
(HighlightKind::Opcode(a), DiffText::Opcode(_, b)) => a == b,
|
||||
(HighlightKind::Arg(a), DiffText::Argument(b, _)) => a.loose_eq(b),
|
||||
(HighlightKind::Symbol(a), DiffText::Symbol(b)) => a == &b.name,
|
||||
(HighlightKind::Address(a), DiffText::Address(b) | DiffText::BranchDest(b)) => a == b,
|
||||
(HighlightKind::Address(a), DiffText::Address(b) | DiffText::BranchDest(b, _)) => {
|
||||
a == b
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@@ -123,7 +125,7 @@ impl From<DiffText<'_>> for HighlightKind {
|
||||
DiffText::Opcode(_, op) => HighlightKind::Opcode(op),
|
||||
DiffText::Argument(arg, _) => HighlightKind::Arg(arg.clone()),
|
||||
DiffText::Symbol(sym) => HighlightKind::Symbol(sym.name.to_string()),
|
||||
DiffText::Address(addr) | DiffText::BranchDest(addr) => HighlightKind::Address(addr),
|
||||
DiffText::Address(addr) | DiffText::BranchDest(addr, _) => HighlightKind::Address(addr),
|
||||
_ => HighlightKind::None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ use crate::{
|
||||
diff::{
|
||||
code::{diff_code, no_diff_code, process_code_symbol},
|
||||
data::{
|
||||
diff_bss_symbol, diff_data_section, diff_data_symbol, diff_generic_section,
|
||||
no_diff_symbol,
|
||||
diff_bss_section, diff_bss_symbol, diff_data_section, diff_data_symbol,
|
||||
diff_generic_section, no_diff_symbol,
|
||||
},
|
||||
},
|
||||
obj::{ObjInfo, ObjIns, ObjSection, ObjSectionKind, ObjSymbol, SymbolRef},
|
||||
@@ -483,7 +483,7 @@ pub fn diff_objs(
|
||||
let left_section = &left_obj.sections[left_section_idx];
|
||||
let right_section = &right_obj.sections[right_section_idx];
|
||||
match section_kind {
|
||||
ObjSectionKind::Code | ObjSectionKind::Bss => {
|
||||
ObjSectionKind::Code => {
|
||||
let left_section_diff = left_out.section_diff(left_section_idx);
|
||||
let right_section_diff = right_out.section_diff(right_section_idx);
|
||||
let (left_diff, right_diff) = diff_generic_section(
|
||||
@@ -507,6 +507,18 @@ pub fn diff_objs(
|
||||
left_out.section_diff_mut(left_section_idx).merge(left_diff);
|
||||
right_out.section_diff_mut(right_section_idx).merge(right_diff);
|
||||
}
|
||||
ObjSectionKind::Bss => {
|
||||
let left_section_diff = left_out.section_diff(left_section_idx);
|
||||
let right_section_diff = right_out.section_diff(right_section_idx);
|
||||
let (left_diff, right_diff) = diff_bss_section(
|
||||
left_section,
|
||||
right_section,
|
||||
left_section_diff,
|
||||
right_section_diff,
|
||||
)?;
|
||||
left_out.section_diff_mut(left_section_idx).merge(left_diff);
|
||||
right_out.section_diff_mut(right_section_idx).merge(right_diff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -546,8 +558,8 @@ fn matching_symbols(
|
||||
for (symbol_idx, symbol) in section.symbols.iter().enumerate() {
|
||||
let symbol_match = SymbolMatch {
|
||||
left: Some(SymbolRef { section_idx, symbol_idx }),
|
||||
right: find_symbol(right, symbol, section),
|
||||
prev: find_symbol(prev, symbol, section),
|
||||
right: find_symbol(right, symbol, section, Some(&right_used)),
|
||||
prev: find_symbol(prev, symbol, section, None),
|
||||
section_kind: section.kind,
|
||||
};
|
||||
matches.push(symbol_match);
|
||||
@@ -579,7 +591,7 @@ fn matching_symbols(
|
||||
matches.push(SymbolMatch {
|
||||
left: None,
|
||||
right: Some(symbol_ref),
|
||||
prev: find_symbol(prev, symbol, section),
|
||||
prev: find_symbol(prev, symbol, section, None),
|
||||
section_kind: section.kind,
|
||||
});
|
||||
}
|
||||
@@ -600,10 +612,25 @@ fn matching_symbols(
|
||||
Ok(matches)
|
||||
}
|
||||
|
||||
fn unmatched_symbols<'section, 'used>(
|
||||
section: &'section ObjSection,
|
||||
section_idx: usize,
|
||||
used: Option<&'used HashSet<SymbolRef>>,
|
||||
) -> impl Iterator<Item = (usize, &'section ObjSymbol)> + 'used
|
||||
where
|
||||
'section: 'used,
|
||||
{
|
||||
section.symbols.iter().enumerate().filter(move |&(symbol_idx, _)| {
|
||||
// Skip symbols that have already been matched
|
||||
!used.map(|u| u.contains(&SymbolRef { section_idx, symbol_idx })).unwrap_or(false)
|
||||
})
|
||||
}
|
||||
|
||||
fn find_symbol(
|
||||
obj: Option<&ObjInfo>,
|
||||
in_symbol: &ObjSymbol,
|
||||
in_section: &ObjSection,
|
||||
used: Option<&HashSet<SymbolRef>>,
|
||||
) -> Option<SymbolRef> {
|
||||
let obj = obj?;
|
||||
// Try to find an exact name match
|
||||
@@ -611,8 +638,8 @@ fn find_symbol(
|
||||
if section.kind != in_section.kind {
|
||||
continue;
|
||||
}
|
||||
if let Some(symbol_idx) =
|
||||
section.symbols.iter().position(|symbol| symbol.name == in_symbol.name)
|
||||
if let Some((symbol_idx, _)) = unmatched_symbols(section, section_idx, used)
|
||||
.find(|(_, symbol)| symbol.name == in_symbol.name)
|
||||
{
|
||||
return Some(SymbolRef { section_idx, symbol_idx });
|
||||
}
|
||||
@@ -625,9 +652,11 @@ fn find_symbol(
|
||||
if let Some((section_idx, section)) =
|
||||
obj.sections.iter().enumerate().find(|(_, s)| s.name == in_section.name)
|
||||
{
|
||||
if let Some(symbol_idx) = section.symbols.iter().position(|symbol| {
|
||||
symbol.address == in_symbol.address && symbol.name.starts_with('@')
|
||||
}) {
|
||||
if let Some((symbol_idx, _)) =
|
||||
unmatched_symbols(section, section_idx, used).find(|(_, symbol)| {
|
||||
symbol.address == in_symbol.address && symbol.name.starts_with('@')
|
||||
})
|
||||
{
|
||||
return Some(SymbolRef { section_idx, symbol_idx });
|
||||
}
|
||||
}
|
||||
@@ -641,13 +670,15 @@ fn find_symbol(
|
||||
if section.kind != in_section.kind {
|
||||
continue;
|
||||
}
|
||||
if let Some(symbol_idx) = section.symbols.iter().position(|symbol| {
|
||||
if let Some((p, s)) = symbol.name.split_once('$') {
|
||||
prefix == p && s.chars().all(char::is_numeric)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}) {
|
||||
if let Some((symbol_idx, _)) =
|
||||
unmatched_symbols(section, section_idx, used).find(|&(_, symbol)| {
|
||||
if let Some((p, s)) = symbol.name.split_once('$') {
|
||||
prefix == p && s.chars().all(char::is_numeric)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
{
|
||||
return Some(SymbolRef { section_idx, symbol_idx });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ fn symbols_by_section(
|
||||
}
|
||||
}
|
||||
}
|
||||
result.sort_by_key(|v| v.address);
|
||||
result.sort_by(|a, b| a.address.cmp(&b.address).then(a.size.cmp(&b.size)));
|
||||
let mut iter = result.iter_mut().peekable();
|
||||
while let Some(symbol) = iter.next() {
|
||||
if symbol.size == 0 {
|
||||
@@ -160,6 +160,23 @@ fn symbols_by_section(
|
||||
}
|
||||
}
|
||||
}
|
||||
if result.is_empty() {
|
||||
// Dummy symbol for empty sections
|
||||
result.push(ObjSymbol {
|
||||
name: format!("[{}]", section.name),
|
||||
demangled_name: None,
|
||||
has_extab: false,
|
||||
extab_name: None,
|
||||
extabindex_name: None,
|
||||
address: 0,
|
||||
section_address: 0,
|
||||
size: section.size,
|
||||
size_known: true,
|
||||
flags: Default::default(),
|
||||
addend: 0,
|
||||
virtual_address: None,
|
||||
});
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
@@ -364,7 +381,7 @@ fn relocations_by_section(
|
||||
_ => None,
|
||||
};
|
||||
let addend = if reloc.has_implicit_addend() {
|
||||
arch.implcit_addend(section, address, &reloc)?
|
||||
arch.implcit_addend(obj_file, section, address, &reloc)?
|
||||
} else {
|
||||
reloc.addend()
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "objdiff-gui"
|
||||
version = "2.0.0-beta.1"
|
||||
version = "2.0.0-beta.2"
|
||||
edition = "2021"
|
||||
rust-version = "1.70"
|
||||
authors = ["Luke Street <luke@street.dev>"]
|
||||
@@ -18,7 +18,7 @@ name = "objdiff"
|
||||
path = "src/main.rs"
|
||||
|
||||
[features]
|
||||
default = ["wgpu", "wsl"]
|
||||
default = ["glow", "wgpu", "wsl"]
|
||||
glow = ["eframe/glow"]
|
||||
wgpu = ["eframe/wgpu", "dep:wgpu"]
|
||||
wsl = []
|
||||
|
||||
@@ -275,7 +275,7 @@ impl App {
|
||||
#[cfg(feature = "glow")]
|
||||
if let Some(gl) = &cc.gl {
|
||||
use eframe::glow::HasContext;
|
||||
app.view_state.graphics_state.active_backend = "OpenGL".to_string();
|
||||
app.view_state.graphics_state.active_backend = "OpenGL (Fallback)".to_string();
|
||||
app.view_state.graphics_state.active_device =
|
||||
unsafe { gl.get_parameter_string(0x1F01) }; // GL_RENDERER
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ mod views;
|
||||
|
||||
use std::{
|
||||
path::PathBuf,
|
||||
process::ExitCode,
|
||||
rc::Rc,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
@@ -37,7 +38,7 @@ const APP_NAME: &str = "objdiff";
|
||||
|
||||
// When compiling natively:
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn main() {
|
||||
fn main() -> ExitCode {
|
||||
// Log to stdout (if you run with `RUST_LOG=debug`).
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
@@ -48,7 +49,6 @@ fn main() {
|
||||
|
||||
let app_path = std::env::current_exe().ok();
|
||||
let exec_path: Rc<Mutex<Option<PathBuf>>> = Rc::new(Mutex::new(None));
|
||||
let exec_path_clone = exec_path.clone();
|
||||
let mut native_options =
|
||||
eframe::NativeOptions { follow_system_theme: false, ..Default::default() };
|
||||
match load_icon() {
|
||||
@@ -56,7 +56,7 @@ fn main() {
|
||||
native_options.viewport.icon = Some(Arc::new(data));
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("Failed to load application icon: {}", e);
|
||||
log::warn!("Failed to load application icon: {e:?}");
|
||||
}
|
||||
}
|
||||
let mut graphics_config = GraphicsConfig::default();
|
||||
@@ -69,7 +69,7 @@ fn main() {
|
||||
}
|
||||
Ok(None) => {}
|
||||
Err(e) => {
|
||||
log::error!("Failed to load native config: {:?}", e);
|
||||
log::error!("Failed to load native config: {e:?}");
|
||||
}
|
||||
}
|
||||
graphics_config_path = Some(config_path);
|
||||
@@ -87,6 +87,104 @@ fn main() {
|
||||
};
|
||||
}
|
||||
}
|
||||
let mut eframe_error = None;
|
||||
if let Err(e) = run_eframe(
|
||||
native_options.clone(),
|
||||
utc_offset,
|
||||
exec_path.clone(),
|
||||
app_path.clone(),
|
||||
graphics_config.clone(),
|
||||
graphics_config_path.clone(),
|
||||
) {
|
||||
eframe_error = Some(e);
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
if let Some(e) = eframe_error {
|
||||
// Attempt to relaunch using wgpu auto backend if the desired backend failed
|
||||
#[allow(unused_mut)]
|
||||
let mut should_relaunch = graphics_config.desired_backend != GraphicsBackend::Auto;
|
||||
#[cfg(feature = "glow")]
|
||||
{
|
||||
// If the desired backend is OpenGL, we should try to relaunch using the glow renderer
|
||||
should_relaunch &= graphics_config.desired_backend != GraphicsBackend::OpenGL;
|
||||
}
|
||||
if should_relaunch {
|
||||
log::warn!("Failed to launch application: {e:?}");
|
||||
log::warn!("Attempting to relaunch using auto-detected backend");
|
||||
native_options.wgpu_options.supported_backends = Default::default();
|
||||
if let Err(e) = run_eframe(
|
||||
native_options.clone(),
|
||||
utc_offset,
|
||||
exec_path.clone(),
|
||||
app_path.clone(),
|
||||
graphics_config.clone(),
|
||||
graphics_config_path.clone(),
|
||||
) {
|
||||
eframe_error = Some(e);
|
||||
} else {
|
||||
eframe_error = None;
|
||||
}
|
||||
} else {
|
||||
eframe_error = Some(e);
|
||||
}
|
||||
}
|
||||
#[cfg(all(feature = "wgpu", feature = "glow"))]
|
||||
if let Some(e) = eframe_error {
|
||||
// Attempt to relaunch using the glow renderer if the wgpu backend failed
|
||||
log::warn!("Failed to launch application: {e:?}");
|
||||
log::warn!("Attempting to relaunch using fallback OpenGL backend");
|
||||
native_options.renderer = eframe::Renderer::Glow;
|
||||
if let Err(e) = run_eframe(
|
||||
native_options,
|
||||
utc_offset,
|
||||
exec_path.clone(),
|
||||
app_path,
|
||||
graphics_config,
|
||||
graphics_config_path,
|
||||
) {
|
||||
eframe_error = Some(e);
|
||||
} else {
|
||||
eframe_error = None;
|
||||
}
|
||||
}
|
||||
if let Some(e) = eframe_error {
|
||||
log::error!("Failed to launch application: {e:?}");
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
// Attempt to relaunch application from the updated path
|
||||
if let Ok(mut guard) = exec_path.lock() {
|
||||
if let Some(path) = guard.take() {
|
||||
cfg_if! {
|
||||
if #[cfg(unix)] {
|
||||
let e = exec::Command::new(path)
|
||||
.args(&std::env::args().collect::<Vec<String>>())
|
||||
.exec();
|
||||
log::error!("Failed to relaunch: {e:?}");
|
||||
return ExitCode::FAILURE;
|
||||
} else {
|
||||
let result = std::process::Command::new(path)
|
||||
.args(std::env::args())
|
||||
.spawn();
|
||||
if let Err(e) = result {
|
||||
log::error!("Failed to relaunch: {e:?}");
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
ExitCode::SUCCESS
|
||||
}
|
||||
|
||||
fn run_eframe(
|
||||
native_options: eframe::NativeOptions,
|
||||
utc_offset: UtcOffset,
|
||||
exec_path_clone: Rc<Mutex<Option<PathBuf>>>,
|
||||
app_path: Option<PathBuf>,
|
||||
graphics_config: GraphicsConfig,
|
||||
graphics_config_path: Option<PathBuf>,
|
||||
) -> Result<(), eframe::Error> {
|
||||
eframe::run_native(
|
||||
APP_NAME,
|
||||
native_options,
|
||||
@@ -101,28 +199,6 @@ fn main() {
|
||||
))
|
||||
}),
|
||||
)
|
||||
.expect("Failed to run eframe application");
|
||||
|
||||
// Attempt to relaunch application from the updated path
|
||||
if let Ok(mut guard) = exec_path.lock() {
|
||||
if let Some(path) = guard.take() {
|
||||
cfg_if! {
|
||||
if #[cfg(unix)] {
|
||||
let result = exec::Command::new(path)
|
||||
.args(&std::env::args().collect::<Vec<String>>())
|
||||
.exec();
|
||||
log::error!("Failed to relaunch: {result:?}");
|
||||
} else {
|
||||
let result = std::process::Command::new(path)
|
||||
.args(std::env::args())
|
||||
.spawn();
|
||||
if let Err(e) = result {
|
||||
log::error!("Failed to relaunch: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// when compiling to web using trunk.
|
||||
|
||||
@@ -216,8 +216,11 @@ fn diff_text_ui(
|
||||
base_color = appearance.diff_colors[diff.idx % appearance.diff_colors.len()]
|
||||
}
|
||||
}
|
||||
DiffText::BranchDest(addr) => {
|
||||
DiffText::BranchDest(addr, diff) => {
|
||||
label_text = format!("{addr:x}");
|
||||
if let Some(diff) = diff {
|
||||
base_color = appearance.diff_colors[diff.idx % appearance.diff_colors.len()]
|
||||
}
|
||||
}
|
||||
DiffText::Symbol(sym) => {
|
||||
let name = sym.demangled_name.as_ref().unwrap_or(&sym.name);
|
||||
|
||||
@@ -36,7 +36,7 @@ pub enum GraphicsBackend {
|
||||
OpenGL,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, serde::Deserialize, serde::Serialize)]
|
||||
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)]
|
||||
pub struct GraphicsConfig {
|
||||
#[serde(default)]
|
||||
pub desired_backend: GraphicsBackend,
|
||||
|
||||
@@ -233,21 +233,28 @@ fn symbol_ui(
|
||||
{
|
||||
selected = symbol_diff.symbol_ref == sym_ref;
|
||||
}
|
||||
write_text("[", appearance.text_color, &mut job, appearance.code_font.clone());
|
||||
if symbol.flags.0.contains(ObjSymbolFlags::Common) {
|
||||
write_text("c", appearance.replace_color, &mut job, appearance.code_font.clone());
|
||||
} else if symbol.flags.0.contains(ObjSymbolFlags::Global) {
|
||||
write_text("g", appearance.insert_color, &mut job, appearance.code_font.clone());
|
||||
} else if symbol.flags.0.contains(ObjSymbolFlags::Local) {
|
||||
write_text("l", appearance.text_color, &mut job, appearance.code_font.clone());
|
||||
if !symbol.flags.0.is_empty() {
|
||||
write_text("[", appearance.text_color, &mut job, appearance.code_font.clone());
|
||||
if symbol.flags.0.contains(ObjSymbolFlags::Common) {
|
||||
write_text("c", appearance.replace_color, &mut job, appearance.code_font.clone());
|
||||
} else if symbol.flags.0.contains(ObjSymbolFlags::Global) {
|
||||
write_text("g", appearance.insert_color, &mut job, appearance.code_font.clone());
|
||||
} else if symbol.flags.0.contains(ObjSymbolFlags::Local) {
|
||||
write_text("l", appearance.text_color, &mut job, appearance.code_font.clone());
|
||||
}
|
||||
if symbol.flags.0.contains(ObjSymbolFlags::Weak) {
|
||||
write_text("w", appearance.text_color, &mut job, appearance.code_font.clone());
|
||||
}
|
||||
if symbol.flags.0.contains(ObjSymbolFlags::Hidden) {
|
||||
write_text(
|
||||
"h",
|
||||
appearance.deemphasized_text_color,
|
||||
&mut job,
|
||||
appearance.code_font.clone(),
|
||||
);
|
||||
}
|
||||
write_text("] ", appearance.text_color, &mut job, appearance.code_font.clone());
|
||||
}
|
||||
if symbol.flags.0.contains(ObjSymbolFlags::Weak) {
|
||||
write_text("w", appearance.text_color, &mut job, appearance.code_font.clone());
|
||||
}
|
||||
if symbol.flags.0.contains(ObjSymbolFlags::Hidden) {
|
||||
write_text("h", appearance.deemphasized_text_color, &mut job, appearance.code_font.clone());
|
||||
}
|
||||
write_text("] ", appearance.text_color, &mut job, appearance.code_font.clone());
|
||||
if let Some(match_percent) = symbol_diff.match_percent {
|
||||
write_text("(", appearance.text_color, &mut job, appearance.code_font.clone());
|
||||
write_text(
|
||||
|
||||
Reference in New Issue
Block a user