mirror of
https://github.com/encounter/objdiff.git
synced 2025-12-15 08:06:25 +00:00
Compare commits
6 Commits
v3.0.0-bet
...
v3.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
| ffb38d1bb0 | |||
| d56dda72f0 | |||
| c6971f3f2d | |||
| 3965a035fa | |||
| f1fc29f77e | |||
| 7c4f1c5d13 |
18
Cargo.lock
generated
18
Cargo.lock
generated
@@ -1,6 +1,6 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "ab_glyph"
|
||||
@@ -2652,7 +2652,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets 0.52.6",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3268,7 +3268,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-cli"
|
||||
version = "3.0.0-beta.1"
|
||||
version = "3.0.0-beta.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argp",
|
||||
@@ -3291,7 +3291,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-core"
|
||||
version = "3.0.0-beta.1"
|
||||
version = "3.0.0-beta.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arm-attr",
|
||||
@@ -3344,7 +3344,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-gui"
|
||||
version = "3.0.0-beta.1"
|
||||
version = "3.0.0-beta.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cfg-if",
|
||||
@@ -3380,7 +3380,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-wasm"
|
||||
version = "3.0.0-beta.1"
|
||||
version = "3.0.0-beta.2"
|
||||
dependencies = [
|
||||
"log",
|
||||
"objdiff-core",
|
||||
@@ -3894,7 +3894,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rabbitizer"
|
||||
version = "2.0.0-dev0"
|
||||
source = "git+https://github.com/Decompollaborate/rabbitizer.git?branch=🦀#06dc8b6c826c3d60e112d4c2cd70aa54e308be12"
|
||||
source = "git+https://github.com/Decompollaborate/rabbitizer.git?branch=%F0%9F%A6%80#06dc8b6c826c3d60e112d4c2cd70aa54e308be12"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
]
|
||||
@@ -4205,9 +4205,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.11"
|
||||
version = "0.17.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da5349ae27d3887ca812fb375b45a4fbb36d8d12d2df394968cd86e35683fe73"
|
||||
checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
|
||||
@@ -14,7 +14,7 @@ strip = "debuginfo"
|
||||
codegen-units = 1
|
||||
|
||||
[workspace.package]
|
||||
version = "3.0.0-beta.1"
|
||||
version = "3.0.0-beta.2"
|
||||
authors = ["Luke Street <luke@street.dev>"]
|
||||
edition = "2024"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
@@ -73,6 +73,7 @@ ignore = [
|
||||
#{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" },
|
||||
#"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish
|
||||
#{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" },
|
||||
{ id = "RUSTSEC-2024-0436", reason = "Unmaintained paste crate is an indirect dependency" },
|
||||
]
|
||||
# If this is true, then cargo deny will use the git executable to fetch advisory database.
|
||||
# If this is false, then it uses a built-in git library.
|
||||
|
||||
@@ -22,7 +22,7 @@ use crossterm::{
|
||||
use objdiff_core::{
|
||||
bindings::diff::DiffResult,
|
||||
build::{
|
||||
BuildConfig,
|
||||
BuildConfig, BuildStatus,
|
||||
watcher::{Watcher, create_watcher},
|
||||
},
|
||||
config::{
|
||||
@@ -251,6 +251,8 @@ pub struct AppState {
|
||||
pub project_config: Option<ProjectConfig>,
|
||||
pub target_path: Option<Utf8PlatformPathBuf>,
|
||||
pub base_path: Option<Utf8PlatformPathBuf>,
|
||||
pub left_status: Option<BuildStatus>,
|
||||
pub right_status: Option<BuildStatus>,
|
||||
pub left_obj: Option<(Object, ObjectDiff)>,
|
||||
pub right_obj: Option<(Object, ObjectDiff)>,
|
||||
pub prev_obj: Option<(Object, ObjectDiff)>,
|
||||
@@ -348,6 +350,8 @@ impl AppState {
|
||||
JobResult::None => unreachable!("Unexpected JobResult::None"),
|
||||
JobResult::ObjDiff(result) => {
|
||||
let result = result.unwrap();
|
||||
self.left_status = Some(result.first_status);
|
||||
self.right_status = Some(result.second_status);
|
||||
self.left_obj = result.first_obj;
|
||||
self.right_obj = result.second_obj;
|
||||
self.reload_time = Some(result.time);
|
||||
@@ -388,6 +392,8 @@ fn run_interactive(
|
||||
project_config,
|
||||
target_path,
|
||||
base_path,
|
||||
left_status: None,
|
||||
right_status: None,
|
||||
left_obj: None,
|
||||
right_obj: None,
|
||||
prev_obj: None,
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use core::cmp::Ordering;
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use anyhow::Result;
|
||||
use crossterm::event::{Event, KeyCode, KeyEventKind, KeyModifiers, MouseButton, MouseEventKind};
|
||||
use objdiff_core::{
|
||||
build::BuildStatus,
|
||||
diff::{
|
||||
DiffObjConfig, FunctionRelocDiffs, InstructionDiffKind, ObjectDiff, SymbolDiff,
|
||||
display::{DiffText, DiffTextColor, HighlightKind, display_row},
|
||||
@@ -126,6 +127,11 @@ impl UiView for FunctionDiffUi {
|
||||
);
|
||||
max_width = max_width.max(text.width());
|
||||
left_text = Some(text);
|
||||
} else if let Some(status) = &state.left_status {
|
||||
let mut text = Text::default();
|
||||
self.print_build_status(&mut text, status);
|
||||
max_width = max_width.max(text.width());
|
||||
left_text = Some(text);
|
||||
}
|
||||
|
||||
let mut right_text = None;
|
||||
@@ -155,6 +161,11 @@ impl UiView for FunctionDiffUi {
|
||||
let rect = content_chunks[1].inner(Margin::new(1, 1));
|
||||
self.print_margin(&mut text, symbol_diff, rect);
|
||||
margin_text = Some(text);
|
||||
} else if let Some(status) = &state.right_status {
|
||||
let mut text = Text::default();
|
||||
self.print_build_status(&mut text, status);
|
||||
max_width = max_width.max(text.width());
|
||||
right_text = Some(text);
|
||||
}
|
||||
|
||||
let mut prev_text = None;
|
||||
@@ -453,7 +464,7 @@ impl UiView for FunctionDiffUi {
|
||||
}
|
||||
(Some((_l, _ls, ld)), None) => ld.instruction_rows.len(),
|
||||
(None, Some((_r, _rs, rd))) => rd.instruction_rows.len(),
|
||||
(None, None) => bail!("Symbol not found: {}", self.symbol_name),
|
||||
(None, None) => 0,
|
||||
};
|
||||
self.left_sym = left_sym;
|
||||
self.right_sym = right_sym;
|
||||
@@ -596,6 +607,18 @@ impl FunctionDiffUi {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_build_status<'a>(&self, out: &mut Text<'a>, status: &'a BuildStatus) {
|
||||
if !status.cmdline.is_empty() {
|
||||
out.lines.push(Line::styled(status.cmdline.clone(), Style::new().fg(Color::LightBlue)));
|
||||
}
|
||||
for line in status.stdout.lines() {
|
||||
out.lines.push(Line::styled(line, Style::new().fg(Color::White)));
|
||||
}
|
||||
for line in status.stderr.lines() {
|
||||
out.lines.push(Line::styled(line, Style::new().fg(Color::Red)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const COLOR_ROTATION: [Color; 7] = [
|
||||
|
||||
@@ -19,7 +19,15 @@ fn compile_protos() {
|
||||
.map(|m| m.modified().unwrap())
|
||||
.unwrap_or(std::time::SystemTime::UNIX_EPOCH);
|
||||
let mut run_protoc = false;
|
||||
let proto_files = vec![root.join("report.proto")];
|
||||
let proto_files = root
|
||||
.read_dir()
|
||||
.unwrap()
|
||||
.filter_map(|e| {
|
||||
let e = e.unwrap();
|
||||
let path = e.path();
|
||||
(path.extension() == Some(std::ffi::OsStr::new("proto"))).then_some(path)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
for proto_file in &proto_files {
|
||||
println!("cargo:rerun-if-changed={}", proto_file.display());
|
||||
let mtime = match std::fs::metadata(proto_file) {
|
||||
|
||||
59
objdiff-core/protos/changes.proto
Normal file
59
objdiff-core/protos/changes.proto
Normal file
@@ -0,0 +1,59 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "report.proto";
|
||||
|
||||
package objdiff.report;
|
||||
|
||||
// A pair of reports to compare and generate changes
|
||||
message ChangesInput {
|
||||
// The previous report
|
||||
Report from = 1;
|
||||
// The current report
|
||||
Report to = 2;
|
||||
}
|
||||
|
||||
// Changes between two reports
|
||||
message Changes {
|
||||
// The progress info for the previous report
|
||||
Measures from = 1;
|
||||
// The progress info for the current report
|
||||
Measures to = 2;
|
||||
// Units that changed
|
||||
repeated ChangeUnit units = 3;
|
||||
}
|
||||
|
||||
// A changed unit
|
||||
message ChangeUnit {
|
||||
// The name of the unit
|
||||
string name = 1;
|
||||
// The previous progress info (omitted if new)
|
||||
optional Measures from = 2;
|
||||
// The current progress info (omitted if removed)
|
||||
optional Measures to = 3;
|
||||
// Sections that changed
|
||||
repeated ChangeItem sections = 4;
|
||||
// Functions that changed
|
||||
repeated ChangeItem functions = 5;
|
||||
// Extra metadata for this unit
|
||||
optional ReportUnitMetadata metadata = 6;
|
||||
}
|
||||
|
||||
// A changed section or function
|
||||
message ChangeItem {
|
||||
// The name of the item
|
||||
string name = 1;
|
||||
// The previous progress info (omitted if new)
|
||||
optional ChangeItemInfo from = 2;
|
||||
// The current progress info (omitted if removed)
|
||||
optional ChangeItemInfo to = 3;
|
||||
// Extra metadata for this item
|
||||
optional ReportItemMetadata metadata = 4;
|
||||
}
|
||||
|
||||
// Progress info for a section or function
|
||||
message ChangeItemInfo {
|
||||
// The overall match percent for this item
|
||||
float fuzzy_match_percent = 1;
|
||||
// The size of the item in bytes
|
||||
uint64 size = 2;
|
||||
}
|
||||
Binary file not shown.
@@ -2,6 +2,18 @@ syntax = "proto3";
|
||||
|
||||
package objdiff.report;
|
||||
|
||||
// Project progress report
|
||||
message Report {
|
||||
// Overall progress info
|
||||
Measures measures = 1;
|
||||
// Units within this report
|
||||
repeated ReportUnit units = 2;
|
||||
// Report version
|
||||
uint32 version = 3;
|
||||
// Progress categories
|
||||
repeated ReportCategory categories = 4;
|
||||
}
|
||||
|
||||
// Progress info for a report or unit
|
||||
message Measures {
|
||||
// Overall match percent, including partially matched functions and data
|
||||
@@ -38,18 +50,6 @@ message Measures {
|
||||
uint32 complete_units = 16;
|
||||
}
|
||||
|
||||
// Project progress report
|
||||
message Report {
|
||||
// Overall progress info
|
||||
Measures measures = 1;
|
||||
// Units within this report
|
||||
repeated ReportUnit units = 2;
|
||||
// Report version
|
||||
uint32 version = 3;
|
||||
// Progress categories
|
||||
repeated ReportCategory categories = 4;
|
||||
}
|
||||
|
||||
message ReportCategory {
|
||||
// The ID of the category
|
||||
string id = 1;
|
||||
@@ -108,57 +108,3 @@ message ReportItemMetadata {
|
||||
// The virtual address of the function or section
|
||||
optional uint64 virtual_address = 2;
|
||||
}
|
||||
|
||||
// A pair of reports to compare and generate changes
|
||||
message ChangesInput {
|
||||
// The previous report
|
||||
Report from = 1;
|
||||
// The current report
|
||||
Report to = 2;
|
||||
}
|
||||
|
||||
// Changes between two reports
|
||||
message Changes {
|
||||
// The progress info for the previous report
|
||||
Measures from = 1;
|
||||
// The progress info for the current report
|
||||
Measures to = 2;
|
||||
// Units that changed
|
||||
repeated ChangeUnit units = 3;
|
||||
}
|
||||
|
||||
// A changed unit
|
||||
message ChangeUnit {
|
||||
// The name of the unit
|
||||
string name = 1;
|
||||
// The previous progress info (omitted if new)
|
||||
optional Measures from = 2;
|
||||
// The current progress info (omitted if removed)
|
||||
optional Measures to = 3;
|
||||
// Sections that changed
|
||||
repeated ChangeItem sections = 4;
|
||||
// Functions that changed
|
||||
repeated ChangeItem functions = 5;
|
||||
// Extra metadata for this unit
|
||||
optional ReportUnitMetadata metadata = 6;
|
||||
}
|
||||
|
||||
// A changed section or function
|
||||
message ChangeItem {
|
||||
// The name of the item
|
||||
string name = 1;
|
||||
// The previous progress info (omitted if new)
|
||||
optional ChangeItemInfo from = 2;
|
||||
// The current progress info (omitted if removed)
|
||||
optional ChangeItemInfo to = 3;
|
||||
// Extra metadata for this item
|
||||
optional ReportItemMetadata metadata = 4;
|
||||
}
|
||||
|
||||
// Progress info for a section or function
|
||||
message ChangeItemInfo {
|
||||
// The overall match percent for this item
|
||||
float fuzzy_match_percent = 1;
|
||||
// The size of the item in bytes
|
||||
uint64 size = 2;
|
||||
}
|
||||
|
||||
@@ -15,17 +15,36 @@ use crate::{
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ArchX86 {
|
||||
bits: u32,
|
||||
arch: Architecture,
|
||||
endianness: object::Endianness,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Architecture {
|
||||
X86,
|
||||
X86_64,
|
||||
}
|
||||
|
||||
impl ArchX86 {
|
||||
pub fn new(object: &object::File) -> Result<Self> {
|
||||
Ok(Self { bits: if object.is_64() { 64 } else { 32 }, endianness: object.endianness() })
|
||||
let arch = match object.architecture() {
|
||||
object::Architecture::I386 => Architecture::X86,
|
||||
object::Architecture::X86_64 => Architecture::X86_64,
|
||||
_ => bail!("Unsupported architecture for ArchX86: {:?}", object.architecture()),
|
||||
};
|
||||
Ok(Self { arch, endianness: object.endianness() })
|
||||
}
|
||||
|
||||
fn decoder<'a>(&self, code: &'a [u8], address: u64) -> Decoder<'a> {
|
||||
Decoder::with_ip(self.bits, code, address, DecoderOptions::NONE)
|
||||
Decoder::with_ip(
|
||||
match self.arch {
|
||||
Architecture::X86 => 32,
|
||||
Architecture::X86_64 => 64,
|
||||
},
|
||||
code,
|
||||
address,
|
||||
DecoderOptions::NONE,
|
||||
)
|
||||
}
|
||||
|
||||
fn formatter(&self, diff_config: &DiffObjConfig) -> Box<dyn iced_x86::Formatter> {
|
||||
@@ -38,6 +57,27 @@ impl ArchX86 {
|
||||
formatter.options_mut().set_space_after_operand_separator(diff_config.space_between_args);
|
||||
formatter
|
||||
}
|
||||
|
||||
fn reloc_size(&self, flags: RelocationFlags) -> Option<usize> {
|
||||
match self.arch {
|
||||
Architecture::X86 => match flags {
|
||||
RelocationFlags::Coff(typ) => match typ {
|
||||
pe::IMAGE_REL_I386_DIR16 | pe::IMAGE_REL_I386_REL16 => Some(2),
|
||||
pe::IMAGE_REL_I386_DIR32 | pe::IMAGE_REL_I386_REL32 => Some(4),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
},
|
||||
Architecture::X86_64 => match flags {
|
||||
RelocationFlags::Coff(typ) => match typ {
|
||||
pe::IMAGE_REL_AMD64_ADDR32NB | pe::IMAGE_REL_AMD64_REL32 => Some(4),
|
||||
pe::IMAGE_REL_AMD64_ADDR64 => Some(8),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Arch for ArchX86 {
|
||||
@@ -88,10 +128,9 @@ impl Arch for ArchX86 {
|
||||
// memory operand.
|
||||
let mut reloc_replace = None;
|
||||
if let Some(reloc) = resolved.relocation {
|
||||
const PLACEHOLDER: u64 = 0x7BDE3E7D; // chosen by fair dice roll.
|
||||
// guaranteed to be random.
|
||||
const PLACEHOLDER: u64 = 0x7BDE3E7D; // chosen by fair dice roll. guaranteed to be random.
|
||||
let reloc_offset = reloc.relocation.address - resolved.ins_ref.address;
|
||||
let reloc_size = reloc_size(reloc.relocation.flags).unwrap_or(usize::MAX);
|
||||
let reloc_size = self.reloc_size(reloc.relocation.flags).unwrap_or(usize::MAX);
|
||||
let offsets = decoder.get_constant_offsets(&instruction);
|
||||
if reloc_offset == offsets.displacement_offset() as u64
|
||||
&& reloc_size == offsets.displacement_size()
|
||||
@@ -148,12 +187,28 @@ impl Arch for ArchX86 {
|
||||
_relocation: &object::Relocation,
|
||||
flags: RelocationFlags,
|
||||
) -> Result<i64> {
|
||||
match flags {
|
||||
RelocationFlags::Coff(pe::IMAGE_REL_I386_DIR32 | pe::IMAGE_REL_I386_REL32) => {
|
||||
let data = section.data()?[address as usize..address as usize + 4].try_into()?;
|
||||
Ok(self.endianness.read_i32_bytes(data) as i64)
|
||||
}
|
||||
flags => bail!("Unsupported x86 implicit relocation {flags:?}"),
|
||||
match self.arch {
|
||||
Architecture::X86 => match flags {
|
||||
RelocationFlags::Coff(pe::IMAGE_REL_I386_DIR32 | pe::IMAGE_REL_I386_REL32) => {
|
||||
let data =
|
||||
section.data()?[address as usize..address as usize + 4].try_into()?;
|
||||
Ok(self.endianness.read_i32_bytes(data) as i64)
|
||||
}
|
||||
flags => bail!("Unsupported x86 implicit relocation {flags:?}"),
|
||||
},
|
||||
Architecture::X86_64 => match flags {
|
||||
RelocationFlags::Coff(pe::IMAGE_REL_AMD64_ADDR32NB | pe::IMAGE_REL_AMD64_REL32) => {
|
||||
let data =
|
||||
section.data()?[address as usize..address as usize + 4].try_into()?;
|
||||
Ok(self.endianness.read_i32_bytes(data) as i64)
|
||||
}
|
||||
RelocationFlags::Coff(pe::IMAGE_REL_AMD64_ADDR64) => {
|
||||
let data =
|
||||
section.data()?[address as usize..address as usize + 8].try_into()?;
|
||||
Ok(self.endianness.read_i64_bytes(data))
|
||||
}
|
||||
flags => bail!("Unsupported x86-64 implicit relocation {flags:?}"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,27 +223,29 @@ impl Arch for ArchX86 {
|
||||
}
|
||||
|
||||
fn reloc_name(&self, flags: RelocationFlags) -> Option<&'static str> {
|
||||
match flags {
|
||||
RelocationFlags::Coff(typ) => match typ {
|
||||
pe::IMAGE_REL_I386_DIR32 => Some("IMAGE_REL_I386_DIR32"),
|
||||
pe::IMAGE_REL_I386_REL32 => Some("IMAGE_REL_I386_REL32"),
|
||||
match self.arch {
|
||||
Architecture::X86 => match flags {
|
||||
RelocationFlags::Coff(typ) => match typ {
|
||||
pe::IMAGE_REL_I386_DIR32 => Some("IMAGE_REL_I386_DIR32"),
|
||||
pe::IMAGE_REL_I386_REL32 => Some("IMAGE_REL_I386_REL32"),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
},
|
||||
Architecture::X86_64 => match flags {
|
||||
RelocationFlags::Coff(typ) => match typ {
|
||||
pe::IMAGE_REL_AMD64_ADDR64 => Some("IMAGE_REL_AMD64_ADDR64"),
|
||||
pe::IMAGE_REL_AMD64_ADDR32NB => Some("IMAGE_REL_AMD64_ADDR32NB"),
|
||||
pe::IMAGE_REL_AMD64_REL32 => Some("IMAGE_REL_AMD64_REL32"),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn data_reloc_size(&self, flags: RelocationFlags) -> usize { reloc_size(flags).unwrap_or(1) }
|
||||
}
|
||||
|
||||
fn reloc_size(flags: RelocationFlags) -> Option<usize> {
|
||||
match flags {
|
||||
RelocationFlags::Coff(typ) => match typ {
|
||||
pe::IMAGE_REL_I386_DIR16 | pe::IMAGE_REL_I386_REL16 => Some(2),
|
||||
pe::IMAGE_REL_I386_DIR32 | pe::IMAGE_REL_I386_REL32 => Some(4),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
fn data_reloc_size(&self, flags: RelocationFlags) -> usize {
|
||||
self.reloc_size(flags).unwrap_or(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,7 +400,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_scan_instructions() {
|
||||
let arch = ArchX86 { bits: 32, endianness: object::Endianness::Little };
|
||||
let arch = ArchX86 { arch: Architecture::X86, endianness: object::Endianness::Little };
|
||||
let code = [
|
||||
0xc7, 0x85, 0x68, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x04, 0x85, 0x00,
|
||||
0x00, 0x00, 0x00,
|
||||
@@ -362,7 +419,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_instruction() {
|
||||
let arch = ArchX86 { bits: 32, endianness: object::Endianness::Little };
|
||||
let arch = ArchX86 { arch: Architecture::X86, endianness: object::Endianness::Little };
|
||||
let code = [0xc7, 0x85, 0x68, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00];
|
||||
let opcode = iced_x86::Mnemonic::Mov as u16;
|
||||
let mut parts = Vec::new();
|
||||
@@ -398,7 +455,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_instruction_with_reloc_1() {
|
||||
let arch = ArchX86 { bits: 32, endianness: object::Endianness::Little };
|
||||
let arch = ArchX86 { arch: Architecture::X86, endianness: object::Endianness::Little };
|
||||
let code = [0xc7, 0x85, 0x68, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00];
|
||||
let opcode = iced_x86::Mnemonic::Mov as u16;
|
||||
let mut parts = Vec::new();
|
||||
@@ -443,7 +500,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_instruction_with_reloc_2() {
|
||||
let arch = ArchX86 { bits: 32, endianness: object::Endianness::Little };
|
||||
let arch = ArchX86 { arch: Architecture::X86, endianness: object::Endianness::Little };
|
||||
let code = [0x8b, 0x04, 0x85, 0x00, 0x00, 0x00, 0x00];
|
||||
let opcode = iced_x86::Mnemonic::Mov as u16;
|
||||
let mut parts = Vec::new();
|
||||
@@ -486,7 +543,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_instruction_with_reloc_3() {
|
||||
let arch = ArchX86 { bits: 32, endianness: object::Endianness::Little };
|
||||
let arch = ArchX86 { arch: Architecture::X86, endianness: object::Endianness::Little };
|
||||
let code = [0xe8, 0x00, 0x00, 0x00, 0x00];
|
||||
let opcode = iced_x86::Mnemonic::Call as u16;
|
||||
let mut parts = Vec::new();
|
||||
|
||||
@@ -91,7 +91,7 @@ pub fn diff_code(
|
||||
left_section_idx,
|
||||
diff_config,
|
||||
)?;
|
||||
let right_ops = left_obj.arch.scan_instructions(
|
||||
let right_ops = right_obj.arch.scan_instructions(
|
||||
right_symbol.address,
|
||||
right_data,
|
||||
right_section_idx,
|
||||
@@ -437,7 +437,7 @@ fn diff_instruction(
|
||||
{
|
||||
// If either the raw code bytes or relocations don't match, process instructions and compare args
|
||||
let left_ins = left_obj.arch.process_instruction(left_resolved, diff_config)?;
|
||||
let right_ins = left_obj.arch.process_instruction(right_resolved, diff_config)?;
|
||||
let right_ins = right_obj.arch.process_instruction(right_resolved, diff_config)?;
|
||||
if left_ins.args.len() != right_ins.args.len() {
|
||||
state.diff_score += PENALTY_REPLACE;
|
||||
return Ok(InstructionDiffResult::new(InstructionDiffKind::Replace));
|
||||
|
||||
@@ -14,3 +14,26 @@ fn read_mips() {
|
||||
let output = common::display_diff(&obj, &diff, symbol_idx, &diff_config);
|
||||
insta::assert_snapshot!(output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "mips")]
|
||||
fn cross_endian_diff() {
|
||||
let diff_config = diff::DiffObjConfig::default();
|
||||
let obj_be = obj::read::parse(include_object!("data/mips/code_be.o"), &diff_config).unwrap();
|
||||
assert_eq!(obj_be.endianness, object::Endianness::Big);
|
||||
let obj_le = obj::read::parse(include_object!("data/mips/code_le.o"), &diff_config).unwrap();
|
||||
assert_eq!(obj_le.endianness, object::Endianness::Little);
|
||||
let left_symbol_idx = obj_be.symbols.iter().position(|s| s.name == "func_00000000").unwrap();
|
||||
let right_symbol_idx =
|
||||
obj_le.symbols.iter().position(|s| s.name == "func_00000000__FPcPc").unwrap();
|
||||
let (left_diff, right_diff) =
|
||||
diff::code::diff_code(&obj_be, &obj_le, left_symbol_idx, right_symbol_idx, &diff_config)
|
||||
.unwrap();
|
||||
// Although the objects differ in endianness, the instructions should match.
|
||||
assert_eq!(left_diff.instruction_rows[0].kind, diff::InstructionDiffKind::None);
|
||||
assert_eq!(right_diff.instruction_rows[0].kind, diff::InstructionDiffKind::None);
|
||||
assert_eq!(left_diff.instruction_rows[1].kind, diff::InstructionDiffKind::None);
|
||||
assert_eq!(right_diff.instruction_rows[1].kind, diff::InstructionDiffKind::None);
|
||||
assert_eq!(left_diff.instruction_rows[2].kind, diff::InstructionDiffKind::None);
|
||||
assert_eq!(right_diff.instruction_rows[2].kind, diff::InstructionDiffKind::None);
|
||||
}
|
||||
|
||||
@@ -26,3 +26,17 @@ fn read_x86_combine_sections() {
|
||||
let obj = obj::read::parse(include_object!("data/x86/rtest.obj"), &diff_config).unwrap();
|
||||
insta::assert_debug_snapshot!(obj.sections);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "x86")]
|
||||
fn read_x86_64() {
|
||||
let diff_config = diff::DiffObjConfig::default();
|
||||
let obj = obj::read::parse(include_object!("data/x86_64/vs2022.o"), &diff_config).unwrap();
|
||||
insta::assert_debug_snapshot!(obj);
|
||||
let symbol_idx =
|
||||
obj.symbols.iter().position(|s| s.name == "?Dot@Vector@@QEAAMPEAU1@@Z").unwrap();
|
||||
let diff = diff::code::no_diff_code(&obj, symbol_idx, &diff_config).unwrap();
|
||||
insta::assert_debug_snapshot!(diff.instruction_rows);
|
||||
let output = common::display_diff(&obj, &diff, symbol_idx, &diff_config);
|
||||
insta::assert_snapshot!(output);
|
||||
}
|
||||
|
||||
BIN
objdiff-core/tests/data/mips/code_be.o
Normal file
BIN
objdiff-core/tests/data/mips/code_be.o
Normal file
Binary file not shown.
BIN
objdiff-core/tests/data/mips/code_le.o
Normal file
BIN
objdiff-core/tests/data/mips/code_le.o
Normal file
Binary file not shown.
BIN
objdiff-core/tests/data/x86_64/vs2022.o
Normal file
BIN
objdiff-core/tests/data/x86_64/vs2022.o
Normal file
Binary file not shown.
@@ -4,7 +4,7 @@ expression: obj
|
||||
---
|
||||
Object {
|
||||
arch: ArchX86 {
|
||||
bits: 32,
|
||||
arch: X86,
|
||||
endianness: Little,
|
||||
},
|
||||
endianness: Little,
|
||||
|
||||
279
objdiff-core/tests/snapshots/arch_x86__read_x86_64-2.snap
Normal file
279
objdiff-core/tests/snapshots/arch_x86__read_x86_64-2.snap
Normal file
@@ -0,0 +1,279 @@
|
||||
---
|
||||
source: objdiff-core/tests/arch_x86.rs
|
||||
expression: diff.instruction_rows
|
||||
---
|
||||
[
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 0,
|
||||
size: 5,
|
||||
opcode: 414,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 5,
|
||||
size: 5,
|
||||
opcode: 414,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 10,
|
||||
size: 1,
|
||||
opcode: 640,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 11,
|
||||
size: 4,
|
||||
opcode: 740,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 15,
|
||||
size: 5,
|
||||
opcode: 414,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 20,
|
||||
size: 5,
|
||||
opcode: 414,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 25,
|
||||
size: 4,
|
||||
opcode: 448,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 29,
|
||||
size: 4,
|
||||
opcode: 460,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 33,
|
||||
size: 5,
|
||||
opcode: 414,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 38,
|
||||
size: 5,
|
||||
opcode: 414,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 43,
|
||||
size: 5,
|
||||
opcode: 448,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 48,
|
||||
size: 5,
|
||||
opcode: 460,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 53,
|
||||
size: 4,
|
||||
opcode: 11,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 57,
|
||||
size: 5,
|
||||
opcode: 414,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 62,
|
||||
size: 5,
|
||||
opcode: 414,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 67,
|
||||
size: 5,
|
||||
opcode: 448,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 72,
|
||||
size: 5,
|
||||
opcode: 460,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 77,
|
||||
size: 4,
|
||||
opcode: 11,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 81,
|
||||
size: 4,
|
||||
opcode: 7,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 85,
|
||||
size: 1,
|
||||
opcode: 590,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
InstructionDiffRow {
|
||||
ins_ref: Some(
|
||||
InstructionRef {
|
||||
address: 86,
|
||||
size: 1,
|
||||
opcode: 662,
|
||||
},
|
||||
),
|
||||
kind: None,
|
||||
branch_from: None,
|
||||
branch_to: None,
|
||||
arg_diff: [],
|
||||
},
|
||||
]
|
||||
25
objdiff-core/tests/snapshots/arch_x86__read_x86_64-3.snap
Normal file
25
objdiff-core/tests/snapshots/arch_x86__read_x86_64-3.snap
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
source: objdiff-core/tests/arch_x86.rs
|
||||
expression: output
|
||||
---
|
||||
[(Address(0), Normal, 5), (Spacing(4), Normal, 0), (Opcode("mov", 414), Normal, 10), (Basic("["), Normal, 0), (Argument(Opaque("rsp")), Normal, 0), (Argument(Opaque("+")), Normal, 0), (Argument(Signed(16)), Normal, 0), (Basic("]"), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Opaque("rdx")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(5), Normal, 5), (Spacing(4), Normal, 0), (Opcode("mov", 414), Normal, 10), (Basic("["), Normal, 0), (Argument(Opaque("rsp")), Normal, 0), (Argument(Opaque("+")), Normal, 0), (Argument(Signed(8)), Normal, 0), (Basic("]"), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Opaque("rcx")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(10), Normal, 5), (Spacing(4), Normal, 0), (Opcode("push", 640), Normal, 10), (Argument(Opaque("rdi")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(11), Normal, 5), (Spacing(4), Normal, 0), (Opcode("sub", 740), Normal, 10), (Argument(Opaque("rsp")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Unsigned(16)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(15), Normal, 5), (Spacing(4), Normal, 0), (Opcode("mov", 414), Normal, 10), (Argument(Opaque("rax")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("rsp")), Normal, 0), (Argument(Opaque("+")), Normal, 0), (Argument(Signed(32)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(20), Normal, 5), (Spacing(4), Normal, 0), (Opcode("mov", 414), Normal, 10), (Argument(Opaque("rcx")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("rsp")), Normal, 0), (Argument(Opaque("+")), Normal, 0), (Argument(Signed(40)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(25), Normal, 5), (Spacing(4), Normal, 0), (Opcode("movss", 448), Normal, 10), (Argument(Opaque("xmm0")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("rax")), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(29), Normal, 5), (Spacing(4), Normal, 0), (Opcode("mulss", 460), Normal, 10), (Argument(Opaque("xmm0")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("rcx")), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(33), Normal, 5), (Spacing(4), Normal, 0), (Opcode("mov", 414), Normal, 10), (Argument(Opaque("rax")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("rsp")), Normal, 0), (Argument(Opaque("+")), Normal, 0), (Argument(Signed(32)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(38), Normal, 5), (Spacing(4), Normal, 0), (Opcode("mov", 414), Normal, 10), (Argument(Opaque("rcx")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("rsp")), Normal, 0), (Argument(Opaque("+")), Normal, 0), (Argument(Signed(40)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(43), Normal, 5), (Spacing(4), Normal, 0), (Opcode("movss", 448), Normal, 10), (Argument(Opaque("xmm1")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("rax")), Normal, 0), (Argument(Opaque("+")), Normal, 0), (Argument(Signed(4)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(48), Normal, 5), (Spacing(4), Normal, 0), (Opcode("mulss", 460), Normal, 10), (Argument(Opaque("xmm1")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("rcx")), Normal, 0), (Argument(Opaque("+")), Normal, 0), (Argument(Signed(4)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(53), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addss", 11), Normal, 10), (Argument(Opaque("xmm0")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Opaque("xmm1")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(57), Normal, 5), (Spacing(4), Normal, 0), (Opcode("mov", 414), Normal, 10), (Argument(Opaque("rax")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("rsp")), Normal, 0), (Argument(Opaque("+")), Normal, 0), (Argument(Signed(32)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(62), Normal, 5), (Spacing(4), Normal, 0), (Opcode("mov", 414), Normal, 10), (Argument(Opaque("rcx")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("rsp")), Normal, 0), (Argument(Opaque("+")), Normal, 0), (Argument(Signed(40)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(67), Normal, 5), (Spacing(4), Normal, 0), (Opcode("movss", 448), Normal, 10), (Argument(Opaque("xmm1")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("rax")), Normal, 0), (Argument(Opaque("+")), Normal, 0), (Argument(Signed(8)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(72), Normal, 5), (Spacing(4), Normal, 0), (Opcode("mulss", 460), Normal, 10), (Argument(Opaque("xmm1")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("rcx")), Normal, 0), (Argument(Opaque("+")), Normal, 0), (Argument(Signed(8)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(77), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addss", 11), Normal, 10), (Argument(Opaque("xmm0")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Opaque("xmm1")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(81), Normal, 5), (Spacing(4), Normal, 0), (Opcode("add", 7), Normal, 10), (Argument(Opaque("rsp")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Unsigned(16)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(85), Normal, 5), (Spacing(4), Normal, 0), (Opcode("pop", 590), Normal, 10), (Argument(Opaque("rdi")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(86), Normal, 5), (Spacing(4), Normal, 0), (Opcode("ret", 662), Normal, 10), (Eol, Normal, 0)]
|
||||
1505
objdiff-core/tests/snapshots/arch_x86__read_x86_64.snap
Normal file
1505
objdiff-core/tests/snapshots/arch_x86__read_x86_64.snap
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "objdiff-wasm",
|
||||
"version": "3.0.0-beta.1",
|
||||
"version": "3.0.0-beta.2",
|
||||
"description": "A local diffing tool for decompilation projects.",
|
||||
"author": {
|
||||
"name": "Luke Street",
|
||||
|
||||
Reference in New Issue
Block a user