mirror of
https://github.com/encounter/objdiff.git
synced 2025-08-10 22:19:10 +00:00
Compare commits
8 Commits
v3.0.0-bet
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
c8ff45f2c8 | ||
|
34e4513c69 | ||
a015971c20 | |||
e67d5998b3 | |||
91bc23edfc | |||
c9c3b32376 | |||
0dc123b064 | |||
1e62d4664c |
23
Cargo.lock
generated
23
Cargo.lock
generated
@ -722,7 +722,7 @@ checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
"unicode-width 0.1.14",
|
"unicode-width 0.2.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3437,7 +3437,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-cli"
|
name = "objdiff-cli"
|
||||||
version = "3.0.0-beta.12"
|
version = "3.0.0-beta.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"argp",
|
"argp",
|
||||||
@ -3460,7 +3460,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-core"
|
name = "objdiff-core"
|
||||||
version = "3.0.0-beta.12"
|
version = "3.0.0-beta.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arm-attr",
|
"arm-attr",
|
||||||
@ -3505,6 +3505,7 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"time",
|
"time",
|
||||||
|
"typed-arena",
|
||||||
"typed-path",
|
"typed-path",
|
||||||
"unarm",
|
"unarm",
|
||||||
"winapi",
|
"winapi",
|
||||||
@ -3514,7 +3515,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-gui"
|
name = "objdiff-gui"
|
||||||
version = "3.0.0-beta.12"
|
version = "3.0.0-beta.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
@ -3550,7 +3551,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-wasm"
|
name = "objdiff-wasm"
|
||||||
version = "3.0.0-beta.12"
|
version = "3.0.0-beta.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"objdiff-core",
|
"objdiff-core",
|
||||||
@ -4014,7 +4015,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "ac6c3320f9abac597dcbc668774ef006702672474aad53c6d596b62e487b40b1"
|
checksum = "ac6c3320f9abac597dcbc668774ef006702672474aad53c6d596b62e487b40b1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"itertools 0.13.0",
|
"itertools 0.14.0",
|
||||||
"log",
|
"log",
|
||||||
"multimap",
|
"multimap",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@ -4034,7 +4035,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425"
|
checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"itertools 0.13.0",
|
"itertools 0.14.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
@ -5620,6 +5621,12 @@ dependencies = [
|
|||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typed-arena"
|
||||||
|
version = "2.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typed-path"
|
name = "typed-path"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
@ -6257,7 +6264,7 @@ version = "0.1.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -14,7 +14,7 @@ strip = "debuginfo"
|
|||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "3.0.0-beta.12"
|
version = "3.0.0-beta.13"
|
||||||
authors = ["Luke Street <luke@street.dev>"]
|
authors = ["Luke Street <luke@street.dev>"]
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
@ -248,13 +248,12 @@ fn report_object(
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let Some(existing_functions) = &mut existing_functions {
|
if let Some(existing_functions) = &mut existing_functions
|
||||||
if (symbol.flags.contains(SymbolFlag::Global)
|
&& (symbol.flags.contains(SymbolFlag::Global)
|
||||||
|| symbol.flags.contains(SymbolFlag::Weak))
|
|| symbol.flags.contains(SymbolFlag::Weak))
|
||||||
&& !existing_functions.insert(symbol.name.clone())
|
&& !existing_functions.insert(symbol.name.clone())
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let match_percent = symbol_diff.match_percent.unwrap_or_else(|| {
|
let match_percent = symbol_diff.match_percent.unwrap_or_else(|| {
|
||||||
// Support cases where we don't have a target object,
|
// Support cases where we don't have a target object,
|
||||||
|
@ -170,32 +170,31 @@ impl UiView for FunctionDiffUi {
|
|||||||
|
|
||||||
let mut prev_text = None;
|
let mut prev_text = None;
|
||||||
let mut prev_margin_text = None;
|
let mut prev_margin_text = None;
|
||||||
if self.three_way {
|
if self.three_way
|
||||||
if let Some((obj, symbol_idx, symbol_diff)) =
|
&& let Some((obj, symbol_idx, symbol_diff)) =
|
||||||
get_symbol(state.prev_obj.as_ref(), self.prev_sym)
|
get_symbol(state.prev_obj.as_ref(), self.prev_sym)
|
||||||
{
|
{
|
||||||
let mut text = Text::default();
|
let mut text = Text::default();
|
||||||
let rect = content_chunks[4].inner(Margin::new(0, 1));
|
let rect = content_chunks[4].inner(Margin::new(0, 1));
|
||||||
self.print_sym(
|
self.print_sym(
|
||||||
&mut text,
|
&mut text,
|
||||||
obj,
|
obj,
|
||||||
symbol_idx,
|
symbol_idx,
|
||||||
symbol_diff,
|
symbol_diff,
|
||||||
&state.diff_obj_config,
|
&state.diff_obj_config,
|
||||||
rect,
|
rect,
|
||||||
&self.right_highlight,
|
&self.right_highlight,
|
||||||
result,
|
result,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
max_width = max_width.max(text.width());
|
max_width = max_width.max(text.width());
|
||||||
prev_text = Some(text);
|
prev_text = Some(text);
|
||||||
|
|
||||||
// Render margin
|
// Render margin
|
||||||
let mut text = Text::default();
|
let mut text = Text::default();
|
||||||
let rect = content_chunks[3].inner(Margin::new(1, 1));
|
let rect = content_chunks[3].inner(Margin::new(1, 1));
|
||||||
self.print_margin(&mut text, symbol_diff, rect);
|
self.print_margin(&mut text, symbol_diff, rect);
|
||||||
prev_margin_text = Some(text);
|
prev_margin_text = Some(text);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let max_scroll_x =
|
let max_scroll_x =
|
||||||
@ -561,10 +560,12 @@ impl FunctionDiffUi {
|
|||||||
let len = label_text.len();
|
let len = label_text.len();
|
||||||
let highlighted =
|
let highlighted =
|
||||||
highlight_kind != HighlightKind::None && *highlight == highlight_kind;
|
highlight_kind != HighlightKind::None && *highlight == highlight_kind;
|
||||||
if let Some((cx, cy)) = result.click_xy {
|
if let Some((cx, cy)) = result.click_xy
|
||||||
if cx >= sx && cx < sx + len as u16 && cy == sy {
|
&& cx >= sx
|
||||||
new_highlight = Some(highlight_kind);
|
&& cx < sx + len as u16
|
||||||
}
|
&& cy == sy
|
||||||
|
{
|
||||||
|
new_highlight = Some(highlight_kind);
|
||||||
}
|
}
|
||||||
let mut style = Style::new().fg(match segment.color {
|
let mut style = Style::new().fg(match segment.color {
|
||||||
DiffTextColor::Normal => Color::Gray,
|
DiffTextColor::Normal => Color::Gray,
|
||||||
|
@ -62,7 +62,10 @@ config = [
|
|||||||
"dep:semver",
|
"dep:semver",
|
||||||
"dep:typed-path",
|
"dep:typed-path",
|
||||||
]
|
]
|
||||||
dwarf = ["dep:gimli"]
|
dwarf = [
|
||||||
|
"dep:gimli",
|
||||||
|
"dep:typed-arena",
|
||||||
|
]
|
||||||
serde = [
|
serde = [
|
||||||
"dep:pbjson",
|
"dep:pbjson",
|
||||||
"dep:pbjson-build",
|
"dep:pbjson-build",
|
||||||
@ -78,6 +81,7 @@ std = [
|
|||||||
"prost?/std",
|
"prost?/std",
|
||||||
"serde?/std",
|
"serde?/std",
|
||||||
"similar?/std",
|
"similar?/std",
|
||||||
|
"typed-arena?/std",
|
||||||
"typed-path?/std",
|
"typed-path?/std",
|
||||||
"dep:filetime",
|
"dep:filetime",
|
||||||
"dep:memmap2",
|
"dep:memmap2",
|
||||||
@ -143,6 +147,7 @@ serde_json = { version = "1.0", default-features = false, features = ["alloc"],
|
|||||||
|
|
||||||
# dwarf
|
# dwarf
|
||||||
gimli = { version = "0.32", default-features = false, features = ["read"], optional = true }
|
gimli = { version = "0.32", default-features = false, features = ["read"], optional = true }
|
||||||
|
typed-arena = { version = "2.0", default-features = false, optional = true }
|
||||||
|
|
||||||
# ppc
|
# ppc
|
||||||
cwdemangle = { version = "1.0", optional = true }
|
cwdemangle = { version = "1.0", optional = true }
|
||||||
|
@ -509,25 +509,25 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
return "ubfx";
|
return "ubfx";
|
||||||
}
|
}
|
||||||
Opcode::SBFM => {
|
Opcode::SBFM => {
|
||||||
if let Operand::Immediate(63) = ins.operands[3] {
|
if let Operand::Immediate(63) = ins.operands[3]
|
||||||
if let Operand::Register(SizeCode::X, _) = ins.operands[0] {
|
&& let Operand::Register(SizeCode::X, _) = ins.operands[0]
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
push_operand(args, &ins.operands[1], ctx);
|
push_separator(args);
|
||||||
push_separator(args);
|
push_operand(args, &ins.operands[1], ctx);
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_separator(args);
|
||||||
return "asr";
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
}
|
return "asr";
|
||||||
}
|
}
|
||||||
if let Operand::Immediate(31) = ins.operands[3] {
|
if let Operand::Immediate(31) = ins.operands[3]
|
||||||
if let Operand::Register(SizeCode::W, _) = ins.operands[0] {
|
&& let Operand::Register(SizeCode::W, _) = ins.operands[0]
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
push_operand(args, &ins.operands[1], ctx);
|
push_separator(args);
|
||||||
push_separator(args);
|
push_operand(args, &ins.operands[1], ctx);
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_separator(args);
|
||||||
return "asr";
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
}
|
return "asr";
|
||||||
}
|
}
|
||||||
if let Operand::Immediate(0) = ins.operands[2] {
|
if let Operand::Immediate(0) = ins.operands[2] {
|
||||||
let newsrc = if let Operand::Register(_size, srcnum) = ins.operands[1] {
|
let newsrc = if let Operand::Register(_size, srcnum) = ins.operands[1] {
|
||||||
@ -554,22 +554,21 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
if let (Operand::Immediate(imms), Operand::Immediate(immr)) =
|
if let (Operand::Immediate(imms), Operand::Immediate(immr)) =
|
||||||
(ins.operands[2], ins.operands[3])
|
(ins.operands[2], ins.operands[3])
|
||||||
|
&& immr < imms
|
||||||
{
|
{
|
||||||
if immr < imms {
|
let size = if let Operand::Register(size, _) = ins.operands[0] {
|
||||||
let size = if let Operand::Register(size, _) = ins.operands[0] {
|
if size == SizeCode::W { 32 } else { 64 }
|
||||||
if size == SizeCode::W { 32 } else { 64 }
|
} else {
|
||||||
} else {
|
unreachable!("operand 0 is always a register");
|
||||||
unreachable!("operand 0 is always a register");
|
};
|
||||||
};
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
push_separator(args);
|
||||||
push_separator(args);
|
push_operand(args, &ins.operands[1], ctx);
|
||||||
push_operand(args, &ins.operands[1], ctx);
|
push_separator(args);
|
||||||
push_separator(args);
|
push_unsigned(args, (size - imms) as u64);
|
||||||
push_unsigned(args, (size - imms) as u64);
|
push_separator(args);
|
||||||
push_separator(args);
|
push_unsigned(args, (immr + 1) as u64);
|
||||||
push_unsigned(args, (immr + 1) as u64);
|
return "sbfiz";
|
||||||
return "sbfiz";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// `sbfm` is never actually displayed: in the remaining case, it is always aliased to `sbfx`
|
// `sbfm` is never actually displayed: in the remaining case, it is always aliased to `sbfx`
|
||||||
let width = if let (Operand::Immediate(lsb), Operand::Immediate(width)) =
|
let width = if let (Operand::Immediate(lsb), Operand::Immediate(width)) =
|
||||||
@ -593,15 +592,14 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
Opcode::EXTR => {
|
Opcode::EXTR => {
|
||||||
if let (Operand::Register(_, rn), Operand::Register(_, rm)) =
|
if let (Operand::Register(_, rn), Operand::Register(_, rm)) =
|
||||||
(ins.operands[1], ins.operands[2])
|
(ins.operands[1], ins.operands[2])
|
||||||
|
&& rn == rm
|
||||||
{
|
{
|
||||||
if rn == rm {
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
push_separator(args);
|
||||||
push_separator(args);
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_separator(args);
|
||||||
push_separator(args);
|
push_operand(args, &ins.operands[3], ctx);
|
||||||
push_operand(args, &ins.operands[3], ctx);
|
return "ror";
|
||||||
return "ror";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
"extr"
|
"extr"
|
||||||
}
|
}
|
||||||
@ -804,27 +802,24 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
"csneg"
|
"csneg"
|
||||||
}
|
}
|
||||||
Opcode::CSINC => {
|
Opcode::CSINC => {
|
||||||
if let (
|
if let (Operand::Register(_, n), Operand::Register(_, m), Operand::ConditionCode(cond)) =
|
||||||
Operand::Register(_, n),
|
(ins.operands[1], ins.operands[2], ins.operands[3])
|
||||||
Operand::Register(_, m),
|
&& n == m
|
||||||
Operand::ConditionCode(cond),
|
&& cond < 0b1110
|
||||||
) = (ins.operands[1], ins.operands[2], ins.operands[3])
|
|
||||||
{
|
{
|
||||||
if n == m && cond < 0b1110 {
|
return if n == 31 {
|
||||||
return if n == 31 {
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
push_separator(args);
|
||||||
push_separator(args);
|
push_condition_code(args, cond ^ 0x01);
|
||||||
push_condition_code(args, cond ^ 0x01);
|
"cset"
|
||||||
"cset"
|
} else {
|
||||||
} else {
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
push_separator(args);
|
||||||
push_separator(args);
|
push_operand(args, &ins.operands[1], ctx);
|
||||||
push_operand(args, &ins.operands[1], ctx);
|
push_separator(args);
|
||||||
push_separator(args);
|
push_condition_code(args, cond ^ 0x01);
|
||||||
push_condition_code(args, cond ^ 0x01);
|
"cinc"
|
||||||
"cinc"
|
};
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
"csinc"
|
"csinc"
|
||||||
}
|
}
|
||||||
@ -1200,15 +1195,13 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
Operand::Register(reg_sz, _),
|
Operand::Register(reg_sz, _),
|
||||||
Operand::SIMDRegisterElementsLane(_, _, elem_sz, _),
|
Operand::SIMDRegisterElementsLane(_, _, elem_sz, _),
|
||||||
) = (ins.operands[0], ins.operands[1])
|
) = (ins.operands[0], ins.operands[1])
|
||||||
|
&& ((reg_sz == SizeCode::W && elem_sz == SIMDSizeCode::S)
|
||||||
|
|| (reg_sz == SizeCode::X && elem_sz == SIMDSizeCode::D))
|
||||||
{
|
{
|
||||||
if (reg_sz == SizeCode::W && elem_sz == SIMDSizeCode::S)
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
|| (reg_sz == SizeCode::X && elem_sz == SIMDSizeCode::D)
|
push_separator(args);
|
||||||
{
|
push_operand(args, &ins.operands[1], ctx);
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
return "mov";
|
||||||
push_separator(args);
|
|
||||||
push_operand(args, &ins.operands[1], ctx);
|
|
||||||
return "mov";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
"umov"
|
"umov"
|
||||||
}
|
}
|
||||||
@ -1308,14 +1301,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDADDB(ar) => {
|
Opcode::LDADDB(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "staddb" } else { "staddlb" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "staddb" } else { "staddlb" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldaddb"
|
"ldaddb"
|
||||||
@ -1328,14 +1322,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDCLRB(ar) => {
|
Opcode::LDCLRB(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "stclrb" } else { "stclrlb" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "stclrb" } else { "stclrlb" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldclrb"
|
"ldclrb"
|
||||||
@ -1348,14 +1343,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDEORB(ar) => {
|
Opcode::LDEORB(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "steorb" } else { "steorlb" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "steorb" } else { "steorlb" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldeorb"
|
"ldeorb"
|
||||||
@ -1368,14 +1364,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDSETB(ar) => {
|
Opcode::LDSETB(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "stsetb" } else { "stsetlb" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "stsetb" } else { "stsetlb" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldsetb"
|
"ldsetb"
|
||||||
@ -1388,14 +1385,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDSMAXB(ar) => {
|
Opcode::LDSMAXB(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "stsmaxb" } else { "stsmaxlb" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "stsmaxb" } else { "stsmaxlb" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldsmaxb"
|
"ldsmaxb"
|
||||||
@ -1408,14 +1406,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDSMINB(ar) => {
|
Opcode::LDSMINB(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "stsminb" } else { "stsminlb" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "stsminb" } else { "stsminlb" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldsminb"
|
"ldsminb"
|
||||||
@ -1428,14 +1427,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDUMAXB(ar) => {
|
Opcode::LDUMAXB(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "stumaxb" } else { "stumaxlb" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "stumaxb" } else { "stumaxlb" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldumaxb"
|
"ldumaxb"
|
||||||
@ -1448,14 +1448,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDUMINB(ar) => {
|
Opcode::LDUMINB(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "stuminb" } else { "stuminlb" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "stuminb" } else { "stuminlb" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
// write!(fmt, "{}", self.opcode)?;
|
// write!(fmt, "{}", self.opcode)?;
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
@ -1469,14 +1470,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDADDH(ar) => {
|
Opcode::LDADDH(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "staddh" } else { "staddlh" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "staddh" } else { "staddlh" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldaddh"
|
"ldaddh"
|
||||||
@ -1489,14 +1491,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDCLRH(ar) => {
|
Opcode::LDCLRH(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "stclrh" } else { "stclrlh" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "stclrh" } else { "stclrlh" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldclrh"
|
"ldclrh"
|
||||||
@ -1509,14 +1512,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDEORH(ar) => {
|
Opcode::LDEORH(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "steorh" } else { "steorlh" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "steorh" } else { "steorlh" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldeorh"
|
"ldeorh"
|
||||||
@ -1529,14 +1533,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDSETH(ar) => {
|
Opcode::LDSETH(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "stseth" } else { "stsetlh" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "stseth" } else { "stsetlh" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldseth"
|
"ldseth"
|
||||||
@ -1549,14 +1554,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDSMAXH(ar) => {
|
Opcode::LDSMAXH(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "stsmaxh" } else { "stsmaxlh" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "stsmaxh" } else { "stsmaxlh" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldsmaxh"
|
"ldsmaxh"
|
||||||
@ -1569,14 +1575,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDSMINH(ar) => {
|
Opcode::LDSMINH(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "stsminh" } else { "stsminlh" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "stsminh" } else { "stsminlh" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldsminh"
|
"ldsminh"
|
||||||
@ -1589,14 +1596,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDUMAXH(ar) => {
|
Opcode::LDUMAXH(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "stumaxh" } else { "stumaxlh" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "stumaxh" } else { "stumaxlh" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldumaxh"
|
"ldumaxh"
|
||||||
@ -1609,14 +1617,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDUMINH(ar) => {
|
Opcode::LDUMINH(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "stuminh" } else { "stuminlh" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "stuminh" } else { "stuminlh" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"lduminh"
|
"lduminh"
|
||||||
@ -1629,14 +1638,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDADD(ar) => {
|
Opcode::LDADD(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "stadd" } else { "staddl" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "stadd" } else { "staddl" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldadd"
|
"ldadd"
|
||||||
@ -1649,14 +1659,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDCLR(ar) => {
|
Opcode::LDCLR(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "stclr" } else { "stclrl" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "stclr" } else { "stclrl" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldclr"
|
"ldclr"
|
||||||
@ -1669,14 +1680,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDEOR(ar) => {
|
Opcode::LDEOR(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "steor" } else { "steorl" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "steor" } else { "steorl" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldeor"
|
"ldeor"
|
||||||
@ -1689,14 +1701,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDSET(ar) => {
|
Opcode::LDSET(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "stset" } else { "stsetl" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "stset" } else { "stsetl" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldset"
|
"ldset"
|
||||||
@ -1709,14 +1722,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDSMAX(ar) => {
|
Opcode::LDSMAX(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "stsmax" } else { "stsmaxl" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "stsmax" } else { "stsmaxl" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldsmax"
|
"ldsmax"
|
||||||
@ -1729,14 +1743,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDSMIN(ar) => {
|
Opcode::LDSMIN(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "stsmin" } else { "stsminl" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "stsmin" } else { "stsminl" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldsmin"
|
"ldsmin"
|
||||||
@ -1749,14 +1764,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDUMAX(ar) => {
|
Opcode::LDUMAX(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "stumax" } else { "stumaxl" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "stumax" } else { "stumaxl" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldumax"
|
"ldumax"
|
||||||
@ -1769,14 +1785,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::LDUMIN(ar) => {
|
Opcode::LDUMIN(ar) => {
|
||||||
if let Operand::Register(_, rt) = ins.operands[1] {
|
if let Operand::Register(_, rt) = ins.operands[1]
|
||||||
if rt == 31 && ar & 0b10 == 0b00 {
|
&& rt == 31
|
||||||
let inst = if ar & 0b01 == 0b00 { "stumin" } else { "stuminl" };
|
&& ar & 0b10 == 0b00
|
||||||
push_operand(args, &ins.operands[0], ctx);
|
{
|
||||||
push_separator(args);
|
let inst = if ar & 0b01 == 0b00 { "stumin" } else { "stuminl" };
|
||||||
push_operand(args, &ins.operands[2], ctx);
|
push_operand(args, &ins.operands[0], ctx);
|
||||||
return inst;
|
push_separator(args);
|
||||||
}
|
push_operand(args, &ins.operands[2], ctx);
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
if ar == 0 {
|
if ar == 0 {
|
||||||
"ldumin"
|
"ldumin"
|
||||||
@ -2067,16 +2084,15 @@ where Cb: FnMut(InstructionPart<'static>) {
|
|||||||
|
|
||||||
/// Relocations that appear in Operand::PCOffset.
|
/// Relocations that appear in Operand::PCOffset.
|
||||||
fn is_pc_offset_reloc(reloc: Option<ResolvedRelocation>) -> Option<ResolvedRelocation> {
|
fn is_pc_offset_reloc(reloc: Option<ResolvedRelocation>) -> Option<ResolvedRelocation> {
|
||||||
if let Some(resolved) = reloc {
|
if let Some(resolved) = reloc
|
||||||
if let RelocationFlags::Elf(
|
&& let RelocationFlags::Elf(
|
||||||
elf::R_AARCH64_ADR_PREL_PG_HI21
|
elf::R_AARCH64_ADR_PREL_PG_HI21
|
||||||
| elf::R_AARCH64_JUMP26
|
| elf::R_AARCH64_JUMP26
|
||||||
| elf::R_AARCH64_CALL26
|
| elf::R_AARCH64_CALL26
|
||||||
| elf::R_AARCH64_ADR_GOT_PAGE,
|
| elf::R_AARCH64_ADR_GOT_PAGE,
|
||||||
) = resolved.relocation.flags
|
) = resolved.relocation.flags
|
||||||
{
|
{
|
||||||
return Some(resolved);
|
return Some(resolved);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ use crate::{
|
|||||||
diff::{DiffObjConfig, MipsAbi, MipsInstrCategory, display::InstructionPart},
|
diff::{DiffObjConfig, MipsAbi, MipsInstrCategory, display::InstructionPart},
|
||||||
obj::{
|
obj::{
|
||||||
InstructionArg, InstructionArgValue, InstructionRef, Relocation, RelocationFlags,
|
InstructionArg, InstructionArgValue, InstructionRef, Relocation, RelocationFlags,
|
||||||
ResolvedInstructionRef, ResolvedRelocation, SymbolFlag, SymbolFlagSet,
|
ResolvedInstructionRef, ResolvedRelocation, Section, Symbol, SymbolFlag, SymbolFlagSet,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -140,6 +140,14 @@ impl ArchMips {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_instruction_flags(&self) -> rabbitizer::InstructionFlags {
|
||||||
|
match self.isa_extension {
|
||||||
|
Some(extension) => rabbitizer::InstructionFlags::new_extension(extension),
|
||||||
|
None => rabbitizer::InstructionFlags::new(IsaVersion::MIPS_III),
|
||||||
|
}
|
||||||
|
.with_abi(self.abi)
|
||||||
|
}
|
||||||
|
|
||||||
fn instruction_flags(&self, diff_config: &DiffObjConfig) -> rabbitizer::InstructionFlags {
|
fn instruction_flags(&self, diff_config: &DiffObjConfig) -> rabbitizer::InstructionFlags {
|
||||||
let isa_extension = match diff_config.mips_instr_category {
|
let isa_extension = match diff_config.mips_instr_category {
|
||||||
MipsInstrCategory::Auto => self.isa_extension,
|
MipsInstrCategory::Auto => self.isa_extension,
|
||||||
@ -151,7 +159,7 @@ impl ArchMips {
|
|||||||
};
|
};
|
||||||
match isa_extension {
|
match isa_extension {
|
||||||
Some(extension) => rabbitizer::InstructionFlags::new_extension(extension),
|
Some(extension) => rabbitizer::InstructionFlags::new_extension(extension),
|
||||||
None => rabbitizer::InstructionFlags::new_isa(IsaVersion::MIPS_III, None),
|
None => rabbitizer::InstructionFlags::new(IsaVersion::MIPS_III),
|
||||||
}
|
}
|
||||||
.with_abi(match diff_config.mips_abi {
|
.with_abi(match diff_config.mips_abi {
|
||||||
MipsAbi::Auto => self.abi,
|
MipsAbi::Auto => self.abi,
|
||||||
@ -234,17 +242,16 @@ impl Arch for ArchMips {
|
|||||||
object::RelocationFlags::Elf { r_type } => {
|
object::RelocationFlags::Elf { r_type } => {
|
||||||
if relocation.has_implicit_addend() {
|
if relocation.has_implicit_addend() {
|
||||||
// Check for paired R_MIPS_HI16 and R_MIPS_LO16 relocations.
|
// Check for paired R_MIPS_HI16 and R_MIPS_LO16 relocations.
|
||||||
if let elf::R_MIPS_HI16 | elf::R_MIPS_LO16 = r_type {
|
if let elf::R_MIPS_HI16 | elf::R_MIPS_LO16 = r_type
|
||||||
if let Some(addend) = self
|
&& let Some(addend) = self
|
||||||
.paired_relocations
|
.paired_relocations
|
||||||
.get(section.index().0)
|
.get(section.index().0)
|
||||||
.and_then(|m| m.get(&address).copied())
|
.and_then(|m| m.get(&address).copied())
|
||||||
{
|
{
|
||||||
return Ok(Some(RelocationOverride {
|
return Ok(Some(RelocationOverride {
|
||||||
target: RelocationOverrideTarget::Keep,
|
target: RelocationOverrideTarget::Keep,
|
||||||
addend,
|
addend,
|
||||||
}));
|
}));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = section.data()?;
|
let data = section.data()?;
|
||||||
@ -331,6 +338,36 @@ impl Arch for ArchMips {
|
|||||||
}
|
}
|
||||||
flags
|
flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn infer_function_size(
|
||||||
|
&self,
|
||||||
|
symbol: &Symbol,
|
||||||
|
section: &Section,
|
||||||
|
next_address: u64,
|
||||||
|
) -> Result<u64> {
|
||||||
|
// Trim any trailing 4-byte zeroes from the end (nops)
|
||||||
|
let mut new_address = next_address;
|
||||||
|
while new_address >= symbol.address + 4
|
||||||
|
&& let Some(data) = section.data_range(new_address - 4, 4)
|
||||||
|
&& data == [0u8; 4]
|
||||||
|
{
|
||||||
|
new_address -= 4;
|
||||||
|
}
|
||||||
|
// Check if the last instruction has a delay slot, if so, include the delay slot nop
|
||||||
|
if new_address + 4 <= next_address
|
||||||
|
&& new_address >= symbol.address + 4
|
||||||
|
&& let Some(data) = section.data_range(new_address - 4, 4)
|
||||||
|
&& let instruction = rabbitizer::Instruction::new(
|
||||||
|
self.endianness.read_u32_bytes(data.try_into().unwrap()),
|
||||||
|
Vram::new((new_address - 4) as u32),
|
||||||
|
self.default_instruction_flags(),
|
||||||
|
)
|
||||||
|
&& instruction.opcode().has_delay_slot()
|
||||||
|
{
|
||||||
|
new_address += 4;
|
||||||
|
}
|
||||||
|
Ok(new_address.saturating_sub(symbol.address))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_args(
|
fn push_args(
|
||||||
|
@ -215,10 +215,10 @@ impl dyn Arch {
|
|||||||
|
|
||||||
// Remove any branch destinations that are outside the function range
|
// Remove any branch destinations that are outside the function range
|
||||||
for ins in result.iter_mut() {
|
for ins in result.iter_mut() {
|
||||||
if let Some(branch_dest) = ins.branch_dest {
|
if let Some(branch_dest) = ins.branch_dest
|
||||||
if branch_dest < function_start || branch_dest >= function_end {
|
&& (branch_dest < function_start || branch_dest >= function_end)
|
||||||
ins.branch_dest = None;
|
{
|
||||||
}
|
ins.branch_dest = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,6 +406,15 @@ pub trait Arch: Send + Sync + Debug {
|
|||||||
) -> Vec<ContextItem> {
|
) -> Vec<ContextItem> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn infer_function_size(
|
||||||
|
&self,
|
||||||
|
symbol: &Symbol,
|
||||||
|
_section: &Section,
|
||||||
|
next_address: u64,
|
||||||
|
) -> Result<u64> {
|
||||||
|
Ok(next_address.saturating_sub(symbol.address))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_arch(object: &object::File) -> Result<Box<dyn Arch>> {
|
pub fn new_arch(object: &object::File) -> Result<Box<dyn Arch>> {
|
||||||
|
@ -514,14 +514,14 @@ pub fn ppc_data_flow_analysis(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_string_data(obj: &Object, symbol_index: usize, offset: Simm) -> Option<&str> {
|
fn get_string_data(obj: &Object, symbol_index: usize, offset: Simm) -> Option<&str> {
|
||||||
if let Some(sym) = obj.symbols.get(symbol_index) {
|
if let Some(sym) = obj.symbols.get(symbol_index)
|
||||||
if sym.name.starts_with("@stringBase") && offset.0 != 0 {
|
&& sym.name.starts_with("@stringBase")
|
||||||
if let Some(data) = obj.symbol_data(symbol_index) {
|
&& offset.0 != 0
|
||||||
let bytes = &data[offset.0 as usize..];
|
&& let Some(data) = obj.symbol_data(symbol_index)
|
||||||
if let Ok(Ok(str)) = CStr::from_bytes_until_nul(bytes).map(|x| x.to_str()) {
|
{
|
||||||
return Some(str);
|
let bytes = &data[offset.0 as usize..];
|
||||||
}
|
if let Ok(Ok(str)) = CStr::from_bytes_until_nul(bytes).map(|x| x.to_str()) {
|
||||||
}
|
return Some(str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
@ -577,19 +577,17 @@ fn generate_flow_analysis_result(
|
|||||||
let registers = register_state_at.get(index as usize).unwrap_or(&default_register_state);
|
let registers = register_state_at.get(index as usize).unwrap_or(&default_register_state);
|
||||||
if let (powerpc::Opcode::Addi, Argument::GPR(rel), Argument::Simm(offset)) =
|
if let (powerpc::Opcode::Addi, Argument::GPR(rel), Argument::Simm(offset)) =
|
||||||
(ins.op, args[1], args[2])
|
(ins.op, args[1], args[2])
|
||||||
|
&& let RegisterContent::Symbol(sym_index) = registers[rel]
|
||||||
|
&& let Some(str) = get_string_data(obj, sym_index, offset)
|
||||||
{
|
{
|
||||||
if let RegisterContent::Symbol(sym_index) = registers[rel] {
|
// Show the string constant in the analysis result
|
||||||
if let Some(str) = get_string_data(obj, sym_index, offset) {
|
let formatted = format!("\"{str}\"");
|
||||||
// Show the string constant in the analysis result
|
analysis_result.set_argument_value_at_address(
|
||||||
let formatted = format!("\"{str}\"");
|
ins_address,
|
||||||
analysis_result.set_argument_value_at_address(
|
2,
|
||||||
ins_address,
|
FlowAnalysisValue::Text(clamp_text_length(formatted, 20)),
|
||||||
2,
|
);
|
||||||
FlowAnalysisValue::Text(clamp_text_length(formatted, 20)),
|
// Don't continue, we want to show the stringbase value as well
|
||||||
);
|
|
||||||
// Don't continue, we want to show the stringbase value as well
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_store = is_store_instruction(ins.op);
|
let is_store = is_store_instruction(ins.op);
|
||||||
|
@ -20,7 +20,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
obj::{
|
obj::{
|
||||||
FlowAnalysisResult, InstructionRef, Object, Relocation, RelocationFlags,
|
FlowAnalysisResult, InstructionRef, Object, Relocation, RelocationFlags,
|
||||||
ResolvedInstructionRef, ResolvedRelocation, Symbol, SymbolFlag, SymbolFlagSet,
|
ResolvedInstructionRef, ResolvedRelocation, Section, Symbol, SymbolFlag, SymbolFlagSet,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -66,7 +66,9 @@ impl ArchPpc {
|
|||||||
if file.is_64() {
|
if file.is_64() {
|
||||||
powerpc::Extension::Ppc64 | powerpc::Extension::AltiVec
|
powerpc::Extension::Ppc64 | powerpc::Extension::AltiVec
|
||||||
} else {
|
} else {
|
||||||
powerpc::Extension::AltiVec.into()
|
// Gekko/Broadway objects often use the EF_PPC_EMB flag,
|
||||||
|
// but ProDG in particular does not emit it.
|
||||||
|
powerpc::Extensions::gekko_broadway()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -455,6 +457,22 @@ impl Arch for ArchPpc {
|
|||||||
}
|
}
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn infer_function_size(
|
||||||
|
&self,
|
||||||
|
symbol: &Symbol,
|
||||||
|
section: &Section,
|
||||||
|
mut next_address: u64,
|
||||||
|
) -> Result<u64> {
|
||||||
|
// Trim any trailing 4-byte zeroes from the end (padding)
|
||||||
|
while next_address >= symbol.address + 4
|
||||||
|
&& let Some(data) = section.data_range(next_address - 4, 4)
|
||||||
|
&& data == [0u8; 4]
|
||||||
|
{
|
||||||
|
next_address -= 4;
|
||||||
|
}
|
||||||
|
Ok(next_address.saturating_sub(symbol.address))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArchPpc {
|
impl ArchPpc {
|
||||||
@ -850,44 +868,43 @@ fn generate_fake_pool_relocations_for_function(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(branch_dest) = branch_dest {
|
if let Some(branch_dest) = branch_dest
|
||||||
if branch_dest >= func_address as u32
|
&& branch_dest >= func_address as u32
|
||||||
&& (branch_dest - func_address as u32) < code.len() as u32
|
&& (branch_dest - func_address as u32) < code.len() as u32
|
||||||
{
|
{
|
||||||
let dest_offset_into_func = branch_dest - func_address as u32;
|
let dest_offset_into_func = branch_dest - func_address as u32;
|
||||||
let dest_code_slice = &code[dest_offset_into_func as usize..];
|
let dest_code_slice = &code[dest_offset_into_func as usize..];
|
||||||
match ins.op {
|
match ins.op {
|
||||||
Opcode::Bc => {
|
Opcode::Bc => {
|
||||||
// Conditional branch.
|
// Conditional branch.
|
||||||
// Add the branch destination to the queue to do later.
|
// Add the branch destination to the queue to do later.
|
||||||
|
ins_iters_with_gpr_state.push((
|
||||||
|
InsIter::new(dest_code_slice, branch_dest, extensions),
|
||||||
|
gpr_pool_relocs.clone(),
|
||||||
|
));
|
||||||
|
// Then continue on with the current iterator.
|
||||||
|
}
|
||||||
|
Opcode::B => {
|
||||||
|
if simplified.mnemonic != "bl" {
|
||||||
|
// Unconditional branch.
|
||||||
|
// Add the branch destination to the queue.
|
||||||
ins_iters_with_gpr_state.push((
|
ins_iters_with_gpr_state.push((
|
||||||
InsIter::new(dest_code_slice, branch_dest, extensions),
|
InsIter::new(dest_code_slice, branch_dest, extensions),
|
||||||
gpr_pool_relocs.clone(),
|
gpr_pool_relocs.clone(),
|
||||||
));
|
));
|
||||||
// Then continue on with the current iterator.
|
// Break out of the current iterator so we can do the newly added one.
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
Opcode::B => {
|
|
||||||
if simplified.mnemonic != "bl" {
|
|
||||||
// Unconditional branch.
|
|
||||||
// Add the branch destination to the queue.
|
|
||||||
ins_iters_with_gpr_state.push((
|
|
||||||
InsIter::new(dest_code_slice, branch_dest, extensions),
|
|
||||||
gpr_pool_relocs.clone(),
|
|
||||||
));
|
|
||||||
// Break out of the current iterator so we can do the newly added one.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Opcode::Bcctr = ins.op {
|
if let Opcode::Bcctr = ins.op
|
||||||
if simplified.mnemonic == "bctr" {
|
&& simplified.mnemonic == "bctr"
|
||||||
// Unconditional branch to count register.
|
{
|
||||||
// Likely a jump table.
|
// Unconditional branch to count register.
|
||||||
gpr_state_at_bctr.insert(cur_addr, gpr_pool_relocs.clone());
|
// Likely a jump table.
|
||||||
}
|
gpr_state_at_bctr.insert(cur_addr, gpr_pool_relocs.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then handle keeping track of which GPR contains which pool relocation.
|
// Then handle keeping track of which GPR contains which pool relocation.
|
||||||
|
@ -11,7 +11,7 @@ use object::{Endian as _, Object as _, ObjectSection as _, elf, pe};
|
|||||||
use crate::{
|
use crate::{
|
||||||
arch::{Arch, RelocationOverride, RelocationOverrideTarget},
|
arch::{Arch, RelocationOverride, RelocationOverrideTarget},
|
||||||
diff::{DiffObjConfig, X86Formatter, display::InstructionPart},
|
diff::{DiffObjConfig, X86Formatter, display::InstructionPart},
|
||||||
obj::{InstructionRef, Relocation, RelocationFlags, ResolvedInstructionRef},
|
obj::{InstructionRef, Relocation, RelocationFlags, ResolvedInstructionRef, Section, Symbol},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -303,6 +303,52 @@ impl Arch for ArchX86 {
|
|||||||
fn data_reloc_size(&self, flags: RelocationFlags) -> usize {
|
fn data_reloc_size(&self, flags: RelocationFlags) -> usize {
|
||||||
self.reloc_size(flags).unwrap_or(1)
|
self.reloc_size(flags).unwrap_or(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn infer_function_size(
|
||||||
|
&self,
|
||||||
|
symbol: &Symbol,
|
||||||
|
section: &Section,
|
||||||
|
next_address: u64,
|
||||||
|
) -> Result<u64> {
|
||||||
|
let Ok(size) = (next_address - symbol.address).try_into() else {
|
||||||
|
return Ok(next_address.saturating_sub(symbol.address));
|
||||||
|
};
|
||||||
|
let Some(code) = section.data_range(symbol.address, size) else {
|
||||||
|
return Ok(0);
|
||||||
|
};
|
||||||
|
// Decode instructions to find the last non-NOP instruction
|
||||||
|
let mut decoder = self.decoder(code, symbol.address);
|
||||||
|
let mut instruction = Instruction::default();
|
||||||
|
let mut new_address = 0;
|
||||||
|
let mut reloc_iter = section.relocations.iter().peekable();
|
||||||
|
'outer: while decoder.can_decode() {
|
||||||
|
let address = decoder.ip();
|
||||||
|
while let Some(reloc) = reloc_iter.peek() {
|
||||||
|
match reloc.address.cmp(&address) {
|
||||||
|
Ordering::Less => {
|
||||||
|
reloc_iter.next();
|
||||||
|
}
|
||||||
|
Ordering::Equal => {
|
||||||
|
// If the instruction starts at a relocation, it's inline data
|
||||||
|
let reloc_size = self.reloc_size(reloc.flags).with_context(|| {
|
||||||
|
format!("Unsupported inline x86 relocation {:?}", reloc.flags)
|
||||||
|
})?;
|
||||||
|
if decoder.set_position(decoder.position() + reloc_size).is_ok() {
|
||||||
|
new_address = address + reloc_size as u64;
|
||||||
|
decoder.set_ip(new_address);
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ordering::Greater => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
decoder.decode_out(&mut instruction);
|
||||||
|
if instruction.mnemonic() != iced_x86::Mnemonic::Nop {
|
||||||
|
new_address = instruction.next_ip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(new_address.saturating_sub(symbol.address))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InstructionFormatterOutput<'a> {
|
struct InstructionFormatterOutput<'a> {
|
||||||
|
@ -127,6 +127,28 @@ fn diff_data_relocs_for_range<'left, 'right>(
|
|||||||
diffs
|
diffs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn no_diff_data_section(obj: &Object, section_idx: usize) -> Result<SectionDiff> {
|
||||||
|
let section = &obj.sections[section_idx];
|
||||||
|
let len = section.data.len();
|
||||||
|
let data = §ion.data[0..len];
|
||||||
|
|
||||||
|
let data_diff =
|
||||||
|
vec![DataDiff { data: data.to_vec(), kind: DataDiffKind::None, len, ..Default::default() }];
|
||||||
|
|
||||||
|
let mut reloc_diffs = Vec::new();
|
||||||
|
for reloc in section.relocations.iter() {
|
||||||
|
let reloc_len = obj.arch.data_reloc_size(reloc.flags);
|
||||||
|
let range = reloc.address as usize..reloc.address as usize + reloc_len;
|
||||||
|
reloc_diffs.push(DataRelocationDiff {
|
||||||
|
reloc: reloc.clone(),
|
||||||
|
kind: DataDiffKind::None,
|
||||||
|
range,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(SectionDiff { match_percent: Some(0.0), data_diff, reloc_diff: reloc_diffs })
|
||||||
|
}
|
||||||
|
|
||||||
/// Compare the data sections of two object files.
|
/// Compare the data sections of two object files.
|
||||||
pub fn diff_data_section(
|
pub fn diff_data_section(
|
||||||
left_obj: &Object,
|
left_obj: &Object,
|
||||||
@ -415,6 +437,10 @@ pub fn diff_generic_section(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn no_diff_bss_section() -> Result<SectionDiff> {
|
||||||
|
Ok(SectionDiff { match_percent: Some(0.0), data_diff: vec![], reloc_diff: vec![] })
|
||||||
|
}
|
||||||
|
|
||||||
/// Compare the addresses and sizes of each symbol in the BSS sections.
|
/// Compare the addresses and sizes of each symbol in the BSS sections.
|
||||||
pub fn diff_bss_section(
|
pub fn diff_bss_section(
|
||||||
left_obj: &Object,
|
left_obj: &Object,
|
||||||
|
@ -385,13 +385,13 @@ pub fn symbol_context(obj: &Object, symbol_index: usize) -> Vec<ContextItem> {
|
|||||||
if let Some(name) = &symbol.demangled_name {
|
if let Some(name) = &symbol.demangled_name {
|
||||||
out.push(ContextItem::Copy { value: name.clone(), label: None });
|
out.push(ContextItem::Copy { value: name.clone(), label: None });
|
||||||
}
|
}
|
||||||
if symbol.section.is_some() {
|
if symbol.section.is_some()
|
||||||
if let Some(address) = symbol.virtual_address {
|
&& let Some(address) = symbol.virtual_address
|
||||||
out.push(ContextItem::Copy {
|
{
|
||||||
value: format!("{address:x}"),
|
out.push(ContextItem::Copy {
|
||||||
label: Some("virtual address".to_string()),
|
value: format!("{address:x}"),
|
||||||
});
|
label: Some("virtual address".to_string()),
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
out.append(&mut obj.arch.symbol_context(obj, symbol_index));
|
out.append(&mut obj.arch.symbol_context(obj, symbol_index));
|
||||||
out
|
out
|
||||||
|
@ -13,7 +13,7 @@ use crate::{
|
|||||||
code::{diff_code, no_diff_code},
|
code::{diff_code, no_diff_code},
|
||||||
data::{
|
data::{
|
||||||
diff_bss_section, diff_bss_symbol, diff_data_section, diff_data_symbol,
|
diff_bss_section, diff_bss_symbol, diff_data_section, diff_data_symbol,
|
||||||
diff_generic_section,
|
diff_generic_section, no_diff_bss_section, no_diff_data_section,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
obj::{InstructionRef, Object, Relocation, SectionKind, Symbol, SymbolFlag},
|
obj::{InstructionRef, Object, Relocation, SectionKind, Symbol, SymbolFlag},
|
||||||
@ -288,52 +288,84 @@ pub fn diff_objs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for section_match in section_matches {
|
for section_match in section_matches {
|
||||||
if let SectionMatch {
|
match section_match {
|
||||||
left: Some(left_section_idx),
|
SectionMatch {
|
||||||
right: Some(right_section_idx),
|
left: Some(left_section_idx),
|
||||||
section_kind,
|
right: Some(right_section_idx),
|
||||||
} = section_match
|
section_kind,
|
||||||
{
|
} => {
|
||||||
let (left_obj, left_out) = left.as_mut().unwrap();
|
let (left_obj, left_out) = left.as_mut().unwrap();
|
||||||
let (right_obj, right_out) = right.as_mut().unwrap();
|
let (right_obj, right_out) = right.as_mut().unwrap();
|
||||||
match section_kind {
|
match section_kind {
|
||||||
SectionKind::Code => {
|
SectionKind::Code => {
|
||||||
let (left_diff, right_diff) = diff_generic_section(
|
let (left_diff, right_diff) = diff_generic_section(
|
||||||
left_obj,
|
left_obj,
|
||||||
right_obj,
|
right_obj,
|
||||||
left_out,
|
left_out,
|
||||||
right_out,
|
right_out,
|
||||||
left_section_idx,
|
left_section_idx,
|
||||||
right_section_idx,
|
right_section_idx,
|
||||||
)?;
|
)?;
|
||||||
left_out.sections[left_section_idx] = left_diff;
|
left_out.sections[left_section_idx] = left_diff;
|
||||||
right_out.sections[right_section_idx] = right_diff;
|
right_out.sections[right_section_idx] = right_diff;
|
||||||
|
}
|
||||||
|
SectionKind::Data => {
|
||||||
|
let (left_diff, right_diff) = diff_data_section(
|
||||||
|
left_obj,
|
||||||
|
right_obj,
|
||||||
|
left_out,
|
||||||
|
right_out,
|
||||||
|
left_section_idx,
|
||||||
|
right_section_idx,
|
||||||
|
)?;
|
||||||
|
left_out.sections[left_section_idx] = left_diff;
|
||||||
|
right_out.sections[right_section_idx] = right_diff;
|
||||||
|
}
|
||||||
|
SectionKind::Bss | SectionKind::Common => {
|
||||||
|
let (left_diff, right_diff) = diff_bss_section(
|
||||||
|
left_obj,
|
||||||
|
right_obj,
|
||||||
|
left_out,
|
||||||
|
right_out,
|
||||||
|
left_section_idx,
|
||||||
|
right_section_idx,
|
||||||
|
)?;
|
||||||
|
left_out.sections[left_section_idx] = left_diff;
|
||||||
|
right_out.sections[right_section_idx] = right_diff;
|
||||||
|
}
|
||||||
|
SectionKind::Unknown => unreachable!(),
|
||||||
}
|
}
|
||||||
SectionKind::Data => {
|
}
|
||||||
let (left_diff, right_diff) = diff_data_section(
|
SectionMatch { left: Some(left_section_idx), right: None, section_kind } => {
|
||||||
left_obj,
|
let (left_obj, left_out) = left.as_mut().unwrap();
|
||||||
right_obj,
|
match section_kind {
|
||||||
left_out,
|
SectionKind::Code => {}
|
||||||
right_out,
|
SectionKind::Data => {
|
||||||
left_section_idx,
|
left_out.sections[left_section_idx] =
|
||||||
right_section_idx,
|
no_diff_data_section(left_obj, left_section_idx)?;
|
||||||
)?;
|
}
|
||||||
left_out.sections[left_section_idx] = left_diff;
|
SectionKind::Bss | SectionKind::Common => {
|
||||||
right_out.sections[right_section_idx] = right_diff;
|
left_out.sections[left_section_idx] = no_diff_bss_section()?;
|
||||||
|
}
|
||||||
|
SectionKind::Unknown => unreachable!(),
|
||||||
}
|
}
|
||||||
SectionKind::Bss | SectionKind::Common => {
|
}
|
||||||
let (left_diff, right_diff) = diff_bss_section(
|
SectionMatch { left: None, right: Some(right_section_idx), section_kind } => {
|
||||||
left_obj,
|
let (right_obj, right_out) = right.as_mut().unwrap();
|
||||||
right_obj,
|
match section_kind {
|
||||||
left_out,
|
SectionKind::Code => {}
|
||||||
right_out,
|
SectionKind::Data => {
|
||||||
left_section_idx,
|
right_out.sections[right_section_idx] =
|
||||||
right_section_idx,
|
no_diff_data_section(right_obj, right_section_idx)?;
|
||||||
)?;
|
}
|
||||||
left_out.sections[left_section_idx] = left_diff;
|
SectionKind::Bss | SectionKind::Common => {
|
||||||
right_out.sections[right_section_idx] = right_diff;
|
right_out.sections[right_section_idx] = no_diff_bss_section()?;
|
||||||
|
}
|
||||||
|
SectionKind::Unknown => unreachable!(),
|
||||||
}
|
}
|
||||||
SectionKind::Unknown => unreachable!(),
|
}
|
||||||
|
SectionMatch { left: None, right: None, .. } => {
|
||||||
|
// Should not happen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -467,15 +499,15 @@ fn apply_symbol_mappings(
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// If we're selecting a symbol to use as a comparison, mark it as used
|
// If we're selecting a symbol to use as a comparison, mark it as used
|
||||||
// This ensures that we don't match it to another symbol at any point
|
// This ensures that we don't match it to another symbol at any point
|
||||||
if let Some(left_name) = &mapping_config.selecting_left {
|
if let Some(left_name) = &mapping_config.selecting_left
|
||||||
if let Some(left_symbol) = left.symbol_by_name(left_name) {
|
&& let Some(left_symbol) = left.symbol_by_name(left_name)
|
||||||
left_used.insert(left_symbol);
|
{
|
||||||
}
|
left_used.insert(left_symbol);
|
||||||
}
|
}
|
||||||
if let Some(right_name) = &mapping_config.selecting_right {
|
if let Some(right_name) = &mapping_config.selecting_right
|
||||||
if let Some(right_symbol) = right.symbol_by_name(right_name) {
|
&& let Some(right_symbol) = right.symbol_by_name(right_name)
|
||||||
right_used.insert(right_symbol);
|
{
|
||||||
}
|
right_used.insert(right_symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply manual symbol mappings
|
// Apply manual symbol mappings
|
||||||
@ -639,17 +671,16 @@ fn find_symbol(
|
|||||||
// If they are at the same address in the same section
|
// If they are at the same address in the same section
|
||||||
if in_symbol.name.starts_with('@')
|
if in_symbol.name.starts_with('@')
|
||||||
&& matches!(section_kind, SectionKind::Data | SectionKind::Bss)
|
&& matches!(section_kind, SectionKind::Data | SectionKind::Bss)
|
||||||
{
|
&& let Some((symbol_idx, _)) = unmatched_symbols(obj, used).find(|(_, symbol)| {
|
||||||
if let Some((symbol_idx, _)) = unmatched_symbols(obj, used).find(|(_, symbol)| {
|
|
||||||
let Some(section_index) = symbol.section else {
|
let Some(section_index) = symbol.section else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
symbol.name.starts_with('@')
|
symbol.name.starts_with('@')
|
||||||
&& symbol.address == in_symbol.address
|
&& symbol.address == in_symbol.address
|
||||||
&& obj.sections[section_index].name == section_name
|
&& obj.sections[section_index].name == section_name
|
||||||
}) {
|
})
|
||||||
return Some(symbol_idx);
|
{
|
||||||
}
|
return Some(symbol_idx);
|
||||||
}
|
}
|
||||||
// Match Metrowerks symbol$1234 against symbol$2345
|
// Match Metrowerks symbol$1234 against symbol$2345
|
||||||
if let Some((prefix, suffix)) = in_symbol.name.split_once('$') {
|
if let Some((prefix, suffix)) = in_symbol.name.split_once('$') {
|
||||||
|
109
objdiff-core/src/obj/dwarf2.rs
Normal file
109
objdiff-core/src/obj/dwarf2.rs
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
use alloc::{borrow::Cow, vec::Vec};
|
||||||
|
|
||||||
|
use anyhow::{Context, Result};
|
||||||
|
use object::{Object as _, ObjectSection as _};
|
||||||
|
use typed_arena::Arena;
|
||||||
|
|
||||||
|
use crate::obj::{Section, SectionKind};
|
||||||
|
|
||||||
|
/// Parse line information from DWARF 2+ sections.
|
||||||
|
pub(crate) fn parse_line_info_dwarf2(
|
||||||
|
obj_file: &object::File,
|
||||||
|
sections: &mut [Section],
|
||||||
|
) -> Result<()> {
|
||||||
|
let arena_data = Arena::new();
|
||||||
|
let arena_relocations = Arena::new();
|
||||||
|
let endian = match obj_file.endianness() {
|
||||||
|
object::Endianness::Little => gimli::RunTimeEndian::Little,
|
||||||
|
object::Endianness::Big => gimli::RunTimeEndian::Big,
|
||||||
|
};
|
||||||
|
let dwarf = gimli::Dwarf::load(|id: gimli::SectionId| -> Result<_> {
|
||||||
|
load_file_section(id, obj_file, endian, &arena_data, &arena_relocations)
|
||||||
|
})
|
||||||
|
.context("loading DWARF sections")?;
|
||||||
|
|
||||||
|
let mut iter = dwarf.units();
|
||||||
|
if let Some(header) = iter.next().map_err(|e| gimli_error(e, "iterating over DWARF units"))? {
|
||||||
|
let unit = dwarf.unit(header).map_err(|e| gimli_error(e, "loading DWARF unit"))?;
|
||||||
|
if let Some(program) = unit.line_program.clone() {
|
||||||
|
let mut text_sections = sections.iter_mut().filter(|s| s.kind == SectionKind::Code);
|
||||||
|
let mut lines = text_sections.next().map(|section| &mut section.line_info);
|
||||||
|
|
||||||
|
let mut rows = program.rows();
|
||||||
|
while let Some((_header, row)) =
|
||||||
|
rows.next_row().map_err(|e| gimli_error(e, "loading program row"))?
|
||||||
|
{
|
||||||
|
if let (Some(line), Some(lines)) = (row.line(), &mut lines) {
|
||||||
|
lines.insert(row.address(), line.get() as u32);
|
||||||
|
}
|
||||||
|
if row.end_sequence() {
|
||||||
|
// The next row is the start of a new sequence, which means we must
|
||||||
|
// advance to the next .text section.
|
||||||
|
lines = text_sections.next().map(|section| &mut section.line_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if iter.next().map_err(|e| gimli_error(e, "checking for next unit"))?.is_some() {
|
||||||
|
log::warn!("Multiple units found in DWARF data, only processing the first");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct RelocationMap(object::read::RelocationMap);
|
||||||
|
|
||||||
|
impl RelocationMap {
|
||||||
|
fn add(&mut self, file: &object::File, section: &object::Section) {
|
||||||
|
for (offset, relocation) in section.relocations() {
|
||||||
|
if let Err(e) = self.0.add(file, offset, relocation) {
|
||||||
|
log::error!(
|
||||||
|
"Relocation error for section {} at offset 0x{:08x}: {}",
|
||||||
|
section.name().unwrap(),
|
||||||
|
offset,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl gimli::read::Relocate for &'_ RelocationMap {
|
||||||
|
fn relocate_address(&self, offset: usize, value: u64) -> gimli::Result<u64> {
|
||||||
|
Ok(self.0.relocate(offset as u64, value))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn relocate_offset(&self, offset: usize, value: usize) -> gimli::Result<usize> {
|
||||||
|
<usize as gimli::ReaderOffset>::from_u64(self.0.relocate(offset as u64, value as u64))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Relocate<'a, R> = gimli::RelocateReader<R, &'a RelocationMap>;
|
||||||
|
|
||||||
|
fn load_file_section<'input, 'arena, Endian: gimli::Endianity>(
|
||||||
|
id: gimli::SectionId,
|
||||||
|
file: &object::File<'input>,
|
||||||
|
endian: Endian,
|
||||||
|
arena_data: &'arena Arena<Cow<'input, [u8]>>,
|
||||||
|
arena_relocations: &'arena Arena<RelocationMap>,
|
||||||
|
) -> Result<Relocate<'arena, gimli::EndianSlice<'arena, Endian>>> {
|
||||||
|
let mut relocations = RelocationMap::default();
|
||||||
|
let data = match file.section_by_name(id.name()) {
|
||||||
|
Some(ref section) => {
|
||||||
|
relocations.add(file, section);
|
||||||
|
section.uncompressed_data()?
|
||||||
|
}
|
||||||
|
// Use a non-zero capacity so that `ReaderOffsetId`s are unique.
|
||||||
|
None => Cow::Owned(Vec::with_capacity(1)),
|
||||||
|
};
|
||||||
|
let data_ref = arena_data.alloc(data);
|
||||||
|
let section = gimli::EndianSlice::new(data_ref, endian);
|
||||||
|
let relocations = arena_relocations.alloc(relocations);
|
||||||
|
Ok(Relocate::new(section, relocations))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn gimli_error(e: gimli::Error, context: &str) -> anyhow::Error {
|
||||||
|
anyhow::anyhow!("gimli error {context}: {e:?}")
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
#[cfg(feature = "dwarf")]
|
||||||
|
mod dwarf2;
|
||||||
pub mod read;
|
pub mod read;
|
||||||
pub mod split_meta;
|
pub mod split_meta;
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ fn map_symbols(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Infer symbol sizes for 0-size symbols
|
// Infer symbol sizes for 0-size symbols
|
||||||
infer_symbol_sizes(&mut symbols, sections);
|
infer_symbol_sizes(arch, &mut symbols, sections)?;
|
||||||
|
|
||||||
Ok((symbols, symbol_indices))
|
Ok((symbols, symbol_indices))
|
||||||
}
|
}
|
||||||
@ -136,7 +136,7 @@ fn is_local_label(symbol: &Symbol) -> bool {
|
|||||||
&& LABEL_PREFIXES.iter().any(|p| symbol.name.starts_with(p))
|
&& LABEL_PREFIXES.iter().any(|p| symbol.name.starts_with(p))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_symbol_sizes(symbols: &mut [Symbol], sections: &[Section]) {
|
fn infer_symbol_sizes(arch: &dyn Arch, symbols: &mut [Symbol], sections: &[Section]) -> Result<()> {
|
||||||
// Create a sorted list of symbol indices by section
|
// Create a sorted list of symbol indices by section
|
||||||
let mut symbols_with_section = Vec::<usize>::with_capacity(symbols.len());
|
let mut symbols_with_section = Vec::<usize>::with_capacity(symbols.len());
|
||||||
for (i, symbol) in symbols.iter().enumerate() {
|
for (i, symbol) in symbols.iter().enumerate() {
|
||||||
@ -206,18 +206,13 @@ fn infer_symbol_sizes(symbols: &mut [Symbol], sections: &[Section]) {
|
|||||||
iter_idx += 1;
|
iter_idx += 1;
|
||||||
};
|
};
|
||||||
let section = §ions[section_idx];
|
let section = §ions[section_idx];
|
||||||
let mut next_address =
|
let next_address =
|
||||||
next_symbol.map(|s| s.address).unwrap_or_else(|| section.address + section.size);
|
next_symbol.map(|s| s.address).unwrap_or_else(|| section.address + section.size);
|
||||||
if section.kind == SectionKind::Code {
|
let new_size = if section.kind == SectionKind::Code {
|
||||||
// For functions, trim any trailing 4-byte zeroes from the end (padding, nops)
|
arch.infer_function_size(symbol, section, next_address)?
|
||||||
while next_address > symbol.address + 4
|
} else {
|
||||||
&& let Some(data) = section.data_range(next_address - 4, 4)
|
next_address.saturating_sub(symbol.address)
|
||||||
&& data == [0u8; 4]
|
};
|
||||||
{
|
|
||||||
next_address -= 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let new_size = next_address.saturating_sub(symbol.address);
|
|
||||||
if new_size > 0 {
|
if new_size > 0 {
|
||||||
let symbol = &mut symbols[symbol_idx];
|
let symbol = &mut symbols[symbol_idx];
|
||||||
symbol.size = new_size;
|
symbol.size = new_size;
|
||||||
@ -234,6 +229,7 @@ fn infer_symbol_sizes(symbols: &mut [Symbol], sections: &[Section]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_sections(
|
fn map_sections(
|
||||||
@ -554,12 +550,11 @@ fn perform_data_flow_analysis(obj: &mut Object, config: &DiffObjConfig) -> Resul
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Optional full data flow analysis
|
// Optional full data flow analysis
|
||||||
if config.analyze_data_flow {
|
if config.analyze_data_flow
|
||||||
if let Some(flow_result) =
|
&& let Some(flow_result) =
|
||||||
obj.arch.data_flow_analysis(obj, symbol, code, §ion.relocations)
|
obj.arch.data_flow_analysis(obj, symbol, code, §ion.relocations)
|
||||||
{
|
{
|
||||||
generated_flow_results.push((symbol.clone(), flow_result));
|
generated_flow_results.push((symbol.clone(), flow_result));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -582,6 +577,28 @@ fn parse_line_info(
|
|||||||
obj_data: &[u8],
|
obj_data: &[u8],
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// DWARF 1.1
|
// DWARF 1.1
|
||||||
|
if let Err(e) = parse_line_info_dwarf1(obj_file, sections) {
|
||||||
|
log::warn!("Failed to parse DWARF 1.1 line info: {e}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// DWARF 2+
|
||||||
|
#[cfg(feature = "dwarf")]
|
||||||
|
if let Err(e) = super::dwarf2::parse_line_info_dwarf2(obj_file, sections) {
|
||||||
|
log::warn!("Failed to parse DWARF 2+ line info: {e}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// COFF
|
||||||
|
if let object::File::Coff(coff) = obj_file
|
||||||
|
&& let Err(e) = parse_line_info_coff(coff, sections, section_indices, obj_data)
|
||||||
|
{
|
||||||
|
log::warn!("Failed to parse COFF line info: {e}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse .line section from DWARF 1.1 format.
|
||||||
|
fn parse_line_info_dwarf1(obj_file: &object::File, sections: &mut [Section]) -> Result<()> {
|
||||||
if let Some(section) = obj_file.section_by_name(".line") {
|
if let Some(section) = obj_file.section_by_name(".line") {
|
||||||
let data = section.uncompressed_data()?;
|
let data = section.uncompressed_data()?;
|
||||||
let mut reader: &[u8] = data.as_ref();
|
let mut reader: &[u8] = data.as_ref();
|
||||||
@ -609,55 +626,6 @@ fn parse_line_info(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DWARF 2+
|
|
||||||
#[cfg(feature = "dwarf")]
|
|
||||||
{
|
|
||||||
fn gimli_error(e: gimli::Error) -> anyhow::Error { anyhow::anyhow!("DWARF error: {e:?}") }
|
|
||||||
let dwarf_cow = gimli::DwarfSections::load(|id| {
|
|
||||||
Ok::<_, gimli::Error>(
|
|
||||||
obj_file
|
|
||||||
.section_by_name(id.name())
|
|
||||||
.and_then(|section| section.uncompressed_data().ok())
|
|
||||||
.unwrap_or(alloc::borrow::Cow::Borrowed(&[][..])),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.map_err(gimli_error)?;
|
|
||||||
let endian = match obj_file.endianness() {
|
|
||||||
object::Endianness::Little => gimli::RunTimeEndian::Little,
|
|
||||||
object::Endianness::Big => gimli::RunTimeEndian::Big,
|
|
||||||
};
|
|
||||||
let dwarf = dwarf_cow.borrow(|section| gimli::EndianSlice::new(section, endian));
|
|
||||||
let mut iter = dwarf.units();
|
|
||||||
if let Some(header) = iter.next().map_err(gimli_error)? {
|
|
||||||
let unit = dwarf.unit(header).map_err(gimli_error)?;
|
|
||||||
if let Some(program) = unit.line_program.clone() {
|
|
||||||
let mut text_sections = sections.iter_mut().filter(|s| s.kind == SectionKind::Code);
|
|
||||||
let mut lines = text_sections.next().map(|section| &mut section.line_info);
|
|
||||||
|
|
||||||
let mut rows = program.rows();
|
|
||||||
while let Some((_header, row)) = rows.next_row().map_err(gimli_error)? {
|
|
||||||
if let (Some(line), Some(lines)) = (row.line(), &mut lines) {
|
|
||||||
lines.insert(row.address(), line.get() as u32);
|
|
||||||
}
|
|
||||||
if row.end_sequence() {
|
|
||||||
// The next row is the start of a new sequence, which means we must
|
|
||||||
// advance to the next .text section.
|
|
||||||
lines = text_sections.next().map(|section| &mut section.line_info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if iter.next().map_err(gimli_error)?.is_some() {
|
|
||||||
log::warn!("Multiple units found in DWARF data, only processing the first");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// COFF
|
|
||||||
if let object::File::Coff(coff) = obj_file {
|
|
||||||
parse_line_info_coff(coff, sections, section_indices, obj_data)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ pub fn align_data_to_4<W: std::io::Write + ?Sized>(
|
|||||||
len: usize,
|
len: usize,
|
||||||
) -> std::io::Result<()> {
|
) -> std::io::Result<()> {
|
||||||
const ALIGN_BYTES: &[u8] = &[0; 4];
|
const ALIGN_BYTES: &[u8] = &[0; 4];
|
||||||
if len % 4 != 0 {
|
if !len.is_multiple_of(4) {
|
||||||
writer.write_all(&ALIGN_BYTES[..4 - len % 4])?;
|
writer.write_all(&ALIGN_BYTES[..4 - len % 4])?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -507,116 +507,4 @@ expression: diff.instruction_rows
|
|||||||
),
|
),
|
||||||
arg_diff: [],
|
arg_diff: [],
|
||||||
},
|
},
|
||||||
InstructionDiffRow {
|
|
||||||
ins_ref: Some(
|
|
||||||
InstructionRef {
|
|
||||||
address: 88,
|
|
||||||
size: 1,
|
|
||||||
opcode: 465,
|
|
||||||
branch_dest: None,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
kind: None,
|
|
||||||
branch_from: None,
|
|
||||||
branch_to: None,
|
|
||||||
arg_diff: [],
|
|
||||||
},
|
|
||||||
InstructionDiffRow {
|
|
||||||
ins_ref: Some(
|
|
||||||
InstructionRef {
|
|
||||||
address: 89,
|
|
||||||
size: 1,
|
|
||||||
opcode: 465,
|
|
||||||
branch_dest: None,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
kind: None,
|
|
||||||
branch_from: None,
|
|
||||||
branch_to: None,
|
|
||||||
arg_diff: [],
|
|
||||||
},
|
|
||||||
InstructionDiffRow {
|
|
||||||
ins_ref: Some(
|
|
||||||
InstructionRef {
|
|
||||||
address: 90,
|
|
||||||
size: 1,
|
|
||||||
opcode: 465,
|
|
||||||
branch_dest: None,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
kind: None,
|
|
||||||
branch_from: None,
|
|
||||||
branch_to: None,
|
|
||||||
arg_diff: [],
|
|
||||||
},
|
|
||||||
InstructionDiffRow {
|
|
||||||
ins_ref: Some(
|
|
||||||
InstructionRef {
|
|
||||||
address: 91,
|
|
||||||
size: 1,
|
|
||||||
opcode: 465,
|
|
||||||
branch_dest: None,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
kind: None,
|
|
||||||
branch_from: None,
|
|
||||||
branch_to: None,
|
|
||||||
arg_diff: [],
|
|
||||||
},
|
|
||||||
InstructionDiffRow {
|
|
||||||
ins_ref: Some(
|
|
||||||
InstructionRef {
|
|
||||||
address: 92,
|
|
||||||
size: 1,
|
|
||||||
opcode: 465,
|
|
||||||
branch_dest: None,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
kind: None,
|
|
||||||
branch_from: None,
|
|
||||||
branch_to: None,
|
|
||||||
arg_diff: [],
|
|
||||||
},
|
|
||||||
InstructionDiffRow {
|
|
||||||
ins_ref: Some(
|
|
||||||
InstructionRef {
|
|
||||||
address: 93,
|
|
||||||
size: 1,
|
|
||||||
opcode: 465,
|
|
||||||
branch_dest: None,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
kind: None,
|
|
||||||
branch_from: None,
|
|
||||||
branch_to: None,
|
|
||||||
arg_diff: [],
|
|
||||||
},
|
|
||||||
InstructionDiffRow {
|
|
||||||
ins_ref: Some(
|
|
||||||
InstructionRef {
|
|
||||||
address: 94,
|
|
||||||
size: 1,
|
|
||||||
opcode: 465,
|
|
||||||
branch_dest: None,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
kind: None,
|
|
||||||
branch_from: None,
|
|
||||||
branch_to: None,
|
|
||||||
arg_diff: [],
|
|
||||||
},
|
|
||||||
InstructionDiffRow {
|
|
||||||
ins_ref: Some(
|
|
||||||
InstructionRef {
|
|
||||||
address: 95,
|
|
||||||
size: 1,
|
|
||||||
opcode: 465,
|
|
||||||
branch_dest: None,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
kind: None,
|
|
||||||
branch_from: None,
|
|
||||||
branch_to: None,
|
|
||||||
arg_diff: [],
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
|
@ -29,11 +29,3 @@ expression: output
|
|||||||
[(Address(76), Normal, 5), (Spacing(4), Normal, 0), (Opcode(".dword", 65534), Normal, 10), (BranchDest(41), Normal, 0), (Basic(" ~>"), Rotating(6), 0), (Eol, Normal, 0)]
|
[(Address(76), Normal, 5), (Spacing(4), Normal, 0), (Opcode(".dword", 65534), Normal, 10), (BranchDest(41), Normal, 0), (Basic(" ~>"), Rotating(6), 0), (Eol, Normal, 0)]
|
||||||
[(Address(80), Normal, 5), (Spacing(4), Normal, 0), (Opcode(".dword", 65534), Normal, 10), (BranchDest(47), Normal, 0), (Basic(" ~>"), Rotating(7), 0), (Eol, Normal, 0)]
|
[(Address(80), Normal, 5), (Spacing(4), Normal, 0), (Opcode(".dword", 65534), Normal, 10), (BranchDest(47), Normal, 0), (Basic(" ~>"), Rotating(7), 0), (Eol, Normal, 0)]
|
||||||
[(Address(84), Normal, 5), (Spacing(4), Normal, 0), (Opcode(".dword", 65534), Normal, 10), (BranchDest(53), Normal, 0), (Basic(" ~>"), Rotating(8), 0), (Eol, Normal, 0)]
|
[(Address(84), Normal, 5), (Spacing(4), Normal, 0), (Opcode(".dword", 65534), Normal, 10), (BranchDest(53), Normal, 0), (Basic(" ~>"), Rotating(8), 0), (Eol, Normal, 0)]
|
||||||
[(Address(88), Normal, 5), (Spacing(4), Normal, 0), (Opcode("nop", 465), Normal, 10), (Eol, Normal, 0)]
|
|
||||||
[(Address(89), Normal, 5), (Spacing(4), Normal, 0), (Opcode("nop", 465), Normal, 10), (Eol, Normal, 0)]
|
|
||||||
[(Address(90), Normal, 5), (Spacing(4), Normal, 0), (Opcode("nop", 465), Normal, 10), (Eol, Normal, 0)]
|
|
||||||
[(Address(91), Normal, 5), (Spacing(4), Normal, 0), (Opcode("nop", 465), Normal, 10), (Eol, Normal, 0)]
|
|
||||||
[(Address(92), Normal, 5), (Spacing(4), Normal, 0), (Opcode("nop", 465), Normal, 10), (Eol, Normal, 0)]
|
|
||||||
[(Address(93), Normal, 5), (Spacing(4), Normal, 0), (Opcode("nop", 465), Normal, 10), (Eol, Normal, 0)]
|
|
||||||
[(Address(94), Normal, 5), (Spacing(4), Normal, 0), (Opcode("nop", 465), Normal, 10), (Eol, Normal, 0)]
|
|
||||||
[(Address(95), Normal, 5), (Spacing(4), Normal, 0), (Opcode("nop", 465), Normal, 10), (Eol, Normal, 0)]
|
|
||||||
|
@ -63,7 +63,7 @@ Object {
|
|||||||
"int __cdecl test(int)",
|
"int __cdecl test(int)",
|
||||||
),
|
),
|
||||||
address: 0,
|
address: 0,
|
||||||
size: 96,
|
size: 88,
|
||||||
kind: Function,
|
kind: Function,
|
||||||
section: Some(
|
section: Some(
|
||||||
1,
|
1,
|
||||||
|
@ -526,14 +526,12 @@ impl App {
|
|||||||
mod_check = true;
|
mod_check = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if mod_check {
|
if mod_check
|
||||||
if let Some(info) = &state.project_config_info {
|
&& let Some(info) = &state.project_config_info
|
||||||
if let Some(last_ts) = info.timestamp {
|
&& let Some(last_ts) = info.timestamp
|
||||||
if file_modified(&info.path, last_ts) {
|
&& file_modified(&info.path, last_ts)
|
||||||
state.config_change = true;
|
{
|
||||||
}
|
state.config_change = true;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if state.config_change {
|
if state.config_change {
|
||||||
@ -581,22 +579,20 @@ impl App {
|
|||||||
state.queue_build = true;
|
state.queue_build = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(result) = &diff_state.build {
|
if let Some(result) = &diff_state.build
|
||||||
if mod_check {
|
&& mod_check
|
||||||
if let Some((obj, _)) = &result.first_obj {
|
{
|
||||||
if let (Some(path), Some(timestamp)) = (&obj.path, obj.timestamp) {
|
if let Some((obj, _)) = &result.first_obj
|
||||||
if file_modified(path, timestamp) {
|
&& let (Some(path), Some(timestamp)) = (&obj.path, obj.timestamp)
|
||||||
state.queue_reload = true;
|
&& file_modified(path, timestamp)
|
||||||
}
|
{
|
||||||
}
|
state.queue_reload = true;
|
||||||
}
|
}
|
||||||
if let Some((obj, _)) = &result.second_obj {
|
if let Some((obj, _)) = &result.second_obj
|
||||||
if let (Some(path), Some(timestamp)) = (&obj.path, obj.timestamp) {
|
&& let (Some(path), Some(timestamp)) = (&obj.path, obj.timestamp)
|
||||||
if file_modified(path, timestamp) {
|
&& file_modified(path, timestamp)
|
||||||
state.queue_reload = true;
|
{
|
||||||
}
|
state.queue_reload = true;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -618,13 +614,12 @@ impl App {
|
|||||||
state.queue_reload = false;
|
state.queue_reload = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if graphics_state.should_relaunch {
|
if graphics_state.should_relaunch
|
||||||
if let Some(app_path) = &self.app_path {
|
&& let Some(app_path) = &self.app_path
|
||||||
if let Ok(mut guard) = self.relaunch_path.lock() {
|
&& let Ok(mut guard) = self.relaunch_path.lock()
|
||||||
*guard = Some(app_path.clone());
|
{
|
||||||
self.should_relaunch = true;
|
*guard = Some(app_path.clone());
|
||||||
}
|
self.should_relaunch = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -665,7 +660,10 @@ impl eframe::App for App {
|
|||||||
let side_panel_available = diff_state.current_view == View::SymbolDiff;
|
let side_panel_available = diff_state.current_view == View::SymbolDiff;
|
||||||
|
|
||||||
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
|
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
|
||||||
egui::MenuBar::new().ui(ui, |ui| {
|
// Temporarily use pre-egui 0.32 menu. ComboBox within menu
|
||||||
|
// is currently broken. Issue TBD
|
||||||
|
#[allow(deprecated)]
|
||||||
|
egui::menu::bar(ui, |ui| {
|
||||||
if ui
|
if ui
|
||||||
.add_enabled(
|
.add_enabled(
|
||||||
side_panel_available,
|
side_panel_available,
|
||||||
@ -677,7 +675,8 @@ impl eframe::App for App {
|
|||||||
*show_side_panel = !*show_side_panel;
|
*show_side_panel = !*show_side_panel;
|
||||||
}
|
}
|
||||||
ui.separator();
|
ui.separator();
|
||||||
ui.menu_button("File", |ui| {
|
let bar_state = egui::menu::BarState::load(ui.ctx(), ui.id());
|
||||||
|
egui::menu::menu_button(ui, "File", |ui| {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
if ui.button("Debug…").clicked() {
|
if ui.button("Debug…").clicked() {
|
||||||
*show_debug = !*show_debug;
|
*show_debug = !*show_debug;
|
||||||
@ -694,22 +693,29 @@ impl eframe::App for App {
|
|||||||
};
|
};
|
||||||
if recent_projects.is_empty() {
|
if recent_projects.is_empty() {
|
||||||
ui.add_enabled(false, egui::Button::new("Recent projects…"));
|
ui.add_enabled(false, egui::Button::new("Recent projects…"));
|
||||||
} else {
|
} else if let Some(menu_root) = bar_state.as_ref() {
|
||||||
ui.menu_button("Recent Projects…", |ui| {
|
egui::menu::submenu_button(
|
||||||
if ui.button("Clear").clicked() {
|
ui,
|
||||||
state.write().unwrap().config.recent_projects.clear();
|
menu_root.menu_state.clone(),
|
||||||
};
|
"Recent Projects…",
|
||||||
ui.separator();
|
|ui| {
|
||||||
for path in recent_projects {
|
if ui.button("Clear").clicked() {
|
||||||
if ui.button(&path).clicked() {
|
state.write().unwrap().config.recent_projects.clear();
|
||||||
state
|
};
|
||||||
.write()
|
ui.separator();
|
||||||
.unwrap()
|
for path in recent_projects {
|
||||||
.set_project_dir(Utf8PlatformPathBuf::from(path));
|
if ui.button(&path).clicked() {
|
||||||
ui.close();
|
state
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.set_project_dir(Utf8PlatformPathBuf::from(path));
|
||||||
|
ui.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
});
|
);
|
||||||
|
} else {
|
||||||
|
ui.add_enabled(false, egui::Button::new("Recent projects…"));
|
||||||
}
|
}
|
||||||
if ui.button("Appearance…").clicked() {
|
if ui.button("Appearance…").clicked() {
|
||||||
*show_appearance_config = !*show_appearance_config;
|
*show_appearance_config = !*show_appearance_config;
|
||||||
@ -723,7 +729,7 @@ impl eframe::App for App {
|
|||||||
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
|
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ui.menu_button("Tools", |ui| {
|
egui::menu::menu_button(ui, "Tools", |ui| {
|
||||||
if ui.button("Demangle…").clicked() {
|
if ui.button("Demangle…").clicked() {
|
||||||
*show_demangle = !*show_demangle;
|
*show_demangle = !*show_demangle;
|
||||||
ui.close();
|
ui.close();
|
||||||
@ -733,7 +739,7 @@ impl eframe::App for App {
|
|||||||
ui.close();
|
ui.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ui.menu_button("Diff Options", |ui| {
|
egui::menu::menu_button(ui, "Diff Options", |ui| {
|
||||||
if ui.button("Arch Settings…").clicked() {
|
if ui.button("Arch Settings…").clicked() {
|
||||||
*show_arch_config = !*show_arch_config;
|
*show_arch_config = !*show_arch_config;
|
||||||
ui.close();
|
ui.close();
|
||||||
|
@ -173,23 +173,23 @@ fn main() -> ExitCode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to relaunch application from the updated path
|
// Attempt to relaunch application from the updated path
|
||||||
if let Ok(mut guard) = exec_path.lock() {
|
if let Ok(mut guard) = exec_path.lock()
|
||||||
if let Some(path) = guard.take() {
|
&& let Some(path) = guard.take()
|
||||||
cfg_if! {
|
{
|
||||||
if #[cfg(unix)] {
|
cfg_if! {
|
||||||
let e = exec::Command::new(path)
|
if #[cfg(unix)] {
|
||||||
.args(&std::env::args().collect::<Vec<String>>())
|
let e = exec::Command::new(path)
|
||||||
.exec();
|
.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:?}");
|
log::error!("Failed to relaunch: {e:?}");
|
||||||
return ExitCode::FAILURE;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,16 +185,15 @@ pub fn config_ui(
|
|||||||
if result.update_available {
|
if result.update_available {
|
||||||
ui.colored_label(appearance.insert_color, "Update available");
|
ui.colored_label(appearance.insert_color, "Update available");
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
if let Some(bin_name) = &result.found_binary {
|
if let Some(bin_name) = &result.found_binary
|
||||||
if ui
|
&& ui
|
||||||
.add_enabled(!config_state.update_running, egui::Button::new("Automatic"))
|
.add_enabled(!config_state.update_running, egui::Button::new("Automatic"))
|
||||||
.on_hover_text_at_pointer(
|
.on_hover_text_at_pointer(
|
||||||
"Automatically download and replace the current build",
|
"Automatically download and replace the current build",
|
||||||
)
|
)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
config_state.queue_update = Some(bin_name.clone());
|
config_state.queue_update = Some(bin_name.clone());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if ui
|
if ui
|
||||||
.button("Manual")
|
.button("Manual")
|
||||||
@ -329,12 +328,12 @@ pub fn config_ui(
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if new_selected_index != selected_index {
|
if new_selected_index != selected_index
|
||||||
if let Some(idx) = new_selected_index {
|
&& let Some(idx) = new_selected_index
|
||||||
// Will set obj_changed, which will trigger a rebuild
|
{
|
||||||
let config = objects[idx].clone();
|
// Will set obj_changed, which will trigger a rebuild
|
||||||
state_guard.set_selected_obj(config);
|
let config = objects[idx].clone();
|
||||||
}
|
state_guard.set_selected_obj(config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,18 +373,17 @@ fn display_unit(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn object_context_ui(ui: &mut egui::Ui, object: &ObjectConfig) {
|
fn object_context_ui(ui: &mut egui::Ui, object: &ObjectConfig) {
|
||||||
if let Some(source_path) = &object.source_path {
|
if let Some(source_path) = &object.source_path
|
||||||
if ui
|
&& ui
|
||||||
.button("Open source file")
|
.button("Open source file")
|
||||||
.on_hover_text("Open the source file in the default editor")
|
.on_hover_text("Open the source file in the default editor")
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
log::info!("Opening file {source_path}");
|
log::info!("Opening file {source_path}");
|
||||||
if let Err(e) = open::that_detached(source_path.as_str()) {
|
if let Err(e) = open::that_detached(source_path.as_str()) {
|
||||||
log::error!("Failed to open source file: {e}");
|
log::error!("Failed to open source file: {e}");
|
||||||
}
|
|
||||||
ui.close();
|
|
||||||
}
|
}
|
||||||
|
ui.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -835,12 +833,11 @@ fn split_obj_config_ui(
|
|||||||
.add_enabled(state.project_config_info.is_none(), egui::Button::new("+").small())
|
.add_enabled(state.project_config_info.is_none(), egui::Button::new("+").small())
|
||||||
.on_disabled_hover_text(CONFIG_DISABLED_TEXT)
|
.on_disabled_hover_text(CONFIG_DISABLED_TEXT)
|
||||||
.clicked()
|
.clicked()
|
||||||
|
&& let Ok(glob) = Glob::new(&config_state.watch_pattern_text)
|
||||||
{
|
{
|
||||||
if let Ok(glob) = Glob::new(&config_state.watch_pattern_text) {
|
state.config.watch_patterns.push(glob);
|
||||||
state.config.watch_patterns.push(glob);
|
state.watcher_change = true;
|
||||||
state.watcher_change = true;
|
config_state.watch_pattern_text.clear();
|
||||||
config_state.watch_pattern_text.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ pub(crate) fn data_row_ui(
|
|||||||
write_text(byte_text.as_str(), byte_color, &mut job, appearance.code_font.clone());
|
write_text(byte_text.as_str(), byte_color, &mut job, appearance.code_font.clone());
|
||||||
cur_addr += 1;
|
cur_addr += 1;
|
||||||
cur_addr_actual += 1;
|
cur_addr_actual += 1;
|
||||||
if cur_addr % 8 == 0 {
|
if cur_addr.is_multiple_of(8) {
|
||||||
write_text(" ", base_color, &mut job, appearance.code_font.clone());
|
write_text(" ", base_color, &mut job, appearance.code_font.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,10 +128,10 @@ pub fn diff_view_ui(
|
|||||||
let mut navigation = current_navigation.clone();
|
let mut navigation = current_navigation.clone();
|
||||||
if let Some((_symbol, symbol_diff, _symbol_idx)) = left_ctx.symbol {
|
if let Some((_symbol, symbol_diff, _symbol_idx)) = left_ctx.symbol {
|
||||||
// If a matching symbol appears, select it
|
// If a matching symbol appears, select it
|
||||||
if !right_ctx.has_symbol() {
|
if !right_ctx.has_symbol()
|
||||||
if let Some(target_symbol_ref) = symbol_diff.target_symbol {
|
&& let Some(target_symbol_ref) = symbol_diff.target_symbol
|
||||||
navigation.right_symbol = Some(target_symbol_ref);
|
{
|
||||||
}
|
navigation.right_symbol = Some(target_symbol_ref);
|
||||||
}
|
}
|
||||||
} else if navigation.left_symbol.is_some()
|
} else if navigation.left_symbol.is_some()
|
||||||
&& left_ctx.obj.is_some()
|
&& left_ctx.obj.is_some()
|
||||||
@ -142,10 +142,10 @@ pub fn diff_view_ui(
|
|||||||
}
|
}
|
||||||
if let Some((_symbol, symbol_diff, _symbol_idx)) = right_ctx.symbol {
|
if let Some((_symbol, symbol_diff, _symbol_idx)) = right_ctx.symbol {
|
||||||
// If a matching symbol appears, select it
|
// If a matching symbol appears, select it
|
||||||
if !left_ctx.has_symbol() {
|
if !left_ctx.has_symbol()
|
||||||
if let Some(target_symbol_ref) = symbol_diff.target_symbol {
|
&& let Some(target_symbol_ref) = symbol_diff.target_symbol
|
||||||
navigation.left_symbol = Some(target_symbol_ref);
|
{
|
||||||
}
|
navigation.left_symbol = Some(target_symbol_ref);
|
||||||
}
|
}
|
||||||
} else if navigation.right_symbol.is_some()
|
} else if navigation.right_symbol.is_some()
|
||||||
&& right_ctx.obj.is_some()
|
&& right_ctx.obj.is_some()
|
||||||
@ -247,16 +247,15 @@ pub fn diff_view_ui(
|
|||||||
|
|
||||||
// Third row
|
// Third row
|
||||||
if left_ctx.has_symbol() && right_ctx.has_symbol() {
|
if left_ctx.has_symbol() && right_ctx.has_symbol() {
|
||||||
if state.current_view == View::FunctionDiff
|
if (state.current_view == View::FunctionDiff
|
||||||
&& ui
|
&& ui
|
||||||
.button("Change target")
|
.button("Change target")
|
||||||
.on_hover_text_at_pointer("Choose a different symbol to use as the target")
|
.on_hover_text_at_pointer("Choose a different symbol to use as the target")
|
||||||
.clicked()
|
.clicked()
|
||||||
|| hotkeys::consume_change_target_shortcut(ui.ctx())
|
|| hotkeys::consume_change_target_shortcut(ui.ctx()))
|
||||||
|
&& let Some(symbol_ref) = state.symbol_state.right_symbol.as_ref()
|
||||||
{
|
{
|
||||||
if let Some(symbol_ref) = state.symbol_state.right_symbol.as_ref() {
|
ret = Some(DiffViewAction::SelectingLeft(symbol_ref.clone()));
|
||||||
ret = Some(DiffViewAction::SelectingLeft(symbol_ref.clone()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if left_ctx.status.success && !left_ctx.has_symbol() {
|
} else if left_ctx.status.success && !left_ctx.has_symbol() {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
@ -409,17 +408,16 @@ pub fn diff_view_ui(
|
|||||||
if needs_separator {
|
if needs_separator {
|
||||||
ui.separator();
|
ui.separator();
|
||||||
}
|
}
|
||||||
if ui
|
if (ui
|
||||||
.button("Change base")
|
.button("Change base")
|
||||||
.on_hover_text_at_pointer(
|
.on_hover_text_at_pointer(
|
||||||
"Choose a different symbol to use as the base",
|
"Choose a different symbol to use as the base",
|
||||||
)
|
)
|
||||||
.clicked()
|
.clicked()
|
||||||
|| hotkeys::consume_change_base_shortcut(ui.ctx())
|
|| hotkeys::consume_change_base_shortcut(ui.ctx()))
|
||||||
|
&& let Some(symbol_ref) = state.symbol_state.left_symbol.as_ref()
|
||||||
{
|
{
|
||||||
if let Some(symbol_ref) = state.symbol_state.left_symbol.as_ref() {
|
ret = Some(DiffViewAction::SelectingRight(symbol_ref.clone()));
|
||||||
ret = Some(DiffViewAction::SelectingRight(symbol_ref.clone()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if right_ctx.status.success && !right_ctx.has_symbol() {
|
} else if right_ctx.status.success && !right_ctx.has_symbol() {
|
||||||
@ -583,8 +581,8 @@ pub fn diff_view_ui(
|
|||||||
) {
|
) {
|
||||||
ret = Some(action);
|
ret = Some(action);
|
||||||
}
|
}
|
||||||
} else if column == 1 {
|
} else if column == 1
|
||||||
if let Some(action) = diff_col_ui(
|
&& let Some(action) = diff_col_ui(
|
||||||
ui,
|
ui,
|
||||||
state,
|
state,
|
||||||
appearance,
|
appearance,
|
||||||
@ -594,9 +592,9 @@ pub fn diff_view_ui(
|
|||||||
available_width,
|
available_width,
|
||||||
open_sections.1,
|
open_sections.1,
|
||||||
diff_config,
|
diff_config,
|
||||||
) {
|
)
|
||||||
ret = Some(action);
|
{
|
||||||
}
|
ret = Some(action);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -211,19 +211,19 @@ impl DiffViewState {
|
|||||||
|
|
||||||
let mut resolved_left = self.resolve_symbol(nav.left_symbol, 0);
|
let mut resolved_left = self.resolve_symbol(nav.left_symbol, 0);
|
||||||
let mut resolved_right = self.resolve_symbol(nav.right_symbol, 1);
|
let mut resolved_right = self.resolve_symbol(nav.right_symbol, 1);
|
||||||
if let Some(resolved_right) = &resolved_right {
|
if let Some(resolved_right) = &resolved_right
|
||||||
if resolved_left.is_none() {
|
&& resolved_left.is_none()
|
||||||
resolved_left = resolved_right
|
{
|
||||||
.target_symbol
|
resolved_left = resolved_right
|
||||||
.and_then(|idx| self.resolve_symbol(Some(idx), 0));
|
.target_symbol
|
||||||
}
|
.and_then(|idx| self.resolve_symbol(Some(idx), 0));
|
||||||
}
|
}
|
||||||
if let Some(resolved_left) = &resolved_left {
|
if let Some(resolved_left) = &resolved_left
|
||||||
if resolved_right.is_none() {
|
&& resolved_right.is_none()
|
||||||
resolved_right = resolved_left
|
{
|
||||||
.target_symbol
|
resolved_right = resolved_left
|
||||||
.and_then(|idx| self.resolve_symbol(Some(idx), 1));
|
.target_symbol
|
||||||
}
|
.and_then(|idx| self.resolve_symbol(Some(idx), 1));
|
||||||
}
|
}
|
||||||
let resolved_nav = resolve_navigation(nav.kind, resolved_left, resolved_right);
|
let resolved_nav = resolve_navigation(nav.kind, resolved_left, resolved_right);
|
||||||
if (resolved_nav.left_symbol.is_some() && resolved_nav.right_symbol.is_some())
|
if (resolved_nav.left_symbol.is_some() && resolved_nav.right_symbol.is_some())
|
||||||
@ -500,16 +500,16 @@ pub fn symbol_context_menu_ui(
|
|||||||
ret = Some(action);
|
ret = Some(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(section) = section {
|
if let Some(section) = section
|
||||||
if ui.button("Map symbol").clicked() {
|
&& ui.button("Map symbol").clicked()
|
||||||
let symbol_ref = SymbolRefByName::new(symbol, Some(section));
|
{
|
||||||
if column == 0 {
|
let symbol_ref = SymbolRefByName::new(symbol, Some(section));
|
||||||
ret = Some(DiffViewAction::SelectingRight(symbol_ref));
|
if column == 0 {
|
||||||
} else {
|
ret = Some(DiffViewAction::SelectingRight(symbol_ref));
|
||||||
ret = Some(DiffViewAction::SelectingLeft(symbol_ref));
|
} else {
|
||||||
}
|
ret = Some(DiffViewAction::SelectingLeft(symbol_ref));
|
||||||
ui.close();
|
|
||||||
}
|
}
|
||||||
|
ui.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ret
|
ret
|
||||||
@ -664,10 +664,10 @@ pub fn symbol_list_ui(
|
|||||||
let mut ret = None;
|
let mut ret = None;
|
||||||
ScrollArea::both().auto_shrink([false, false]).show(ui, |ui| {
|
ScrollArea::both().auto_shrink([false, false]).show(ui, |ui| {
|
||||||
let mut show_mapped_symbols = state.show_mapped_symbols;
|
let mut show_mapped_symbols = state.show_mapped_symbols;
|
||||||
if let SymbolFilter::Mapping(_, _) = filter {
|
if let SymbolFilter::Mapping(_, _) = filter
|
||||||
if ui.checkbox(&mut show_mapped_symbols, "Show mapped symbols").changed() {
|
&& ui.checkbox(&mut show_mapped_symbols, "Show mapped symbols").changed()
|
||||||
ret = Some(DiffViewAction::SetShowMappedSymbols(show_mapped_symbols));
|
{
|
||||||
}
|
ret = Some(DiffViewAction::SetShowMappedSymbols(show_mapped_symbols));
|
||||||
}
|
}
|
||||||
let section_display = display_sections(
|
let section_display = display_sections(
|
||||||
ctx.obj,
|
ctx.obj,
|
||||||
|
4
objdiff-wasm/package-lock.json
generated
4
objdiff-wasm/package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "objdiff-wasm",
|
"name": "objdiff-wasm",
|
||||||
"version": "3.0.0-beta.12",
|
"version": "3.0.0-beta.13",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "objdiff-wasm",
|
"name": "objdiff-wasm",
|
||||||
"version": "3.0.0-beta.12",
|
"version": "3.0.0-beta.13",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "^1.9.3",
|
"@biomejs/biome": "^1.9.3",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "objdiff-wasm",
|
"name": "objdiff-wasm",
|
||||||
"version": "3.0.0-beta.12",
|
"version": "3.0.0-beta.13",
|
||||||
"description": "A local diffing tool for decompilation projects.",
|
"description": "A local diffing tool for decompilation projects.",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Luke Street",
|
"name": "Luke Street",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user