From c45f4bbc99b00d2da42f1a197f7d53e3fcf9eaa4 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Tue, 17 Dec 2024 21:18:45 -0700 Subject: [PATCH] Diff schema updates & WASM updates --- objdiff-core/protos/diff.proto | 17 ++++++++++---- objdiff-core/protos/proto_descriptor.bin | Bin 17396 -> 17875 bytes objdiff-core/src/bindings/diff.rs | 28 +++++++++++++++-------- objdiff-core/src/config/mod.rs | 13 +++++++++-- objdiff-core/src/diff/mod.rs | 4 ++-- objdiff-wasm/package.json | 4 ++-- objdiff-wasm/src/main.ts | 7 +++++- objdiff-wasm/src/worker.ts | 9 +++++++- 8 files changed, 60 insertions(+), 22 deletions(-) diff --git a/objdiff-core/protos/diff.proto b/objdiff-core/protos/diff.proto index bd91287..1a0ba97 100644 --- a/objdiff-core/protos/diff.proto +++ b/objdiff-core/protos/diff.proto @@ -21,9 +21,9 @@ enum SymbolFlag { SYMBOL_NONE = 0; SYMBOL_GLOBAL = 1; SYMBOL_LOCAL = 2; - SYMBOL_WEAK = 3; - SYMBOL_COMMON = 4; - SYMBOL_HIDDEN = 5; + SYMBOL_WEAK = 4; + SYMBOL_COMMON = 8; + SYMBOL_HIDDEN = 16; } // A single parsed instruction @@ -122,10 +122,17 @@ message InstructionBranchTo { uint32 branch_index = 2; } -message FunctionDiff { +message SymbolRef { + optional uint32 section_index = 1; + uint32 symbol_index = 2; +} + +message SymbolDiff { Symbol symbol = 1; repeated InstructionDiff instructions = 2; optional float match_percent = 3; + // The symbol ref in the _other_ object that this symbol was diffed against + optional SymbolRef target = 5; } message DataDiff { @@ -140,7 +147,7 @@ message SectionDiff { SectionKind kind = 2; uint64 size = 3; uint64 address = 4; - repeated FunctionDiff functions = 5; + repeated SymbolDiff symbols = 5; repeated DataDiff data = 6; optional float match_percent = 7; } diff --git a/objdiff-core/protos/proto_descriptor.bin b/objdiff-core/protos/proto_descriptor.bin index 88b01fdf9d94ed4c931dc8dd9bb7bc23037ac476..b8cbfb635e3ab7b290ee5ca1ae1300c070b312ae 100644 GIT binary patch delta 2129 zcmY+E&re)c6vyAW@4h!P_szU{Tz(dWzJdu&X}Tc&3n(Vkl#);vx|$3y(@tZ-Fq5cB z%d>@03u21H4?~q|F@?G_EV}W3aN)wgK@(lMa^?5_D!Q4>=bdxD=iGD7y?;NZUpL7Y ze_i{@zm&`Fio&f=@69cJI9sdBi=x!5&9@p$i&TSjY-GM^uZcv&mH(*?|3gBUWRs10U0xPpvptd9lk%zvTh-;;wN_sMooKwb zJ(KGmtJSAy)*6sg3*M`?=I>NKsx8mg7F!bqk*nyy_V2klI%wa>e>OfYa;AzV#C(YL zU0IsDyMTmO^v_uVv)1vH7rvlTE;~f&)(6uQGdC*NW~QfSZYKHve44sGIr+}bBx%1E ze-yqS6FC`p-mB9equzaMnGlRelHd0-^g#GLg6sW! zhlm8{5%Z+~fW58a6mUhtQ2>fM93kw1JnzT{4Ubq6m{wT7H4(yASl&^lj0IgMG7#cc z`p&_~cu|HA$$Lx$6`vPL@`sd{FmYZ)UHlQTE>S{ZpipDpA$%WEq3qCCC_8N^jH|>h zTVqCCv#?B%TBWGpq4pjabqJ|dx-@2`nB;53My!!R3FwqqpfF0D6-sN=G2{?RYjj~a z6YuK-0oRG8{qLsl-KnK!PtxUDJ#8$eEqtjg;di-`VqK?Fl`MQuHHAu!wGJHbbmv#gtcs`+gq7PqE zBiL{w06`XLvH;<`L6I2&5ULw)1SJOJCNXTa2(EGnAC9~ zr~-{D5Wd?^6$sUBrJAWlj8)FBi1pf7wLL&n0*u-kJ7sJ)tld4jfw4MC`z)X??^3U91}E4i(Ji!5Q8=)Y)azVjXsg4cky|(9A7n90%B? z$O&^O?NZO6bB59`rFdcm&rk-^?h$j=08&6F6+mi_qD~u&CkWWp=MYkRH1L)!3cma9 zCdDj-63{7y$g}Tm60A_#r_5d@Fr@Zzl_13eCc^{rzB7XkR2L5@&?_4-HRxx=dQ=ID zUmBJ-`0Dty1IJj+Y%pCScZ>I3+b`lqu@T**PVpytQrsVFHE-XUo<8Lyp^in`C0jKJnqtg=e;YYPWJBJPQP-iCr;xa@Himt z@8_B$2IRlkVZ00j0Yj~Tu|tTTQBrg03u403i{dOX zwqvXm80>Ors!{3?)>*36;}O%AwVET=1N#q8OckG6%{*m{Bfmw~!0^veC36V>9M!wc zM41j3$a`)l%Aj1Js616B6D=az_&`VnmZ?B!7hNh4sf&`D%S4&jmQSw Self { let section = &obj.sections[section_index]; - let functions = section_diff.symbols.iter().map(|d| FunctionDiff::new(obj, d)).collect(); + let symbols = section_diff.symbols.iter().map(|d| SymbolDiff::new(obj, d)).collect(); let data = section_diff.data_diff.iter().map(|d| DataDiff::new(obj, d)).collect(); Self { name: section.name.to_string(), kind: SectionKind::from(section.kind) as i32, size: section.size, address: section.address, - functions, + symbols, data, match_percent: section_diff.match_percent, } @@ -64,13 +65,22 @@ impl From for SectionKind { } } -impl FunctionDiff { +impl From for SymbolRef { + fn from(value: obj::SymbolRef) -> Self { + Self { + section_index: if value.section_idx == obj::SECTION_COMMON { + None + } else { + Some(value.section_idx as u32) + }, + symbol_index: value.symbol_idx as u32, + } + } +} + +impl SymbolDiff { pub fn new(object: &ObjInfo, symbol_diff: &ObjSymbolDiff) -> Self { let (_section, symbol) = object.section_symbol(symbol_diff.symbol_ref); - // let diff_symbol = symbol_diff.diff_symbol.map(|symbol_ref| { - // let (_section, symbol) = object.section_symbol(symbol_ref); - // Symbol::from(symbol) - // }); let instructions = symbol_diff .instructions .iter() @@ -78,9 +88,9 @@ impl FunctionDiff { .collect(); Self { symbol: Some(Symbol::new(symbol)), - // diff_symbol, instructions, match_percent: symbol_diff.match_percent, + target: symbol_diff.target_symbol.map(SymbolRef::from), } } } @@ -110,7 +120,7 @@ impl Symbol { fn symbol_flags(value: ObjSymbolFlagSet) -> u32 { let mut flags = 0u32; if value.0.contains(ObjSymbolFlags::Global) { - flags |= SymbolFlag::SymbolNone as u32; + flags |= SymbolFlag::SymbolGlobal as u32; } if value.0.contains(ObjSymbolFlags::Local) { flags |= SymbolFlag::SymbolLocal as u32; diff --git a/objdiff-core/src/config/mod.rs b/objdiff-core/src/config/mod.rs index 0705d6b..26f11fc 100644 --- a/objdiff-core/src/config/mod.rs +++ b/objdiff-core/src/config/mod.rs @@ -6,11 +6,11 @@ use std::{ }; use anyhow::{anyhow, Context, Result}; -use bimap::BiBTreeMap; use filetime::FileTime; use globset::{Glob, GlobSet, GlobSetBuilder}; #[derive(Default, Clone, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify), tsify(from_wasm_abi))] pub struct ProjectConfig { #[serde(default, skip_serializing_if = "Option::is_none")] pub min_version: Option, @@ -55,6 +55,7 @@ impl ProjectConfig { } #[derive(Default, Clone, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify), tsify(from_wasm_abi))] pub struct ProjectObject { #[serde(default, skip_serializing_if = "Option::is_none")] pub name: Option, @@ -78,9 +79,15 @@ pub struct ProjectObject { pub symbol_mappings: Option, } -pub type SymbolMappings = BiBTreeMap; +#[cfg(feature = "wasm")] +#[tsify_next::declare] +pub type SymbolMappings = std::collections::BTreeMap; + +#[cfg(not(feature = "wasm"))] +pub type SymbolMappings = bimap::BiBTreeMap; #[derive(Default, Clone, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify), tsify(from_wasm_abi))] pub struct ProjectObjectMetadata { #[serde(default, skip_serializing_if = "Option::is_none")] pub complete: Option, @@ -95,6 +102,7 @@ pub struct ProjectObjectMetadata { } #[derive(Default, Clone, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify), tsify(from_wasm_abi))] pub struct ProjectProgressCategory { #[serde(default)] pub id: String, @@ -154,6 +162,7 @@ impl ProjectObject { } #[derive(Default, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)] +#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify), tsify(from_wasm_abi))] pub struct ScratchConfig { #[serde(default, skip_serializing_if = "Option::is_none")] pub platform: Option, diff --git a/objdiff-core/src/diff/mod.rs b/objdiff-core/src/diff/mod.rs index 5a17e90..2401e4d 100644 --- a/objdiff-core/src/diff/mod.rs +++ b/objdiff-core/src/diff/mod.rs @@ -155,8 +155,7 @@ pub enum ArmR9Usage { const fn default_true() -> bool { true } #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)] -#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))] -#[cfg_attr(feature = "wasm", tsify(from_wasm_abi))] +#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify), tsify(from_wasm_abi))] #[serde(default)] pub struct DiffObjConfig { pub relax_reloc_diffs: bool, @@ -637,6 +636,7 @@ struct SectionMatch { } #[derive(Debug, Clone, PartialEq, Eq, Hash, Default, serde::Deserialize, serde::Serialize)] +#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify), tsify(from_wasm_abi))] pub struct MappingConfig { /// Manual symbol mappings pub mappings: SymbolMappings, diff --git a/objdiff-wasm/package.json b/objdiff-wasm/package.json index 3186e94..bfaba00 100644 --- a/objdiff-wasm/package.json +++ b/objdiff-wasm/package.json @@ -1,6 +1,6 @@ { "name": "objdiff-wasm", - "version": "2.0.0", + "version": "2.5.0", "description": "A local diffing tool for decompilation projects.", "author": { "name": "Luke Street", @@ -21,7 +21,7 @@ "build": "tsup", "build:all": "npm run build:wasm && npm run build:proto && npm run build", "build:proto": "protoc --ts_out=gen --ts_opt add_pb_suffix,eslint_disable,ts_nocheck,use_proto_field_name --proto_path=../objdiff-core/protos ../objdiff-core/protos/*.proto", - "build:wasm": "cd ../objdiff-core && wasm-pack build --out-dir ../objdiff-wasm/pkg --target web -- --features arm,dwarf,ppc,x86,wasm" + "build:wasm": "cd ../objdiff-core && wasm-pack build --out-dir ../objdiff-wasm/pkg --target web -- --features arm,arm64,dwarf,config,ppc,x86,wasm" }, "dependencies": { "@protobuf-ts/runtime": "^2.9.4" diff --git a/objdiff-wasm/src/main.ts b/objdiff-wasm/src/main.ts index 0d5ad81..0847479 100644 --- a/objdiff-wasm/src/main.ts +++ b/objdiff-wasm/src/main.ts @@ -194,12 +194,17 @@ export function displayDiff(diff: InstructionDiff, baseAddr: bigint, cb: (text: cb({type: 'spacing', count: 4}); } cb({type: 'opcode', mnemonic: ins.mnemonic, opcode: ins.opcode}); + let arg_diff_idx = 0; // non-PlainText argument index for (let i = 0; i < ins.arguments.length; i++) { if (i === 0) { cb({type: 'spacing', count: 1}); } const arg = ins.arguments[i].value; - const diff_index = diff.arg_diff[i]?.diff_index; + let diff_index: number | undefined; + if (arg.oneofKind !== 'plain_text') { + diff_index = diff.arg_diff[arg_diff_idx]?.diff_index; + arg_diff_idx++; + } switch (arg.oneofKind) { case "plain_text": cb({type: 'basic', text: arg.plain_text, diff_index}); diff --git a/objdiff-wasm/src/worker.ts b/objdiff-wasm/src/worker.ts index c9e78b5..defad77 100644 --- a/objdiff-wasm/src/worker.ts +++ b/objdiff-wasm/src/worker.ts @@ -73,12 +73,19 @@ self.onmessage = (event: MessageEvent) => { const result = await handler(data as never); const end = performance.now(); console.debug(`Worker message ${data.messageId} took ${end - start}ms`); + let transfer: Transferable[] = []; + if (result instanceof Uint8Array) { + console.log("Transferring!", result.byteLength); + transfer = [result.buffer]; + } else { + console.log("Didn't transfer", typeof result); + } self.postMessage({ type: 'result', result: result, error: null, messageId, - } as OutMessage); + } as OutMessage, {transfer}); } else { throw new Error(`No handler for ${data.type}`); }