1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use std::collections::{BTreeMap, BTreeSet};
use crate::instruction::Instruction;
mod control_flow;
mod core;
mod dispatch;
mod helpers;
mod postprocess;
mod slots;
mod stack;
mod types;
mod util;
use helpers::{
convert_target_name, format_int_bytes_as_decimal, format_pushdata, format_type_operand,
literal_from_operand,
};
use types::{DoWhileLoop, LiteralValue, LoopContext, LoopJump, SlotKind};
#[derive(Debug, Default)]
pub(crate) struct HighLevelEmitter {
stack: Vec<String>,
statements: Vec<String>,
warnings: Vec<String>,
next_temp: usize,
inline_single_use_temps: bool,
/// When true, every instruction handler emits a `// XXXX: OPCODE` trace
/// comment alongside the lifted statement. Useful for learning the lift
/// rules or correlating high-level lines with raw bytecode, but produces
/// noisy output for end users. Defaults to true to preserve historical
/// rendering. Disable via `Decompiler::with_trace_comments(false)` for
/// clean human-readable output.
emit_trace_comments: bool,
pending_closers: BTreeMap<usize, usize>,
else_targets: BTreeMap<usize, usize>,
pending_if_headers: BTreeMap<usize, Vec<String>>,
catch_targets: BTreeMap<usize, usize>,
finally_targets: BTreeMap<usize, usize>,
skip_jumps: BTreeSet<usize>,
transfer_labels: BTreeSet<usize>,
program: Vec<Instruction>,
index_by_offset: BTreeMap<usize, usize>,
do_while_headers: BTreeMap<usize, Vec<DoWhileLoop>>,
active_do_while_tails: BTreeSet<usize>,
loop_stack: Vec<LoopContext>,
initialized_locals: BTreeSet<usize>,
initialized_statics: BTreeSet<usize>,
local_pointer_values: BTreeMap<usize, usize>,
static_pointer_values: BTreeMap<usize, usize>,
argument_labels: BTreeMap<usize, String>,
literal_values: BTreeMap<String, LiteralValue>,
/// Concrete element lists for values emitted by PACK with literal count.
/// Enables precise UNPACK stack modeling when those values are loaded later.
packed_values_by_name: BTreeMap<String, Vec<String>>,
/// Pre-resolved labels for CALLT method-token indices.
/// Index `i` corresponds to method-token index `i` in the NEF file.
callt_labels: Vec<String>,
/// Declared parameter counts for CALLT method-token indices.
callt_param_counts: Vec<usize>,
/// Declared return-value flags for CALLT method-token indices.
callt_returns_value: Vec<bool>,
/// Stack snapshots saved before entering if-bodies so that the stack can
/// be restored when the closing brace is emitted. Keyed by the offset
/// where the closer will be placed (i.e. the false-target of the branch).
branch_saved_stacks: BTreeMap<usize, Vec<String>>,
/// Pre-resolved method names keyed by method start offset.
/// Used to replace `call_0xXXXX()` placeholders when a stable symbol exists.
method_labels_by_offset: BTreeMap<usize, String>,
/// Resolved argument counts keyed by method start offset.
/// Used to preserve call-site argument expressions for internal calls.
method_arg_counts_by_offset: BTreeMap<usize, usize>,
/// Resolved internal CALL/CALL_L targets keyed by call instruction offset.
/// Used when the immediate call target lands inside a method body.
call_targets_by_offset: BTreeMap<usize, usize>,
/// Resolved internal targets keyed by CALLA instruction offset.
/// Used when pointer provenance is outside the current method body.
calla_targets_by_offset: BTreeMap<usize, usize>,
/// Method start offsets whose bodies always terminate without returning
/// (every exit path ends with ABORT, ABORTMSG, or THROW).
noreturn_method_offsets: BTreeSet<usize>,
/// Pre-branch stack depths keyed by merge offset. Used to detect
/// when both branches of an if/else produce stack values that must
/// be unified at the merge point (phi-variable reconciliation).
pre_branch_stack_depth: BTreeMap<usize, usize>,
/// When true, the current method is declared void in the manifest.
/// `emit_return` will emit `return;` instead of `return <value>;`.
returns_void: bool,
/// Ranges `[start, end)` of finally bodies already registered.
/// Used to suppress duplicate `finally {` when an outer TRY's finally
/// target falls inside an inner TRY's already-registered finally body.
finally_body_ranges: Vec<(usize, usize)>,
/// Maps catch_target offset → resume offset after try-catch.
/// Used to save the try block's exit stack before catch clears it.
try_catch_resume: BTreeMap<usize, usize>,
/// Stack snapshots saved at try block exit, keyed by resume offset.
/// Restored after the catch/finally block closes.
try_exit_stacks: BTreeMap<usize, Vec<String>>,
}
pub(crate) struct HighLevelOutput {
pub(crate) statements: Vec<String>,
pub(crate) warnings: Vec<String>,
}