vendor: Ghidra resynced to master 918acd744d, the commit the specifications come from

libsla-sys vendors 0verflowme/ghidra r2sleigh-sleigh-context-12: Ghidra
master 918acd744d (2026-10-13) with PF0 and W2 re-ported onto GP-6554's
ParserContext. The parse-depth check this tree carried is gone: GP-6554
bounds the operand path and operand index itself (LowlevelError), and
context.hh is the fork's exactly. metatype.cc joins CORE (marshal.hh
includes it).

API moves: GP-2493 renames CPUI_EXTRACT to CPUI_ZPULL and adds CPUI_SPULL
(74, CPUI_MAX 75); libsla maps them to AnalysisOp::Extract and the new
SignedExtract, refused at the lift boundary as every analysis op is.
sleigh-compiler's slgh_compile.cc is re-ported onto 918acd744d (main and
run_xml dropped, errors collected), and largeTemporaryWarning is gone with
GP-6316, which raised the temporary limit to 256 bytes and made a larger one
an error.

Census: 20 files, 1477 lines, every one a Sleigh temporary renumbered, one to
one within each function: GP-6237 inserts the cross-build bits at bit 8 of a
unique offset where they were shifted in by 4, so the compiler lays the unique
space out anew. GP-5581's truncated unique reads would have moved C in
manual_limits_O2 and rv_O2 and lost switch-hello-world's aarch64 table; the
two previous commits read them as pieces and through the temporary's copy.
Two r2s command tests named temporaries by their offset (`tmp_11f80_3`); they
read the output with the offset dropped, as the census normaliser does.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01456qmqCGpCWJkrg6JUZNNM
This commit is contained in:
Priyanshu KumarandClaude Opus 5.5 committed 2026-10-15 19:20:38 +05:30
1 parent 9386165cfb
commit d7d966651c
185 files changed
+19532 -9485

No files matched your search

+23 -5
View File
@@ -28,6 +28,25 @@ struct Run {
ok: bool,
}
/// `text` with each Sleigh temporary's unique offset dropped (`tmp_23d00_3` is `tmp_3`): the
/// specification's compiler lays that space out, so the offset is no fact a test can hold.
fn unnumbered(text: &str) -> String {
let mut out = String::with_capacity(text.len());
let mut rest = text;
while let Some(at) = rest.find("tmp_") {
out.push_str(&rest[..at + 4]);
rest = &rest[at + 4..];
let digits = rest.len()
- rest
.trim_start_matches(|c: char| c.is_ascii_hexdigit())
.len();
if digits > 0 && rest[digits..].starts_with('_') {
rest = &rest[digits + 1..];
}
}
out + rest
}
fn r2s(script: &str) -> Run {
on(fixture(), script)
}
@@ -531,9 +550,7 @@ fn a_staged_call_passes_its_stack_arguments() {
let pinned = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../tests/coverage/pinned");
let staged = on(pinned.join("shapes_gcc_x64_O0"), "pdd @ sym.shape_variadic");
assert!(
staged
.out
.contains("tmp_11f80_19, tmp_11f80_18, rax_45, tmp_4a00_1, rax_42);"),
unnumbered(&staged.out).contains("tmp_19, tmp_18, rax_45, tmp_1, rax_42);"),
"{}",
staged.out
);
@@ -583,9 +600,10 @@ fn a_call_taking_a_pair_assigns_the_half_its_caller_reads() {
for line in [
"pair_401984 = mixed_from(arg0, arg1);",
"rdx_2 = (uint64_t)((__uint128_t)pair_401984 >> 64U);",
"mixed_fold(tmp_11f80_3, rdx_2);",
"mixed_fold(tmp_3, rdx_2);",
] {
assert!(staged.out.contains(line), "{line}: {}", staged.out);
let text = unnumbered(&staged.out);
assert!(text.contains(line), "{line}: {}", staged.out);
}
assert!(!staged.out.contains("r2sleigh_residual"), "{}", staged.out);
}
+1
View File
@@ -1291,6 +1291,7 @@ fn analysis_pcode_is_invalid_at_the_machine_lift_boundary() {
libsla::AnalysisOp::Cast,
libsla::AnalysisOp::Insert,
libsla::AnalysisOp::Extract,
libsla::AnalysisOp::SignedExtract,
libsla::AnalysisOp::SegmentOp,
] {
let instruction = PcodeInstruction {
+48 -48
View File
@@ -114,11 +114,11 @@ CMDS=aa; pdd @ 0x00401070
EXPECT=<<EOF
void _start(void)
{
uint64_t tmp_55400_2;
uint64_t tmp_aa300_2;
/* r2dec proof: 5 constructs are marked below; 28 source obligations: 0 rendered, 6 elided, 0 refused, 22 residual; 1 statements rendered; 1 held from entry, read as residuals (stack_p0) */
{
tmp_55400_2 = r2sleigh_residual_u64(1);
tmp_aa300_2 = r2sleigh_residual_u64(1);
r2sleigh_residual_void(2); /* r2dec gap: StoreNotSpelled at 0x401070:29 covering 1 op (render::values) */
r2sleigh_residual_void(3); /* r2dec gap: StoreNotSpelled at 0x401070:32 covering 1 op (render::values) */
r2sleigh_residual_void(4); /* r2dec gap: CallNotRendered at 0x401070:68 covering 1 op (render::values): call to __libc_start_main: the import's declaration has an argument this convention does not place */
@@ -217,12 +217,12 @@ uint64_t __do_global_dtors_aux(void)
void deregister_tm_clones(void);
extern char __TMC_END__[];
uint8_t tmp_3e180_1;
uint8_t tmp_7c100_1;
/* r2dec proof: 2 constructs are marked below; 24 source obligations: 8 rendered, 12 elided, 0 refused, 4 residual; 6 statements rendered; 1 data object type refused */
{
tmp_3e180_1 = r2sleigh_load_u8((void*)&__TMC_END__);
if ((uint8_t)((uint8_t)tmp_3e180_1 != (uint8_t)0U)) {
tmp_7c100_1 = r2sleigh_load_u8((void*)&__TMC_END__);
if ((uint8_t)((uint8_t)tmp_7c100_1 != (uint8_t)0U)) {
return r2sleigh_residual_u64(1);
} else {
deregister_tm_clones();
@@ -418,7 +418,7 @@ CMDS=aa; pdd @ 0x00401247
EXPECT=<<EOF
uint64_t bounded_fetch(uint32_t* arg0, uint32_t arg1, uint32_t arg2)
{
uint32_t tmp_11f00_4;
uint32_t tmp_23c00_4;
uint64_t rax_8;
/* r2dec proof: no individual construct is marked; 25 source obligations: 18 rendered, 7 elided, 0 refused; 7 statements rendered */
@@ -429,8 +429,8 @@ uint64_t bounded_fetch(uint32_t* arg0, uint32_t arg1, uint32_t arg2)
}
} else {
if ((uint8_t)((int32_t)arg1 < (int32_t)arg2)) {
tmp_11f00_4 = r2sleigh_load_u32((void*)((uint64_t)arg0 + (uint64_t)(int32_t)arg1 * 4U));
rax_8 = (uint64_t)(uint32_t)tmp_11f00_4;
tmp_23c00_4 = r2sleigh_load_u32((void*)((uint64_t)arg0 + (uint64_t)(int32_t)arg1 * 4U));
rax_8 = (uint64_t)(uint32_t)tmp_23c00_4;
} else {
{
rax_8 = (uint64_t)0xffffffffU;
@@ -723,16 +723,16 @@ struct fcn_401472_arg0 {
uint32_t rec_spread(struct fcn_401472_arg0* arg0, uint32_t arg1)
{
uint64_t tmp_11f80_4;
uint32_t tmp_11f00_3;
uint64_t tmp_23d00_4;
uint32_t tmp_23c00_3;
/* r2dec proof: no individual construct is marked; 21 source obligations: 14 rendered, 7 elided, 0 refused; 5 statements rendered; the result's second register is open: no call read decides it; 1 structure laid out from a parameter's accesses */
{
r2sleigh_store_u32((void*)&arg0->f_0, (uint32_t)arg1);
r2sleigh_store_u64((void*)&arg0->f_8, (uint64_t)(int32_t)((uint32_t)arg1 + (uint32_t)9U));
tmp_11f80_4 = r2sleigh_load_u64((void*)&arg0->f_8);
tmp_11f00_3 = r2sleigh_load_u32((void*)&arg0->f_0);
return (uint32_t)((uint32_t)((uint64_t)tmp_11f80_4 >> 0U) + (uint32_t)tmp_11f00_3);
tmp_23d00_4 = r2sleigh_load_u64((void*)&arg0->f_8);
tmp_23c00_3 = r2sleigh_load_u32((void*)&arg0->f_0);
return (uint32_t)((uint32_t)((uint64_t)tmp_23d00_4 >> 0U) + (uint32_t)tmp_23c00_3);
}
}
@@ -747,12 +747,12 @@ CMDS=aa; pdd @ 0x004014af
EXPECT=<<EOF
uint32_t half_stride(uint16_t* arg0, uint32_t arg1)
{
uint16_t tmp_11e80_1;
uint16_t tmp_23b00_1;
/* r2dec proof: no individual construct is marked; 15 source obligations: 8 rendered, 7 elided, 0 refused; 2 statements rendered; the result's second register is open: no call read decides it */
{
tmp_11e80_1 = r2sleigh_load_u16((void*)((uint64_t)arg0 + (uint64_t)(int32_t)arg1 * 2U));
return (uint32_t)(uint16_t)tmp_11e80_1;
tmp_23b00_1 = r2sleigh_load_u16((void*)((uint64_t)arg0 + (uint64_t)(int32_t)arg1 * 2U));
return (uint32_t)(uint16_t)tmp_23b00_1;
}
}
@@ -767,15 +767,15 @@ CMDS=aa; pdd @ 0x004014d3
EXPECT=<<EOF
uint32_t rec_index(uint32_t* arg0, uint32_t arg1, uint32_t arg2)
{
uint32_t tmp_11f00_4;
uint32_t tmp_11f00_6;
uint32_t tmp_23c00_4;
uint32_t tmp_23c00_6;
/* r2dec proof: no individual construct is marked; 26 source obligations: 19 rendered, 7 elided, 0 refused; 4 statements rendered; the result's second register is open: no call read decides it */
{
r2sleigh_store_u32((void*)((uint64_t)arg0 + (uint64_t)((uint64_t)((uint64_t)(int32_t)arg1 * (uint64_t)4U) + (uint64_t)1U) * 4U), (uint32_t)arg2);
tmp_11f00_4 = r2sleigh_load_u32((void*)((uint64_t)arg0 + (uint64_t)((uint64_t)((uint64_t)(int32_t)arg1 * (uint64_t)4U) + (uint64_t)1U) * 4U));
tmp_11f00_6 = r2sleigh_load_u32((void*)((uint64_t)arg0 + (uint64_t)((uint64_t)(int32_t)arg1 * (uint64_t)4U) * 4U));
return (uint32_t)((uint32_t)tmp_11f00_6 + (uint32_t)tmp_11f00_4);
tmp_23c00_4 = r2sleigh_load_u32((void*)((uint64_t)arg0 + (uint64_t)((uint64_t)((uint64_t)(int32_t)arg1 * (uint64_t)4U) + (uint64_t)1U) * 4U));
tmp_23c00_6 = r2sleigh_load_u32((void*)((uint64_t)arg0 + (uint64_t)((uint64_t)(int32_t)arg1 * (uint64_t)4U) * 4U));
return (uint32_t)((uint32_t)tmp_23c00_6 + (uint32_t)tmp_23c00_4);
}
}
@@ -790,13 +790,13 @@ CMDS=aa; pdd @ 0x0040152d
EXPECT=<<EOF
uint32_t wide_tail(uint32_t* arg0, uint32_t arg1)
{
uint32_t tmp_11f00_2;
uint32_t tmp_23c00_2;
/* r2dec proof: no individual construct is marked; 15 source obligations: 8 rendered, 7 elided, 0 refused; 3 statements rendered */
{
r2sleigh_store_u32((void*)((uint64_t)arg0 + (uint64_t)96U * 4U), (uint32_t)arg1);
tmp_11f00_2 = r2sleigh_load_u32((void*)((uint64_t)arg0 + (uint64_t)96U * 4U));
return (uint32_t)((uint32_t)tmp_11f00_2 + (uint32_t)2U);
tmp_23c00_2 = r2sleigh_load_u32((void*)((uint64_t)arg0 + (uint64_t)96U * 4U));
return (uint32_t)((uint32_t)tmp_23c00_2 + (uint32_t)2U);
}
}
@@ -1148,16 +1148,16 @@ uint64_t fcn_401764(void)
uint64_t rax_7;
uint64_t rax_8;
uint64_t rax_9;
uint32_t tmp_11f00_2;
uint32_t tmp_23c00_2;
uint64_t rdx_7;
uint32_t tmp_11f00_3;
uint32_t tmp_11f00_4;
uint32_t tmp_23c00_3;
uint32_t tmp_23c00_4;
uint64_t rsi_5;
uint64_t rax_11;
uint32_t tmp_11f00_5;
uint32_t tmp_23c00_5;
uint64_t rax_13;
uint64_t rax_17;
uint32_t tmp_11f00_7;
uint32_t tmp_23c00_7;
uint64_t rax_19;
uint64_t rax_20;
uint64_t rax_21;
@@ -1172,17 +1172,17 @@ uint64_t fcn_401764(void)
uint64_t rax_38;
uint64_t rax_40;
uint64_t rax_42;
uint32_t tmp_11f00_8;
uint32_t tmp_23c00_8;
uint64_t rax_44;
uint64_t rax_46;
uint64_t rax_49;
uint64_t rax_50;
uint64_t rax_51;
uint64_t rax_52;
uint32_t tmp_11f00_9;
uint32_t tmp_23c00_9;
uint64_t rax_54;
uint64_t rax_59;
uint32_t tmp_11f00_10;
uint32_t tmp_23c00_10;
uint64_t rdi_45;
uint64_t rax_61;
uint64_t rax_62;
@@ -1226,20 +1226,20 @@ uint64_t fcn_401764(void)
rax_7 = mask_probe(69);
rax_8 = paired_sum_diff(140, 110);
rax_9 = affine_probe(15);
tmp_11f00_2 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
rdx_7 = (uint64_t)(uint32_t)tmp_11f00_2;
tmp_11f00_3 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_11f00_4 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
rsi_5 = (uint64_t)(uint32_t)tmp_11f00_3;
rax_11 = gate_three((uint32_t)tmp_11f00_4, (uint32_t)rsi_5, (uint32_t)rdx_7);
tmp_11f00_5 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
rax_13 = gate_one((uint32_t)tmp_11f00_5);
tmp_23c00_2 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
rdx_7 = (uint64_t)(uint32_t)tmp_23c00_2;
tmp_23c00_3 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_23c00_4 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
rsi_5 = (uint64_t)(uint32_t)tmp_23c00_3;
rax_11 = gate_three((uint32_t)tmp_23c00_4, (uint32_t)rsi_5, (uint32_t)rdx_7);
tmp_23c00_5 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
rax_13 = gate_one((uint32_t)tmp_23c00_5);
r2sleigh_store_u64((void*)(uint64_t)(frame + 16U), (uint64_t)rbx_1);
printf("%d %d %d %d %d %d\n", (uint64_t)(uint32_t)((uint64_t)rax_13 >> 0U), (uint64_t)(uint32_t)((uint64_t)rax_11 >> 0U), (uint64_t)(uint32_t)((uint64_t)rax_9 >> 0U), (uint64_t)(uint32_t)((uint64_t)rax_8 >> 0U), (uint64_t)(uint32_t)((uint64_t)rax_7 >> 0U), rbx_1);
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
rax_17 = pure_zero_guard();
tmp_11f00_7 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
rax_19 = opaque_self_xor((uint32_t)tmp_11f00_7);
tmp_23c00_7 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
rax_19 = opaque_self_xor((uint32_t)tmp_23c00_7);
rax_20 = (uint64_t)sign_xor(1, (uint32_t)0xffffffffU);
rax_21 = widen_pair(1, 2);
rax_23 = narrow64((uint64_t)0x1122334455667788U);
@@ -1255,8 +1255,8 @@ uint64_t fcn_401764(void)
rax_38 = (uint64_t)rec_index((uint64_t)(frame + 48U), 0, 6);
rax_40 = (uint64_t)half_stride((uint64_t)((uint64_t)(frame + 48U) + (uint64_t)16U), 1);
rax_42 = (uint64_t)rec_spread((uint64_t)(frame + 48U), 3);
tmp_11f00_8 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
rax_44 = (uint64_t)triple_temp((uint32_t)tmp_11f00_8);
tmp_23c00_8 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
rax_44 = (uint64_t)triple_temp((uint32_t)tmp_23c00_8);
rax_46 = (uint64_t)rec_write((uint64_t)(frame + 48U), 4);
r2sleigh_store_u64((void*)(uint64_t)(frame + 16U), (uint64_t)rbx_4);
printf("%d %d %d %u %d %d\n", (uint64_t)(uint32_t)((uint64_t)rax_46 >> 0U), (uint64_t)(uint32_t)((uint64_t)rax_44 >> 0U), (uint64_t)(uint32_t)((uint64_t)rax_42 >> 0U), (uint64_t)(uint16_t)((uint64_t)rax_40 >> 0U), (uint64_t)(uint32_t)((uint64_t)rax_38 >> 0U), rbx_4);
@@ -1264,14 +1264,14 @@ uint64_t fcn_401764(void)
rax_50 = inverted_goto(20);
rax_51 = inverted_guard(20);
rax_52 = and_chain(1, 1);
tmp_11f00_9 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
rax_54 = (uint64_t)constant_branch((uint32_t)tmp_11f00_9);
tmp_23c00_9 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
rax_54 = (uint64_t)constant_branch((uint32_t)tmp_23c00_9);
printf("%d %d %d %d %d\n", (uint64_t)(uint32_t)((uint64_t)rax_54 >> 0U), (uint64_t)(uint32_t)((uint64_t)rax_52 >> 0U), (uint64_t)(uint32_t)((uint64_t)rax_51 >> 0U), (uint64_t)(uint32_t)((uint64_t)rax_50 >> 0U), (uint64_t)(uint32_t)((uint64_t)rax_49 >> 0U));
inverted_void(20);
and_chain_effect(1, 1);
rax_59 = bool_relay(1, 1);
tmp_11f00_10 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
rdi_45 = (uint64_t)(uint32_t)tmp_11f00_10;
tmp_23c00_10 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
rdi_45 = (uint64_t)(uint32_t)tmp_23c00_10;
rax_61 = (uint64_t)typed_compete((uint32_t)rdi_45);
rax_62 = (uint64_t)addr_chain();
printf("%d %d %d\n", (uint64_t)(uint32_t)((uint64_t)rax_62 >> 0U), (uint64_t)(uint32_t)((uint64_t)rax_61 >> 0U), (uint64_t)(uint32_t)((uint64_t)rax_59 >> 0U));
+4 -4
View File
@@ -131,7 +131,7 @@ void __libc_csu_init(int32_t argc, char** argv, char** envp)
uint64_t x22_2;
uint64_t x23_2;
uint64_t x8_4;
uint64_t tmp_40b00_1;
uint64_t tmp_80000_1;
/* r2dec proof: 2 constructs are marked below; 45 source obligations: 21 rendered, 15 elided, 0 refused, 9 residual; 11 statements rendered */
{
@@ -143,10 +143,10 @@ void __libc_csu_init(int32_t argc, char** argv, char** envp)
x8_4 = r2sleigh_load_u64((void*)x22_2);
r2sleigh_residual_void(1); /* r2dec gap: CallNotRendered at 0x10105e4:13 covering 1 op (render::values): call to an indirect target: no arity is stated, only the registers written before it */
r2sleigh_residual_void(2); /* r2dec gap: EffectNotRendered at 0x10105e4:47 covering 1 op (render::values) */
tmp_40b00_1 = (uint64_t)((uint64_t)x23_2 - (uint64_t)1U);
if ((uint8_t)((uint64_t)tmp_40b00_1 != (uint64_t)0U)) {
tmp_80000_1 = (uint64_t)((uint64_t)x23_2 - (uint64_t)1U);
if ((uint8_t)((uint64_t)tmp_80000_1 != (uint64_t)0U)) {
x22_2 = (uint64_t)((uint64_t)x22_2 + (uint64_t)8U);
x23_2 = tmp_40b00_1;
x23_2 = tmp_80000_1;
} else {
break;
}
+10 -10
View File
@@ -23,11 +23,11 @@ CMDS=aa; pdd @ 0x010014e0
EXPECT=<<EOF
void _start(void)
{
uint64_t tmp_55400_2;
uint64_t tmp_aa300_2;
/* r2dec proof: 5 constructs are marked below; 27 source obligations: 0 rendered, 5 elided, 0 refused, 22 residual; 1 statements rendered; 1 held from entry, read as residuals (stack_p0) */
{
tmp_55400_2 = r2sleigh_residual_u64(1);
tmp_aa300_2 = r2sleigh_residual_u64(1);
r2sleigh_residual_void(2); /* r2dec gap: StoreNotSpelled at 0x10014e0:29 covering 1 op (render::values) */
r2sleigh_residual_void(3); /* r2dec gap: StoreNotSpelled at 0x10014e0:32 covering 1 op (render::values) */
r2sleigh_residual_void(4); /* r2dec gap: CallNotRendered at 0x10014e0:46 covering 1 op (render::values): call to __libc_start_main: the import's declaration has an argument this convention does not place */
@@ -108,18 +108,18 @@ int32_t main(int32_t argc, char** argv)
void call_store(double*);
void forward(double, double*);
uint64_t tmp_6b00_1;
uint64_t tmp_6b00_2;
uint64_t tmp_d400_1;
uint64_t tmp_d400_2;
_Alignas(16) uint8_t frame[40];
/* r2dec proof: 2 constructs are marked below; 35 source obligations: 14 rendered, 18 elided, 0 refused, 3 residual; 6 statements rendered; 1 held from entry, read as residuals (RAX_0); 2 callee prototypes supplied by the source */
{
r2sleigh_store_u64((void*)(uint64_t)(frame + 16U), (uint64_t)r2sleigh_residual_u64(1));
call_store((double*)(uint64_t)(frame + 16U));
tmp_6b00_1 = r2sleigh_load_u64((void*)(uint64_t)(frame + 16U));
forward(r2sleigh_float_from_bits_64(tmp_6b00_1), (double*)(uint64_t)(frame + 16U));
tmp_6b00_2 = r2sleigh_load_u64((void*)(uint64_t)(frame + 16U));
return (int32_t)(r2sleigh_float_from_bits_64(tmp_6b00_2) > -2147483649.0 && r2sleigh_float_from_bits_64(tmp_6b00_2) < 2147483648.0 ? (int32_t)r2sleigh_float_from_bits_64(tmp_6b00_2) : r2sleigh_residual_i32(2));
tmp_d400_1 = r2sleigh_load_u64((void*)(uint64_t)(frame + 16U));
forward(r2sleigh_float_from_bits_64(tmp_d400_1), (double*)(uint64_t)(frame + 16U));
tmp_d400_2 = r2sleigh_load_u64((void*)(uint64_t)(frame + 16U));
return (int32_t)(r2sleigh_float_from_bits_64(tmp_d400_2) > -2147483649.0 && r2sleigh_float_from_bits_64(tmp_d400_2) < 2147483648.0 ? (int32_t)r2sleigh_float_from_bits_64(tmp_d400_2) : r2sleigh_residual_i32(2));
}
}
@@ -136,7 +136,7 @@ void __libc_csu_init(int32_t argc, char** argv, char** envp)
{
uint64_t r12_2;
uint64_t r13_5;
uint64_t tmp_11f80_1;
uint64_t tmp_23d00_1;
uint64_t r13_6;
/* r2dec proof: 2 constructs are marked below; 61 source obligations: 22 rendered, 30 elided, 0 refused, 9 residual; 11 statements rendered */
@@ -146,7 +146,7 @@ void __libc_csu_init(int32_t argc, char** argv, char** envp)
r12_2 = 0x1000000;
r13_5 = 1;
for (; ; ) {
tmp_11f80_1 = r2sleigh_load_u64((void*)r12_2);
tmp_23d00_1 = r2sleigh_load_u64((void*)r12_2);
r2sleigh_residual_void(1); /* r2dec gap: CallNotRendered at 0x10015e0:13 covering 1 op (render::values): call to an indirect target: no arity is stated, only the registers written before it */
r2sleigh_residual_void(2); /* r2dec gap: EffectNotRendered at 0x10015e0:19 covering 1 op (render::values) */
r13_6 = (uint64_t)((uint64_t)r13_5 - (uint64_t)1U);
@@ -78,12 +78,12 @@ CMDS=aa; pdd @ 0x01010544
EXPECT=<<EOF
double floor_at(double x, double lo)
{
uint8_t tmp_e000_1;
uint8_t tmp_1b800_1;
/* r2dec proof: no individual construct is marked; 12 source obligations: 12 rendered, 0 elided, 0 refused; 2 statements rendered */
{
tmp_e000_1 = (uint8_t)((uint32_t)(uint8_t)r2sleigh_float_isnan_64(x) | (uint32_t)(uint8_t)r2sleigh_float_isnan_64(lo));
return (double)r2sleigh_float_from_bits_64((uint8_t)((uint8_t)(tmp_e000_1 ? (uint8_t)0U : (uint8_t)(x < lo)) == (uint8_t)tmp_e000_1) ? (uint64_t)r2sleigh_float_to_bits_64(x) : (uint64_t)r2sleigh_float_to_bits_64(lo));
tmp_1b800_1 = (uint8_t)((uint32_t)(uint8_t)r2sleigh_float_isnan_64(x) | (uint32_t)(uint8_t)r2sleigh_float_isnan_64(lo));
return (double)r2sleigh_float_from_bits_64((uint8_t)((uint8_t)(tmp_1b800_1 ? (uint8_t)0U : (uint8_t)(x < lo)) == (uint8_t)tmp_1b800_1) ? (uint64_t)r2sleigh_float_to_bits_64(x) : (uint64_t)r2sleigh_float_to_bits_64(lo));
}
}
@@ -180,7 +180,7 @@ void __libc_csu_init(int32_t argc, char** argv, char** envp)
uint64_t x22_2;
uint64_t x23_2;
uint64_t x8_4;
uint64_t tmp_40b00_1;
uint64_t tmp_80000_1;
/* r2dec proof: 2 constructs are marked below; 45 source obligations: 21 rendered, 15 elided, 0 refused, 9 residual; 11 statements rendered */
{
@@ -192,10 +192,10 @@ void __libc_csu_init(int32_t argc, char** argv, char** envp)
x8_4 = r2sleigh_load_u64((void*)x22_2);
r2sleigh_residual_void(1); /* r2dec gap: CallNotRendered at 0x1010610:13 covering 1 op (render::values): call to an indirect target: no arity is stated, only the registers written before it */
r2sleigh_residual_void(2); /* r2dec gap: EffectNotRendered at 0x1010610:47 covering 1 op (render::values) */
tmp_40b00_1 = (uint64_t)((uint64_t)x23_2 - (uint64_t)1U);
if ((uint8_t)((uint64_t)tmp_40b00_1 != (uint64_t)0U)) {
tmp_80000_1 = (uint64_t)((uint64_t)x23_2 - (uint64_t)1U);
if ((uint8_t)((uint64_t)tmp_80000_1 != (uint64_t)0U)) {
x22_2 = (uint64_t)((uint64_t)x22_2 + (uint64_t)8U);
x23_2 = tmp_40b00_1;
x23_2 = tmp_80000_1;
} else {
break;
}
@@ -24,11 +24,11 @@ CMDS=aa; pdd @ 0x01001520
EXPECT=<<EOF
void _start(void)
{
uint64_t tmp_55400_2;
uint64_t tmp_aa300_2;
/* r2dec proof: 5 constructs are marked below; 27 source obligations: 0 rendered, 5 elided, 0 refused, 22 residual; 1 statements rendered; 1 held from entry, read as residuals (stack_p0) */
{
tmp_55400_2 = r2sleigh_residual_u64(1);
tmp_aa300_2 = r2sleigh_residual_u64(1);
r2sleigh_residual_void(2); /* r2dec gap: StoreNotSpelled at 0x1001520:29 covering 1 op (render::values) */
r2sleigh_residual_void(3); /* r2dec gap: StoreNotSpelled at 0x1001520:32 covering 1 op (render::values) */
r2sleigh_residual_void(4); /* r2dec gap: CallNotRendered at 0x1001520:46 covering 1 op (render::values): call to __libc_start_main: the import's declaration has an argument this convention does not place */
@@ -177,7 +177,7 @@ void __libc_csu_init(int32_t argc, char** argv, char** envp)
{
uint64_t r12_2;
uint64_t r13_5;
uint64_t tmp_11f80_1;
uint64_t tmp_23d00_1;
uint64_t r13_6;
/* r2dec proof: 2 constructs are marked below; 61 source obligations: 22 rendered, 30 elided, 0 refused, 9 residual; 11 statements rendered */
@@ -187,7 +187,7 @@ void __libc_csu_init(int32_t argc, char** argv, char** envp)
r12_2 = 0x1000000;
r13_5 = 1;
for (; ; ) {
tmp_11f80_1 = r2sleigh_load_u64((void*)r12_2);
tmp_23d00_1 = r2sleigh_load_u64((void*)r12_2);
r2sleigh_residual_void(1); /* r2dec gap: CallNotRendered at 0x1001670:13 covering 1 op (render::values): call to an indirect target: no arity is stated, only the registers written before it */
r2sleigh_residual_void(2); /* r2dec gap: EffectNotRendered at 0x1001670:19 covering 1 op (render::values) */
r13_6 = (uint64_t)((uint64_t)r13_5 - (uint64_t)1U);
+4 -4
View File
@@ -132,7 +132,7 @@ void __libc_csu_init(int32_t argc, char** argv, char** envp)
uint64_t x22_2;
uint64_t x23_2;
uint64_t x8_4;
uint64_t tmp_40b00_1;
uint64_t tmp_80000_1;
/* r2dec proof: 2 constructs are marked below; 45 source obligations: 21 rendered, 15 elided, 0 refused, 9 residual; 11 statements rendered */
{
@@ -144,10 +144,10 @@ void __libc_csu_init(int32_t argc, char** argv, char** envp)
x8_4 = r2sleigh_load_u64((void*)x22_2);
r2sleigh_residual_void(1); /* r2dec gap: CallNotRendered at 0x1010564:13 covering 1 op (render::values): call to an indirect target: no arity is stated, only the registers written before it */
r2sleigh_residual_void(2); /* r2dec gap: EffectNotRendered at 0x1010564:47 covering 1 op (render::values) */
tmp_40b00_1 = (uint64_t)((uint64_t)x23_2 - (uint64_t)1U);
if ((uint8_t)((uint64_t)tmp_40b00_1 != (uint64_t)0U)) {
tmp_80000_1 = (uint64_t)((uint64_t)x23_2 - (uint64_t)1U);
if ((uint8_t)((uint64_t)tmp_80000_1 != (uint64_t)0U)) {
x22_2 = (uint64_t)((uint64_t)x22_2 + (uint64_t)8U);
x23_2 = tmp_40b00_1;
x23_2 = tmp_80000_1;
} else {
break;
}
+4 -4
View File
@@ -22,11 +22,11 @@ CMDS=aa; pdd @ 0x010014b0
EXPECT=<<EOF
void _start(void)
{
uint64_t tmp_55400_2;
uint64_t tmp_aa300_2;
/* r2dec proof: 5 constructs are marked below; 27 source obligations: 0 rendered, 5 elided, 0 refused, 22 residual; 1 statements rendered; 1 held from entry, read as residuals (stack_p0) */
{
tmp_55400_2 = r2sleigh_residual_u64(1);
tmp_aa300_2 = r2sleigh_residual_u64(1);
r2sleigh_residual_void(2); /* r2dec gap: StoreNotSpelled at 0x10014b0:29 covering 1 op (render::values) */
r2sleigh_residual_void(3); /* r2dec gap: StoreNotSpelled at 0x10014b0:32 covering 1 op (render::values) */
r2sleigh_residual_void(4); /* r2dec gap: CallNotRendered at 0x10014b0:46 covering 1 op (render::values): call to __libc_start_main: the import's declaration has an argument this convention does not place */
@@ -107,7 +107,7 @@ void __libc_csu_init(int32_t argc, char** argv, char** envp)
{
uint64_t r12_2;
uint64_t r13_5;
uint64_t tmp_11f80_1;
uint64_t tmp_23d00_1;
uint64_t r13_6;
/* r2dec proof: 2 constructs are marked below; 61 source obligations: 22 rendered, 30 elided, 0 refused, 9 residual; 11 statements rendered */
@@ -117,7 +117,7 @@ void __libc_csu_init(int32_t argc, char** argv, char** envp)
r12_2 = 0x1000000;
r13_5 = 1;
for (; ; ) {
tmp_11f80_1 = r2sleigh_load_u64((void*)r12_2);
tmp_23d00_1 = r2sleigh_load_u64((void*)r12_2);
r2sleigh_residual_void(1); /* r2dec gap: CallNotRendered at 0x1001570:13 covering 1 op (render::values): call to an indirect target: no arity is stated, only the registers written before it */
r2sleigh_residual_void(2); /* r2dec gap: EffectNotRendered at 0x1001570:19 covering 1 op (render::values) */
r13_6 = (uint64_t)((uint64_t)r13_5 - (uint64_t)1U);
+18 -18
View File
@@ -167,11 +167,11 @@ double loop_sum(const double* v, int32_t n)
uint64_t x10_2;
uint64_t x11_2;
struct r2sleigh_bits_256 z0_5;
uint64_t tmp_7b80_1;
uint64_t tmp_ef00_1;
__uint128_t tmp_lane_1010598_1_7_1;
uint64_t tmp_d1c00_1;
uint64_t tmp_1a1500_1;
__uint128_t tmp_lane_1010598_5_a_1;
uint64_t tmp_40b00_1;
uint64_t tmp_80000_1;
uint64_t tmp_lane_1010598_1a_d_1;
uint64_t tmp_lane_1010598_1e_12_1;
uint64_t tmp_lane_1010598_1e_13_1;
@@ -188,7 +188,7 @@ double loop_sum(const double* v, int32_t n)
uint64_t x8_3;
struct r2sleigh_bits_256 z0_23;
uint64_t tmp_lane_10105d0_2_2f_1;
uint64_t tmp_40b00_2;
uint64_t tmp_80000_2;
uint64_t tmp_lane_10105d0_11_33_1;
double tmp_lane_10105d0_11_35_1;
struct r2sleigh_bits_256 z0_24;
@@ -213,11 +213,11 @@ double loop_sum(const double* v, int32_t n)
x11_2 = (uint64_t)((uint64_t)x8_1 & (uint64_t)0x7ffffffcU);
z0_5 = z0_4;
for (; ; ) {
tmp_7b80_1 = (uint64_t)((uint64_t)x10_2 - (uint64_t)16U);
tmp_lane_1010598_1_7_1 = r2sleigh_load_u128((void*)tmp_7b80_1);
tmp_d1c00_1 = (uint64_t)((uint64_t)tmp_7b80_1 + (uint64_t)16U);
tmp_lane_1010598_5_a_1 = r2sleigh_load_u128((void*)tmp_d1c00_1);
tmp_40b00_1 = (uint64_t)((uint64_t)x11_2 - (uint64_t)4U);
tmp_ef00_1 = (uint64_t)((uint64_t)x10_2 - (uint64_t)16U);
tmp_lane_1010598_1_7_1 = r2sleigh_load_u128((void*)tmp_ef00_1);
tmp_1a1500_1 = (uint64_t)((uint64_t)tmp_ef00_1 + (uint64_t)16U);
tmp_lane_1010598_5_a_1 = r2sleigh_load_u128((void*)tmp_1a1500_1);
tmp_80000_1 = (uint64_t)((uint64_t)x11_2 - (uint64_t)4U);
tmp_lane_1010598_1a_d_1 = (uint64_t)((__uint128_t)tmp_lane_1010598_1_7_1 >> 64U);
tmp_lane_1010598_1e_12_1 = r2sleigh_bits_extract_256_64(z0_5, 0U);
tmp_lane_1010598_1e_13_1 = (uint64_t)((__uint128_t)tmp_lane_1010598_1_7_1 >> 0U);
@@ -228,9 +228,9 @@ double loop_sum(const double* v, int32_t n)
z0_19 = r2sleigh_bits_insert_256_64(z0_18, (uint64_t)0U, 64U);
z0_20 = r2sleigh_bits_insert_256_64(z0_19, (uint64_t)0U, 128U);
z0_21 = r2sleigh_bits_insert_256_64(z0_20, (uint64_t)0U, 192U);
if ((uint8_t)((uint64_t)tmp_40b00_1 != (uint64_t)0U)) {
if ((uint8_t)((uint64_t)tmp_80000_1 != (uint64_t)0U)) {
x10_2 = (uint64_t)((uint64_t)x10_2 + (uint64_t)32U);
x11_2 = tmp_40b00_1;
x11_2 = tmp_80000_1;
z0_5 = z0_21;
} else {
break;
@@ -255,16 +255,16 @@ double loop_sum(const double* v, int32_t n)
z0_23 = z0_22;
for (; ; ) {
tmp_lane_10105d0_2_2f_1 = r2sleigh_load_u64((void*)x10_5);
tmp_40b00_2 = (uint64_t)((uint64_t)x8_3 - (uint64_t)1U);
tmp_80000_2 = (uint64_t)((uint64_t)x8_3 - (uint64_t)1U);
tmp_lane_10105d0_11_33_1 = r2sleigh_bits_extract_256_64(z0_23, 0U);
tmp_lane_10105d0_11_35_1 = r2sleigh_float_from_bits_64(tmp_lane_10105d0_11_33_1) + r2sleigh_float_from_bits_64(tmp_lane_10105d0_2_2f_1);
z0_24 = r2sleigh_bits_insert_256_64(r2sleigh_bits_zero_extend_64_256((uint64_t)0U), (uint64_t)r2sleigh_float_to_bits_64(tmp_lane_10105d0_11_35_1), 0U);
z0_25 = r2sleigh_bits_insert_256_64(z0_24, (uint64_t)0U, 64U);
z0_26 = r2sleigh_bits_insert_256_64(z0_25, (uint64_t)0U, 128U);
z0_27 = r2sleigh_bits_insert_256_64(z0_26, (uint64_t)0U, 192U);
if ((uint8_t)((uint64_t)tmp_40b00_2 != (uint64_t)0U)) {
if ((uint8_t)((uint64_t)tmp_80000_2 != (uint64_t)0U)) {
x10_5 = (uint64_t)((uint64_t)x10_5 + (uint64_t)8U);
x8_3 = tmp_40b00_2;
x8_3 = tmp_80000_2;
z0_23 = z0_27;
} else {
z0_28 = z0_27;
@@ -356,7 +356,7 @@ void __libc_csu_init(int32_t argc, char** argv, char** envp)
uint64_t x22_2;
uint64_t x23_2;
uint64_t x8_4;
uint64_t tmp_40b00_1;
uint64_t tmp_80000_1;
/* r2dec proof: 2 constructs are marked below; 45 source obligations: 21 rendered, 15 elided, 0 refused, 9 residual; 11 statements rendered */
{
@@ -368,10 +368,10 @@ void __libc_csu_init(int32_t argc, char** argv, char** envp)
x8_4 = r2sleigh_load_u64((void*)x22_2);
r2sleigh_residual_void(1); /* r2dec gap: CallNotRendered at 0x1010674:13 covering 1 op (render::values): call to an indirect target: no arity is stated, only the registers written before it */
r2sleigh_residual_void(2); /* r2dec gap: EffectNotRendered at 0x1010674:47 covering 1 op (render::values) */
tmp_40b00_1 = (uint64_t)((uint64_t)x23_2 - (uint64_t)1U);
if ((uint8_t)((uint64_t)tmp_40b00_1 != (uint64_t)0U)) {
tmp_80000_1 = (uint64_t)((uint64_t)x23_2 - (uint64_t)1U);
if ((uint8_t)((uint64_t)tmp_80000_1 != (uint64_t)0U)) {
x22_2 = (uint64_t)((uint64_t)x22_2 + (uint64_t)8U);
x23_2 = tmp_40b00_1;
x23_2 = tmp_80000_1;
} else {
break;
}
+39 -39
View File
@@ -23,11 +23,11 @@ CMDS=aa; pdd @ 0x010014f0
EXPECT=<<EOF
void _start(void)
{
uint64_t tmp_55400_2;
uint64_t tmp_aa300_2;
/* r2dec proof: 5 constructs are marked below; 27 source obligations: 0 rendered, 5 elided, 0 refused, 22 residual; 1 statements rendered; 1 held from entry, read as residuals (stack_p0) */
{
tmp_55400_2 = r2sleigh_residual_u64(1);
tmp_aa300_2 = r2sleigh_residual_u64(1);
r2sleigh_residual_void(2); /* r2dec gap: StoreNotSpelled at 0x10014f0:29 covering 1 op (render::values) */
r2sleigh_residual_void(3); /* r2dec gap: StoreNotSpelled at 0x10014f0:32 covering 1 op (render::values) */
r2sleigh_residual_void(4); /* r2dec gap: CallNotRendered at 0x10014f0:46 covering 1 op (render::values): call to __libc_start_main: the import's declaration has an argument this convention does not place */
@@ -91,45 +91,45 @@ CMDS=aa; pdd @ 0x01001570
EXPECT=<<EOF
double loop_sum(const double* v, int32_t n)
{
uint32_t tmp_70400_1;
uint32_t tmp_e0200_1;
uint64_t rax_2;
__uint128_t xmm0_1;
uint64_t rdx_2;
__uint128_t xmm0_3;
uint64_t rcx_3;
__uint128_t xmm0_5;
uint64_t tmp_6b00_1;
uint64_t tmp_d400_1;
uint64_t tmp_lane_10015a0_3_1a_1;
double tmp_lane_10015a0_3_1b_1;
__uint128_t xmm0_6;
uint64_t tmp_6b00_2;
uint64_t tmp_d400_2;
double tmp_lane_10015a0_8_1d_1;
__uint128_t xmm0_7;
uint64_t tmp_6b00_3;
uint64_t tmp_d400_3;
double tmp_lane_10015a0_d_1f_1;
__uint128_t xmm0_8;
uint64_t tmp_6b00_4;
uint64_t tmp_d400_4;
double tmp_lane_10015a0_12_21_1;
__uint128_t xmm0_9;
uint64_t tmp_6b00_5;
uint64_t tmp_d400_5;
double tmp_lane_10015a0_17_23_1;
__uint128_t xmm0_10;
uint64_t tmp_6b00_6;
uint64_t tmp_d400_6;
double tmp_lane_10015a0_1c_25_1;
__uint128_t xmm0_11;
uint64_t tmp_6b00_7;
uint64_t tmp_d400_7;
double tmp_lane_10015a0_21_27_1;
__uint128_t xmm0_12;
uint64_t tmp_6b00_8;
uint64_t tmp_d400_8;
double tmp_lane_10015a0_26_29_1;
__uint128_t xmm0_13;
uint64_t rcx_4;
uint64_t rcx_5;
__uint128_t xmm0_14;
uint64_t tmp_4a00_2;
uint64_t tmp_9400_2;
uint64_t rdx_5;
__uint128_t xmm0_15;
uint64_t tmp_6b00_9;
uint64_t tmp_d400_9;
uint64_t tmp_lane_10015f0_3_2d_1;
double tmp_lane_10015f0_3_2e_1;
__uint128_t xmm0_16;
@@ -139,8 +139,8 @@ double loop_sum(const double* v, int32_t n)
/* r2dec proof: no individual construct is marked; 138 source obligations: 126 rendered, 12 elided, 0 refused; 65 statements rendered */
{
tmp_70400_1 = (uint32_t)n;
if ((uint8_t)((int32_t)tmp_70400_1 <= (int32_t)0U)) {
tmp_e0200_1 = (uint32_t)n;
if ((uint8_t)((int32_t)tmp_e0200_1 <= (int32_t)0U)) {
xmm0_18 = (__uint128_t)(((__uint128_t)0U & (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffff00000000U)) | ((__uint128_t)(uint32_t)0U & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffU)) << 0U);
return (double)r2sleigh_float_from_bits_64((uint64_t)(((__uint128_t)xmm0_18 & (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffU)) | ((__uint128_t)(uint32_t)0U & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffU)) << 32U));
} else {
@@ -151,30 +151,30 @@ double loop_sum(const double* v, int32_t n)
rcx_3 = 0;
xmm0_5 = (__uint128_t)(((__uint128_t)xmm0_3 & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffffffffffULL)) | ((__uint128_t)(uint64_t)0U & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffffffffffULL)) << 64U);
for (; ; ) {
tmp_6b00_1 = r2sleigh_load_u64((void*)((uint64_t)v + (uint64_t)rcx_3 * 8U));
tmp_d400_1 = r2sleigh_load_u64((void*)((uint64_t)v + (uint64_t)rcx_3 * 8U));
tmp_lane_10015a0_3_1a_1 = (uint64_t)((__uint128_t)xmm0_5 >> 0U);
tmp_lane_10015a0_3_1b_1 = r2sleigh_float_from_bits_64(tmp_lane_10015a0_3_1a_1) + r2sleigh_float_from_bits_64(tmp_6b00_1);
tmp_lane_10015a0_3_1b_1 = r2sleigh_float_from_bits_64(tmp_lane_10015a0_3_1a_1) + r2sleigh_float_from_bits_64(tmp_d400_1);
xmm0_6 = (__uint128_t)(((__uint128_t)xmm0_5 & (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0U)) | ((__uint128_t)r2sleigh_float_to_bits_64(tmp_lane_10015a0_3_1b_1) & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffffffffffULL)) << 0U);
tmp_6b00_2 = r2sleigh_load_u64((void*)((uint64_t)v + (uint64_t)((uint64_t)rcx_3 + (uint64_t)1U) * 8U));
tmp_lane_10015a0_8_1d_1 = tmp_lane_10015a0_3_1b_1 + r2sleigh_float_from_bits_64(tmp_6b00_2);
tmp_d400_2 = r2sleigh_load_u64((void*)((uint64_t)v + (uint64_t)((uint64_t)rcx_3 + (uint64_t)1U) * 8U));
tmp_lane_10015a0_8_1d_1 = tmp_lane_10015a0_3_1b_1 + r2sleigh_float_from_bits_64(tmp_d400_2);
xmm0_7 = (__uint128_t)(((__uint128_t)xmm0_6 & (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0U)) | ((__uint128_t)r2sleigh_float_to_bits_64(tmp_lane_10015a0_8_1d_1) & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffffffffffULL)) << 0U);
tmp_6b00_3 = r2sleigh_load_u64((void*)((uint64_t)v + (uint64_t)((uint64_t)rcx_3 + (uint64_t)2U) * 8U));
tmp_lane_10015a0_d_1f_1 = tmp_lane_10015a0_8_1d_1 + r2sleigh_float_from_bits_64(tmp_6b00_3);
tmp_d400_3 = r2sleigh_load_u64((void*)((uint64_t)v + (uint64_t)((uint64_t)rcx_3 + (uint64_t)2U) * 8U));
tmp_lane_10015a0_d_1f_1 = tmp_lane_10015a0_8_1d_1 + r2sleigh_float_from_bits_64(tmp_d400_3);
xmm0_8 = (__uint128_t)(((__uint128_t)xmm0_7 & (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0U)) | ((__uint128_t)r2sleigh_float_to_bits_64(tmp_lane_10015a0_d_1f_1) & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffffffffffULL)) << 0U);
tmp_6b00_4 = r2sleigh_load_u64((void*)((uint64_t)v + (uint64_t)((uint64_t)rcx_3 + (uint64_t)3U) * 8U));
tmp_lane_10015a0_12_21_1 = tmp_lane_10015a0_d_1f_1 + r2sleigh_float_from_bits_64(tmp_6b00_4);
tmp_d400_4 = r2sleigh_load_u64((void*)((uint64_t)v + (uint64_t)((uint64_t)rcx_3 + (uint64_t)3U) * 8U));
tmp_lane_10015a0_12_21_1 = tmp_lane_10015a0_d_1f_1 + r2sleigh_float_from_bits_64(tmp_d400_4);
xmm0_9 = (__uint128_t)(((__uint128_t)xmm0_8 & (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0U)) | ((__uint128_t)r2sleigh_float_to_bits_64(tmp_lane_10015a0_12_21_1) & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffffffffffULL)) << 0U);
tmp_6b00_5 = r2sleigh_load_u64((void*)((uint64_t)v + (uint64_t)((uint64_t)rcx_3 + (uint64_t)4U) * 8U));
tmp_lane_10015a0_17_23_1 = tmp_lane_10015a0_12_21_1 + r2sleigh_float_from_bits_64(tmp_6b00_5);
tmp_d400_5 = r2sleigh_load_u64((void*)((uint64_t)v + (uint64_t)((uint64_t)rcx_3 + (uint64_t)4U) * 8U));
tmp_lane_10015a0_17_23_1 = tmp_lane_10015a0_12_21_1 + r2sleigh_float_from_bits_64(tmp_d400_5);
xmm0_10 = (__uint128_t)(((__uint128_t)xmm0_9 & (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0U)) | ((__uint128_t)r2sleigh_float_to_bits_64(tmp_lane_10015a0_17_23_1) & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffffffffffULL)) << 0U);
tmp_6b00_6 = r2sleigh_load_u64((void*)((uint64_t)v + (uint64_t)((uint64_t)rcx_3 + (uint64_t)5U) * 8U));
tmp_lane_10015a0_1c_25_1 = tmp_lane_10015a0_17_23_1 + r2sleigh_float_from_bits_64(tmp_6b00_6);
tmp_d400_6 = r2sleigh_load_u64((void*)((uint64_t)v + (uint64_t)((uint64_t)rcx_3 + (uint64_t)5U) * 8U));
tmp_lane_10015a0_1c_25_1 = tmp_lane_10015a0_17_23_1 + r2sleigh_float_from_bits_64(tmp_d400_6);
xmm0_11 = (__uint128_t)(((__uint128_t)xmm0_10 & (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0U)) | ((__uint128_t)r2sleigh_float_to_bits_64(tmp_lane_10015a0_1c_25_1) & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffffffffffULL)) << 0U);
tmp_6b00_7 = r2sleigh_load_u64((void*)((uint64_t)v + (uint64_t)((uint64_t)rcx_3 + (uint64_t)6U) * 8U));
tmp_lane_10015a0_21_27_1 = tmp_lane_10015a0_1c_25_1 + r2sleigh_float_from_bits_64(tmp_6b00_7);
tmp_d400_7 = r2sleigh_load_u64((void*)((uint64_t)v + (uint64_t)((uint64_t)rcx_3 + (uint64_t)6U) * 8U));
tmp_lane_10015a0_21_27_1 = tmp_lane_10015a0_1c_25_1 + r2sleigh_float_from_bits_64(tmp_d400_7);
xmm0_12 = (__uint128_t)(((__uint128_t)xmm0_11 & (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0U)) | ((__uint128_t)r2sleigh_float_to_bits_64(tmp_lane_10015a0_21_27_1) & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffffffffffULL)) << 0U);
tmp_6b00_8 = r2sleigh_load_u64((void*)((uint64_t)v + (uint64_t)((uint64_t)rcx_3 + (uint64_t)7U) * 8U));
tmp_lane_10015a0_26_29_1 = tmp_lane_10015a0_21_27_1 + r2sleigh_float_from_bits_64(tmp_6b00_8);
tmp_d400_8 = r2sleigh_load_u64((void*)((uint64_t)v + (uint64_t)((uint64_t)rcx_3 + (uint64_t)7U) * 8U));
tmp_lane_10015a0_26_29_1 = tmp_lane_10015a0_21_27_1 + r2sleigh_float_from_bits_64(tmp_d400_8);
xmm0_13 = (__uint128_t)(((__uint128_t)xmm0_12 & (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0U)) | ((__uint128_t)r2sleigh_float_to_bits_64(tmp_lane_10015a0_26_29_1) & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffffffffffULL)) << 0U);
rcx_4 = (uint64_t)((uint64_t)rcx_3 + (uint64_t)8U);
if ((uint8_t)((uint64_t)rdx_2 != (uint64_t)rcx_4)) {
@@ -199,13 +199,13 @@ double loop_sum(const double* v, int32_t n)
xmm0_14 = (__uint128_t)(((__uint128_t)xmm0_1 & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffffffffffULL)) | ((__uint128_t)(uint64_t)0U & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffffffffffULL)) << 64U);
}
{
tmp_4a00_2 = (uint64_t)((uint64_t)((uint64_t)rcx_5 * (uint64_t)8U) + (uint64_t)v);
tmp_9400_2 = (uint64_t)((uint64_t)((uint64_t)rcx_5 * (uint64_t)8U) + (uint64_t)v);
rdx_5 = 0;
xmm0_15 = xmm0_14;
for (; ; ) {
tmp_6b00_9 = r2sleigh_load_u64((void*)(uint64_t)((uint64_t)((uint64_t)rdx_5 * (uint64_t)8U) + (uint64_t)tmp_4a00_2));
tmp_d400_9 = r2sleigh_load_u64((void*)(uint64_t)((uint64_t)((uint64_t)rdx_5 * (uint64_t)8U) + (uint64_t)tmp_9400_2));
tmp_lane_10015f0_3_2d_1 = (uint64_t)((__uint128_t)xmm0_15 >> 0U);
tmp_lane_10015f0_3_2e_1 = r2sleigh_float_from_bits_64(tmp_lane_10015f0_3_2d_1) + r2sleigh_float_from_bits_64(tmp_6b00_9);
tmp_lane_10015f0_3_2e_1 = r2sleigh_float_from_bits_64(tmp_lane_10015f0_3_2d_1) + r2sleigh_float_from_bits_64(tmp_d400_9);
xmm0_16 = (__uint128_t)(((__uint128_t)xmm0_15 & (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0U)) | ((__uint128_t)r2sleigh_float_to_bits_64(tmp_lane_10015f0_3_2e_1) & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffffffffffULL)) << 0U);
rdx_6 = (uint64_t)((uint64_t)rdx_5 + (uint64_t)1U);
if ((uint8_t)((uint64_t)rax_2 != (uint64_t)rdx_6)) {
@@ -242,7 +242,7 @@ int32_t main(int32_t argc, char** argv)
double tmp_lane_1001600_d_1_1;
__uint128_t xmm0_2;
__uint128_t xmm0_3;
uint64_t tmp_6b00_4;
uint64_t tmp_d400_4;
uint64_t tmp_lane_1001600_23_4_1;
_Alignas(16) uint8_t frame[56];
@@ -254,9 +254,9 @@ int32_t main(int32_t argc, char** argv)
xmm0_2 = (__uint128_t)r2sleigh_float_to_bits_64(twice_half(tmp_lane_1001600_d_1_1));
r2sleigh_store_u64((void*)(uint64_t)(frame + 40U), (uint64_t)((__uint128_t)xmm0_2 >> 0U));
xmm0_3 = (__uint128_t)r2sleigh_float_to_bits_64(loop_sum((const double*)(uint64_t)(frame + 16U), 2));
tmp_6b00_4 = r2sleigh_load_u64((void*)(uint64_t)(frame + 40U));
tmp_d400_4 = r2sleigh_load_u64((void*)(uint64_t)(frame + 40U));
tmp_lane_1001600_23_4_1 = (uint64_t)((__uint128_t)xmm0_3 >> 0U);
return (int32_t)(r2sleigh_float_from_bits_64(tmp_lane_1001600_23_4_1) + r2sleigh_float_from_bits_64(tmp_6b00_4) > -2147483649.0 && r2sleigh_float_from_bits_64(tmp_lane_1001600_23_4_1) + r2sleigh_float_from_bits_64(tmp_6b00_4) < 2147483648.0 ? (int32_t)(r2sleigh_float_from_bits_64(tmp_lane_1001600_23_4_1) + r2sleigh_float_from_bits_64(tmp_6b00_4)) : r2sleigh_residual_i32(1));
return (int32_t)(r2sleigh_float_from_bits_64(tmp_lane_1001600_23_4_1) + r2sleigh_float_from_bits_64(tmp_d400_4) > -2147483649.0 && r2sleigh_float_from_bits_64(tmp_lane_1001600_23_4_1) + r2sleigh_float_from_bits_64(tmp_d400_4) < 2147483648.0 ? (int32_t)(r2sleigh_float_from_bits_64(tmp_lane_1001600_23_4_1) + r2sleigh_float_from_bits_64(tmp_d400_4)) : r2sleigh_residual_i32(1));
}
}
@@ -273,7 +273,7 @@ void __libc_csu_init(int32_t argc, char** argv, char** envp)
{
uint64_t r12_2;
uint64_t r13_5;
uint64_t tmp_11f80_1;
uint64_t tmp_23d00_1;
uint64_t r13_6;
/* r2dec proof: 2 constructs are marked below; 61 source obligations: 22 rendered, 30 elided, 0 refused, 9 residual; 11 statements rendered */
@@ -283,7 +283,7 @@ void __libc_csu_init(int32_t argc, char** argv, char** envp)
r12_2 = 0x1000000;
r13_5 = 1;
for (; ; ) {
tmp_11f80_1 = r2sleigh_load_u64((void*)r12_2);
tmp_23d00_1 = r2sleigh_load_u64((void*)r12_2);
r2sleigh_residual_void(1); /* r2dec gap: CallNotRendered at 0x1001690:13 covering 1 op (render::values): call to an indirect target: no arity is stated, only the registers written before it */
r2sleigh_residual_void(2); /* r2dec gap: EffectNotRendered at 0x1001690:19 covering 1 op (render::values) */
r13_6 = (uint64_t)((uint64_t)r13_5 - (uint64_t)1U);
+24 -24
View File
@@ -68,11 +68,11 @@ CMDS=aa; pdd @ 0x00001040
EXPECT=<<EOF
void _start(void)
{
uint64_t tmp_55400_2;
uint64_t tmp_aa300_2;
/* r2dec proof: 5 constructs are marked below; 28 source obligations: 0 rendered, 6 elided, 0 refused, 22 residual; 1 statements rendered; 1 held from entry, read as residuals (stack_p0) */
{
tmp_55400_2 = r2sleigh_residual_u64(1);
tmp_aa300_2 = r2sleigh_residual_u64(1);
r2sleigh_residual_void(2); /* r2dec gap: StoreNotSpelled at 0x1040:29 covering 1 op (render::values) */
r2sleigh_residual_void(3); /* r2dec gap: StoreNotSpelled at 0x1040:32 covering 1 op (render::values) */
r2sleigh_residual_void(4); /* r2dec gap: CallNotRendered at 0x1040:68 covering 1 op (render::values): call to __libc_start_main: the import's declaration has an argument this convention does not place */
@@ -159,18 +159,18 @@ uint64_t __do_global_dtors_aux(void)
extern char __dso_handle[];
extern char __TMC_END__[];
uint8_t tmp_3e180_1;
uint64_t tmp_3ea80_1;
uint8_t tmp_7c100_1;
uint64_t tmp_7d300_1;
uint64_t rdi_1;
/* r2dec proof: 3 constructs are marked below; 40 source obligations: 16 rendered, 17 elided, 0 refused, 7 residual; 9 statements rendered; 2 data object types refused; 1 callee prototype supplied by the source */
{
tmp_3e180_1 = r2sleigh_load_u8((void*)&__TMC_END__);
if ((uint8_t)((uint8_t)tmp_3e180_1 != (uint8_t)0U)) {
tmp_7c100_1 = r2sleigh_load_u8((void*)&__TMC_END__);
if ((uint8_t)((uint8_t)tmp_7c100_1 != (uint8_t)0U)) {
return r2sleigh_residual_u64(1);
} else {
tmp_3ea80_1 = r2sleigh_load_u64((void*)(uint64_t)0x3fe0U);
if ((uint8_t)((uint64_t)tmp_3ea80_1 == (uint64_t)0U)) {
tmp_7d300_1 = r2sleigh_load_u64((void*)(uint64_t)0x3fe0U);
if ((uint8_t)((uint64_t)tmp_7d300_1 == (uint64_t)0U)) {
} else {
rdi_1 = r2sleigh_load_u64((void*)&__dso_handle);
__cxa_finalize((void*)rdi_1);
@@ -214,12 +214,12 @@ CMDS=aa; pdd @ 0x00001130
EXPECT=<<EOF
int32_t counter(void)
{
uint32_t tmp_11f00_1;
uint32_t tmp_6a80_3;
uint32_t tmp_11f00_2;
uint64_t tmp_11f80_3;
uint32_t tmp_11f00_3;
uint64_t tmp_11f80_4;
uint32_t tmp_23c00_1;
uint32_t tmp_d300_3;
uint32_t tmp_23c00_2;
uint64_t tmp_23d00_3;
uint32_t tmp_23c00_3;
uint64_t tmp_23d00_4;
_Alignas(16) uint8_t frame[40];
/* r2dec proof: no individual construct is marked; 44 source obligations: 27 rendered, 17 elided, 0 refused; 15 statements rendered */
@@ -228,21 +228,21 @@ int32_t counter(void)
r2sleigh_store_u64((void*)(uint64_t)(frame + 16U), (uint64_t)10U);
r2sleigh_store_u32((void*)(uint64_t)(frame + 12U), (uint32_t)0U);
for (; ; ) {
tmp_11f00_1 = r2sleigh_load_u32((void*)(uint64_t)(frame + 12U));
tmp_6a80_3 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
if ((uint8_t)((int32_t)tmp_6a80_3 <= (int32_t)tmp_11f00_1)) {
tmp_23c00_1 = r2sleigh_load_u32((void*)(uint64_t)(frame + 12U));
tmp_d300_3 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
if ((uint8_t)((int32_t)tmp_d300_3 <= (int32_t)tmp_23c00_1)) {
break;
} else {
tmp_11f00_2 = r2sleigh_load_u32((void*)(uint64_t)(frame + 12U));
tmp_11f80_3 = r2sleigh_load_u64((void*)(uint64_t)(frame + 16U));
r2sleigh_store_u64((void*)(uint64_t)(frame + 16U), (uint64_t)((uint64_t)(int32_t)tmp_11f00_2 + (uint64_t)tmp_11f80_3));
tmp_11f00_3 = r2sleigh_load_u32((void*)(uint64_t)(frame + 12U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 12U), (uint32_t)((uint32_t)tmp_11f00_3 + (uint32_t)1U));
tmp_23c00_2 = r2sleigh_load_u32((void*)(uint64_t)(frame + 12U));
tmp_23d00_3 = r2sleigh_load_u64((void*)(uint64_t)(frame + 16U));
r2sleigh_store_u64((void*)(uint64_t)(frame + 16U), (uint64_t)((uint64_t)(int32_t)tmp_23c00_2 + (uint64_t)tmp_23d00_3));
tmp_23c00_3 = r2sleigh_load_u32((void*)(uint64_t)(frame + 12U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 12U), (uint32_t)((uint32_t)tmp_23c00_3 + (uint32_t)1U));
}
}
{
tmp_11f80_4 = r2sleigh_load_u64((void*)(uint64_t)(frame + 16U));
return (int32_t)tmp_11f80_4;
tmp_23d00_4 = r2sleigh_load_u64((void*)(uint64_t)(frame + 16U));
return (int32_t)tmp_23d00_4;
}
}
}
+114 -114
View File
@@ -157,11 +157,11 @@ CMDS=aa; pdd @ 0x00401240
EXPECT=<<EOF
void _start(void)
{
uint64_t tmp_55400_2;
uint64_t tmp_aa300_2;
/* r2dec proof: 5 constructs are marked below; 28 source obligations: 0 rendered, 6 elided, 0 refused, 22 residual; 1 statements rendered; 1 held from entry, read as residuals (stack_p0) */
{
tmp_55400_2 = r2sleigh_residual_u64(1);
tmp_aa300_2 = r2sleigh_residual_u64(1);
r2sleigh_residual_void(2); /* r2dec gap: StoreNotSpelled at 0x401240:29 covering 1 op (render::values) */
r2sleigh_residual_void(3); /* r2dec gap: StoreNotSpelled at 0x401240:32 covering 1 op (render::values) */
r2sleigh_residual_void(4); /* r2dec gap: CallNotRendered at 0x401240:68 covering 1 op (render::values): call to __libc_start_main: the import's declaration has an argument this convention does not place */
@@ -260,12 +260,12 @@ uint64_t __do_global_dtors_aux(void)
void deregister_tm_clones(void);
extern char completed_0[];
uint8_t tmp_3e180_1;
uint8_t tmp_7c100_1;
/* r2dec proof: 2 constructs are marked below; 24 source obligations: 8 rendered, 12 elided, 0 refused, 4 residual; 6 statements rendered; 1 data object type refused */
{
tmp_3e180_1 = r2sleigh_load_u8((void*)&completed_0);
if ((uint8_t)((uint8_t)tmp_3e180_1 != (uint8_t)0U)) {
tmp_7c100_1 = r2sleigh_load_u8((void*)&completed_0);
if ((uint8_t)((uint8_t)tmp_7c100_1 != (uint8_t)0U)) {
return r2sleigh_residual_u64(1);
} else {
deregister_tm_clones();
@@ -308,7 +308,7 @@ uint64_t fnv1a32(uint64_t arg0, uint64_t arg1)
uint64_t rsi_1;
uint64_t rax_2;
uint64_t rdi_1;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rdi_2;
uint64_t rax_4;
@@ -321,9 +321,9 @@ uint64_t fnv1a32(uint64_t arg0, uint64_t arg1)
rax_2 = (uint64_t)0x811c9dc5U;
rdi_1 = arg0;
for (; ; ) {
tmp_11e00_1 = r2sleigh_load_u8((void*)rdi_1);
tmp_23a00_1 = r2sleigh_load_u8((void*)rdi_1);
rdi_2 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)1U);
rax_4 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)(uint8_t)tmp_11e00_1 ^ (uint32_t)((uint64_t)rax_2 >> 0U)) * (uint64_t)0x1000193U) >> 0U);
rax_4 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)(uint8_t)tmp_23a00_1 ^ (uint32_t)((uint64_t)rax_2 >> 0U)) * (uint64_t)0x1000193U) >> 0U);
if ((uint8_t)((uint64_t)rsi_1 != (uint64_t)rdi_2)) {
rax_2 = rax_4;
rdi_1 = rdi_2;
@@ -352,7 +352,7 @@ uint64_t fnv1a64(uint64_t arg0, uint64_t arg1)
uint64_t rsi_1;
uint64_t rax_2;
uint64_t rdi_1;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rdi_2;
uint64_t rax_4;
uint64_t rax_5;
@@ -366,9 +366,9 @@ uint64_t fnv1a64(uint64_t arg0, uint64_t arg1)
rax_2 = (uint64_t)0xcbf29ce484222325U;
rdi_1 = arg0;
for (; ; ) {
tmp_11e00_1 = r2sleigh_load_u8((void*)rdi_1);
tmp_23a00_1 = r2sleigh_load_u8((void*)rdi_1);
rdi_2 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)1U);
rax_4 = (uint64_t)((uint64_t)((uint64_t)rax_2 ^ (uint64_t)(uint8_t)tmp_11e00_1) * (uint64_t)0x100000001b3U);
rax_4 = (uint64_t)((uint64_t)((uint64_t)rax_2 ^ (uint64_t)(uint8_t)tmp_23a00_1) * (uint64_t)0x100000001b3U);
if ((uint8_t)((uint64_t)rsi_1 != (uint64_t)rdi_2)) {
rax_2 = rax_4;
rdi_1 = rdi_2;
@@ -399,7 +399,7 @@ uint64_t djb2(uint64_t arg0, uint64_t arg1)
uint64_t rax_2;
uint64_t rdi_1;
uint64_t rdi_2;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rax_4;
/* r2dec proof: no individual construct is marked; 41 source obligations: 33 rendered, 8 elided, 0 refused; 14 statements rendered */
@@ -412,8 +412,8 @@ uint64_t djb2(uint64_t arg0, uint64_t arg1)
rdi_1 = arg0;
for (; ; ) {
rdi_2 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)1U);
tmp_11e00_1 = r2sleigh_load_u8((void*)(uint64_t)((uint64_t)rdi_2 - (uint64_t)1U));
rax_4 = (uint64_t)(uint32_t)((uint32_t)(uint8_t)tmp_11e00_1 + (uint32_t)((uint32_t)((uint32_t)((uint64_t)rax_2 >> 0U) * (uint32_t)32U) + (uint32_t)((uint64_t)rax_2 >> 0U)));
tmp_23a00_1 = r2sleigh_load_u8((void*)(uint64_t)((uint64_t)rdi_2 - (uint64_t)1U));
rax_4 = (uint64_t)(uint32_t)((uint32_t)(uint8_t)tmp_23a00_1 + (uint32_t)((uint32_t)((uint32_t)((uint64_t)rax_2 >> 0U) * (uint32_t)32U) + (uint32_t)((uint64_t)rax_2 >> 0U)));
if ((uint8_t)((uint64_t)rdi_2 != (uint64_t)rsi_1)) {
rax_2 = rax_4;
rdi_1 = rdi_2;
@@ -442,7 +442,7 @@ uint32_t sdbm(uint64_t arg0, uint64_t arg1)
uint64_t rsi_1;
uint64_t rax_2;
uint64_t rdi_1;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rdi_2;
uint32_t tmp_lane_401400_17_8_1;
@@ -455,9 +455,9 @@ uint32_t sdbm(uint64_t arg0, uint64_t arg1)
rax_2 = 0;
rdi_1 = arg0;
for (; ; ) {
tmp_11e00_1 = r2sleigh_load_u8((void*)rdi_1);
tmp_23a00_1 = r2sleigh_load_u8((void*)rdi_1);
rdi_2 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)1U);
tmp_lane_401400_17_8_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)((uint64_t)rax_2 >> 0U) * (uint64_t)0x1003fU) >> 0U) + (uint32_t)(uint8_t)tmp_11e00_1);
tmp_lane_401400_17_8_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)((uint64_t)rax_2 >> 0U) * (uint64_t)0x1003fU) >> 0U) + (uint32_t)(uint8_t)tmp_23a00_1);
if ((uint8_t)((uint64_t)rsi_1 != (uint64_t)rdi_2)) {
rax_2 = (uint64_t)(uint32_t)tmp_lane_401400_17_8_1;
rdi_1 = rdi_2;
@@ -487,7 +487,7 @@ uint64_t adler32(uint64_t arg0, uint64_t arg1)
uint64_t rax_2;
uint64_t rdi_1;
uint64_t rdx_2;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rdi_2;
uint64_t rdx_3;
uint32_t tmp_lane_401440_4f_c_1;
@@ -504,9 +504,9 @@ uint64_t adler32(uint64_t arg0, uint64_t arg1)
rdi_1 = arg0;
rdx_2 = 1;
for (; ; ) {
tmp_11e00_1 = r2sleigh_load_u8((void*)rdi_1);
tmp_23a00_1 = r2sleigh_load_u8((void*)rdi_1);
rdi_2 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)1U);
rdx_3 = (uint64_t)(uint32_t)((uint32_t)(uint8_t)tmp_11e00_1 + (uint32_t)((uint64_t)rdx_2 >> 0U));
rdx_3 = (uint64_t)(uint32_t)((uint32_t)(uint8_t)tmp_23a00_1 + (uint32_t)((uint64_t)rdx_2 >> 0U));
tmp_lane_401440_4f_c_1 = (uint32_t)((uint32_t)((uint64_t)rdx_3 >> 0U) - (uint32_t)((uint64_t)((uint64_t)(int32_t)((uint64_t)((uint64_t)(uint32_t)47U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)((uint64_t)rdx_3 * (uint64_t)0x80078071U) >> (uint64_t)(uint32_t)47U)) >> 0U) * (uint64_t)0xfff1U) >> 0U));
rax_4 = (uint64_t)(uint32_t)((uint32_t)((uint64_t)rax_2 >> 0U) + (uint32_t)tmp_lane_401440_4f_c_1);
tmp_lane_401440_a0_1c_1 = (uint32_t)((uint32_t)((uint64_t)rax_4 >> 0U) - (uint32_t)((uint64_t)((uint64_t)(int32_t)((uint64_t)((uint64_t)(uint32_t)47U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)((uint64_t)rax_4 * (uint64_t)0x80078071U) >> (uint64_t)(uint32_t)47U)) >> 0U) * (uint64_t)0xfff1U) >> 0U));
@@ -536,11 +536,11 @@ CMDS=aa; pdd @ 0x004014a0
EXPECT=<<EOF
uint64_t fletcher32(uint64_t arg0, uint64_t arg1)
{
uint64_t tmp_4a00_1;
uint64_t tmp_9400_1;
uint64_t rax_2;
uint64_t rdi_1;
uint64_t rdx_2;
uint16_t tmp_11e80_1;
uint16_t tmp_23b00_1;
uint64_t rdi_2;
uint64_t r8_1;
uint64_t rdx_8;
@@ -554,20 +554,20 @@ uint64_t fletcher32(uint64_t arg0, uint64_t arg1)
if ((uint8_t)((uint64_t)arg1 == (uint64_t)0U)) {
return (uint64_t)0xffffffffU;
} else {
tmp_4a00_1 = (uint64_t)((uint64_t)((uint64_t)arg1 * (uint64_t)2U) + (uint64_t)arg0);
tmp_9400_1 = (uint64_t)((uint64_t)((uint64_t)arg1 * (uint64_t)2U) + (uint64_t)arg0);
rax_2 = 0xffff;
rdi_1 = arg0;
rdx_2 = 0xffff;
for (; ; ) {
tmp_11e80_1 = r2sleigh_load_u16((void*)rdi_1);
tmp_23b00_1 = r2sleigh_load_u16((void*)rdi_1);
rdi_2 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)2U);
r8_1 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)rdx_2 + (uint64_t)(uint16_t)tmp_11e80_1) >> 0U);
r8_1 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)rdx_2 + (uint64_t)(uint16_t)tmp_23b00_1) >> 0U);
rdx_8 = (uint64_t)(uint32_t)47U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)((uint64_t)r8_1 + (uint64_t)((uint64_t)((uint64_t)r8_1 + (uint64_t)((uint64_t)r8_1 * (uint64_t)0x10000U)) * (uint64_t)0x8000U)) >> (uint64_t)(uint32_t)47U);
tmp_lane_4014c0_c7_d_1 = (uint32_t)((uint32_t)((uint32_t)((uint64_t)rdx_8 >> 0U) + (uint32_t)((uint64_t)r8_1 >> 0U)) - (uint32_t)((uint32_t)((uint64_t)rdx_8 >> 0U) * (uint32_t)0x10000U));
rcx_4 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)(uint32_t)tmp_lane_4014c0_c7_d_1 + (uint64_t)rax_2) >> 0U);
rax_8 = (uint64_t)(uint32_t)47U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)((uint64_t)rcx_4 + (uint64_t)((uint64_t)((uint64_t)rcx_4 + (uint64_t)((uint64_t)rcx_4 * (uint64_t)0x10000U)) * (uint64_t)0x8000U)) >> (uint64_t)(uint32_t)47U);
tmp_lane_4014c0_18e_1f_1 = (uint32_t)((uint32_t)((uint32_t)((uint64_t)rax_8 >> 0U) + (uint32_t)((uint64_t)rcx_4 >> 0U)) - (uint32_t)((uint32_t)((uint64_t)rax_8 >> 0U) * (uint32_t)0x10000U));
if ((uint8_t)((uint64_t)tmp_4a00_1 != (uint64_t)rdi_2)) {
if ((uint8_t)((uint64_t)tmp_9400_1 != (uint64_t)rdi_2)) {
rax_2 = (uint64_t)(uint32_t)tmp_lane_4014c0_18e_1f_1;
rdi_1 = rdi_2;
rdx_2 = (uint64_t)(uint32_t)tmp_lane_4014c0_c7_d_1;
@@ -596,7 +596,7 @@ uint32_t crc32_bitwise(uint64_t arg0, uint64_t arg1)
uint64_t rsi_1;
uint64_t rax_2;
uint64_t rdi_1;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rax_4;
uint64_t rdx_3;
uint32_t tmp_lane_401558_2d_14_1;
@@ -613,8 +613,8 @@ uint32_t crc32_bitwise(uint64_t arg0, uint64_t arg1)
rax_2 = (uint64_t)0xffffffffU;
rdi_1 = arg0;
for (; ; ) {
tmp_11e00_1 = r2sleigh_load_u8((void*)rdi_1);
rax_4 = (uint64_t)(uint32_t)((uint32_t)(uint8_t)tmp_11e00_1 ^ (uint32_t)((uint64_t)rax_2 >> 0U));
tmp_23a00_1 = r2sleigh_load_u8((void*)rdi_1);
rax_4 = (uint64_t)(uint32_t)((uint32_t)(uint8_t)tmp_23a00_1 ^ (uint32_t)((uint64_t)rax_2 >> 0U));
rdx_3 = 8;
for (; ; ) {
tmp_lane_401558_2d_14_1 = (uint32_t)((uint32_t)((uint32_t)1U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)((uint64_t)rax_4 >> 0U) >> (uint32_t)1U)) ^ (uint32_t)((uint32_t)((uint32_t)0U - (uint32_t)((uint32_t)((uint64_t)rax_4 >> 0U) & (uint32_t)1U)) & (uint32_t)0xedb88320U));
@@ -1047,9 +1047,9 @@ uint32_t crc32_table(uint64_t arg0, uint64_t arg1)
uint64_t rsi_1;
uint64_t rax_2;
uint64_t rdi_1;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rdi_2;
uint32_t tmp_11f00_1;
uint32_t tmp_23c00_1;
uint32_t tmp_lane_401648_43_b_1;
/* r2dec proof: no individual construct is marked; 48 source obligations: 40 rendered, 8 elided, 0 refused; 15 statements rendered; 1 data object type refused */
@@ -1061,10 +1061,10 @@ uint32_t crc32_table(uint64_t arg0, uint64_t arg1)
rax_2 = (uint64_t)0xffffffffU;
rdi_1 = arg0;
for (; ; ) {
tmp_11e00_1 = r2sleigh_load_u8((void*)rdi_1);
tmp_23a00_1 = r2sleigh_load_u8((void*)rdi_1);
rdi_2 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)1U);
tmp_11f00_1 = r2sleigh_load_u32((void*)((uint64_t)((uint64_t)(uint8_t)((uint32_t)((uint32_t)(uint8_t)tmp_11e00_1 ^ (uint32_t)((uint64_t)rax_2 >> 0U)) >> 0U) * (uint64_t)4U) + (uint64_t)&crc_tab));
tmp_lane_401648_43_b_1 = (uint32_t)((uint32_t)((uint32_t)8U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)((uint64_t)rax_2 >> 0U) >> (uint32_t)8U)) ^ (uint32_t)tmp_11f00_1);
tmp_23c00_1 = r2sleigh_load_u32((void*)((uint64_t)((uint64_t)(uint8_t)((uint32_t)((uint32_t)(uint8_t)tmp_23a00_1 ^ (uint32_t)((uint64_t)rax_2 >> 0U)) >> 0U) * (uint64_t)4U) + (uint64_t)&crc_tab));
tmp_lane_401648_43_b_1 = (uint32_t)((uint32_t)((uint32_t)8U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)((uint64_t)rax_2 >> 0U) >> (uint32_t)8U)) ^ (uint32_t)tmp_23c00_1);
if ((uint8_t)((uint64_t)rsi_1 != (uint64_t)rdi_2)) {
rax_2 = (uint64_t)(uint32_t)tmp_lane_401648_43_b_1;
rdi_1 = rdi_2;
@@ -1092,10 +1092,10 @@ uint32_t murmur3_32(uint8_t* arg0, uint64_t arg1, uint32_t arg2)
{
uint64_t rcx_1;
uint64_t rax_2;
uint64_t tmp_4a00_1;
uint64_t tmp_9400_1;
uint64_t rcx_2;
uint64_t rdx_2;
uint32_t tmp_11f00_1;
uint32_t tmp_23c00_1;
uint32_t tmp_lane_4016a0_4_2_1;
uint64_t rdx_3;
uint32_t tmp_lane_4016a0_32_9_1;
@@ -1104,11 +1104,11 @@ uint32_t murmur3_32(uint8_t* arg0, uint64_t arg1, uint32_t arg2)
uint64_t rcx_4;
uint64_t rdi_1;
uint64_t rax_11;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rax_26;
uint8_t tmp_11e00_3;
uint8_t tmp_23a00_3;
uint64_t rdx_6;
uint8_t tmp_11e00_2;
uint8_t tmp_23a00_2;
uint32_t tmp_lane_4016e8_10_1e_1;
uint64_t rcx_6;
uint32_t tmp_lane_4016fe_2_29_1;
@@ -1122,17 +1122,17 @@ uint32_t murmur3_32(uint8_t* arg0, uint64_t arg1, uint32_t arg2)
if ((uint8_t)((uint64_t)rax_2 == (uint64_t)0U)) {
rcx_4 = rcx_1;
} else {
tmp_4a00_1 = (uint64_t)((uint64_t)((uint64_t)rax_2 * (uint64_t)4U) + (uint64_t)arg0);
tmp_9400_1 = (uint64_t)((uint64_t)((uint64_t)rax_2 * (uint64_t)4U) + (uint64_t)arg0);
rcx_2 = rcx_1;
rdx_2 = (uint64_t)arg0;
for (; ; ) {
tmp_11f00_1 = r2sleigh_load_u32((void*)rdx_2);
tmp_lane_4016a0_4_2_1 = (uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_11f00_1 * (uint64_t)0xffffffffcc9e2d51U) >> 0U);
tmp_23c00_1 = r2sleigh_load_u32((void*)rdx_2);
tmp_lane_4016a0_4_2_1 = (uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_23c00_1 * (uint64_t)0xffffffffcc9e2d51U) >> 0U);
rdx_3 = (uint64_t)((uint64_t)rdx_2 + (uint64_t)4U);
tmp_lane_4016a0_32_9_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)((uint32_t)15U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_4016a0_4_2_1 << (uint32_t)15U)) | (uint32_t)((uint32_t)17U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_4016a0_4_2_1 >> (uint32_t)17U))) * (uint64_t)0x1b873593U) >> 0U) ^ (uint32_t)((uint64_t)rcx_2 >> 0U));
rax_7 = (uint64_t)(uint32_t)((uint32_t)((uint32_t)13U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_4016a0_32_9_1 << (uint32_t)13U)) | (uint32_t)((uint32_t)19U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_4016a0_32_9_1 >> (uint32_t)19U)));
rcx_3 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)((uint64_t)rax_7 + (uint64_t)((uint64_t)rax_7 * (uint64_t)4U)) - (uint64_t)0x19ab949cU) >> 0U);
if ((uint8_t)((uint64_t)tmp_4a00_1 != (uint64_t)rdx_3)) {
if ((uint8_t)((uint64_t)tmp_9400_1 != (uint64_t)rdx_3)) {
rcx_2 = rcx_3;
rdx_2 = rdx_3;
} else {
@@ -1147,16 +1147,16 @@ uint32_t murmur3_32(uint8_t* arg0, uint64_t arg1, uint32_t arg2)
if ((uint8_t)((uint64_t)rax_11 == (uint64_t)2U)) {
rax_26 = 0;
{
tmp_11e00_3 = r2sleigh_load_u8((void*)((uint64_t)rdi_1 + (uint64_t)1U * 1U));
rdx_6 = (uint64_t)(uint32_t)((uint32_t)((uint32_t)8U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)(uint8_t)tmp_11e00_3 << (uint32_t)8U)) ^ (uint32_t)((uint64_t)rax_26 >> 0U));
tmp_23a00_3 = r2sleigh_load_u8((void*)((uint64_t)rdi_1 + (uint64_t)1U * 1U));
rdx_6 = (uint64_t)(uint32_t)((uint32_t)((uint32_t)8U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)(uint8_t)tmp_23a00_3 << (uint32_t)8U)) ^ (uint32_t)((uint64_t)rax_26 >> 0U));
}
} else {
if ((uint8_t)((uint64_t)rax_11 == (uint64_t)3U)) {
tmp_11e00_1 = r2sleigh_load_u8((void*)((uint64_t)rdi_1 + (uint64_t)2U * 1U));
rax_26 = (uint64_t)(uint32_t)((uint32_t)16U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)(uint8_t)tmp_11e00_1 << (uint32_t)16U));
tmp_23a00_1 = r2sleigh_load_u8((void*)((uint64_t)rdi_1 + (uint64_t)2U * 1U));
rax_26 = (uint64_t)(uint32_t)((uint32_t)16U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)(uint8_t)tmp_23a00_1 << (uint32_t)16U));
{
tmp_11e00_3 = r2sleigh_load_u8((void*)((uint64_t)rdi_1 + (uint64_t)1U * 1U));
rdx_6 = (uint64_t)(uint32_t)((uint32_t)((uint32_t)8U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)(uint8_t)tmp_11e00_3 << (uint32_t)8U)) ^ (uint32_t)((uint64_t)rax_26 >> 0U));
tmp_23a00_3 = r2sleigh_load_u8((void*)((uint64_t)rdi_1 + (uint64_t)1U * 1U));
rdx_6 = (uint64_t)(uint32_t)((uint32_t)((uint32_t)8U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)(uint8_t)tmp_23a00_3 << (uint32_t)8U)) ^ (uint32_t)((uint64_t)rax_26 >> 0U));
}
} else {
if ((uint8_t)((uint64_t)rax_11 != (uint64_t)1U)) {
@@ -1168,8 +1168,8 @@ uint32_t murmur3_32(uint8_t* arg0, uint64_t arg1, uint32_t arg2)
}
}
{
tmp_11e00_2 = r2sleigh_load_u8((void*)rdi_1);
tmp_lane_4016e8_10_1e_1 = (uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)(uint8_t)tmp_11e00_2 ^ (uint32_t)((uint64_t)rdx_6 >> 0U)) * (uint64_t)0xffffffffcc9e2d51U) >> 0U);
tmp_23a00_2 = r2sleigh_load_u8((void*)rdi_1);
tmp_lane_4016e8_10_1e_1 = (uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)(uint8_t)tmp_23a00_2 ^ (uint32_t)((uint64_t)rdx_6 >> 0U)) * (uint64_t)0xffffffffcc9e2d51U) >> 0U);
rcx_6 = (uint64_t)(uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)((uint32_t)15U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_4016e8_10_1e_1 << (uint32_t)15U)) | (uint32_t)((uint32_t)17U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_4016e8_10_1e_1 >> (uint32_t)17U))) * (uint64_t)0x1b873593U) >> 0U) ^ (uint32_t)((uint64_t)rcx_4 >> 0U));
}
{
@@ -1196,32 +1196,32 @@ uint32_t xxhash32(uint64_t arg0, uint64_t arg1, uint32_t arg2)
{
uint64_t rdx_1;
uint64_t rsi_1;
uint64_t tmp_4700_1;
uint64_t tmp_8e00_1;
uint64_t r10_2;
uint64_t r11_2;
uint64_t r9_2;
uint64_t rax_2;
uint64_t rdx_2;
uint32_t tmp_11f00_1;
uint32_t tmp_23c00_1;
uint64_t rdx_3;
uint32_t tmp_lane_401788_15_8_1;
uint32_t tmp_lane_401788_34_d_1;
uint32_t tmp_11f00_2;
uint32_t tmp_23c00_2;
uint32_t tmp_lane_401788_47_11_1;
uint32_t tmp_11f00_3;
uint32_t tmp_23c00_3;
uint32_t tmp_lane_401788_71_17_1;
uint32_t tmp_lane_401788_79_1a_1;
uint32_t tmp_lane_401788_98_1f_1;
uint32_t tmp_11f00_4;
uint32_t tmp_23c00_4;
uint32_t tmp_lane_401788_ab_23_1;
uint32_t tmp_lane_401788_ca_28_1;
uint64_t rdi_2;
uint64_t rdx_11;
uint64_t rdx_12;
uint64_t tmp_4700_8;
uint64_t tmp_8e00_8;
uint64_t rcx_14;
uint64_t rdx_13;
uint32_t tmp_11f00_5;
uint32_t tmp_23c00_5;
uint64_t rcx_15;
uint32_t tmp_lane_401830_16_41_1;
uint64_t rdx_14;
@@ -1229,7 +1229,7 @@ uint32_t xxhash32(uint64_t arg0, uint64_t arg1, uint32_t arg2)
uint64_t rdx_15;
uint64_t rdi_5;
uint64_t rdx_16;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rdi_6;
uint32_t tmp_lane_40185f_17_4c_1;
uint64_t rdx_17;
@@ -1245,27 +1245,27 @@ uint32_t xxhash32(uint64_t arg0, uint64_t arg1, uint32_t arg2)
rdi_2 = arg0;
rdx_11 = (uint64_t)(uint32_t)((uint32_t)arg2 + (uint32_t)0x165667b1U);
} else {
tmp_4700_1 = (uint64_t)((uint64_t)rsi_1 - (uint64_t)16U);
tmp_8e00_1 = (uint64_t)((uint64_t)rsi_1 - (uint64_t)16U);
r10_2 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)rdx_1 + (uint64_t)0x61c8864fU) >> 0U);
r11_2 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)rdx_1 + (uint64_t)0x24234428U) >> 0U);
r9_2 = (uint64_t)(uint32_t)arg2;
rax_2 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)rdx_1 - (uint64_t)0x7a143589U) >> 0U);
rdx_2 = arg0;
for (; ; ) {
tmp_11f00_1 = r2sleigh_load_u32((void*)rdx_2);
tmp_23c00_1 = r2sleigh_load_u32((void*)rdx_2);
rdx_3 = (uint64_t)((uint64_t)rdx_2 + (uint64_t)16U);
tmp_lane_401788_15_8_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_11f00_1 * (uint64_t)0xffffffff85ebca77U) >> 0U) + (uint32_t)((uint64_t)r11_2 >> 0U));
tmp_lane_401788_15_8_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_23c00_1 * (uint64_t)0xffffffff85ebca77U) >> 0U) + (uint32_t)((uint64_t)r11_2 >> 0U));
tmp_lane_401788_34_d_1 = (uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)((uint32_t)13U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_401788_15_8_1 << (uint32_t)13U)) | (uint32_t)((uint32_t)19U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_401788_15_8_1 >> (uint32_t)19U))) * (uint64_t)0xffffffff9e3779b1U) >> 0U);
tmp_11f00_2 = r2sleigh_load_u32((void*)(uint64_t)((uint64_t)rdx_3 - (uint64_t)12U));
tmp_lane_401788_47_11_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_11f00_2 * (uint64_t)0xffffffff85ebca77U) >> 0U) + (uint32_t)((uint64_t)rax_2 >> 0U));
tmp_11f00_3 = r2sleigh_load_u32((void*)(uint64_t)((uint64_t)rdx_3 - (uint64_t)8U));
tmp_23c00_2 = r2sleigh_load_u32((void*)(uint64_t)((uint64_t)rdx_3 - (uint64_t)12U));
tmp_lane_401788_47_11_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_23c00_2 * (uint64_t)0xffffffff85ebca77U) >> 0U) + (uint32_t)((uint64_t)rax_2 >> 0U));
tmp_23c00_3 = r2sleigh_load_u32((void*)(uint64_t)((uint64_t)rdx_3 - (uint64_t)8U));
tmp_lane_401788_71_17_1 = (uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)((uint32_t)13U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_401788_47_11_1 << (uint32_t)13U)) | (uint32_t)((uint32_t)19U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_401788_47_11_1 >> (uint32_t)19U))) * (uint64_t)0xffffffff9e3779b1U) >> 0U);
tmp_lane_401788_79_1a_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_11f00_3 * (uint64_t)0xffffffff85ebca77U) >> 0U) + (uint32_t)((uint64_t)r9_2 >> 0U));
tmp_lane_401788_79_1a_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_23c00_3 * (uint64_t)0xffffffff85ebca77U) >> 0U) + (uint32_t)((uint64_t)r9_2 >> 0U));
tmp_lane_401788_98_1f_1 = (uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)((uint32_t)13U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_401788_79_1a_1 << (uint32_t)13U)) | (uint32_t)((uint32_t)19U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_401788_79_1a_1 >> (uint32_t)19U))) * (uint64_t)0xffffffff9e3779b1U) >> 0U);
tmp_11f00_4 = r2sleigh_load_u32((void*)(uint64_t)((uint64_t)rdx_3 - (uint64_t)4U));
tmp_lane_401788_ab_23_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_11f00_4 * (uint64_t)0xffffffff85ebca77U) >> 0U) + (uint32_t)((uint64_t)r10_2 >> 0U));
tmp_23c00_4 = r2sleigh_load_u32((void*)(uint64_t)((uint64_t)rdx_3 - (uint64_t)4U));
tmp_lane_401788_ab_23_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_23c00_4 * (uint64_t)0xffffffff85ebca77U) >> 0U) + (uint32_t)((uint64_t)r10_2 >> 0U));
tmp_lane_401788_ca_28_1 = (uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)((uint32_t)13U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_401788_ab_23_1 << (uint32_t)13U)) | (uint32_t)((uint32_t)19U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_401788_ab_23_1 >> (uint32_t)19U))) * (uint64_t)0xffffffff9e3779b1U) >> 0U);
if ((uint8_t)((uint64_t)rdx_3 <= (uint64_t)tmp_4700_1)) {
if ((uint8_t)((uint64_t)rdx_3 <= (uint64_t)tmp_8e00_1)) {
r10_2 = (uint64_t)(uint32_t)tmp_lane_401788_ca_28_1;
r11_2 = (uint64_t)(uint32_t)tmp_lane_401788_34_d_1;
r9_2 = (uint64_t)(uint32_t)tmp_lane_401788_98_1f_1;
@@ -1282,17 +1282,17 @@ uint32_t xxhash32(uint64_t arg0, uint64_t arg1, uint32_t arg2)
}
{
rdx_12 = (uint64_t)(uint32_t)((uint32_t)((uint64_t)rdx_11 >> 0U) + (uint32_t)((uint64_t)arg1 >> 0U));
tmp_4700_8 = (uint64_t)((uint64_t)rdi_2 + (uint64_t)4U);
if ((uint8_t)((uint64_t)rsi_1 < (uint64_t)tmp_4700_8)) {
tmp_8e00_8 = (uint64_t)((uint64_t)rdi_2 + (uint64_t)4U);
if ((uint8_t)((uint64_t)rsi_1 < (uint64_t)tmp_8e00_8)) {
rdi_4 = rdi_2;
rdx_15 = rdx_12;
} else {
rcx_14 = tmp_4700_8;
rcx_14 = tmp_8e00_8;
rdx_13 = rdx_12;
for (; ; ) {
tmp_11f00_5 = r2sleigh_load_u32((void*)(uint64_t)((uint64_t)rcx_14 - (uint64_t)4U));
tmp_23c00_5 = r2sleigh_load_u32((void*)(uint64_t)((uint64_t)rcx_14 - (uint64_t)4U));
rcx_15 = (uint64_t)((uint64_t)rcx_14 + (uint64_t)4U);
tmp_lane_401830_16_41_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_11f00_5 * (uint64_t)0xffffffffc2b2ae3dU) >> 0U) + (uint32_t)((uint64_t)rdx_13 >> 0U));
tmp_lane_401830_16_41_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_23c00_5 * (uint64_t)0xffffffffc2b2ae3dU) >> 0U) + (uint32_t)((uint64_t)rdx_13 >> 0U));
rdx_14 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)((uint32_t)15U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_401830_16_41_1 >> (uint32_t)15U)) | (uint32_t)((uint32_t)17U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_401830_16_41_1 << (uint32_t)17U))) * (uint64_t)0x27d4eb2fU) >> 0U);
if ((uint8_t)((uint64_t)rcx_15 <= (uint64_t)rsi_1)) {
rcx_14 = rcx_15;
@@ -1302,7 +1302,7 @@ uint32_t xxhash32(uint64_t arg0, uint64_t arg1, uint32_t arg2)
}
}
{
rdi_4 = (uint64_t)((uint64_t)tmp_4700_8 + (uint64_t)((uint64_t)((uint64_t)((uint64_t)rsi_1 - (uint64_t)rdi_2) - (uint64_t)4U) & (uint64_t)-0x4));
rdi_4 = (uint64_t)((uint64_t)tmp_8e00_8 + (uint64_t)((uint64_t)((uint64_t)((uint64_t)rsi_1 - (uint64_t)rdi_2) - (uint64_t)4U) & (uint64_t)-0x4));
rdx_15 = rdx_14;
}
}
@@ -1313,9 +1313,9 @@ uint32_t xxhash32(uint64_t arg0, uint64_t arg1, uint32_t arg2)
rdi_5 = rdi_4;
rdx_16 = rdx_15;
for (; ; ) {
tmp_11e00_1 = r2sleigh_load_u8((void*)rdi_5);
tmp_23a00_1 = r2sleigh_load_u8((void*)rdi_5);
rdi_6 = (uint64_t)((uint64_t)rdi_5 + (uint64_t)1U);
tmp_lane_40185f_17_4c_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(uint8_t)tmp_11e00_1 * (uint64_t)0x165667b1U) >> 0U) + (uint32_t)((uint64_t)rdx_16 >> 0U));
tmp_lane_40185f_17_4c_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(uint8_t)tmp_23a00_1 * (uint64_t)0x165667b1U) >> 0U) + (uint32_t)((uint64_t)rdx_16 >> 0U));
rdx_17 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)((uint32_t)11U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_40185f_17_4c_1 << (uint32_t)11U)) | (uint32_t)((uint32_t)21U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_40185f_17_4c_1 >> (uint32_t)21U))) * (uint64_t)0xffffffff9e3779b1U) >> 0U);
if ((uint8_t)((uint64_t)rsi_1 != (uint64_t)rdi_6)) {
rdi_5 = rdi_6;
@@ -1358,7 +1358,7 @@ uint64_t siphash24(uint8_t* arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3)
uint64_t rcx_2;
uint64_t rdi_1;
uint64_t rdx_2;
uint64_t tmp_11f80_1;
uint64_t tmp_23d00_1;
uint64_t rax_4;
uint64_t rdi_2;
uint64_t r11_5;
@@ -1384,27 +1384,27 @@ uint64_t siphash24(uint8_t* arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3)
uint64_t rcx_12;
uint64_t rdx_9;
uint32_t tmp_lane_40197a_2_1_1;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rsi_6;
uint8_t tmp_11e00_2;
uint8_t tmp_23a00_2;
uint64_t rsi_8;
uint8_t tmp_11e00_3;
uint8_t tmp_23a00_3;
uint64_t rsi_10;
uint8_t tmp_11e00_4;
uint8_t tmp_23a00_4;
uint64_t rsi_12;
uint8_t tmp_11e00_5;
uint8_t tmp_23a00_5;
uint64_t rsi_14;
uint8_t tmp_11e00_6;
uint8_t tmp_23a00_6;
uint64_t rsi_16;
uint8_t tmp_11e00_7;
uint8_t tmp_23a00_7;
uint64_t rsi_18;
uint64_t rcx_13;
uint64_t tmp_4a00_1;
uint64_t tmp_9400_1;
uint64_t rdx_10;
uint64_t r11_14;
uint64_t rcx_15;
uint64_t rdx_11;
uint64_t tmp_4a00_2;
uint64_t tmp_9400_2;
uint64_t rcx_17;
uint64_t rax_16;
uint64_t rdi_18;
@@ -1467,11 +1467,11 @@ uint64_t siphash24(uint8_t* arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3)
rdi_1 = (uint64_t)arg0;
rdx_2 = rdx_1;
for (; ; ) {
tmp_11f80_1 = r2sleigh_load_u64((void*)rdi_1);
tmp_23d00_1 = r2sleigh_load_u64((void*)rdi_1);
rax_4 = (uint64_t)((uint64_t)rax_3 + (uint64_t)r11_3);
rdi_2 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)8U);
r11_5 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)13U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)r11_3 << (uint64_t)(uint32_t)13U)) | (uint64_t)((uint64_t)(uint32_t)51U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)r11_3 >> (uint64_t)(uint32_t)51U))) ^ (uint64_t)rax_4);
rcx_3 = (uint64_t)((uint64_t)rcx_2 ^ (uint64_t)tmp_11f80_1);
rcx_3 = (uint64_t)((uint64_t)rcx_2 ^ (uint64_t)tmp_23d00_1);
rdx_3 = (uint64_t)((uint64_t)rdx_2 + (uint64_t)rcx_3);
rcx_5 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)16U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_3 << (uint64_t)(uint32_t)16U)) | (uint64_t)((uint64_t)(uint32_t)48U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_3 >> (uint64_t)(uint32_t)48U))) ^ (uint64_t)rdx_3);
rdx_4 = (uint64_t)((uint64_t)rdx_3 + (uint64_t)r11_5);
@@ -1487,7 +1487,7 @@ uint64_t siphash24(uint8_t* arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3)
r11_11 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)17U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)r11_9 << (uint64_t)(uint32_t)17U)) | (uint64_t)((uint64_t)(uint32_t)47U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)r11_9 >> (uint64_t)(uint32_t)47U))) ^ (uint64_t)rdx_7);
rcx_11 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)21U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_9 << (uint64_t)(uint32_t)21U)) | (uint64_t)((uint64_t)(uint32_t)43U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_9 >> (uint64_t)(uint32_t)43U))) ^ (uint64_t)rax_9);
rdx_8 = (uint64_t)((uint64_t)((uint64_t)(uint32_t)32U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rdx_7 << (uint64_t)(uint32_t)32U)) | (uint64_t)((uint64_t)(uint32_t)32U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rdx_7 >> (uint64_t)(uint32_t)32U)));
rax_10 = (uint64_t)((uint64_t)rax_9 ^ (uint64_t)tmp_11f80_1);
rax_10 = (uint64_t)((uint64_t)rax_9 ^ (uint64_t)tmp_23d00_1);
if ((uint8_t)((uint64_t)r10_3 != (uint64_t)rdi_2)) {
r11_3 = r11_11;
rax_3 = rax_10;
@@ -1508,8 +1508,8 @@ uint64_t siphash24(uint8_t* arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3)
switch (tmp_lane_40197a_2_1_1) {
case 7:
{
tmp_11e00_1 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)6U * 1U));
rsi_6 = (uint64_t)((uint64_t)rsi_4 | (uint64_t)((uint64_t)(uint32_t)48U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_11e00_1 << (uint64_t)(uint32_t)48U)));
tmp_23a00_1 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)6U * 1U));
rsi_6 = (uint64_t)((uint64_t)rsi_4 | (uint64_t)((uint64_t)(uint32_t)48U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_23a00_1 << (uint64_t)(uint32_t)48U)));
break;
}
case 6:
@@ -1535,46 +1535,46 @@ uint64_t siphash24(uint8_t* arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3)
goto L7;
}
{
tmp_11e00_2 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)5U * 1U));
rsi_8 = (uint64_t)((uint64_t)rsi_6 | (uint64_t)((uint64_t)(uint32_t)40U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_11e00_2 << (uint64_t)(uint32_t)40U)));
tmp_23a00_2 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)5U * 1U));
rsi_8 = (uint64_t)((uint64_t)rsi_6 | (uint64_t)((uint64_t)(uint32_t)40U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_23a00_2 << (uint64_t)(uint32_t)40U)));
}
{
L2: ;
tmp_11e00_3 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)4U * 1U));
rsi_10 = (uint64_t)((uint64_t)rsi_8 | (uint64_t)((uint64_t)(uint32_t)32U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_11e00_3 << (uint64_t)(uint32_t)32U)));
tmp_23a00_3 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)4U * 1U));
rsi_10 = (uint64_t)((uint64_t)rsi_8 | (uint64_t)((uint64_t)(uint32_t)32U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_23a00_3 << (uint64_t)(uint32_t)32U)));
}
{
L3: ;
tmp_11e00_4 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)3U * 1U));
rsi_12 = (uint64_t)((uint64_t)rsi_10 | (uint64_t)((uint64_t)(uint32_t)24U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_11e00_4 << (uint64_t)(uint32_t)24U)));
tmp_23a00_4 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)3U * 1U));
rsi_12 = (uint64_t)((uint64_t)rsi_10 | (uint64_t)((uint64_t)(uint32_t)24U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_23a00_4 << (uint64_t)(uint32_t)24U)));
}
{
L4: ;
tmp_11e00_5 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)2U * 1U));
rsi_14 = (uint64_t)((uint64_t)rsi_12 | (uint64_t)((uint64_t)(uint32_t)16U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_11e00_5 << (uint64_t)(uint32_t)16U)));
tmp_23a00_5 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)2U * 1U));
rsi_14 = (uint64_t)((uint64_t)rsi_12 | (uint64_t)((uint64_t)(uint32_t)16U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_23a00_5 << (uint64_t)(uint32_t)16U)));
}
{
L5: ;
tmp_11e00_6 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)1U * 1U));
rsi_16 = (uint64_t)((uint64_t)rsi_14 | (uint64_t)((uint64_t)(uint32_t)8U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_11e00_6 << (uint64_t)(uint32_t)8U)));
tmp_23a00_6 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)1U * 1U));
rsi_16 = (uint64_t)((uint64_t)rsi_14 | (uint64_t)((uint64_t)(uint32_t)8U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_23a00_6 << (uint64_t)(uint32_t)8U)));
}
{
L6: ;
tmp_11e00_7 = r2sleigh_load_u8((void*)r10_3);
rsi_18 = (uint64_t)((uint64_t)rsi_16 | (uint64_t)(uint8_t)tmp_11e00_7);
tmp_23a00_7 = r2sleigh_load_u8((void*)r10_3);
rsi_18 = (uint64_t)((uint64_t)rsi_16 | (uint64_t)(uint8_t)tmp_23a00_7);
}
{
L7: ;
rcx_13 = (uint64_t)((uint64_t)rcx_12 ^ (uint64_t)rsi_18);
tmp_4a00_1 = (uint64_t)((uint64_t)rax_11 + (uint64_t)r11_12);
tmp_9400_1 = (uint64_t)((uint64_t)rax_11 + (uint64_t)r11_12);
rdx_10 = (uint64_t)((uint64_t)rdx_9 + (uint64_t)rcx_13);
r11_14 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)13U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)r11_12 << (uint64_t)(uint32_t)13U)) | (uint64_t)((uint64_t)(uint32_t)51U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)r11_12 >> (uint64_t)(uint32_t)51U))) ^ (uint64_t)tmp_4a00_1);
r11_14 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)13U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)r11_12 << (uint64_t)(uint32_t)13U)) | (uint64_t)((uint64_t)(uint32_t)51U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)r11_12 >> (uint64_t)(uint32_t)51U))) ^ (uint64_t)tmp_9400_1);
rcx_15 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)16U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_13 << (uint64_t)(uint32_t)16U)) | (uint64_t)((uint64_t)(uint32_t)48U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_13 >> (uint64_t)(uint32_t)48U))) ^ (uint64_t)rdx_10);
rdx_11 = (uint64_t)((uint64_t)rdx_10 + (uint64_t)r11_14);
tmp_4a00_2 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)32U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)tmp_4a00_1 << (uint64_t)(uint32_t)32U)) | (uint64_t)((uint64_t)(uint32_t)32U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)tmp_4a00_1 >> (uint64_t)(uint32_t)32U))) + (uint64_t)rcx_15);
rcx_17 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)21U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_15 << (uint64_t)(uint32_t)21U)) | (uint64_t)((uint64_t)(uint32_t)43U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_15 >> (uint64_t)(uint32_t)43U))) ^ (uint64_t)tmp_4a00_2);
tmp_9400_2 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)32U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)tmp_9400_1 << (uint64_t)(uint32_t)32U)) | (uint64_t)((uint64_t)(uint32_t)32U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)tmp_9400_1 >> (uint64_t)(uint32_t)32U))) + (uint64_t)rcx_15);
rcx_17 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)21U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_15 << (uint64_t)(uint32_t)21U)) | (uint64_t)((uint64_t)(uint32_t)43U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_15 >> (uint64_t)(uint32_t)43U))) ^ (uint64_t)tmp_9400_2);
rax_16 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)17U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)r11_14 << (uint64_t)(uint32_t)17U)) | (uint64_t)((uint64_t)(uint32_t)47U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)r11_14 >> (uint64_t)(uint32_t)47U))) ^ (uint64_t)rdx_11);
rdi_18 = (uint64_t)((uint64_t)tmp_4a00_2 + (uint64_t)rax_16);
rdi_18 = (uint64_t)((uint64_t)tmp_9400_2 + (uint64_t)rax_16);
rdx_13 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)32U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rdx_11 << (uint64_t)(uint32_t)32U)) | (uint64_t)((uint64_t)(uint32_t)32U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rdx_11 >> (uint64_t)(uint32_t)32U))) + (uint64_t)rcx_17);
rax_18 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)13U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rax_16 << (uint64_t)(uint32_t)13U)) | (uint64_t)((uint64_t)(uint32_t)51U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rax_16 >> (uint64_t)(uint32_t)51U))) ^ (uint64_t)rdi_18);
rcx_19 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)16U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_17 << (uint64_t)(uint32_t)16U)) | (uint64_t)((uint64_t)(uint32_t)48U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_17 >> (uint64_t)(uint32_t)48U))) ^ (uint64_t)rdx_13);
@@ -1635,9 +1635,9 @@ uint32_t pearson(uint64_t arg0, uint64_t arg1)
uint64_t rsi_1;
uint64_t rax_2;
uint64_t rdi_1;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rdi_2;
uint8_t tmp_11e00_2;
uint8_t tmp_23a00_2;
uint32_t tmp_lane_401b20_17_7_1;
/* r2dec proof: no individual construct is marked; 42 source obligations: 34 rendered, 8 elided, 0 refused; 15 statements rendered; 1 data object type refused */
@@ -1649,10 +1649,10 @@ uint32_t pearson(uint64_t arg0, uint64_t arg1)
rax_2 = 0;
rdi_1 = arg0;
for (; ; ) {
tmp_11e00_1 = r2sleigh_load_u8((void*)rdi_1);
tmp_23a00_1 = r2sleigh_load_u8((void*)rdi_1);
rdi_2 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)1U);
tmp_11e00_2 = r2sleigh_load_u8((void*)((uint64_t)(uint8_t)((uint32_t)(uint8_t)((uint64_t)rax_2 >> 0U) ^ (uint32_t)tmp_11e00_1) + (uint64_t)&pearson_tab));
tmp_lane_401b20_17_7_1 = (uint32_t)(uint8_t)tmp_11e00_2;
tmp_23a00_2 = r2sleigh_load_u8((void*)((uint64_t)(uint8_t)((uint32_t)(uint8_t)((uint64_t)rax_2 >> 0U) ^ (uint32_t)tmp_23a00_1) + (uint64_t)&pearson_tab));
tmp_lane_401b20_17_7_1 = (uint32_t)(uint8_t)tmp_23a00_2;
if ((uint8_t)((uint64_t)rdi_2 != (uint64_t)rsi_1)) {
rax_2 = (uint64_t)(uint32_t)tmp_lane_401b20_17_7_1;
rdi_1 = rdi_2;
+114 -114
View File
@@ -155,11 +155,11 @@ CMDS=aa; pdd @ 0x00401240
EXPECT=<<EOF
void entry0(void)
{
uint64_t tmp_55400_2;
uint64_t tmp_aa300_2;
/* r2dec proof: 5 constructs are marked below; 28 source obligations: 0 rendered, 6 elided, 0 refused, 22 residual; 1 statements rendered; 1 held from entry, read as residuals (stack_p0) */
{
tmp_55400_2 = r2sleigh_residual_u64(1);
tmp_aa300_2 = r2sleigh_residual_u64(1);
r2sleigh_residual_void(2); /* r2dec gap: StoreNotSpelled at 0x401240:29 covering 1 op (render::values) */
r2sleigh_residual_void(3); /* r2dec gap: StoreNotSpelled at 0x401240:32 covering 1 op (render::values) */
r2sleigh_residual_void(4); /* r2dec gap: CallNotRendered at 0x401240:68 covering 1 op (render::values): call to __libc_start_main: the import's declaration has an argument this convention does not place */
@@ -227,12 +227,12 @@ uint64_t entry_fini0(void)
{
void fcn_401280(void);
uint8_t tmp_3e180_1;
uint8_t tmp_7c100_1;
/* r2dec proof: 2 constructs are marked below; 24 source obligations: 8 rendered, 12 elided, 0 refused, 4 residual; 6 statements rendered */
{
tmp_3e180_1 = r2sleigh_load_u8((void*)(uint64_t)0x404020U);
if ((uint8_t)((uint8_t)tmp_3e180_1 != (uint8_t)0U)) {
tmp_7c100_1 = r2sleigh_load_u8((void*)(uint64_t)0x404020U);
if ((uint8_t)((uint8_t)tmp_7c100_1 != (uint8_t)0U)) {
return r2sleigh_residual_u64(1);
} else {
fcn_401280();
@@ -288,7 +288,7 @@ uint64_t fcn_401330(uint64_t arg0, uint64_t arg1)
uint64_t rsi_1;
uint64_t rax_2;
uint64_t rdi_1;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rdi_2;
uint64_t rax_4;
@@ -301,9 +301,9 @@ uint64_t fcn_401330(uint64_t arg0, uint64_t arg1)
rax_2 = (uint64_t)0x811c9dc5U;
rdi_1 = arg0;
for (; ; ) {
tmp_11e00_1 = r2sleigh_load_u8((void*)rdi_1);
tmp_23a00_1 = r2sleigh_load_u8((void*)rdi_1);
rdi_2 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)1U);
rax_4 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)(uint8_t)tmp_11e00_1 ^ (uint32_t)((uint64_t)rax_2 >> 0U)) * (uint64_t)0x1000193U) >> 0U);
rax_4 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)(uint8_t)tmp_23a00_1 ^ (uint32_t)((uint64_t)rax_2 >> 0U)) * (uint64_t)0x1000193U) >> 0U);
if ((uint8_t)((uint64_t)rsi_1 != (uint64_t)rdi_2)) {
rax_2 = rax_4;
rdi_1 = rdi_2;
@@ -332,7 +332,7 @@ uint64_t fcn_401370(uint64_t arg0, uint64_t arg1)
uint64_t rsi_1;
uint64_t rax_2;
uint64_t rdi_1;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rdi_2;
uint64_t rax_4;
uint64_t rax_5;
@@ -346,9 +346,9 @@ uint64_t fcn_401370(uint64_t arg0, uint64_t arg1)
rax_2 = (uint64_t)0xcbf29ce484222325U;
rdi_1 = arg0;
for (; ; ) {
tmp_11e00_1 = r2sleigh_load_u8((void*)rdi_1);
tmp_23a00_1 = r2sleigh_load_u8((void*)rdi_1);
rdi_2 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)1U);
rax_4 = (uint64_t)((uint64_t)((uint64_t)rax_2 ^ (uint64_t)(uint8_t)tmp_11e00_1) * (uint64_t)0x100000001b3U);
rax_4 = (uint64_t)((uint64_t)((uint64_t)rax_2 ^ (uint64_t)(uint8_t)tmp_23a00_1) * (uint64_t)0x100000001b3U);
if ((uint8_t)((uint64_t)rsi_1 != (uint64_t)rdi_2)) {
rax_2 = rax_4;
rdi_1 = rdi_2;
@@ -379,7 +379,7 @@ uint64_t fcn_4013b0(uint64_t arg0, uint64_t arg1)
uint64_t rax_2;
uint64_t rdi_1;
uint64_t rdi_2;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rax_4;
/* r2dec proof: no individual construct is marked; 41 source obligations: 33 rendered, 8 elided, 0 refused; 14 statements rendered */
@@ -392,8 +392,8 @@ uint64_t fcn_4013b0(uint64_t arg0, uint64_t arg1)
rdi_1 = arg0;
for (; ; ) {
rdi_2 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)1U);
tmp_11e00_1 = r2sleigh_load_u8((void*)(uint64_t)((uint64_t)rdi_2 - (uint64_t)1U));
rax_4 = (uint64_t)(uint32_t)((uint32_t)(uint8_t)tmp_11e00_1 + (uint32_t)((uint32_t)((uint32_t)((uint64_t)rax_2 >> 0U) * (uint32_t)32U) + (uint32_t)((uint64_t)rax_2 >> 0U)));
tmp_23a00_1 = r2sleigh_load_u8((void*)(uint64_t)((uint64_t)rdi_2 - (uint64_t)1U));
rax_4 = (uint64_t)(uint32_t)((uint32_t)(uint8_t)tmp_23a00_1 + (uint32_t)((uint32_t)((uint32_t)((uint64_t)rax_2 >> 0U) * (uint32_t)32U) + (uint32_t)((uint64_t)rax_2 >> 0U)));
if ((uint8_t)((uint64_t)rdi_2 != (uint64_t)rsi_1)) {
rax_2 = rax_4;
rdi_1 = rdi_2;
@@ -422,7 +422,7 @@ uint32_t fcn_4013f0(uint64_t arg0, uint64_t arg1)
uint64_t rsi_1;
uint64_t rax_2;
uint64_t rdi_1;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rdi_2;
uint32_t tmp_lane_401400_17_8_1;
@@ -435,9 +435,9 @@ uint32_t fcn_4013f0(uint64_t arg0, uint64_t arg1)
rax_2 = 0;
rdi_1 = arg0;
for (; ; ) {
tmp_11e00_1 = r2sleigh_load_u8((void*)rdi_1);
tmp_23a00_1 = r2sleigh_load_u8((void*)rdi_1);
rdi_2 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)1U);
tmp_lane_401400_17_8_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)((uint64_t)rax_2 >> 0U) * (uint64_t)0x1003fU) >> 0U) + (uint32_t)(uint8_t)tmp_11e00_1);
tmp_lane_401400_17_8_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)((uint64_t)rax_2 >> 0U) * (uint64_t)0x1003fU) >> 0U) + (uint32_t)(uint8_t)tmp_23a00_1);
if ((uint8_t)((uint64_t)rsi_1 != (uint64_t)rdi_2)) {
rax_2 = (uint64_t)(uint32_t)tmp_lane_401400_17_8_1;
rdi_1 = rdi_2;
@@ -467,7 +467,7 @@ uint64_t fcn_401420(uint64_t arg0, uint64_t arg1)
uint64_t rax_2;
uint64_t rdi_1;
uint64_t rdx_2;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rdi_2;
uint64_t rdx_3;
uint32_t tmp_lane_401440_4f_c_1;
@@ -484,9 +484,9 @@ uint64_t fcn_401420(uint64_t arg0, uint64_t arg1)
rdi_1 = arg0;
rdx_2 = 1;
for (; ; ) {
tmp_11e00_1 = r2sleigh_load_u8((void*)rdi_1);
tmp_23a00_1 = r2sleigh_load_u8((void*)rdi_1);
rdi_2 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)1U);
rdx_3 = (uint64_t)(uint32_t)((uint32_t)(uint8_t)tmp_11e00_1 + (uint32_t)((uint64_t)rdx_2 >> 0U));
rdx_3 = (uint64_t)(uint32_t)((uint32_t)(uint8_t)tmp_23a00_1 + (uint32_t)((uint64_t)rdx_2 >> 0U));
tmp_lane_401440_4f_c_1 = (uint32_t)((uint32_t)((uint64_t)rdx_3 >> 0U) - (uint32_t)((uint64_t)((uint64_t)(int32_t)((uint64_t)((uint64_t)(uint32_t)47U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)((uint64_t)rdx_3 * (uint64_t)0x80078071U) >> (uint64_t)(uint32_t)47U)) >> 0U) * (uint64_t)0xfff1U) >> 0U));
rax_4 = (uint64_t)(uint32_t)((uint32_t)((uint64_t)rax_2 >> 0U) + (uint32_t)tmp_lane_401440_4f_c_1);
tmp_lane_401440_a0_1c_1 = (uint32_t)((uint32_t)((uint64_t)rax_4 >> 0U) - (uint32_t)((uint64_t)((uint64_t)(int32_t)((uint64_t)((uint64_t)(uint32_t)47U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)((uint64_t)rax_4 * (uint64_t)0x80078071U) >> (uint64_t)(uint32_t)47U)) >> 0U) * (uint64_t)0xfff1U) >> 0U));
@@ -516,11 +516,11 @@ CMDS=aa; pdd @ 0x004014a0
EXPECT=<<EOF
uint64_t fcn_4014a0(uint64_t arg0, uint64_t arg1)
{
uint64_t tmp_4a00_1;
uint64_t tmp_9400_1;
uint64_t rax_2;
uint64_t rdi_1;
uint64_t rdx_2;
uint16_t tmp_11e80_1;
uint16_t tmp_23b00_1;
uint64_t rdi_2;
uint64_t r8_1;
uint64_t rdx_8;
@@ -534,20 +534,20 @@ uint64_t fcn_4014a0(uint64_t arg0, uint64_t arg1)
if ((uint8_t)((uint64_t)arg1 == (uint64_t)0U)) {
return (uint64_t)0xffffffffU;
} else {
tmp_4a00_1 = (uint64_t)((uint64_t)((uint64_t)arg1 * (uint64_t)2U) + (uint64_t)arg0);
tmp_9400_1 = (uint64_t)((uint64_t)((uint64_t)arg1 * (uint64_t)2U) + (uint64_t)arg0);
rax_2 = 0xffff;
rdi_1 = arg0;
rdx_2 = 0xffff;
for (; ; ) {
tmp_11e80_1 = r2sleigh_load_u16((void*)rdi_1);
tmp_23b00_1 = r2sleigh_load_u16((void*)rdi_1);
rdi_2 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)2U);
r8_1 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)rdx_2 + (uint64_t)(uint16_t)tmp_11e80_1) >> 0U);
r8_1 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)rdx_2 + (uint64_t)(uint16_t)tmp_23b00_1) >> 0U);
rdx_8 = (uint64_t)(uint32_t)47U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)((uint64_t)r8_1 + (uint64_t)((uint64_t)((uint64_t)r8_1 + (uint64_t)((uint64_t)r8_1 * (uint64_t)0x10000U)) * (uint64_t)0x8000U)) >> (uint64_t)(uint32_t)47U);
tmp_lane_4014c0_c7_d_1 = (uint32_t)((uint32_t)((uint32_t)((uint64_t)rdx_8 >> 0U) + (uint32_t)((uint64_t)r8_1 >> 0U)) - (uint32_t)((uint32_t)((uint64_t)rdx_8 >> 0U) * (uint32_t)0x10000U));
rcx_4 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)(uint32_t)tmp_lane_4014c0_c7_d_1 + (uint64_t)rax_2) >> 0U);
rax_8 = (uint64_t)(uint32_t)47U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)((uint64_t)rcx_4 + (uint64_t)((uint64_t)((uint64_t)rcx_4 + (uint64_t)((uint64_t)rcx_4 * (uint64_t)0x10000U)) * (uint64_t)0x8000U)) >> (uint64_t)(uint32_t)47U);
tmp_lane_4014c0_18e_1f_1 = (uint32_t)((uint32_t)((uint32_t)((uint64_t)rax_8 >> 0U) + (uint32_t)((uint64_t)rcx_4 >> 0U)) - (uint32_t)((uint32_t)((uint64_t)rax_8 >> 0U) * (uint32_t)0x10000U));
if ((uint8_t)((uint64_t)tmp_4a00_1 != (uint64_t)rdi_2)) {
if ((uint8_t)((uint64_t)tmp_9400_1 != (uint64_t)rdi_2)) {
rax_2 = (uint64_t)(uint32_t)tmp_lane_4014c0_18e_1f_1;
rdi_1 = rdi_2;
rdx_2 = (uint64_t)(uint32_t)tmp_lane_4014c0_c7_d_1;
@@ -576,7 +576,7 @@ uint32_t fcn_401530(uint64_t arg0, uint64_t arg1)
uint64_t rsi_1;
uint64_t rax_2;
uint64_t rdi_1;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rax_4;
uint64_t rdx_3;
uint32_t tmp_lane_401558_2d_14_1;
@@ -593,8 +593,8 @@ uint32_t fcn_401530(uint64_t arg0, uint64_t arg1)
rax_2 = (uint64_t)0xffffffffU;
rdi_1 = arg0;
for (; ; ) {
tmp_11e00_1 = r2sleigh_load_u8((void*)rdi_1);
rax_4 = (uint64_t)(uint32_t)((uint32_t)(uint8_t)tmp_11e00_1 ^ (uint32_t)((uint64_t)rax_2 >> 0U));
tmp_23a00_1 = r2sleigh_load_u8((void*)rdi_1);
rax_4 = (uint64_t)(uint32_t)((uint32_t)(uint8_t)tmp_23a00_1 ^ (uint32_t)((uint64_t)rax_2 >> 0U));
rdx_3 = 8;
for (; ; ) {
tmp_lane_401558_2d_14_1 = (uint32_t)((uint32_t)((uint32_t)1U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)((uint64_t)rax_4 >> 0U) >> (uint32_t)1U)) ^ (uint32_t)((uint32_t)((uint32_t)0U - (uint32_t)((uint32_t)((uint64_t)rax_4 >> 0U) & (uint32_t)1U)) & (uint32_t)0xedb88320U));
@@ -1025,9 +1025,9 @@ uint32_t fcn_401630(uint64_t arg0, uint64_t arg1)
uint64_t rsi_1;
uint64_t rax_2;
uint64_t rdi_1;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rdi_2;
uint32_t tmp_11f00_1;
uint32_t tmp_23c00_1;
uint32_t tmp_lane_401648_43_b_1;
/* r2dec proof: no individual construct is marked; 48 source obligations: 40 rendered, 8 elided, 0 refused; 15 statements rendered */
@@ -1039,10 +1039,10 @@ uint32_t fcn_401630(uint64_t arg0, uint64_t arg1)
rax_2 = (uint64_t)0xffffffffU;
rdi_1 = arg0;
for (; ; ) {
tmp_11e00_1 = r2sleigh_load_u8((void*)rdi_1);
tmp_23a00_1 = r2sleigh_load_u8((void*)rdi_1);
rdi_2 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)1U);
tmp_11f00_1 = r2sleigh_load_u32((void*)(uint64_t)((uint64_t)((uint64_t)(uint8_t)((uint32_t)((uint32_t)(uint8_t)tmp_11e00_1 ^ (uint32_t)((uint64_t)rax_2 >> 0U)) >> 0U) * (uint64_t)4U) + (uint64_t)0x404040U));
tmp_lane_401648_43_b_1 = (uint32_t)((uint32_t)((uint32_t)8U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)((uint64_t)rax_2 >> 0U) >> (uint32_t)8U)) ^ (uint32_t)tmp_11f00_1);
tmp_23c00_1 = r2sleigh_load_u32((void*)(uint64_t)((uint64_t)((uint64_t)(uint8_t)((uint32_t)((uint32_t)(uint8_t)tmp_23a00_1 ^ (uint32_t)((uint64_t)rax_2 >> 0U)) >> 0U) * (uint64_t)4U) + (uint64_t)0x404040U));
tmp_lane_401648_43_b_1 = (uint32_t)((uint32_t)((uint32_t)8U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)((uint64_t)rax_2 >> 0U) >> (uint32_t)8U)) ^ (uint32_t)tmp_23c00_1);
if ((uint8_t)((uint64_t)rsi_1 != (uint64_t)rdi_2)) {
rax_2 = (uint64_t)(uint32_t)tmp_lane_401648_43_b_1;
rdi_1 = rdi_2;
@@ -1070,10 +1070,10 @@ uint32_t fcn_401680(uint8_t* arg0, uint64_t arg1, uint32_t arg2)
{
uint64_t rcx_1;
uint64_t rax_2;
uint64_t tmp_4a00_1;
uint64_t tmp_9400_1;
uint64_t rcx_2;
uint64_t rdx_2;
uint32_t tmp_11f00_1;
uint32_t tmp_23c00_1;
uint32_t tmp_lane_4016a0_4_2_1;
uint64_t rdx_3;
uint32_t tmp_lane_4016a0_32_9_1;
@@ -1082,11 +1082,11 @@ uint32_t fcn_401680(uint8_t* arg0, uint64_t arg1, uint32_t arg2)
uint64_t rcx_4;
uint64_t rdi_1;
uint64_t rax_11;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rax_26;
uint8_t tmp_11e00_3;
uint8_t tmp_23a00_3;
uint64_t rdx_6;
uint8_t tmp_11e00_2;
uint8_t tmp_23a00_2;
uint32_t tmp_lane_4016e8_10_1e_1;
uint64_t rcx_6;
uint32_t tmp_lane_4016fe_2_29_1;
@@ -1100,17 +1100,17 @@ uint32_t fcn_401680(uint8_t* arg0, uint64_t arg1, uint32_t arg2)
if ((uint8_t)((uint64_t)rax_2 == (uint64_t)0U)) {
rcx_4 = rcx_1;
} else {
tmp_4a00_1 = (uint64_t)((uint64_t)((uint64_t)rax_2 * (uint64_t)4U) + (uint64_t)arg0);
tmp_9400_1 = (uint64_t)((uint64_t)((uint64_t)rax_2 * (uint64_t)4U) + (uint64_t)arg0);
rcx_2 = rcx_1;
rdx_2 = (uint64_t)arg0;
for (; ; ) {
tmp_11f00_1 = r2sleigh_load_u32((void*)rdx_2);
tmp_lane_4016a0_4_2_1 = (uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_11f00_1 * (uint64_t)0xffffffffcc9e2d51U) >> 0U);
tmp_23c00_1 = r2sleigh_load_u32((void*)rdx_2);
tmp_lane_4016a0_4_2_1 = (uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_23c00_1 * (uint64_t)0xffffffffcc9e2d51U) >> 0U);
rdx_3 = (uint64_t)((uint64_t)rdx_2 + (uint64_t)4U);
tmp_lane_4016a0_32_9_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)((uint32_t)15U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_4016a0_4_2_1 << (uint32_t)15U)) | (uint32_t)((uint32_t)17U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_4016a0_4_2_1 >> (uint32_t)17U))) * (uint64_t)0x1b873593U) >> 0U) ^ (uint32_t)((uint64_t)rcx_2 >> 0U));
rax_7 = (uint64_t)(uint32_t)((uint32_t)((uint32_t)13U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_4016a0_32_9_1 << (uint32_t)13U)) | (uint32_t)((uint32_t)19U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_4016a0_32_9_1 >> (uint32_t)19U)));
rcx_3 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)((uint64_t)rax_7 + (uint64_t)((uint64_t)rax_7 * (uint64_t)4U)) - (uint64_t)0x19ab949cU) >> 0U);
if ((uint8_t)((uint64_t)tmp_4a00_1 != (uint64_t)rdx_3)) {
if ((uint8_t)((uint64_t)tmp_9400_1 != (uint64_t)rdx_3)) {
rcx_2 = rcx_3;
rdx_2 = rdx_3;
} else {
@@ -1125,16 +1125,16 @@ uint32_t fcn_401680(uint8_t* arg0, uint64_t arg1, uint32_t arg2)
if ((uint8_t)((uint64_t)rax_11 == (uint64_t)2U)) {
rax_26 = 0;
{
tmp_11e00_3 = r2sleigh_load_u8((void*)((uint64_t)rdi_1 + (uint64_t)1U * 1U));
rdx_6 = (uint64_t)(uint32_t)((uint32_t)((uint32_t)8U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)(uint8_t)tmp_11e00_3 << (uint32_t)8U)) ^ (uint32_t)((uint64_t)rax_26 >> 0U));
tmp_23a00_3 = r2sleigh_load_u8((void*)((uint64_t)rdi_1 + (uint64_t)1U * 1U));
rdx_6 = (uint64_t)(uint32_t)((uint32_t)((uint32_t)8U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)(uint8_t)tmp_23a00_3 << (uint32_t)8U)) ^ (uint32_t)((uint64_t)rax_26 >> 0U));
}
} else {
if ((uint8_t)((uint64_t)rax_11 == (uint64_t)3U)) {
tmp_11e00_1 = r2sleigh_load_u8((void*)((uint64_t)rdi_1 + (uint64_t)2U * 1U));
rax_26 = (uint64_t)(uint32_t)((uint32_t)16U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)(uint8_t)tmp_11e00_1 << (uint32_t)16U));
tmp_23a00_1 = r2sleigh_load_u8((void*)((uint64_t)rdi_1 + (uint64_t)2U * 1U));
rax_26 = (uint64_t)(uint32_t)((uint32_t)16U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)(uint8_t)tmp_23a00_1 << (uint32_t)16U));
{
tmp_11e00_3 = r2sleigh_load_u8((void*)((uint64_t)rdi_1 + (uint64_t)1U * 1U));
rdx_6 = (uint64_t)(uint32_t)((uint32_t)((uint32_t)8U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)(uint8_t)tmp_11e00_3 << (uint32_t)8U)) ^ (uint32_t)((uint64_t)rax_26 >> 0U));
tmp_23a00_3 = r2sleigh_load_u8((void*)((uint64_t)rdi_1 + (uint64_t)1U * 1U));
rdx_6 = (uint64_t)(uint32_t)((uint32_t)((uint32_t)8U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)(uint8_t)tmp_23a00_3 << (uint32_t)8U)) ^ (uint32_t)((uint64_t)rax_26 >> 0U));
}
} else {
if ((uint8_t)((uint64_t)rax_11 != (uint64_t)1U)) {
@@ -1146,8 +1146,8 @@ uint32_t fcn_401680(uint8_t* arg0, uint64_t arg1, uint32_t arg2)
}
}
{
tmp_11e00_2 = r2sleigh_load_u8((void*)rdi_1);
tmp_lane_4016e8_10_1e_1 = (uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)(uint8_t)tmp_11e00_2 ^ (uint32_t)((uint64_t)rdx_6 >> 0U)) * (uint64_t)0xffffffffcc9e2d51U) >> 0U);
tmp_23a00_2 = r2sleigh_load_u8((void*)rdi_1);
tmp_lane_4016e8_10_1e_1 = (uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)(uint8_t)tmp_23a00_2 ^ (uint32_t)((uint64_t)rdx_6 >> 0U)) * (uint64_t)0xffffffffcc9e2d51U) >> 0U);
rcx_6 = (uint64_t)(uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)((uint32_t)15U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_4016e8_10_1e_1 << (uint32_t)15U)) | (uint32_t)((uint32_t)17U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_4016e8_10_1e_1 >> (uint32_t)17U))) * (uint64_t)0x1b873593U) >> 0U) ^ (uint32_t)((uint64_t)rcx_4 >> 0U));
}
{
@@ -1174,32 +1174,32 @@ uint32_t fcn_401750(uint64_t arg0, uint64_t arg1, uint32_t arg2)
{
uint64_t rdx_1;
uint64_t rsi_1;
uint64_t tmp_4700_1;
uint64_t tmp_8e00_1;
uint64_t r10_2;
uint64_t r11_2;
uint64_t r9_2;
uint64_t rax_2;
uint64_t rdx_2;
uint32_t tmp_11f00_1;
uint32_t tmp_23c00_1;
uint64_t rdx_3;
uint32_t tmp_lane_401788_15_8_1;
uint32_t tmp_lane_401788_34_d_1;
uint32_t tmp_11f00_2;
uint32_t tmp_23c00_2;
uint32_t tmp_lane_401788_47_11_1;
uint32_t tmp_11f00_3;
uint32_t tmp_23c00_3;
uint32_t tmp_lane_401788_71_17_1;
uint32_t tmp_lane_401788_79_1a_1;
uint32_t tmp_lane_401788_98_1f_1;
uint32_t tmp_11f00_4;
uint32_t tmp_23c00_4;
uint32_t tmp_lane_401788_ab_23_1;
uint32_t tmp_lane_401788_ca_28_1;
uint64_t rdi_2;
uint64_t rdx_11;
uint64_t rdx_12;
uint64_t tmp_4700_8;
uint64_t tmp_8e00_8;
uint64_t rcx_14;
uint64_t rdx_13;
uint32_t tmp_11f00_5;
uint32_t tmp_23c00_5;
uint64_t rcx_15;
uint32_t tmp_lane_401830_16_41_1;
uint64_t rdx_14;
@@ -1207,7 +1207,7 @@ uint32_t fcn_401750(uint64_t arg0, uint64_t arg1, uint32_t arg2)
uint64_t rdx_15;
uint64_t rdi_5;
uint64_t rdx_16;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rdi_6;
uint32_t tmp_lane_40185f_17_4c_1;
uint64_t rdx_17;
@@ -1223,27 +1223,27 @@ uint32_t fcn_401750(uint64_t arg0, uint64_t arg1, uint32_t arg2)
rdi_2 = arg0;
rdx_11 = (uint64_t)(uint32_t)((uint32_t)arg2 + (uint32_t)0x165667b1U);
} else {
tmp_4700_1 = (uint64_t)((uint64_t)rsi_1 - (uint64_t)16U);
tmp_8e00_1 = (uint64_t)((uint64_t)rsi_1 - (uint64_t)16U);
r10_2 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)rdx_1 + (uint64_t)0x61c8864fU) >> 0U);
r11_2 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)rdx_1 + (uint64_t)0x24234428U) >> 0U);
r9_2 = (uint64_t)(uint32_t)arg2;
rax_2 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)rdx_1 - (uint64_t)0x7a143589U) >> 0U);
rdx_2 = arg0;
for (; ; ) {
tmp_11f00_1 = r2sleigh_load_u32((void*)rdx_2);
tmp_23c00_1 = r2sleigh_load_u32((void*)rdx_2);
rdx_3 = (uint64_t)((uint64_t)rdx_2 + (uint64_t)16U);
tmp_lane_401788_15_8_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_11f00_1 * (uint64_t)0xffffffff85ebca77U) >> 0U) + (uint32_t)((uint64_t)r11_2 >> 0U));
tmp_lane_401788_15_8_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_23c00_1 * (uint64_t)0xffffffff85ebca77U) >> 0U) + (uint32_t)((uint64_t)r11_2 >> 0U));
tmp_lane_401788_34_d_1 = (uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)((uint32_t)13U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_401788_15_8_1 << (uint32_t)13U)) | (uint32_t)((uint32_t)19U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_401788_15_8_1 >> (uint32_t)19U))) * (uint64_t)0xffffffff9e3779b1U) >> 0U);
tmp_11f00_2 = r2sleigh_load_u32((void*)(uint64_t)((uint64_t)rdx_3 - (uint64_t)12U));
tmp_lane_401788_47_11_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_11f00_2 * (uint64_t)0xffffffff85ebca77U) >> 0U) + (uint32_t)((uint64_t)rax_2 >> 0U));
tmp_11f00_3 = r2sleigh_load_u32((void*)(uint64_t)((uint64_t)rdx_3 - (uint64_t)8U));
tmp_23c00_2 = r2sleigh_load_u32((void*)(uint64_t)((uint64_t)rdx_3 - (uint64_t)12U));
tmp_lane_401788_47_11_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_23c00_2 * (uint64_t)0xffffffff85ebca77U) >> 0U) + (uint32_t)((uint64_t)rax_2 >> 0U));
tmp_23c00_3 = r2sleigh_load_u32((void*)(uint64_t)((uint64_t)rdx_3 - (uint64_t)8U));
tmp_lane_401788_71_17_1 = (uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)((uint32_t)13U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_401788_47_11_1 << (uint32_t)13U)) | (uint32_t)((uint32_t)19U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_401788_47_11_1 >> (uint32_t)19U))) * (uint64_t)0xffffffff9e3779b1U) >> 0U);
tmp_lane_401788_79_1a_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_11f00_3 * (uint64_t)0xffffffff85ebca77U) >> 0U) + (uint32_t)((uint64_t)r9_2 >> 0U));
tmp_lane_401788_79_1a_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_23c00_3 * (uint64_t)0xffffffff85ebca77U) >> 0U) + (uint32_t)((uint64_t)r9_2 >> 0U));
tmp_lane_401788_98_1f_1 = (uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)((uint32_t)13U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_401788_79_1a_1 << (uint32_t)13U)) | (uint32_t)((uint32_t)19U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_401788_79_1a_1 >> (uint32_t)19U))) * (uint64_t)0xffffffff9e3779b1U) >> 0U);
tmp_11f00_4 = r2sleigh_load_u32((void*)(uint64_t)((uint64_t)rdx_3 - (uint64_t)4U));
tmp_lane_401788_ab_23_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_11f00_4 * (uint64_t)0xffffffff85ebca77U) >> 0U) + (uint32_t)((uint64_t)r10_2 >> 0U));
tmp_23c00_4 = r2sleigh_load_u32((void*)(uint64_t)((uint64_t)rdx_3 - (uint64_t)4U));
tmp_lane_401788_ab_23_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_23c00_4 * (uint64_t)0xffffffff85ebca77U) >> 0U) + (uint32_t)((uint64_t)r10_2 >> 0U));
tmp_lane_401788_ca_28_1 = (uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)((uint32_t)13U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_401788_ab_23_1 << (uint32_t)13U)) | (uint32_t)((uint32_t)19U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_401788_ab_23_1 >> (uint32_t)19U))) * (uint64_t)0xffffffff9e3779b1U) >> 0U);
if ((uint8_t)((uint64_t)rdx_3 <= (uint64_t)tmp_4700_1)) {
if ((uint8_t)((uint64_t)rdx_3 <= (uint64_t)tmp_8e00_1)) {
r10_2 = (uint64_t)(uint32_t)tmp_lane_401788_ca_28_1;
r11_2 = (uint64_t)(uint32_t)tmp_lane_401788_34_d_1;
r9_2 = (uint64_t)(uint32_t)tmp_lane_401788_98_1f_1;
@@ -1260,17 +1260,17 @@ uint32_t fcn_401750(uint64_t arg0, uint64_t arg1, uint32_t arg2)
}
{
rdx_12 = (uint64_t)(uint32_t)((uint32_t)((uint64_t)rdx_11 >> 0U) + (uint32_t)((uint64_t)arg1 >> 0U));
tmp_4700_8 = (uint64_t)((uint64_t)rdi_2 + (uint64_t)4U);
if ((uint8_t)((uint64_t)rsi_1 < (uint64_t)tmp_4700_8)) {
tmp_8e00_8 = (uint64_t)((uint64_t)rdi_2 + (uint64_t)4U);
if ((uint8_t)((uint64_t)rsi_1 < (uint64_t)tmp_8e00_8)) {
rdi_4 = rdi_2;
rdx_15 = rdx_12;
} else {
rcx_14 = tmp_4700_8;
rcx_14 = tmp_8e00_8;
rdx_13 = rdx_12;
for (; ; ) {
tmp_11f00_5 = r2sleigh_load_u32((void*)(uint64_t)((uint64_t)rcx_14 - (uint64_t)4U));
tmp_23c00_5 = r2sleigh_load_u32((void*)(uint64_t)((uint64_t)rcx_14 - (uint64_t)4U));
rcx_15 = (uint64_t)((uint64_t)rcx_14 + (uint64_t)4U);
tmp_lane_401830_16_41_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_11f00_5 * (uint64_t)0xffffffffc2b2ae3dU) >> 0U) + (uint32_t)((uint64_t)rdx_13 >> 0U));
tmp_lane_401830_16_41_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(int32_t)tmp_23c00_5 * (uint64_t)0xffffffffc2b2ae3dU) >> 0U) + (uint32_t)((uint64_t)rdx_13 >> 0U));
rdx_14 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)((uint32_t)15U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_401830_16_41_1 >> (uint32_t)15U)) | (uint32_t)((uint32_t)17U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_401830_16_41_1 << (uint32_t)17U))) * (uint64_t)0x27d4eb2fU) >> 0U);
if ((uint8_t)((uint64_t)rcx_15 <= (uint64_t)rsi_1)) {
rcx_14 = rcx_15;
@@ -1280,7 +1280,7 @@ uint32_t fcn_401750(uint64_t arg0, uint64_t arg1, uint32_t arg2)
}
}
{
rdi_4 = (uint64_t)((uint64_t)tmp_4700_8 + (uint64_t)((uint64_t)((uint64_t)((uint64_t)rsi_1 - (uint64_t)rdi_2) - (uint64_t)4U) & (uint64_t)-0x4));
rdi_4 = (uint64_t)((uint64_t)tmp_8e00_8 + (uint64_t)((uint64_t)((uint64_t)((uint64_t)rsi_1 - (uint64_t)rdi_2) - (uint64_t)4U) & (uint64_t)-0x4));
rdx_15 = rdx_14;
}
}
@@ -1291,9 +1291,9 @@ uint32_t fcn_401750(uint64_t arg0, uint64_t arg1, uint32_t arg2)
rdi_5 = rdi_4;
rdx_16 = rdx_15;
for (; ; ) {
tmp_11e00_1 = r2sleigh_load_u8((void*)rdi_5);
tmp_23a00_1 = r2sleigh_load_u8((void*)rdi_5);
rdi_6 = (uint64_t)((uint64_t)rdi_5 + (uint64_t)1U);
tmp_lane_40185f_17_4c_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(uint8_t)tmp_11e00_1 * (uint64_t)0x165667b1U) >> 0U) + (uint32_t)((uint64_t)rdx_16 >> 0U));
tmp_lane_40185f_17_4c_1 = (uint32_t)((uint32_t)((uint64_t)((uint64_t)(uint8_t)tmp_23a00_1 * (uint64_t)0x165667b1U) >> 0U) + (uint32_t)((uint64_t)rdx_16 >> 0U));
rdx_17 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)((uint32_t)11U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_40185f_17_4c_1 << (uint32_t)11U)) | (uint32_t)((uint32_t)21U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)tmp_lane_40185f_17_4c_1 >> (uint32_t)21U))) * (uint64_t)0xffffffff9e3779b1U) >> 0U);
if ((uint8_t)((uint64_t)rsi_1 != (uint64_t)rdi_6)) {
rdi_5 = rdi_6;
@@ -1336,7 +1336,7 @@ uint64_t fcn_4018b0(uint8_t* arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3)
uint64_t rcx_2;
uint64_t rdi_1;
uint64_t rdx_2;
uint64_t tmp_11f80_1;
uint64_t tmp_23d00_1;
uint64_t rax_4;
uint64_t rdi_2;
uint64_t r11_5;
@@ -1362,27 +1362,27 @@ uint64_t fcn_4018b0(uint8_t* arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3)
uint64_t rcx_12;
uint64_t rdx_9;
uint32_t tmp_lane_40197a_2_1_1;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rsi_6;
uint8_t tmp_11e00_2;
uint8_t tmp_23a00_2;
uint64_t rsi_8;
uint8_t tmp_11e00_3;
uint8_t tmp_23a00_3;
uint64_t rsi_10;
uint8_t tmp_11e00_4;
uint8_t tmp_23a00_4;
uint64_t rsi_12;
uint8_t tmp_11e00_5;
uint8_t tmp_23a00_5;
uint64_t rsi_14;
uint8_t tmp_11e00_6;
uint8_t tmp_23a00_6;
uint64_t rsi_16;
uint8_t tmp_11e00_7;
uint8_t tmp_23a00_7;
uint64_t rsi_18;
uint64_t rcx_13;
uint64_t tmp_4a00_1;
uint64_t tmp_9400_1;
uint64_t rdx_10;
uint64_t r11_14;
uint64_t rcx_15;
uint64_t rdx_11;
uint64_t tmp_4a00_2;
uint64_t tmp_9400_2;
uint64_t rcx_17;
uint64_t rax_16;
uint64_t rdi_18;
@@ -1445,11 +1445,11 @@ uint64_t fcn_4018b0(uint8_t* arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3)
rdi_1 = (uint64_t)arg0;
rdx_2 = rdx_1;
for (; ; ) {
tmp_11f80_1 = r2sleigh_load_u64((void*)rdi_1);
tmp_23d00_1 = r2sleigh_load_u64((void*)rdi_1);
rax_4 = (uint64_t)((uint64_t)rax_3 + (uint64_t)r11_3);
rdi_2 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)8U);
r11_5 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)13U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)r11_3 << (uint64_t)(uint32_t)13U)) | (uint64_t)((uint64_t)(uint32_t)51U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)r11_3 >> (uint64_t)(uint32_t)51U))) ^ (uint64_t)rax_4);
rcx_3 = (uint64_t)((uint64_t)rcx_2 ^ (uint64_t)tmp_11f80_1);
rcx_3 = (uint64_t)((uint64_t)rcx_2 ^ (uint64_t)tmp_23d00_1);
rdx_3 = (uint64_t)((uint64_t)rdx_2 + (uint64_t)rcx_3);
rcx_5 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)16U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_3 << (uint64_t)(uint32_t)16U)) | (uint64_t)((uint64_t)(uint32_t)48U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_3 >> (uint64_t)(uint32_t)48U))) ^ (uint64_t)rdx_3);
rdx_4 = (uint64_t)((uint64_t)rdx_3 + (uint64_t)r11_5);
@@ -1465,7 +1465,7 @@ uint64_t fcn_4018b0(uint8_t* arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3)
r11_11 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)17U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)r11_9 << (uint64_t)(uint32_t)17U)) | (uint64_t)((uint64_t)(uint32_t)47U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)r11_9 >> (uint64_t)(uint32_t)47U))) ^ (uint64_t)rdx_7);
rcx_11 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)21U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_9 << (uint64_t)(uint32_t)21U)) | (uint64_t)((uint64_t)(uint32_t)43U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_9 >> (uint64_t)(uint32_t)43U))) ^ (uint64_t)rax_9);
rdx_8 = (uint64_t)((uint64_t)((uint64_t)(uint32_t)32U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rdx_7 << (uint64_t)(uint32_t)32U)) | (uint64_t)((uint64_t)(uint32_t)32U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rdx_7 >> (uint64_t)(uint32_t)32U)));
rax_10 = (uint64_t)((uint64_t)rax_9 ^ (uint64_t)tmp_11f80_1);
rax_10 = (uint64_t)((uint64_t)rax_9 ^ (uint64_t)tmp_23d00_1);
if ((uint8_t)((uint64_t)r10_3 != (uint64_t)rdi_2)) {
r11_3 = r11_11;
rax_3 = rax_10;
@@ -1486,8 +1486,8 @@ uint64_t fcn_4018b0(uint8_t* arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3)
switch (tmp_lane_40197a_2_1_1) {
case 7:
{
tmp_11e00_1 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)6U * 1U));
rsi_6 = (uint64_t)((uint64_t)rsi_4 | (uint64_t)((uint64_t)(uint32_t)48U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_11e00_1 << (uint64_t)(uint32_t)48U)));
tmp_23a00_1 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)6U * 1U));
rsi_6 = (uint64_t)((uint64_t)rsi_4 | (uint64_t)((uint64_t)(uint32_t)48U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_23a00_1 << (uint64_t)(uint32_t)48U)));
break;
}
case 6:
@@ -1513,46 +1513,46 @@ uint64_t fcn_4018b0(uint8_t* arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3)
goto L7;
}
{
tmp_11e00_2 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)5U * 1U));
rsi_8 = (uint64_t)((uint64_t)rsi_6 | (uint64_t)((uint64_t)(uint32_t)40U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_11e00_2 << (uint64_t)(uint32_t)40U)));
tmp_23a00_2 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)5U * 1U));
rsi_8 = (uint64_t)((uint64_t)rsi_6 | (uint64_t)((uint64_t)(uint32_t)40U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_23a00_2 << (uint64_t)(uint32_t)40U)));
}
{
L2: ;
tmp_11e00_3 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)4U * 1U));
rsi_10 = (uint64_t)((uint64_t)rsi_8 | (uint64_t)((uint64_t)(uint32_t)32U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_11e00_3 << (uint64_t)(uint32_t)32U)));
tmp_23a00_3 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)4U * 1U));
rsi_10 = (uint64_t)((uint64_t)rsi_8 | (uint64_t)((uint64_t)(uint32_t)32U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_23a00_3 << (uint64_t)(uint32_t)32U)));
}
{
L3: ;
tmp_11e00_4 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)3U * 1U));
rsi_12 = (uint64_t)((uint64_t)rsi_10 | (uint64_t)((uint64_t)(uint32_t)24U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_11e00_4 << (uint64_t)(uint32_t)24U)));
tmp_23a00_4 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)3U * 1U));
rsi_12 = (uint64_t)((uint64_t)rsi_10 | (uint64_t)((uint64_t)(uint32_t)24U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_23a00_4 << (uint64_t)(uint32_t)24U)));
}
{
L4: ;
tmp_11e00_5 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)2U * 1U));
rsi_14 = (uint64_t)((uint64_t)rsi_12 | (uint64_t)((uint64_t)(uint32_t)16U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_11e00_5 << (uint64_t)(uint32_t)16U)));
tmp_23a00_5 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)2U * 1U));
rsi_14 = (uint64_t)((uint64_t)rsi_12 | (uint64_t)((uint64_t)(uint32_t)16U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_23a00_5 << (uint64_t)(uint32_t)16U)));
}
{
L5: ;
tmp_11e00_6 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)1U * 1U));
rsi_16 = (uint64_t)((uint64_t)rsi_14 | (uint64_t)((uint64_t)(uint32_t)8U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_11e00_6 << (uint64_t)(uint32_t)8U)));
tmp_23a00_6 = r2sleigh_load_u8((void*)((uint64_t)r10_3 + (uint64_t)1U * 1U));
rsi_16 = (uint64_t)((uint64_t)rsi_14 | (uint64_t)((uint64_t)(uint32_t)8U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)(uint8_t)tmp_23a00_6 << (uint64_t)(uint32_t)8U)));
}
{
L6: ;
tmp_11e00_7 = r2sleigh_load_u8((void*)r10_3);
rsi_18 = (uint64_t)((uint64_t)rsi_16 | (uint64_t)(uint8_t)tmp_11e00_7);
tmp_23a00_7 = r2sleigh_load_u8((void*)r10_3);
rsi_18 = (uint64_t)((uint64_t)rsi_16 | (uint64_t)(uint8_t)tmp_23a00_7);
}
{
L7: ;
rcx_13 = (uint64_t)((uint64_t)rcx_12 ^ (uint64_t)rsi_18);
tmp_4a00_1 = (uint64_t)((uint64_t)rax_11 + (uint64_t)r11_12);
tmp_9400_1 = (uint64_t)((uint64_t)rax_11 + (uint64_t)r11_12);
rdx_10 = (uint64_t)((uint64_t)rdx_9 + (uint64_t)rcx_13);
r11_14 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)13U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)r11_12 << (uint64_t)(uint32_t)13U)) | (uint64_t)((uint64_t)(uint32_t)51U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)r11_12 >> (uint64_t)(uint32_t)51U))) ^ (uint64_t)tmp_4a00_1);
r11_14 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)13U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)r11_12 << (uint64_t)(uint32_t)13U)) | (uint64_t)((uint64_t)(uint32_t)51U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)r11_12 >> (uint64_t)(uint32_t)51U))) ^ (uint64_t)tmp_9400_1);
rcx_15 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)16U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_13 << (uint64_t)(uint32_t)16U)) | (uint64_t)((uint64_t)(uint32_t)48U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_13 >> (uint64_t)(uint32_t)48U))) ^ (uint64_t)rdx_10);
rdx_11 = (uint64_t)((uint64_t)rdx_10 + (uint64_t)r11_14);
tmp_4a00_2 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)32U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)tmp_4a00_1 << (uint64_t)(uint32_t)32U)) | (uint64_t)((uint64_t)(uint32_t)32U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)tmp_4a00_1 >> (uint64_t)(uint32_t)32U))) + (uint64_t)rcx_15);
rcx_17 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)21U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_15 << (uint64_t)(uint32_t)21U)) | (uint64_t)((uint64_t)(uint32_t)43U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_15 >> (uint64_t)(uint32_t)43U))) ^ (uint64_t)tmp_4a00_2);
tmp_9400_2 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)32U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)tmp_9400_1 << (uint64_t)(uint32_t)32U)) | (uint64_t)((uint64_t)(uint32_t)32U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)tmp_9400_1 >> (uint64_t)(uint32_t)32U))) + (uint64_t)rcx_15);
rcx_17 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)21U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_15 << (uint64_t)(uint32_t)21U)) | (uint64_t)((uint64_t)(uint32_t)43U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_15 >> (uint64_t)(uint32_t)43U))) ^ (uint64_t)tmp_9400_2);
rax_16 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)17U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)r11_14 << (uint64_t)(uint32_t)17U)) | (uint64_t)((uint64_t)(uint32_t)47U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)r11_14 >> (uint64_t)(uint32_t)47U))) ^ (uint64_t)rdx_11);
rdi_18 = (uint64_t)((uint64_t)tmp_4a00_2 + (uint64_t)rax_16);
rdi_18 = (uint64_t)((uint64_t)tmp_9400_2 + (uint64_t)rax_16);
rdx_13 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)32U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rdx_11 << (uint64_t)(uint32_t)32U)) | (uint64_t)((uint64_t)(uint32_t)32U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rdx_11 >> (uint64_t)(uint32_t)32U))) + (uint64_t)rcx_17);
rax_18 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)13U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rax_16 << (uint64_t)(uint32_t)13U)) | (uint64_t)((uint64_t)(uint32_t)51U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rax_16 >> (uint64_t)(uint32_t)51U))) ^ (uint64_t)rdi_18);
rcx_19 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)(uint32_t)16U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_17 << (uint64_t)(uint32_t)16U)) | (uint64_t)((uint64_t)(uint32_t)48U >= (uint64_t)64U ? (uint64_t)0U : (uint64_t)((uint64_t)rcx_17 >> (uint64_t)(uint32_t)48U))) ^ (uint64_t)rdx_13);
@@ -1611,9 +1611,9 @@ uint32_t fcn_401b10(uint64_t arg0, uint64_t arg1)
uint64_t rsi_1;
uint64_t rax_2;
uint64_t rdi_1;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rdi_2;
uint8_t tmp_11e00_2;
uint8_t tmp_23a00_2;
uint32_t tmp_lane_401b20_17_7_1;
/* r2dec proof: no individual construct is marked; 42 source obligations: 34 rendered, 8 elided, 0 refused; 15 statements rendered */
@@ -1625,10 +1625,10 @@ uint32_t fcn_401b10(uint64_t arg0, uint64_t arg1)
rax_2 = 0;
rdi_1 = arg0;
for (; ; ) {
tmp_11e00_1 = r2sleigh_load_u8((void*)rdi_1);
tmp_23a00_1 = r2sleigh_load_u8((void*)rdi_1);
rdi_2 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)1U);
tmp_11e00_2 = r2sleigh_load_u8((void*)(uint64_t)((uint64_t)(uint8_t)((uint32_t)(uint8_t)((uint64_t)rax_2 >> 0U) ^ (uint32_t)tmp_11e00_1) + (uint64_t)0x4020a0U));
tmp_lane_401b20_17_7_1 = (uint32_t)(uint8_t)tmp_11e00_2;
tmp_23a00_2 = r2sleigh_load_u8((void*)(uint64_t)((uint64_t)(uint8_t)((uint32_t)(uint8_t)((uint64_t)rax_2 >> 0U) ^ (uint32_t)tmp_23a00_1) + (uint64_t)0x4020a0U));
tmp_lane_401b20_17_7_1 = (uint32_t)(uint8_t)tmp_23a00_2;
if ((uint8_t)((uint64_t)rdi_2 != (uint64_t)rsi_1)) {
rax_2 = (uint64_t)(uint32_t)tmp_lane_401b20_17_7_1;
rdi_1 = rdi_2;
+139 -139
View File
@@ -25,30 +25,30 @@ CMDS=aa; pdd @ 0x100000548
EXPECT=<<EOF
uint32_t _struct_nested_array(void* arg0, uint32_t arg1, uint32_t arg2)
{
uint64_t tmp_12480_1;
uint32_t tmp_26080_2;
uint16_t tmp_26b80_1;
uint32_t tmp_26080_3;
uint32_t tmp_26080_4;
uint32_t tmp_26080_5;
uint16_t tmp_26b80_2;
uint64_t tmp_24100_1;
uint32_t tmp_4b700_2;
uint16_t tmp_4cd00_1;
uint32_t tmp_4b700_3;
uint32_t tmp_4b700_4;
uint32_t tmp_4b700_5;
uint16_t tmp_4cd00_2;
uint32_t stack_m4_1;
/* r2dec proof: no individual construct is marked; 47 source obligations: 44 rendered, 3 elided, 0 refused; 12 statements rendered */
{
tmp_12480_1 = (uint64_t)((uint64_t)((uint64_t)(int32_t)arg1 * (uint64_t)40U) + (uint64_t)arg0);
tmp_26080_2 = r2sleigh_load_u32((void*)((uint64_t)tmp_12480_1 + (uint64_t)4U * 4U));
r2sleigh_store_u32((void*)((uint64_t)tmp_12480_1 + (uint64_t)4U * 4U), (uint32_t)((uint32_t)tmp_26080_2 + (uint32_t)arg2));
tmp_26b80_1 = r2sleigh_load_u16((void*)((uint64_t)tmp_12480_1 + (uint64_t)2U * 2U));
if ((uint8_t)((uint32_t)((uint32_t)((uint32_t)2U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)((uint64_t)(uint16_t)tmp_26b80_1 >> 0U) >> (uint32_t)2U)) & (uint32_t)1U) == (uint32_t)0U)) {
tmp_26080_5 = r2sleigh_load_u32((void*)((uint64_t)tmp_12480_1 + (uint64_t)2U * 4U));
tmp_26b80_2 = r2sleigh_load_u16((void*)((uint64_t)tmp_12480_1 + (uint64_t)3U * 2U));
stack_m4_1 = (uint32_t)((uint32_t)tmp_26080_5 - (uint32_t)((uint64_t)(uint16_t)tmp_26b80_2 >> 0U));
tmp_24100_1 = (uint64_t)((uint64_t)((uint64_t)(int32_t)arg1 * (uint64_t)40U) + (uint64_t)arg0);
tmp_4b700_2 = r2sleigh_load_u32((void*)((uint64_t)tmp_24100_1 + (uint64_t)4U * 4U));
r2sleigh_store_u32((void*)((uint64_t)tmp_24100_1 + (uint64_t)4U * 4U), (uint32_t)((uint32_t)tmp_4b700_2 + (uint32_t)arg2));
tmp_4cd00_1 = r2sleigh_load_u16((void*)((uint64_t)tmp_24100_1 + (uint64_t)2U * 2U));
if ((uint8_t)((uint32_t)((uint32_t)((uint32_t)2U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)((uint64_t)(uint16_t)tmp_4cd00_1 >> 0U) >> (uint32_t)2U)) & (uint32_t)1U) == (uint32_t)0U)) {
tmp_4b700_5 = r2sleigh_load_u32((void*)((uint64_t)tmp_24100_1 + (uint64_t)2U * 4U));
tmp_4cd00_2 = r2sleigh_load_u16((void*)((uint64_t)tmp_24100_1 + (uint64_t)3U * 2U));
stack_m4_1 = (uint32_t)((uint32_t)tmp_4b700_5 - (uint32_t)((uint64_t)(uint16_t)tmp_4cd00_2 >> 0U));
} else {
{
tmp_26080_3 = r2sleigh_load_u32((void*)((uint64_t)tmp_12480_1 + (uint64_t)4U * 4U));
tmp_26080_4 = r2sleigh_load_u32((void*)tmp_12480_1);
stack_m4_1 = (uint32_t)((uint32_t)tmp_26080_3 + (uint32_t)tmp_26080_4);
tmp_4b700_3 = r2sleigh_load_u32((void*)((uint64_t)tmp_24100_1 + (uint64_t)4U * 4U));
tmp_4b700_4 = r2sleigh_load_u32((void*)tmp_24100_1);
stack_m4_1 = (uint32_t)((uint32_t)tmp_4b700_3 + (uint32_t)tmp_4b700_4);
}
}
{
@@ -76,26 +76,26 @@ struct fcn_1000005d8_arg1 {
uint32_t _out_param_parse(uint8_t* arg0, struct fcn_1000005d8_arg1* arg1)
{
uint8_t tmp_26e80_1;
uint8_t tmp_4d300_1;
uint64_t stack_m40_1;
uint32_t stack_m20_1;
uint64_t stack_m48_1;
uint64_t stack_m40_2;
uint64_t stack_m32_1;
uint8_t tmp_27780_1;
uint8_t tmp_27780_2;
uint8_t tmp_4e500_1;
uint8_t tmp_4e500_2;
uint32_t stack_m52_1;
uint8_t tmp_27780_3;
uint8_t tmp_4e500_3;
uint64_t stack_m32_3;
uint8_t tmp_26a80_1;
uint8_t tmp_4cb00_1;
uint64_t stack_m48_4;
uint8_t tmp_27780_4;
uint8_t tmp_4e500_4;
uint32_t stack_m56_1;
/* r2dec proof: no individual construct is marked; 116 source obligations: 113 rendered, 3 elided, 0 refused; 33 statements rendered; 1 structure laid out from a parameter's accesses */
{
tmp_26e80_1 = r2sleigh_load_u8((void*)(uint64_t)arg0);
if ((uint8_t)((uint32_t)(int8_t)tmp_26e80_1 != (uint32_t)45U)) {
tmp_4d300_1 = r2sleigh_load_u8((void*)(uint64_t)arg0);
if ((uint8_t)((uint32_t)(int8_t)tmp_4d300_1 != (uint32_t)45U)) {
stack_m40_1 = 0;
stack_m20_1 = 1;
} else {
@@ -109,13 +109,13 @@ uint32_t _out_param_parse(uint8_t* arg0, struct fcn_1000005d8_arg1* arg1)
stack_m40_2 = stack_m40_1;
stack_m32_1 = 0;
for (; ; ) {
tmp_27780_1 = r2sleigh_load_u8((void*)((uint64_t)arg0 + (uint64_t)stack_m40_2 * 1U));
if ((uint8_t)((int32_t)(int8_t)tmp_27780_1 < (int32_t)48U)) {
tmp_4e500_1 = r2sleigh_load_u8((void*)((uint64_t)arg0 + (uint64_t)stack_m40_2 * 1U));
if ((uint8_t)((int32_t)(int8_t)tmp_4e500_1 < (int32_t)48U)) {
stack_m52_1 = 0;
} else {
{
tmp_27780_2 = r2sleigh_load_u8((void*)((uint64_t)arg0 + (uint64_t)stack_m40_2 * 1U));
stack_m52_1 = (uint32_t)((uint64_t)(uint8_t)((int32_t)(int8_t)tmp_27780_2 <= (int32_t)57U) >> 0U);
tmp_4e500_2 = r2sleigh_load_u8((void*)((uint64_t)arg0 + (uint64_t)stack_m40_2 * 1U));
stack_m52_1 = (uint32_t)((uint64_t)(uint8_t)((int32_t)(int8_t)tmp_4e500_2 <= (int32_t)57U) >> 0U);
}
}
{
@@ -123,10 +123,10 @@ uint32_t _out_param_parse(uint8_t* arg0, struct fcn_1000005d8_arg1* arg1)
break;
} else {
{
tmp_27780_3 = r2sleigh_load_u8((void*)((uint64_t)arg0 + (uint64_t)stack_m40_2 * 1U));
stack_m32_3 = (uint64_t)((uint64_t)((uint64_t)stack_m32_1 * (uint64_t)10U) + (uint64_t)(int32_t)((uint32_t)(int8_t)tmp_27780_3 - (uint32_t)48U));
tmp_26a80_1 = r2sleigh_load_u8((void*)((uint64_t)arg0 + (uint64_t)stack_m40_2 * 1U));
stack_m48_4 = (uint64_t)((uint64_t)((uint64_t)(uint8_t)tmp_26a80_1 ^ (uint64_t)stack_m48_1) * (uint64_t)0x100000001b3U);
tmp_4e500_3 = r2sleigh_load_u8((void*)((uint64_t)arg0 + (uint64_t)stack_m40_2 * 1U));
stack_m32_3 = (uint64_t)((uint64_t)((uint64_t)stack_m32_1 * (uint64_t)10U) + (uint64_t)(int32_t)((uint32_t)(int8_t)tmp_4e500_3 - (uint32_t)48U));
tmp_4cb00_1 = r2sleigh_load_u8((void*)((uint64_t)arg0 + (uint64_t)stack_m40_2 * 1U));
stack_m48_4 = (uint64_t)((uint64_t)((uint64_t)(uint8_t)tmp_4cb00_1 ^ (uint64_t)stack_m48_1) * (uint64_t)0x100000001b3U);
{
stack_m48_1 = stack_m48_4;
stack_m40_2 = (uint64_t)((uint64_t)stack_m40_2 + (uint64_t)1U);
@@ -145,8 +145,8 @@ uint32_t _out_param_parse(uint8_t* arg0, struct fcn_1000005d8_arg1* arg1)
stack_m56_1 = 0;
} else {
{
tmp_27780_4 = r2sleigh_load_u8((void*)((uint64_t)arg0 + (uint64_t)stack_m40_2 * 1U));
stack_m56_1 = (uint32_t)((uint64_t)(uint8_t)((uint32_t)(int8_t)tmp_27780_4 == (uint32_t)0U) >> 0U);
tmp_4e500_4 = r2sleigh_load_u8((void*)((uint64_t)arg0 + (uint64_t)stack_m40_2 * 1U));
stack_m56_1 = (uint32_t)((uint64_t)(uint8_t)((uint32_t)(int8_t)tmp_4e500_4 == (uint32_t)0U) >> 0U);
}
}
{
@@ -170,7 +170,7 @@ uint64_t _fnv_fold(uint8_t* arg0, uint64_t arg1)
{
uint64_t stack_m32_1;
uint64_t stack_m24_1;
uint8_t tmp_26980_1;
uint8_t tmp_4c900_1;
uint8_t stack_m33_2;
uint8_t stack_m33_1;
uint64_t stack_m24_4;
@@ -184,8 +184,8 @@ uint64_t _fnv_fold(uint8_t* arg0, uint64_t arg1)
break;
} else {
{
tmp_26980_1 = r2sleigh_load_u8((void*)((uint64_t)arg0 + (uint64_t)stack_m32_1 * 1U));
stack_m33_2 = tmp_26980_1;
tmp_4c900_1 = r2sleigh_load_u8((void*)((uint64_t)arg0 + (uint64_t)stack_m32_1 * 1U));
stack_m33_2 = tmp_4c900_1;
if ((uint8_t)((int32_t)((uint64_t)(uint8_t)stack_m33_2 >> 0U) < (int32_t)65U)) {
stack_m33_1 = stack_m33_2;
} else {
@@ -226,9 +226,9 @@ CMDS=aa; pdd @ 0x100000824
EXPECT=<<EOF
uint32_t _sparse_switch(uint32_t arg0, uint32_t arg1, uint32_t arg2)
{
uint8_t tmp_38d00_1;
uint32_t tmp_38d08_1;
uint32_t tmp_38d10_1;
uint8_t tmp_71000_1;
uint32_t tmp_71008_1;
uint32_t tmp_71010_1;
uint32_t stack_m24_1;
uint32_t stack_m4_1;
@@ -252,10 +252,10 @@ uint32_t _sparse_switch(uint32_t arg0, uint32_t arg1, uint32_t arg2)
{
if ((uint8_t)((uint32_t)arg0 == (uint32_t)0x3e8U)) {
if ((uint8_t)((uint32_t)arg2 != (uint32_t)0U)) {
tmp_38d00_1 = (uint8_t)((uint32_t)arg2 == (uint32_t)0U);
tmp_38d08_1 = tmp_38d00_1 ? (uint32_t)1U : (uint32_t)arg2;
tmp_38d10_1 = (uint32_t)arg1 == (uint32_t)0x80000000U && (uint32_t)tmp_38d08_1 == (uint32_t)0xffffffffU ? r2sleigh_residual_u32(1) : (uint32_t)((int32_t)arg1 / (int32_t)tmp_38d08_1);
stack_m24_1 = tmp_38d00_1 ? (uint32_t)0U : (uint32_t)tmp_38d10_1;
tmp_71000_1 = (uint8_t)((uint32_t)arg2 == (uint32_t)0U);
tmp_71008_1 = tmp_71000_1 ? (uint32_t)1U : (uint32_t)arg2;
tmp_71010_1 = (uint32_t)arg1 == (uint32_t)0x80000000U && (uint32_t)tmp_71008_1 == (uint32_t)0xffffffffU ? r2sleigh_residual_u32(1) : (uint32_t)((int32_t)arg1 / (int32_t)tmp_71008_1);
stack_m24_1 = tmp_71000_1 ? (uint32_t)0U : (uint32_t)tmp_71010_1;
} else {
{
stack_m24_1 = (uint32_t)0xffffffffU;
@@ -298,17 +298,17 @@ uint32_t _table_walk(uint64_t arg0, uint8_t* arg1)
uint32_t stack_m28_1;
uint32_t stack_m28_3;
uint64_t x8_6;
uint16_t tmp_26b80_1;
uint16_t tmp_4cd00_1;
uint64_t stack_m48_1;
uint16_t tmp_26b80_2;
uint8_t tmp_27780_1;
uint16_t tmp_4cd00_2;
uint8_t tmp_4e500_1;
uint64_t x8_15;
uint8_t tmp_27780_2;
uint8_t tmp_27780_3;
uint8_t tmp_4e500_2;
uint8_t tmp_4e500_3;
uint32_t stack_m52_1;
uint16_t tmp_26b80_3;
uint8_t tmp_27780_4;
uint32_t tmp_26080_3;
uint16_t tmp_4cd00_3;
uint8_t tmp_4e500_4;
uint32_t tmp_4b700_3;
uint64_t x8_30;
uint32_t stack_m4_1;
@@ -328,24 +328,24 @@ uint32_t _table_walk(uint64_t arg0, uint8_t* arg1)
}
} else {
{
tmp_26b80_1 = r2sleigh_load_u16((void*)((uint64_t)stack_m40_1 + (uint64_t)3U * 2U));
if ((uint8_t)((uint32_t)((uint64_t)(uint16_t)tmp_26b80_1 >> 0U) != (uint32_t)0U)) {
tmp_4cd00_1 = r2sleigh_load_u16((void*)((uint64_t)stack_m40_1 + (uint64_t)3U * 2U));
if ((uint8_t)((uint32_t)((uint64_t)(uint16_t)tmp_4cd00_1 >> 0U) != (uint32_t)0U)) {
stack_m48_1 = 0;
for (; ; ) {
tmp_26b80_2 = r2sleigh_load_u16((void*)((uint64_t)stack_m40_1 + (uint64_t)3U * 2U));
if ((uint8_t)((uint64_t)(uint16_t)tmp_26b80_2 <= (uint64_t)stack_m48_1)) {
tmp_4cd00_2 = r2sleigh_load_u16((void*)((uint64_t)stack_m40_1 + (uint64_t)3U * 2U));
if ((uint8_t)((uint64_t)(uint16_t)tmp_4cd00_2 <= (uint64_t)stack_m48_1)) {
stack_m52_1 = 0;
} else {
{
tmp_27780_1 = r2sleigh_load_u8((void*)((uint64_t)arg1 + (uint64_t)stack_m48_1 * 1U));
if ((uint8_t)((uint32_t)(int8_t)tmp_27780_1 == (uint32_t)0U)) {
tmp_4e500_1 = r2sleigh_load_u8((void*)((uint64_t)arg1 + (uint64_t)stack_m48_1 * 1U));
if ((uint8_t)((uint32_t)(int8_t)tmp_4e500_1 == (uint32_t)0U)) {
stack_m52_1 = 0;
} else {
{
x8_15 = r2sleigh_load_u64((void*)((uint64_t)stack_m40_1 + (uint64_t)3U * 8U));
tmp_27780_2 = r2sleigh_load_u8((void*)(uint64_t)((uint64_t)x8_15 + (uint64_t)stack_m48_1));
tmp_27780_3 = r2sleigh_load_u8((void*)((uint64_t)arg1 + (uint64_t)stack_m48_1 * 1U));
stack_m52_1 = (uint32_t)((uint64_t)(uint8_t)((uint32_t)(int8_t)tmp_27780_2 == (uint32_t)(int8_t)tmp_27780_3) >> 0U);
tmp_4e500_2 = r2sleigh_load_u8((void*)(uint64_t)((uint64_t)x8_15 + (uint64_t)stack_m48_1));
tmp_4e500_3 = r2sleigh_load_u8((void*)((uint64_t)arg1 + (uint64_t)stack_m48_1 * 1U));
stack_m52_1 = (uint32_t)((uint64_t)(uint8_t)((uint32_t)(int8_t)tmp_4e500_2 == (uint32_t)(int8_t)tmp_4e500_3) >> 0U);
}
}
}
@@ -361,12 +361,12 @@ uint32_t _table_walk(uint64_t arg0, uint8_t* arg1)
}
}
{
tmp_26b80_3 = r2sleigh_load_u16((void*)((uint64_t)stack_m40_1 + (uint64_t)3U * 2U));
if ((uint8_t)((uint64_t)(uint16_t)tmp_26b80_3 != (uint64_t)stack_m48_1)) {
tmp_4cd00_3 = r2sleigh_load_u16((void*)((uint64_t)stack_m40_1 + (uint64_t)3U * 2U));
if ((uint8_t)((uint64_t)(uint16_t)tmp_4cd00_3 != (uint64_t)stack_m48_1)) {
} else {
{
tmp_27780_4 = r2sleigh_load_u8((void*)((uint64_t)arg1 + (uint64_t)stack_m48_1 * 1U));
if ((uint8_t)((uint32_t)(int8_t)tmp_27780_4 != (uint32_t)0U)) {
tmp_4e500_4 = r2sleigh_load_u8((void*)((uint64_t)arg1 + (uint64_t)stack_m48_1 * 1U));
if ((uint8_t)((uint32_t)(int8_t)tmp_4e500_4 != (uint32_t)0U)) {
} else {
break;
}
@@ -391,8 +391,8 @@ uint32_t _table_walk(uint64_t arg0, uint8_t* arg1)
}
{
{
tmp_26080_3 = r2sleigh_load_u32((void*)stack_m40_1);
stack_m4_1 = (uint32_t)((uint32_t)tmp_26080_3 + (uint32_t)stack_m28_3);
tmp_4b700_3 = r2sleigh_load_u32((void*)stack_m40_1);
stack_m4_1 = (uint32_t)((uint32_t)tmp_4b700_3 + (uint32_t)stack_m28_3);
goto L7;
}
}
@@ -421,8 +421,8 @@ uint32_t _state_machine(uint8_t* arg0)
uint64_t stack_m32_1;
uint32_t stack_m24_1;
uint32_t stack_m20_1;
uint8_t tmp_27780_1;
uint8_t tmp_26980_1;
uint8_t tmp_4e500_1;
uint8_t tmp_4c900_1;
uint32_t stack_m20_5;
uint32_t stack_m20_6;
uint32_t stack_m24_3;
@@ -442,29 +442,29 @@ uint32_t _state_machine(uint8_t* arg0)
stack_m24_1 = 0;
stack_m20_1 = 0;
for (; ; ) {
tmp_27780_1 = r2sleigh_load_u8((void*)((uint64_t)arg0 + (uint64_t)stack_m32_1 * 1U));
if ((uint8_t)((uint32_t)(int8_t)tmp_27780_1 == (uint32_t)0U)) {
tmp_4e500_1 = r2sleigh_load_u8((void*)((uint64_t)arg0 + (uint64_t)stack_m32_1 * 1U));
if ((uint8_t)((uint32_t)(int8_t)tmp_4e500_1 == (uint32_t)0U)) {
goto L16;
} else {
{
tmp_26980_1 = r2sleigh_load_u8((void*)((uint64_t)arg0 + (uint64_t)stack_m32_1 * 1U));
tmp_4c900_1 = r2sleigh_load_u8((void*)((uint64_t)arg0 + (uint64_t)stack_m32_1 * 1U));
if ((uint8_t)((uint32_t)stack_m20_1 == (uint32_t)0U)) {
if ((uint8_t)((int32_t)((uint64_t)(uint8_t)tmp_26980_1 >> 0U) < (int32_t)97U)) {
if ((uint8_t)((int32_t)((uint64_t)(uint8_t)tmp_4c900_1 >> 0U) < (int32_t)97U)) {
} else {
{
if ((uint8_t)((int32_t)((uint64_t)(uint8_t)tmp_26980_1 >> 0U) <= (int32_t)122U)) {
if ((uint8_t)((int32_t)((uint64_t)(uint8_t)tmp_4c900_1 >> 0U) <= (int32_t)122U)) {
goto L1;
} else {
}
}
}
{
if ((uint8_t)((uint32_t)((uint64_t)(uint8_t)tmp_26980_1 >> 0U) != (uint32_t)95U)) {
if ((uint8_t)((int32_t)((uint64_t)(uint8_t)tmp_26980_1 >> 0U) < (int32_t)48U)) {
if ((uint8_t)((uint32_t)((uint64_t)(uint8_t)tmp_4c900_1 >> 0U) != (uint32_t)95U)) {
if ((uint8_t)((int32_t)((uint64_t)(uint8_t)tmp_4c900_1 >> 0U) < (int32_t)48U)) {
goto L2;
} else {
{
if ((uint8_t)((int32_t)57U < (int32_t)((uint64_t)(uint8_t)tmp_26980_1 >> 0U))) {
if ((uint8_t)((int32_t)57U < (int32_t)((uint64_t)(uint8_t)tmp_4c900_1 >> 0U))) {
goto L2;
} else {
{
@@ -494,13 +494,13 @@ L3: ;
} else {
{
if ((uint8_t)((uint32_t)stack_m20_1 == (uint32_t)1U)) {
if ((uint8_t)((int32_t)((uint64_t)(uint8_t)tmp_26980_1 >> 0U) < (int32_t)48U)) {
if ((uint8_t)((int32_t)((uint64_t)(uint8_t)tmp_4c900_1 >> 0U) < (int32_t)48U)) {
} else {
{
if ((uint8_t)((int32_t)57U < (int32_t)((uint64_t)(uint8_t)tmp_26980_1 >> 0U))) {
if ((uint8_t)((int32_t)57U < (int32_t)((uint64_t)(uint8_t)tmp_4c900_1 >> 0U))) {
} else {
{
stack_m24_4 = (uint32_t)((uint32_t)((uint32_t)((uint64_t)(uint8_t)tmp_26980_1 >> 0U) + (uint32_t)stack_m24_1) - (uint32_t)48U);
stack_m24_4 = (uint32_t)((uint32_t)((uint32_t)((uint64_t)(uint8_t)tmp_4c900_1 >> 0U) + (uint32_t)stack_m24_1) - (uint32_t)48U);
stack_m20_4 = 2;
goto L9;
}
@@ -508,18 +508,18 @@ L3: ;
}
}
{
if ((uint8_t)((uint32_t)((uint64_t)(uint8_t)tmp_26980_1 >> 0U) != (uint32_t)45U)) {
if ((uint8_t)((int32_t)((uint64_t)(uint8_t)tmp_26980_1 >> 0U) < (int32_t)97U)) {
if ((uint8_t)((uint32_t)((uint64_t)(uint8_t)tmp_4c900_1 >> 0U) != (uint32_t)45U)) {
if ((uint8_t)((int32_t)((uint64_t)(uint8_t)tmp_4c900_1 >> 0U) < (int32_t)97U)) {
} else {
{
if ((uint8_t)((int32_t)((uint64_t)(uint8_t)tmp_26980_1 >> 0U) <= (int32_t)122U)) {
if ((uint8_t)((int32_t)((uint64_t)(uint8_t)tmp_4c900_1 >> 0U) <= (int32_t)122U)) {
goto L7;
} else {
}
}
}
{
if ((uint8_t)((uint32_t)((uint64_t)(uint8_t)tmp_26980_1 >> 0U) == (uint32_t)95U)) {
if ((uint8_t)((uint32_t)((uint64_t)(uint8_t)tmp_4c900_1 >> 0U) == (uint32_t)95U)) {
} else {
goto L6;
}
@@ -548,13 +548,13 @@ L9: ;
} else {
{
if ((uint8_t)((uint32_t)stack_m20_1 == (uint32_t)2U)) {
if ((uint8_t)((uint32_t)((uint64_t)(uint8_t)tmp_26980_1 >> 0U) != (uint32_t)95U)) {
if ((uint8_t)((uint32_t)((uint64_t)(uint8_t)tmp_26980_1 >> 0U) != (uint32_t)45U)) {
if ((uint8_t)((int32_t)((uint64_t)(uint8_t)tmp_26980_1 >> 0U) < (int32_t)48U)) {
if ((uint8_t)((uint32_t)((uint64_t)(uint8_t)tmp_4c900_1 >> 0U) != (uint32_t)95U)) {
if ((uint8_t)((uint32_t)((uint64_t)(uint8_t)tmp_4c900_1 >> 0U) != (uint32_t)45U)) {
if ((uint8_t)((int32_t)((uint64_t)(uint8_t)tmp_4c900_1 >> 0U) < (int32_t)48U)) {
goto L11;
} else {
{
if ((uint8_t)((int32_t)((uint64_t)(uint8_t)tmp_26980_1 >> 0U) <= (int32_t)57U)) {
if ((uint8_t)((int32_t)((uint64_t)(uint8_t)tmp_4c900_1 >> 0U) <= (int32_t)57U)) {
stack_m20_5 = stack_m20_1;
} else {
goto L10;
@@ -580,7 +580,7 @@ L9: ;
}
} else {
{
if ((uint8_t)((uint32_t)((uint64_t)(uint8_t)tmp_26980_1 >> 0U) == (uint32_t)120U)) {
if ((uint8_t)((uint32_t)((uint64_t)(uint8_t)tmp_4c900_1 >> 0U) == (uint32_t)120U)) {
stack_m24_5 = stack_m24_1;
stack_m20_7 = 0;
} else {
@@ -652,7 +652,7 @@ uint64_t _mem_scan2(uint8_t* arg0, uint64_t arg1, uint8_t arg2, uint8_t arg3)
{
uint64_t stack_m40_1;
uint64_t stack_m32_1;
uint8_t tmp_26980_1;
uint8_t tmp_4c900_1;
uint64_t stack_m32_2;
/* r2dec proof: no individual construct is marked; 49 source obligations: 46 rendered, 3 elided, 0 refused; 14 statements rendered */
@@ -664,14 +664,14 @@ uint64_t _mem_scan2(uint8_t* arg0, uint64_t arg1, uint8_t arg2, uint8_t arg3)
break;
} else {
{
tmp_26980_1 = r2sleigh_load_u8((void*)((uint64_t)arg0 + (uint64_t)stack_m40_1 * 1U));
if ((uint8_t)((uint32_t)((uint64_t)(uint8_t)arg2 >> 0U) == (uint32_t)((uint64_t)(uint8_t)tmp_26980_1 >> 0U))) {
tmp_4c900_1 = r2sleigh_load_u8((void*)((uint64_t)arg0 + (uint64_t)stack_m40_1 * 1U));
if ((uint8_t)((uint32_t)((uint64_t)(uint8_t)arg2 >> 0U) == (uint32_t)((uint64_t)(uint8_t)tmp_4c900_1 >> 0U))) {
{
stack_m32_2 = (uint64_t)((uint64_t)stack_m32_1 + (uint64_t)1U);
}
} else {
{
if ((uint8_t)((uint32_t)((uint64_t)(uint8_t)arg3 >> 0U) != (uint32_t)((uint64_t)(uint8_t)tmp_26980_1 >> 0U))) {
if ((uint8_t)((uint32_t)((uint64_t)(uint8_t)arg3 >> 0U) != (uint32_t)((uint64_t)(uint8_t)tmp_4c900_1 >> 0U))) {
stack_m32_2 = stack_m32_1;
} else {
{
@@ -762,37 +762,37 @@ uint64_t _main(uint32_t arg0, uint64_t* arg1)
uint64_t x0_3;
struct r2sleigh_bits_256 z0_2;
struct r2sleigh_bits_256 z0_3;
uint32_t tmp_26180_1;
uint32_t tmp_26180_2;
uint32_t tmp_4b900_1;
uint32_t tmp_4b900_2;
uint64_t x2_3;
uint64_t x0_4;
uint32_t tmp_26080_1;
uint32_t tmp_26180_3;
uint32_t tmp_4b700_1;
uint32_t tmp_4b900_3;
uint64_t x8_9;
uint64_t x0_6;
uint32_t tmp_26080_2;
uint32_t tmp_4b700_2;
uint64_t x0_9;
uint64_t x8_18;
uint32_t tmp_26080_3;
uint32_t tmp_26180_4;
uint32_t tmp_26080_4;
uint32_t tmp_4b700_3;
uint32_t tmp_4b900_4;
uint32_t tmp_4b700_4;
uint64_t x8_19;
uint64_t x0_11;
uint64_t x9_12;
uint32_t tmp_26080_5;
uint32_t tmp_26180_5;
uint32_t tmp_4b700_5;
uint32_t tmp_4b900_5;
uint64_t x8_25;
uint64_t x1_8;
uint64_t x0_13;
uint32_t tmp_26080_6;
uint32_t tmp_26180_6;
uint32_t tmp_4b700_6;
uint32_t tmp_4b900_6;
uint64_t x8_35;
uint64_t x0_15;
uint32_t tmp_26080_7;
uint32_t tmp_4b700_7;
uint64_t x0_18;
uint64_t x8_44;
uint32_t tmp_26080_8;
uint32_t tmp_26080_9;
uint32_t tmp_4b700_8;
uint32_t tmp_4b700_9;
_Alignas(16) uint8_t frame[192];
/* r2dec proof: no individual construct is marked; 229 source obligations: 178 rendered, 35 elided, 0 refused, 16 assumed (frame extent unproven); 61 statements rendered; 1 data object type refused; 1 callee prototype supplied by the source */
@@ -808,14 +808,14 @@ uint64_t _main(uint32_t arg0, uint64_t* arg1)
r2sleigh_store_u128((void*)(uint64_t)(frame + 48U), (__uint128_t)r2sleigh_bits_extract_256_128(z0_3, 0U));
r2sleigh_store_u128((void*)(uint64_t)((uint64_t)(frame + 48U) + (uint64_t)16U), (__uint128_t)r2sleigh_bits_extract_256_128(z0_3, 0U));
r2sleigh_store_u64((void*)((uint64_t)(frame + 48U) + (uint64_t)64U), (uint64_t)((uint64_t)x0_3 + (uint64_t)40U));
tmp_26180_1 = r2sleigh_load_u32((void*)((uint64_t)(frame + 48U) + (uint64_t)120U));
tmp_26180_2 = r2sleigh_load_u32((void*)((uint64_t)(frame + 48U) + (uint64_t)120U));
x2_3 = (uint64_t)(uint32_t)tmp_26180_2;
x0_4 = (uint64_t)_struct_nested_array(x0_3, (uint32_t)((uint32_t)tmp_26180_1 & (uint32_t)1U), (uint32_t)x2_3);
tmp_26080_1 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_4 >> 0U) + (uint32_t)tmp_26080_1));
tmp_26180_3 = r2sleigh_load_u32((void*)((uint64_t)(frame + 48U) + (uint64_t)120U));
if ((uint8_t)((int32_t)tmp_26180_3 <= (int32_t)1U)) {
tmp_4b900_1 = r2sleigh_load_u32((void*)((uint64_t)(frame + 48U) + (uint64_t)120U));
tmp_4b900_2 = r2sleigh_load_u32((void*)((uint64_t)(frame + 48U) + (uint64_t)120U));
x2_3 = (uint64_t)(uint32_t)tmp_4b900_2;
x0_4 = (uint64_t)_struct_nested_array(x0_3, (uint32_t)((uint32_t)tmp_4b900_1 & (uint32_t)1U), (uint32_t)x2_3);
tmp_4b700_1 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_4 >> 0U) + (uint32_t)tmp_4b700_1));
tmp_4b900_3 = r2sleigh_load_u32((void*)((uint64_t)(frame + 48U) + (uint64_t)120U));
if ((uint8_t)((int32_t)tmp_4b900_3 <= (int32_t)1U)) {
r2sleigh_store_u64((void*)(uint64_t)(frame + 32U), (uint64_t)0x100000fecU);
} else {
{
@@ -826,21 +826,21 @@ uint64_t _main(uint32_t arg0, uint64_t* arg1)
{
x0_6 = (uint64_t)_out_param_parse(r2sleigh_load_u64((void*)(uint64_t)(frame + 32U)), (uint64_t)(frame + 48U));
r2sleigh_store_u64((void*)(uint64_t)(frame + 24U), (uint64_t)0x100008000U);
tmp_26080_2 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_6 >> 0U) + (uint32_t)tmp_26080_2));
tmp_4b700_2 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_6 >> 0U) + (uint32_t)tmp_4b700_2));
x0_9 = _fnv_fold((uint64_t)0x100000ff0U, 3);
x8_18 = r2sleigh_load_u64((void*)(uint64_t)(frame + 24U));
tmp_26080_3 = r2sleigh_load_u32((void*)x8_18);
r2sleigh_store_u32((void*)x8_18, (uint32_t)((uint32_t)((uint64_t)x0_9 >> 0U) + (uint32_t)tmp_26080_3));
tmp_26180_4 = r2sleigh_load_u32((void*)((uint64_t)(frame + 48U) + (uint64_t)120U));
tmp_26080_4 = r2sleigh_load_u32((void*)x8_18);
tmp_4b700_3 = r2sleigh_load_u32((void*)x8_18);
r2sleigh_store_u32((void*)x8_18, (uint32_t)((uint32_t)((uint64_t)x0_9 >> 0U) + (uint32_t)tmp_4b700_3));
tmp_4b900_4 = r2sleigh_load_u32((void*)((uint64_t)(frame + 48U) + (uint64_t)120U));
tmp_4b700_4 = r2sleigh_load_u32((void*)x8_18);
x8_19 = r2sleigh_load_u64((void*)((uint64_t)(frame + 48U) + (uint64_t)24U));
x0_11 = (uint64_t)_sparse_switch((uint32_t)tmp_26180_4, (uint32_t)tmp_26080_4, (uint32_t)x8_19);
x0_11 = (uint64_t)_sparse_switch((uint32_t)tmp_4b900_4, (uint32_t)tmp_4b700_4, (uint32_t)x8_19);
x9_12 = r2sleigh_load_u64((void*)(uint64_t)(frame + 24U));
tmp_26080_5 = r2sleigh_load_u32((void*)x9_12);
r2sleigh_store_u32((void*)x9_12, (uint32_t)((uint32_t)((uint64_t)x0_11 >> 0U) + (uint32_t)tmp_26080_5));
tmp_26180_5 = r2sleigh_load_u32((void*)((uint64_t)(frame + 48U) + (uint64_t)120U));
if ((uint8_t)((int32_t)tmp_26180_5 <= (int32_t)2U)) {
tmp_4b700_5 = r2sleigh_load_u32((void*)x9_12);
r2sleigh_store_u32((void*)x9_12, (uint32_t)((uint32_t)((uint64_t)x0_11 >> 0U) + (uint32_t)tmp_4b700_5));
tmp_4b900_5 = r2sleigh_load_u32((void*)((uint64_t)(frame + 48U) + (uint64_t)120U));
if ((uint8_t)((int32_t)tmp_4b900_5 <= (int32_t)2U)) {
r2sleigh_store_u64((void*)(uint64_t)(frame + 16U), (uint64_t)0x100000fe8U);
} else {
{
@@ -851,10 +851,10 @@ uint64_t _main(uint32_t arg0, uint64_t* arg1)
{
x1_8 = r2sleigh_load_u64((void*)(uint64_t)(frame + 16U));
x0_13 = (uint64_t)_table_walk((uint64_t)((uint64_t)(frame + 48U) + (uint64_t)32U), x1_8);
tmp_26080_6 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_13 >> 0U) + (uint32_t)tmp_26080_6));
tmp_26180_6 = r2sleigh_load_u32((void*)((uint64_t)(frame + 48U) + (uint64_t)120U));
if ((uint8_t)((int32_t)tmp_26180_6 <= (int32_t)3U)) {
tmp_4b700_6 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_13 >> 0U) + (uint32_t)tmp_4b700_6));
tmp_4b900_6 = r2sleigh_load_u32((void*)((uint64_t)(frame + 48U) + (uint64_t)120U));
if ((uint8_t)((int32_t)tmp_4b900_6 <= (int32_t)3U)) {
r2sleigh_store_u64((void*)(uint64_t)(frame + 8U), (uint64_t)0x100000ff4U);
} else {
{
@@ -865,14 +865,14 @@ uint64_t _main(uint32_t arg0, uint64_t* arg1)
{
x0_15 = (uint64_t)_state_machine(r2sleigh_load_u64((void*)(uint64_t)(frame + 8U)));
r2sleigh_store_u64((void*)(uint64_t)(frame + 0U), (uint64_t)0x100008000U);
tmp_26080_7 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_15 >> 0U) + (uint32_t)tmp_26080_7));
tmp_4b700_7 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_15 >> 0U) + (uint32_t)tmp_4b700_7));
x0_18 = _mem_scan2((uint64_t)0x100000ffbU, 6, 97, 122);
x8_44 = r2sleigh_load_u64((void*)(uint64_t)(frame + 0U));
tmp_26080_8 = r2sleigh_load_u32((void*)x8_44);
r2sleigh_store_u32((void*)x8_44, (uint32_t)((uint32_t)((uint64_t)x0_18 >> 0U) + (uint32_t)tmp_26080_8));
tmp_26080_9 = r2sleigh_load_u32((void*)x8_44);
return (uint64_t)(uint8_t)((uint32_t)tmp_26080_9 == (uint32_t)0U);
tmp_4b700_8 = r2sleigh_load_u32((void*)x8_44);
r2sleigh_store_u32((void*)x8_44, (uint32_t)((uint32_t)((uint64_t)x0_18 >> 0U) + (uint32_t)tmp_4b700_8));
tmp_4b700_9 = r2sleigh_load_u32((void*)x8_44);
return (uint64_t)(uint8_t)((uint32_t)tmp_4b700_9 == (uint32_t)0U);
}
}
}
+129 -129
View File
@@ -25,27 +25,27 @@ EXPECT=<<EOF
uint32_t _struct_nested_array(void* arg0, uint32_t arg1, uint32_t arg2)
{
uint64_t x8_2;
uint32_t tmp_26080_1;
uint32_t tmp_12280_1;
uint16_t tmp_26b80_1;
uint32_t tmp_26080_2;
uint16_t tmp_26b80_2;
uint32_t tmp_26080_3;
uint32_t tmp_4b700_1;
uint32_t tmp_23d00_1;
uint16_t tmp_4cd00_1;
uint32_t tmp_4b700_2;
uint16_t tmp_4cd00_2;
uint32_t tmp_4b700_3;
/* r2dec proof: no individual construct is marked; 36 source obligations: 36 rendered, 0 elided, 0 refused; 11 statements rendered */
{
x8_2 = (uint64_t)((uint64_t)((uint64_t)(int32_t)arg1 * (uint64_t)40U) + (uint64_t)arg0);
tmp_26080_1 = r2sleigh_load_u32((void*)((uint64_t)x8_2 + (uint64_t)4U * 4U));
tmp_12280_1 = (uint32_t)((uint32_t)tmp_26080_1 + (uint32_t)arg2);
r2sleigh_store_u32((void*)((uint64_t)x8_2 + (uint64_t)4U * 4U), (uint32_t)tmp_12280_1);
tmp_26b80_1 = r2sleigh_load_u16((void*)((uint64_t)x8_2 + (uint64_t)2U * 2U));
if ((uint8_t)((uint32_t)((uint32_t)((uint32_t)2U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)((uint64_t)(uint16_t)tmp_26b80_1 >> 0U) >> (uint32_t)2U)) & (uint32_t)1U) != (uint32_t)0U)) {
tmp_26080_3 = r2sleigh_load_u32((void*)x8_2);
return (uint32_t)((uint32_t)tmp_26080_3 + (uint32_t)tmp_12280_1);
tmp_4b700_1 = r2sleigh_load_u32((void*)((uint64_t)x8_2 + (uint64_t)4U * 4U));
tmp_23d00_1 = (uint32_t)((uint32_t)tmp_4b700_1 + (uint32_t)arg2);
r2sleigh_store_u32((void*)((uint64_t)x8_2 + (uint64_t)4U * 4U), (uint32_t)tmp_23d00_1);
tmp_4cd00_1 = r2sleigh_load_u16((void*)((uint64_t)x8_2 + (uint64_t)2U * 2U));
if ((uint8_t)((uint32_t)((uint32_t)((uint32_t)2U >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)((uint64_t)(uint16_t)tmp_4cd00_1 >> 0U) >> (uint32_t)2U)) & (uint32_t)1U) != (uint32_t)0U)) {
tmp_4b700_3 = r2sleigh_load_u32((void*)x8_2);
return (uint32_t)((uint32_t)tmp_4b700_3 + (uint32_t)tmp_23d00_1);
} else {
tmp_26080_2 = r2sleigh_load_u32((void*)((uint64_t)x8_2 + (uint64_t)2U * 4U));
tmp_26b80_2 = r2sleigh_load_u16((void*)((uint64_t)x8_2 + (uint64_t)3U * 2U));
return (uint32_t)((uint32_t)tmp_26080_2 - (uint32_t)((uint64_t)(uint16_t)tmp_26b80_2 >> 0U));
tmp_4b700_2 = r2sleigh_load_u32((void*)((uint64_t)x8_2 + (uint64_t)2U * 4U));
tmp_4cd00_2 = r2sleigh_load_u16((void*)((uint64_t)x8_2 + (uint64_t)3U * 2U));
return (uint32_t)((uint32_t)tmp_4b700_2 - (uint32_t)((uint64_t)(uint16_t)tmp_4cd00_2 >> 0U));
}
}
}
@@ -69,13 +69,13 @@ struct fcn_1000004e0_arg1 {
uint64_t _out_param_parse(uint8_t* arg0, struct fcn_1000004e0_arg1* arg1)
{
uint8_t tmp_26880_1;
uint8_t tmp_4c700_1;
uint64_t x9_1;
uint8_t tmpzr_1;
uint64_t x10_1;
uint8_t tmp_26980_1;
uint8_t tmp_4c900_1;
uint64_t x12_1;
uint64_t tmp_11f80_1;
uint64_t tmp_23700_1;
uint64_t x11_6;
uint64_t x12_2;
uint64_t x16_2;
@@ -83,28 +83,28 @@ uint64_t _out_param_parse(uint8_t* arg0, struct fcn_1000004e0_arg1* arg1)
uint64_t x11_8;
uint64_t x8_10;
uint64_t x10_4;
uint8_t tmp_26a80_1;
uint8_t tmp_4cb00_1;
uint64_t x12_3;
uint64_t x10_5;
uint64_t x11_10;
uint64_t x8_11;
uint32_t tmp_lane_100000564_a_b_1;
uint8_t tmp_26a80_2;
uint8_t tmp_4cb00_2;
/* r2dec proof: no individual construct is marked; 98 source obligations: 98 rendered, 0 elided, 0 refused; 39 statements rendered; 1 structure laid out from a parameter's accesses */
{
tmp_26880_1 = r2sleigh_load_u8((void*)(uint64_t)arg0);
x9_1 = (uint64_t)(uint8_t)tmp_26880_1;
tmp_4c700_1 = r2sleigh_load_u8((void*)(uint64_t)arg0);
x9_1 = (uint64_t)(uint8_t)tmp_4c700_1;
tmpzr_1 = (uint8_t)((uint32_t)((uint64_t)x9_1 >> 0U) == (uint32_t)45U);
x10_1 = (uint64_t)(uint8_t)tmpzr_1;
tmp_26980_1 = r2sleigh_load_u8((void*)((uint8_t)((uint32_t)tmpzr_1 ^ (uint32_t)(uint8_t)1U) ? (uint64_t)arg0 : (uint64_t)((uint64_t)arg0 + (uint64_t)1U)));
x12_1 = (uint64_t)(uint8_t)tmp_26980_1;
tmp_4c900_1 = r2sleigh_load_u8((void*)((uint8_t)((uint32_t)tmpzr_1 ^ (uint32_t)(uint8_t)1U) ? (uint64_t)arg0 : (uint64_t)((uint64_t)arg0 + (uint64_t)1U)));
x12_1 = (uint64_t)(uint8_t)tmp_4c900_1;
if ((uint8_t)((uint32_t)9U < (uint32_t)((uint32_t)((uint64_t)x12_1 >> 0U) - (uint32_t)48U))) {
x10_5 = x10_1;
x11_10 = 0;
x8_11 = (uint64_t)0x14650fb0739d0383U;
} else {
tmp_11f80_1 = (uint64_t)((uint64_t)arg0 + (uint64_t)1U);
tmp_23700_1 = (uint64_t)((uint64_t)arg0 + (uint64_t)1U);
x11_6 = 0;
x12_2 = x12_1;
x16_2 = x10_1;
@@ -113,8 +113,8 @@ uint64_t _out_param_parse(uint8_t* arg0, struct fcn_1000004e0_arg1* arg1)
x11_8 = (uint64_t)(uint32_t)((uint32_t)((uint32_t)((uint64_t)x11_6 >> 0U) * (uint32_t)10U) + (uint32_t)(uint8_t)((uint32_t)((uint32_t)((uint64_t)x12_2 >> 0U) - (uint32_t)48U) >> 0U));
x8_10 = (uint64_t)((uint64_t)((uint64_t)((uint64_t)x12_2 & (uint64_t)255U) ^ (uint64_t)x8_8) * (uint64_t)0x100000001b3U);
x10_4 = (uint64_t)((uint64_t)x16_2 + (uint64_t)1U);
tmp_26a80_1 = r2sleigh_load_u8((void*)((uint64_t)tmp_11f80_1 + (uint64_t)x16_2 * 1U));
x12_3 = (uint64_t)(uint8_t)tmp_26a80_1;
tmp_4cb00_1 = r2sleigh_load_u8((void*)((uint64_t)tmp_23700_1 + (uint64_t)x16_2 * 1U));
x12_3 = (uint64_t)(uint8_t)tmp_4cb00_1;
if ((uint8_t)((uint32_t)((uint32_t)((uint64_t)x12_3 >> 0U) - (uint32_t)48U) < (uint32_t)10U)) {
x11_6 = x11_8;
x12_2 = x12_3;
@@ -139,8 +139,8 @@ uint64_t _out_param_parse(uint8_t* arg0, struct fcn_1000004e0_arg1* arg1)
if ((uint8_t)((uint64_t)x10_5 == (uint64_t)0U)) {
return 0;
} else {
tmp_26a80_2 = r2sleigh_load_u8((void*)((uint64_t)arg0 + (uint64_t)x10_5 * 1U));
return (uint64_t)(uint8_t)((uint32_t)((uint64_t)(uint8_t)tmp_26a80_2 >> 0U) == (uint32_t)0U);
tmp_4cb00_2 = r2sleigh_load_u8((void*)((uint64_t)arg0 + (uint64_t)x10_5 * 1U));
return (uint64_t)(uint8_t)((uint32_t)((uint64_t)(uint8_t)tmp_4cb00_2 >> 0U) == (uint32_t)0U);
}
}
}
@@ -161,10 +161,10 @@ uint64_t _fnv_fold(uint64_t arg0, uint64_t arg1)
uint64_t x0_8;
uint64_t x1_1;
uint64_t x8_2;
uint8_t tmp_26880_1;
uint8_t tmp_4c700_1;
uint64_t x10_1;
uint64_t x0_9;
uint64_t tmp_40b00_1;
uint64_t tmp_80000_1;
uint64_t x0_10;
/* r2dec proof: no individual construct is marked; 47 source obligations: 47 rendered, 0 elided, 0 refused; 18 statements rendered */
@@ -177,13 +177,13 @@ uint64_t _fnv_fold(uint64_t arg0, uint64_t arg1)
x1_1 = arg1;
x8_2 = x8_1;
for (; ; ) {
tmp_26880_1 = r2sleigh_load_u8((void*)x8_2);
x10_1 = (uint64_t)(uint8_t)tmp_26880_1;
tmp_4c700_1 = r2sleigh_load_u8((void*)x8_2);
x10_1 = (uint64_t)(uint8_t)tmp_4c700_1;
x0_9 = (uint64_t)((uint64_t)((uint64_t)x0_8 ^ (uint64_t)(uint32_t)((uint8_t)((uint32_t)((uint32_t)((uint64_t)x10_1 >> 0U) - (uint32_t)65U) < (uint32_t)26U) ? (uint32_t)((uint32_t)((uint64_t)x10_1 >> 0U) | (uint32_t)32U) : (uint32_t)((uint64_t)x10_1 >> 0U))) * (uint64_t)0x100000001b3U);
tmp_40b00_1 = (uint64_t)((uint64_t)x1_1 - (uint64_t)1U);
if ((uint8_t)((uint64_t)tmp_40b00_1 != (uint64_t)0U)) {
tmp_80000_1 = (uint64_t)((uint64_t)x1_1 - (uint64_t)1U);
if ((uint8_t)((uint64_t)tmp_80000_1 != (uint64_t)0U)) {
x0_8 = x0_9;
x1_1 = tmp_40b00_1;
x1_1 = tmp_80000_1;
x8_2 = (uint64_t)((uint64_t)x8_2 + (uint64_t)1U);
} else {
x0_10 = x0_9;
@@ -208,9 +208,9 @@ CMDS=aa; pdd @ 0x1000005dc
EXPECT=<<EOF
uint64_t _sparse_switch(uint32_t arg0, uint32_t arg1, uint32_t arg2)
{
uint8_t tmp_38d00_1;
uint32_t tmp_38d08_1;
uint32_t tmp_38d10_1;
uint8_t tmp_71000_1;
uint32_t tmp_71008_1;
uint32_t tmp_71010_1;
/* r2dec proof: 1 construct is marked below; 58 source obligations: 56 rendered, 0 elided, 0 refused, 2 residual; 17 statements rendered */
{
@@ -235,10 +235,10 @@ uint64_t _sparse_switch(uint32_t arg0, uint32_t arg1, uint32_t arg2)
if ((uint8_t)((uint32_t)arg2 == (uint32_t)0U)) {
return (uint64_t)0xffffffffU;
} else {
tmp_38d00_1 = (uint8_t)((uint32_t)arg2 == (uint32_t)0U);
tmp_38d08_1 = tmp_38d00_1 ? (uint32_t)1U : (uint32_t)arg2;
tmp_38d10_1 = (uint32_t)arg1 == (uint32_t)0x80000000U && (uint32_t)tmp_38d08_1 == (uint32_t)0xffffffffU ? r2sleigh_residual_u32(1) : (uint32_t)((int32_t)arg1 / (int32_t)tmp_38d08_1);
return (uint64_t)(uint32_t)(tmp_38d00_1 ? (uint32_t)0U : (uint32_t)tmp_38d10_1);
tmp_71000_1 = (uint8_t)((uint32_t)arg2 == (uint32_t)0U);
tmp_71008_1 = tmp_71000_1 ? (uint32_t)1U : (uint32_t)arg2;
tmp_71010_1 = (uint32_t)arg1 == (uint32_t)0x80000000U && (uint32_t)tmp_71008_1 == (uint32_t)0xffffffffU ? r2sleigh_residual_u32(1) : (uint32_t)((int32_t)arg1 / (int32_t)tmp_71008_1);
return (uint64_t)(uint32_t)(tmp_71000_1 ? (uint32_t)0U : (uint32_t)tmp_71010_1);
}
}
}
@@ -263,22 +263,22 @@ uint32_t _table_walk(uint64_t arg0, uint64_t arg1)
{
uint64_t x0_1;
uint64_t x8_2;
uint32_t tmp_11b80_1;
uint32_t tmp_22f00_1;
uint64_t x8_3;
uint64_t x11_1;
uint16_t tmp_26b80_1;
uint16_t tmp_4cd00_1;
uint64_t x10_1;
uint64_t x11_2;
uint64_t x12_2;
uint64_t x13_2;
uint64_t x12_3;
uint8_t tmp_26880_1;
uint8_t tmp_4c700_1;
uint64_t x14_1;
uint64_t x11_3;
uint8_t tmp_26880_2;
uint64_t tmp_40b00_1;
uint8_t tmp_26a80_1;
uint32_t tmp_26080_1;
uint8_t tmp_4c700_2;
uint64_t tmp_80000_1;
uint8_t tmp_4cb00_1;
uint32_t tmp_4b700_1;
uint64_t x0_2;
uint64_t x0_5;
@@ -290,13 +290,13 @@ uint32_t _table_walk(uint64_t arg0, uint64_t arg1)
x0_1 = arg0;
x8_2 = 0;
for (; ; ) {
tmp_11b80_1 = (uint32_t)((uint32_t)((uint64_t)x8_2 >> 0U) + (uint32_t)1U);
x8_3 = (uint64_t)(uint32_t)tmp_11b80_1;
tmp_22f00_1 = (uint32_t)((uint32_t)((uint64_t)x8_2 >> 0U) + (uint32_t)1U);
x8_3 = (uint64_t)(uint32_t)tmp_22f00_1;
x11_1 = r2sleigh_load_u64((void*)((uint64_t)x0_1 + (uint64_t)3U * 8U));
if ((uint8_t)((uint64_t)x11_1 == (uint64_t)0U)) {
} else {
tmp_26b80_1 = r2sleigh_load_u16((void*)((uint64_t)x0_1 + (uint64_t)3U * 2U));
x10_1 = (uint64_t)(uint16_t)tmp_26b80_1;
tmp_4cd00_1 = r2sleigh_load_u16((void*)((uint64_t)x0_1 + (uint64_t)3U * 2U));
x10_1 = (uint64_t)(uint16_t)tmp_4cd00_1;
if ((uint8_t)((uint64_t)x10_1 == (uint64_t)0U)) {
} else {
x11_2 = x11_1;
@@ -304,21 +304,21 @@ uint32_t _table_walk(uint64_t arg0, uint64_t arg1)
x13_2 = x10_1;
for (; ; ) {
x12_3 = (uint64_t)((uint64_t)x12_2 + (uint64_t)1U);
tmp_26880_1 = r2sleigh_load_u8((void*)x12_2);
x14_1 = (uint64_t)(uint8_t)tmp_26880_1;
tmp_4c700_1 = r2sleigh_load_u8((void*)x12_2);
x14_1 = (uint64_t)(uint8_t)tmp_4c700_1;
if ((uint8_t)((uint32_t)((uint64_t)x14_1 >> 0U) == (uint32_t)0U)) {
goto L3;
} else {
x11_3 = (uint64_t)((uint64_t)x11_2 + (uint64_t)1U);
tmp_26880_2 = r2sleigh_load_u8((void*)x11_2);
if ((uint8_t)((uint32_t)((uint64_t)x14_1 >> 0U) != (uint32_t)((uint64_t)(uint8_t)tmp_26880_2 >> 0U))) {
tmp_4c700_2 = r2sleigh_load_u8((void*)x11_2);
if ((uint8_t)((uint32_t)((uint64_t)x14_1 >> 0U) != (uint32_t)((uint64_t)(uint8_t)tmp_4c700_2 >> 0U))) {
goto L3;
} else {
tmp_40b00_1 = (uint64_t)((uint64_t)x13_2 - (uint64_t)1U);
if ((uint8_t)((uint64_t)tmp_40b00_1 != (uint64_t)0U)) {
tmp_80000_1 = (uint64_t)((uint64_t)x13_2 - (uint64_t)1U);
if ((uint8_t)((uint64_t)tmp_80000_1 != (uint64_t)0U)) {
x11_2 = x11_3;
x12_2 = x12_3;
x13_2 = tmp_40b00_1;
x13_2 = tmp_80000_1;
} else {
break;
}
@@ -337,8 +337,8 @@ L3: ;
}
{
L0: ;
tmp_26a80_1 = r2sleigh_load_u8((void*)(uint64_t)((uint64_t)arg1 + (uint64_t)x10_1));
if ((uint8_t)((uint32_t)((uint64_t)(uint8_t)tmp_26a80_1 >> 0U) == (uint32_t)0U)) {
tmp_4cb00_1 = r2sleigh_load_u8((void*)(uint64_t)((uint64_t)arg1 + (uint64_t)x10_1));
if ((uint8_t)((uint32_t)((uint64_t)(uint8_t)tmp_4cb00_1 >> 0U) == (uint32_t)0U)) {
break;
} else {
}
@@ -357,8 +357,8 @@ L1: ;
}
}
{
tmp_26080_1 = r2sleigh_load_u32((void*)x0_1);
return (uint32_t)((uint32_t)tmp_26080_1 + (uint32_t)tmp_11b80_1);
tmp_4b700_1 = r2sleigh_load_u32((void*)x0_1);
return (uint32_t)((uint32_t)tmp_4b700_1 + (uint32_t)tmp_22f00_1);
}
{
L4: ;
@@ -382,27 +382,27 @@ CMDS=aa; pdd @ 0x1000006c8
EXPECT=<<EOF
uint64_t _state_machine(uint8_t* arg0)
{
uint8_t tmp_26980_1;
uint8_t tmp_4c900_1;
uint64_t x11_1;
uint64_t x0_2;
uint64_t x10_2;
uint64_t x11_2;
uint64_t x8_2;
uint64_t x9_2;
uint32_t tmp_3f900_7;
uint32_t tmp_3f900_8;
uint32_t tmp_7dc00_7;
uint32_t tmp_7dc00_8;
uint64_t x8_3;
uint64_t x8_10;
uint64_t x10_4;
uint64_t x8_4;
uint8_t tmp_26880_1;
uint8_t tmp_4c700_1;
uint64_t x11_3;
uint64_t x0_9;
/* r2dec proof: no individual construct is marked; 154 source obligations: 150 rendered, 4 elided, 0 refused; 78 statements rendered */
{
tmp_26980_1 = r2sleigh_load_u8((void*)(uint64_t)arg0);
x11_1 = (uint64_t)(uint8_t)tmp_26980_1;
tmp_4c900_1 = r2sleigh_load_u8((void*)(uint64_t)arg0);
x11_1 = (uint64_t)(uint8_t)tmp_4c900_1;
if ((uint8_t)((uint32_t)((uint64_t)x11_1 >> 0U) == (uint32_t)0U)) {
x0_9 = 0;
} else {
@@ -425,8 +425,8 @@ uint64_t _state_machine(uint8_t* arg0)
}
default:
{
tmp_3f900_8 = (uint32_t)((uint32_t)((uint64_t)x11_2 >> 0U) - (uint32_t)58U);
if ((uint8_t)((uint32_t)(uint8_t)r2sleigh_int_carry_32((uint32_t)tmp_3f900_8, (uint32_t)11U) & (uint32_t)(uint8_t)((uint32_t)((uint32_t)tmp_3f900_8 + (uint32_t)11U) != (uint32_t)0U))) {
tmp_7dc00_8 = (uint32_t)((uint32_t)((uint64_t)x11_2 >> 0U) - (uint32_t)58U);
if ((uint8_t)((uint32_t)(uint8_t)r2sleigh_int_carry_32((uint32_t)tmp_7dc00_8, (uint32_t)11U) & (uint32_t)(uint8_t)((uint32_t)((uint32_t)tmp_7dc00_8 + (uint32_t)11U) != (uint32_t)0U))) {
x8_3 = x8_2;
} else {
goto L4;
@@ -451,8 +451,8 @@ uint64_t _state_machine(uint8_t* arg0)
goto L1;
default:
{
tmp_3f900_7 = (uint32_t)((uint32_t)((uint64_t)x11_2 >> 0U) - (uint32_t)123U);
if ((uint8_t)((uint32_t)(uint8_t)r2sleigh_int_carry_32((uint32_t)tmp_3f900_7, (uint32_t)27U) & (uint32_t)(uint8_t)((uint32_t)((uint32_t)tmp_3f900_7 + (uint32_t)27U) != (uint32_t)0U))) {
tmp_7dc00_7 = (uint32_t)((uint32_t)((uint64_t)x11_2 >> 0U) - (uint32_t)123U);
if ((uint8_t)((uint32_t)(uint8_t)r2sleigh_int_carry_32((uint32_t)tmp_7dc00_7, (uint32_t)27U) & (uint32_t)(uint8_t)((uint32_t)((uint32_t)tmp_7dc00_7 + (uint32_t)27U) != (uint32_t)0U))) {
x10_4 = 1;
x8_4 = x8_2;
goto L1;
@@ -505,8 +505,8 @@ L3: ;
}
{
L1: ;
tmp_26880_1 = r2sleigh_load_u8((void*)x9_2);
x11_3 = (uint64_t)(uint8_t)tmp_26880_1;
tmp_4c700_1 = r2sleigh_load_u8((void*)x9_2);
x11_3 = (uint64_t)(uint8_t)tmp_4c700_1;
if ((uint8_t)((uint32_t)((uint64_t)x11_3 >> 0U) == (uint32_t)0U)) {
goto L6;
} else {
@@ -777,9 +777,9 @@ uint64_t _mem_scan2(uint64_t arg0, uint64_t arg1, uint32_t arg2, uint32_t arg3)
struct r2sleigh_bits_256 z7_5;
__uint128_t tmp_lane_100000884_1_74_1;
__uint128_t tmp_lane_100000884_3_75_1;
uint64_t tmp_7b80_6;
uint64_t tmp_ef00_6;
__uint128_t tmp_lane_100000884_5_76_1;
uint64_t tmp_d1c00_1;
uint64_t tmp_1a1500_1;
__uint128_t tmp_lane_100000884_9_79_1;
uint8_t tmp_lane_100000884_15_82_1;
uint8_t tmp_lane_100000884_15_83_1;
@@ -1519,7 +1519,7 @@ uint64_t _mem_scan2(uint64_t arg0, uint64_t arg1, uint32_t arg2, uint32_t arg3)
uint64_t tmp_lane_100000884_31f_685_1;
struct r2sleigh_bits_256 z18_7;
struct r2sleigh_bits_256 z18_8;
uint64_t tmp_40b00_1;
uint64_t tmp_80000_1;
uint64_t tmp_lane_100000a04_18_6b9_1;
uint64_t tmp_lane_100000a04_19_6bc_1;
uint64_t x8_7;
@@ -1700,17 +1700,17 @@ uint64_t _mem_scan2(uint64_t arg0, uint64_t arg1, uint32_t arg2, uint32_t arg3)
uint64_t tmp_lane_100000a8c_ca_8bc_1;
struct r2sleigh_bits_256 z0_215;
struct r2sleigh_bits_256 z0_216;
uint64_t tmp_11f80_3;
uint64_t tmp_23700_3;
uint64_t x8_12;
uint64_t x8_13;
uint64_t x9_6;
uint64_t x10_9;
uint64_t x8_14;
uint64_t x9_8;
uint8_t tmp_26880_1;
uint8_t tmp_4c700_1;
uint64_t x11_2;
uint64_t x8_15;
uint64_t tmp_40b00_2;
uint64_t tmp_80000_2;
uint64_t x8_16;
/* r2dec proof: no individual construct is marked; 1466 source obligations: 1463 rendered, 3 elided, 0 refused; 1096 statements rendered */
@@ -1825,10 +1825,10 @@ uint64_t _mem_scan2(uint64_t arg0, uint64_t arg1, uint32_t arg2, uint32_t arg3)
for (; ; ) {
tmp_lane_100000884_1_74_1 = r2sleigh_bits_extract_256_128(z29_5, 0U);
tmp_lane_100000884_3_75_1 = r2sleigh_bits_extract_256_128(z27_5, 0U);
tmp_7b80_6 = (uint64_t)((uint64_t)x8_5 - (uint64_t)16U);
tmp_lane_100000884_5_76_1 = r2sleigh_load_u128((void*)tmp_7b80_6);
tmp_d1c00_1 = (uint64_t)((uint64_t)tmp_7b80_6 + (uint64_t)16U);
tmp_lane_100000884_9_79_1 = r2sleigh_load_u128((void*)tmp_d1c00_1);
tmp_ef00_6 = (uint64_t)((uint64_t)x8_5 - (uint64_t)16U);
tmp_lane_100000884_5_76_1 = r2sleigh_load_u128((void*)tmp_ef00_6);
tmp_1a1500_1 = (uint64_t)((uint64_t)tmp_ef00_6 + (uint64_t)16U);
tmp_lane_100000884_9_79_1 = r2sleigh_load_u128((void*)tmp_1a1500_1);
tmp_lane_100000884_15_82_1 = (uint8_t)((__uint128_t)tmp_lane_100000884_5_76_1 >> 0U);
tmp_lane_100000884_15_83_1 = (uint8_t)((__uint128_t)tmp_lane_100000824_29_2f_1 >> 0U);
tmp_lane_100000884_17_85_1 = (uint8_t)((__uint128_t)tmp_lane_100000884_5_76_1 >> 8U);
@@ -2567,9 +2567,9 @@ uint64_t _mem_scan2(uint64_t arg0, uint64_t arg1, uint32_t arg2, uint32_t arg3)
tmp_lane_100000884_31f_685_1 = (uint64_t)((uint64_t)tmp_lane_100000884_31f_683_1 + (uint64_t)tmp_lane_100000884_31f_684_1);
z18_7 = r2sleigh_bits_insert_256_64(z18_6, (uint64_t)tmp_lane_100000884_31f_685_1, 64U);
z18_8 = r2sleigh_bits_insert_256_64(z18_7, (uint64_t)0U, 128U);
tmp_40b00_1 = (uint64_t)((uint64_t)x10_2 - (uint64_t)32U);
if ((uint8_t)((uint64_t)tmp_40b00_1 != (uint64_t)0U)) {
x10_2 = tmp_40b00_1;
tmp_80000_1 = (uint64_t)((uint64_t)x10_2 - (uint64_t)32U);
if ((uint8_t)((uint64_t)tmp_80000_1 != (uint64_t)0U)) {
x10_2 = tmp_80000_1;
x8_5 = (uint64_t)((uint64_t)x8_5 + (uint64_t)32U);
z16_5 = r2sleigh_bits_insert_256_64(z16_8, (uint64_t)0U, 192U);
z17_5 = r2sleigh_bits_insert_256_64(z17_8, (uint64_t)0U, 192U);
@@ -2790,10 +2790,10 @@ uint64_t _mem_scan2(uint64_t arg0, uint64_t arg1, uint32_t arg2, uint32_t arg3)
tmp_lane_100000a8c_ca_8bc_1 = (uint64_t)((uint64_t)tmp_lane_100000a8c_ca_8ba_1 + (uint64_t)tmp_lane_100000a8c_ca_8bb_1);
z0_215 = r2sleigh_bits_insert_256_64(z0_214, (uint64_t)tmp_lane_100000a8c_ca_8bc_1, 64U);
z0_216 = r2sleigh_bits_insert_256_64(z0_215, (uint64_t)0U, 128U);
tmp_11f80_3 = (uint64_t)((uint64_t)x8_10 + (uint64_t)8U);
if ((uint8_t)((uint64_t)tmp_11f80_3 != (uint64_t)0U)) {
tmp_23700_3 = (uint64_t)((uint64_t)x8_10 + (uint64_t)8U);
if ((uint8_t)((uint64_t)tmp_23700_3 != (uint64_t)0U)) {
x10_6 = (uint64_t)((uint64_t)x10_6 + (uint64_t)8U);
x8_10 = tmp_11f80_3;
x8_10 = tmp_23700_3;
z0_213 = r2sleigh_bits_insert_256_64(z0_216, (uint64_t)0U, 192U);
z1_58 = r2sleigh_bits_insert_256_64(z1_61, (uint64_t)0U, 192U);
z5_18 = r2sleigh_bits_insert_256_64(z5_21, (uint64_t)0U, 192U);
@@ -2823,12 +2823,12 @@ L3: ;
x8_14 = x8_13;
x9_8 = (uint64_t)((uint64_t)arg0 + (uint64_t)x9_6);
for (; ; ) {
tmp_26880_1 = r2sleigh_load_u8((void*)x9_8);
x11_2 = (uint64_t)(uint8_t)tmp_26880_1;
tmp_4c700_1 = r2sleigh_load_u8((void*)x9_8);
x11_2 = (uint64_t)(uint8_t)tmp_4c700_1;
x8_15 = (uint8_t)((uint32_t)((uint8_t)((uint32_t)((uint64_t)x11_2 >> 0U) == (uint32_t)arg2) ? (uint8_t)1U : (uint8_t)((uint32_t)((uint64_t)x11_2 >> 0U) == (uint32_t)arg3)) ^ (uint32_t)(uint8_t)1U) ? (uint64_t)x8_14 : (uint64_t)((uint64_t)x8_14 + (uint64_t)1U);
tmp_40b00_2 = (uint64_t)((uint64_t)x10_9 - (uint64_t)1U);
if ((uint8_t)((uint64_t)tmp_40b00_2 != (uint64_t)0U)) {
x10_9 = tmp_40b00_2;
tmp_80000_2 = (uint64_t)((uint64_t)x10_9 - (uint64_t)1U);
if ((uint8_t)((uint64_t)tmp_80000_2 != (uint64_t)0U)) {
x10_9 = tmp_80000_2;
x8_14 = x8_15;
x9_8 = (uint64_t)((uint64_t)x9_8 + (uint64_t)1U);
} else {
@@ -2914,29 +2914,29 @@ uint64_t _main(uint64_t arg0, uint64_t* arg1)
struct r2sleigh_bits_256 z0_11;
__uint128_t tmp_lane_100000b4c_48_18_1;
uint64_t x0_2;
uint32_t tmp_26080_1;
uint32_t tmp_4b700_1;
uint64_t x0_3;
uint64_t x0_6;
uint64_t x0_7;
uint32_t tmp_26080_2;
uint32_t tmp_4b700_2;
uint64_t x0_10;
uint32_t tmp_26080_3;
uint32_t tmp_26080_4;
uint32_t tmp_26080_5;
uint32_t tmp_4b700_3;
uint32_t tmp_4b700_4;
uint32_t tmp_4b700_5;
uint64_t x2_2;
uint64_t x0_12;
uint32_t tmp_26080_6;
uint32_t tmp_4b700_6;
uint64_t x1_6;
uint64_t x1_9;
uint64_t x0_14;
uint32_t tmp_26080_7;
uint32_t tmp_4b700_7;
uint64_t x0_15;
uint64_t x0_18;
uint64_t x0_19;
uint32_t tmp_26080_8;
uint32_t tmp_4b700_8;
uint64_t x0_22;
uint32_t tmp_26080_9;
uint32_t tmp_26080_10;
uint32_t tmp_4b700_9;
uint32_t tmp_4b700_10;
_Alignas(16) uint8_t frame[160];
/* r2dec proof: no individual construct is marked; 175 source obligations: 155 rendered, 20 elided, 0 refused; 51 statements rendered; 1 data object type refused */
@@ -2955,8 +2955,8 @@ uint64_t _main(uint64_t arg0, uint64_t* arg1)
r2sleigh_store_u128((void*)(uint64_t)((uint64_t)(frame + 0U) + (uint64_t)16U), (__uint128_t)tmp_lane_100000b4c_48_18_1);
r2sleigh_store_u64((void*)((uint64_t)(frame + 0U) + (uint64_t)64U), (uint64_t)((uint64_t)(frame + 0U) + (uint64_t)72U));
x0_2 = (uint64_t)_struct_nested_array((uint64_t)((uint64_t)(frame + 0U) + (uint64_t)32U), (uint32_t)((uint32_t)((uint64_t)arg0 >> 0U) & (uint32_t)1U), (uint32_t)arg0);
tmp_26080_1 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_2 >> 0U) + (uint32_t)tmp_26080_1));
tmp_4b700_1 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_2 >> 0U) + (uint32_t)tmp_4b700_1));
if ((uint8_t)((int32_t)((uint64_t)arg0 >> 0U) < (int32_t)2U)) {
x0_6 = (uint64_t)0x100000cc4U;
} else {
@@ -2965,17 +2965,17 @@ uint64_t _main(uint64_t arg0, uint64_t* arg1)
}
{
x0_7 = _out_param_parse(x0_6, (uint64_t)(frame + 0U));
tmp_26080_2 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_7 >> 0U) + (uint32_t)tmp_26080_2));
tmp_4b700_2 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_7 >> 0U) + (uint32_t)tmp_4b700_2));
x0_10 = _fnv_fold((uint64_t)0x100000cc8U, 3);
tmp_26080_3 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_10 >> 0U) + (uint32_t)tmp_26080_3));
tmp_26080_4 = r2sleigh_load_u32((void*)&_manual_sink);
tmp_26080_5 = r2sleigh_load_u32((void*)((uint64_t)(frame + 0U) + (uint64_t)24U));
x2_2 = (uint64_t)(uint32_t)tmp_26080_5;
x0_12 = _sparse_switch((uint32_t)arg0, (uint32_t)tmp_26080_4, (uint32_t)x2_2);
tmp_26080_6 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_12 >> 0U) + (uint32_t)tmp_26080_6));
tmp_4b700_3 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_10 >> 0U) + (uint32_t)tmp_4b700_3));
tmp_4b700_4 = r2sleigh_load_u32((void*)&_manual_sink);
tmp_4b700_5 = r2sleigh_load_u32((void*)((uint64_t)(frame + 0U) + (uint64_t)24U));
x2_2 = (uint64_t)(uint32_t)tmp_4b700_5;
x0_12 = _sparse_switch((uint32_t)arg0, (uint32_t)tmp_4b700_4, (uint32_t)x2_2);
tmp_4b700_6 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_12 >> 0U) + (uint32_t)tmp_4b700_6));
if ((uint8_t)((int32_t)((uint64_t)arg0 >> 0U) <= (int32_t)2U)) {
x1_9 = (uint64_t)0x100000cc0U;
} else {
@@ -2984,8 +2984,8 @@ uint64_t _main(uint64_t arg0, uint64_t* arg1)
}
{
x0_14 = (uint64_t)_table_walk((uint64_t)((uint64_t)(frame + 0U) + (uint64_t)32U), x1_9);
tmp_26080_7 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_14 >> 0U) + (uint32_t)tmp_26080_7));
tmp_4b700_7 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_14 >> 0U) + (uint32_t)tmp_4b700_7));
if ((uint8_t)((int32_t)((uint64_t)arg0 >> 0U) < (int32_t)4U)) {
x0_18 = (uint64_t)0x100000cccU;
} else {
@@ -2994,13 +2994,13 @@ uint64_t _main(uint64_t arg0, uint64_t* arg1)
}
{
x0_19 = _state_machine(x0_18);
tmp_26080_8 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_19 >> 0U) + (uint32_t)tmp_26080_8));
tmp_4b700_8 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_19 >> 0U) + (uint32_t)tmp_4b700_8));
x0_22 = _mem_scan2((uint64_t)0x100000cd3U, 6, 97, 122);
tmp_26080_9 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_22 >> 0U) + (uint32_t)tmp_26080_9));
tmp_26080_10 = r2sleigh_load_u32((void*)&_manual_sink);
return (uint64_t)(uint8_t)((uint32_t)tmp_26080_10 == (uint32_t)0U);
tmp_4b700_9 = r2sleigh_load_u32((void*)&_manual_sink);
r2sleigh_store_u32((void*)&_manual_sink, (uint32_t)((uint32_t)((uint64_t)x0_22 >> 0U) + (uint32_t)tmp_4b700_9));
tmp_4b700_10 = r2sleigh_load_u32((void*)&_manual_sink);
return (uint64_t)(uint8_t)((uint32_t)tmp_4b700_10 == (uint32_t)0U);
}
}
}
+201 -201
View File
@@ -133,11 +133,11 @@ CMDS=aa; pdd @ 0x000010c0
EXPECT=<<EOF
void _start(void)
{
uint64_t tmp_55400_2;
uint64_t tmp_aa300_2;
/* r2dec proof: 5 constructs are marked below; 28 source obligations: 0 rendered, 6 elided, 0 refused, 22 residual; 1 statements rendered; 1 held from entry, read as residuals (stack_p0) */
{
tmp_55400_2 = r2sleigh_residual_u64(1);
tmp_aa300_2 = r2sleigh_residual_u64(1);
r2sleigh_residual_void(2); /* r2dec gap: StoreNotSpelled at 0x10c0:29 covering 1 op (render::values) */
r2sleigh_residual_void(3); /* r2dec gap: StoreNotSpelled at 0x10c0:32 covering 1 op (render::values) */
r2sleigh_residual_void(4); /* r2dec gap: CallNotRendered at 0x10c0:68 covering 1 op (render::values): call to __libc_start_main: the import's declaration has an argument this convention does not place */
@@ -224,18 +224,18 @@ uint64_t __do_global_dtors_aux(void)
extern char __dso_handle[];
extern char __TMC_END__[];
uint8_t tmp_3e180_1;
uint64_t tmp_3ea80_1;
uint8_t tmp_7c100_1;
uint64_t tmp_7d300_1;
uint64_t rdi_1;
/* r2dec proof: 3 constructs are marked below; 40 source obligations: 16 rendered, 17 elided, 0 refused, 7 residual; 9 statements rendered; 2 data object types refused; 1 callee prototype supplied by the source */
{
tmp_3e180_1 = r2sleigh_load_u8((void*)&__TMC_END__);
if ((uint8_t)((uint8_t)tmp_3e180_1 != (uint8_t)0U)) {
tmp_7c100_1 = r2sleigh_load_u8((void*)&__TMC_END__);
if ((uint8_t)((uint8_t)tmp_7c100_1 != (uint8_t)0U)) {
return r2sleigh_residual_u64(1);
} else {
tmp_3ea80_1 = r2sleigh_load_u64((void*)(uint64_t)0x3ff8U);
if ((uint8_t)((uint64_t)tmp_3ea80_1 == (uint64_t)0U)) {
tmp_7d300_1 = r2sleigh_load_u64((void*)(uint64_t)0x3ff8U);
if ((uint8_t)((uint64_t)tmp_7d300_1 == (uint64_t)0U)) {
} else {
rdi_1 = r2sleigh_load_u64((void*)&__dso_handle);
__cxa_finalize((void*)rdi_1);
@@ -296,11 +296,11 @@ CMDS=aa; pdd @ 0x000011c1
EXPECT=<<EOF
uint32_t sum_array(const uint32_t* v, int32_t n)
{
uint32_t tmp_11f00_1;
uint32_t tmp_11f00_2;
uint32_t tmp_11f00_3;
uint32_t tmp_6a80_7;
uint32_t tmp_6a80_14;
uint32_t tmp_23c00_1;
uint32_t tmp_23c00_2;
uint32_t tmp_23c00_3;
uint32_t tmp_d300_7;
uint32_t tmp_d300_14;
_Alignas(16) uint8_t frame[40];
/* r2dec proof: no individual construct is marked; 42 source obligations: 28 rendered, 14 elided, 0 refused; 13 statements rendered */
@@ -308,14 +308,14 @@ uint32_t sum_array(const uint32_t* v, int32_t n)
r2sleigh_store_u32((void*)(uint64_t)(frame + 24U), (uint32_t)0U);
r2sleigh_store_u32((void*)(uint64_t)(frame + 28U), (uint32_t)0U);
for (; ; ) {
tmp_11f00_1 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
if ((uint8_t)((int32_t)tmp_11f00_1 < (int32_t)n)) {
tmp_11f00_2 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
tmp_11f00_3 = r2sleigh_load_u32((void*)((uint64_t)v + (uint64_t)(int32_t)tmp_11f00_2 * 4U));
tmp_6a80_7 = r2sleigh_load_u32((void*)(uint64_t)(frame + 24U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 24U), (uint32_t)((uint32_t)tmp_6a80_7 + (uint32_t)tmp_11f00_3));
tmp_6a80_14 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 28U), (uint32_t)((uint32_t)tmp_6a80_14 + (uint32_t)1U));
tmp_23c00_1 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
if ((uint8_t)((int32_t)tmp_23c00_1 < (int32_t)n)) {
tmp_23c00_2 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
tmp_23c00_3 = r2sleigh_load_u32((void*)((uint64_t)v + (uint64_t)(int32_t)tmp_23c00_2 * 4U));
tmp_d300_7 = r2sleigh_load_u32((void*)(uint64_t)(frame + 24U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 24U), (uint32_t)((uint32_t)tmp_d300_7 + (uint32_t)tmp_23c00_3));
tmp_d300_14 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 28U), (uint32_t)((uint32_t)tmp_d300_14 + (uint32_t)1U));
} else {
break;
}
@@ -410,9 +410,9 @@ struct node {
int32_t list_len(const struct node* n)
{
uint64_t tmp_11f80_1;
uint32_t tmp_6a80_4;
uint64_t tmp_11f80_2;
uint64_t tmp_23d00_1;
uint32_t tmp_d300_4;
uint64_t tmp_23d00_2;
_Alignas(16) uint8_t frame[40];
/* r2dec proof: no individual construct is marked; 37 source obligations: 23 rendered, 14 elided, 0 refused; 11 statements rendered */
@@ -420,12 +420,12 @@ int32_t list_len(const struct node* n)
r2sleigh_store_u64((void*)(uint64_t)(frame + 8U), (uint64_t)n);
r2sleigh_store_u32((void*)(uint64_t)(frame + 28U), (uint32_t)0U);
for (; ; ) {
tmp_11f80_1 = r2sleigh_load_u64((void*)(uint64_t)(frame + 8U));
if ((uint8_t)((uint64_t)tmp_11f80_1 != (uint64_t)0U)) {
tmp_6a80_4 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 28U), (uint32_t)((uint32_t)tmp_6a80_4 + (uint32_t)1U));
tmp_11f80_2 = r2sleigh_load_u64((void*)(uint64_t)(frame + 8U));
r2sleigh_store_u64((void*)(uint64_t)(frame + 8U), (uint64_t)r2sleigh_load_u64((void*)(uint64_t)((uint64_t)tmp_11f80_2 + (uint64_t)8U)));
tmp_23d00_1 = r2sleigh_load_u64((void*)(uint64_t)(frame + 8U));
if ((uint8_t)((uint64_t)tmp_23d00_1 != (uint64_t)0U)) {
tmp_d300_4 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 28U), (uint32_t)((uint32_t)tmp_d300_4 + (uint32_t)1U));
tmp_23d00_2 = r2sleigh_load_u64((void*)(uint64_t)(frame + 8U));
r2sleigh_store_u64((void*)(uint64_t)(frame + 8U), (uint64_t)r2sleigh_load_u64((void*)(uint64_t)((uint64_t)tmp_23d00_2 + (uint64_t)8U)));
} else {
break;
}
@@ -448,23 +448,23 @@ EXPECT=<<EOF
int64_t mul_div(int64_t a, int64_t b)
{
uint64_t rax_4;
__uint128_t tmp_3d800_1;
__uint128_t tmp_7ae00_1;
uint64_t rdx_2;
__uint128_t tmp_49d00_1;
__uint128_t tmp_49d80_1;
__uint128_t tmp_49e00_1;
__uint128_t tmp_49e80_1;
__uint128_t tmp_49f80_1;
__uint128_t tmp_4a080_1;
__uint128_t tmp_93800_1;
__uint128_t tmp_93900_1;
__uint128_t tmp_93a00_1;
__uint128_t tmp_93b00_1;
__uint128_t tmp_93d00_1;
__uint128_t tmp_93f00_1;
uint64_t rax_5;
__uint128_t tmp_3d800_2;
__uint128_t tmp_7ae00_2;
uint64_t rdx_4;
__uint128_t tmp_49d00_2;
__uint128_t tmp_49d80_2;
__uint128_t tmp_49e00_2;
__uint128_t tmp_49e80_2;
__uint128_t tmp_49f80_2;
__uint128_t tmp_4a200_2;
__uint128_t tmp_93800_2;
__uint128_t tmp_93900_2;
__uint128_t tmp_93a00_2;
__uint128_t tmp_93b00_2;
__uint128_t tmp_93d00_2;
__uint128_t tmp_94200_2;
uint64_t rdx_5;
uint64_t rax_10;
@@ -472,26 +472,26 @@ int64_t mul_div(int64_t a, int64_t b)
{
if ((uint8_t)((uint64_t)b != (uint64_t)0U)) {
rax_4 = (uint64_t)((uint64_t)((uint64_t)a * (uint64_t)8U) - (uint64_t)a);
tmp_3d800_1 = (__uint128_t)(int64_t)rax_4;
rdx_2 = (uint64_t)((__uint128_t)tmp_3d800_1 >> 64U);
tmp_49d00_1 = (__uint128_t)(int64_t)b;
tmp_49d80_1 = (__uint128_t)(uint64_t)rdx_2;
tmp_49e00_1 = (__uint128_t)(uint32_t)64U >= (__uint128_t)128U ? (__uint128_t)0U : (__uint128_t)((__uint128_t)tmp_49d80_1 << (__uint128_t)(uint32_t)64U);
tmp_49e80_1 = (__uint128_t)(uint64_t)rax_4;
tmp_49f80_1 = (__uint128_t)((__uint128_t)tmp_49e00_1 | (__uint128_t)tmp_49e80_1);
tmp_4a080_1 = (__uint128_t)tmp_49f80_1 == (__uint128_t)((__uint128_t)0x8000000000000000U << 64U | (__uint128_t)0U) && (__uint128_t)tmp_49d00_1 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? r2sleigh_residual_u128(1) : (__uint128_t)((__int128_t)tmp_49f80_1 / (__int128_t)tmp_49d00_1);
rax_5 = (uint64_t)((__uint128_t)tmp_4a080_1 >> 0U);
(void)((__uint128_t)tmp_49d00_1 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0U) : (__uint128_t)((__int128_t)tmp_49f80_1 % (__int128_t)tmp_49d00_1));
tmp_3d800_2 = (__uint128_t)(int64_t)a;
rdx_4 = (uint64_t)((__uint128_t)tmp_3d800_2 >> 64U);
tmp_49d00_2 = (__uint128_t)(int64_t)b;
tmp_49d80_2 = (__uint128_t)(uint64_t)rdx_4;
tmp_49e00_2 = (__uint128_t)(uint32_t)64U >= (__uint128_t)128U ? (__uint128_t)0U : (__uint128_t)((__uint128_t)tmp_49d80_2 << (__uint128_t)(uint32_t)64U);
tmp_49e80_2 = (__uint128_t)(uint64_t)a;
tmp_49f80_2 = (__uint128_t)((__uint128_t)tmp_49e00_2 | (__uint128_t)tmp_49e80_2);
(void)((__uint128_t)tmp_49f80_2 == (__uint128_t)((__uint128_t)0x8000000000000000U << 64U | (__uint128_t)0U) && (__uint128_t)tmp_49d00_2 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? r2sleigh_residual_u128(2) : (__uint128_t)((__int128_t)tmp_49f80_2 / (__int128_t)tmp_49d00_2));
tmp_4a200_2 = (__uint128_t)tmp_49d00_2 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0U) : (__uint128_t)((__int128_t)tmp_49f80_2 % (__int128_t)tmp_49d00_2);
rdx_5 = (uint64_t)((__uint128_t)tmp_4a200_2 >> 0U);
tmp_7ae00_1 = (__uint128_t)(int64_t)rax_4;
rdx_2 = (uint64_t)((__uint128_t)tmp_7ae00_1 >> 64U);
tmp_93800_1 = (__uint128_t)(int64_t)b;
tmp_93900_1 = (__uint128_t)(uint64_t)rdx_2;
tmp_93a00_1 = (__uint128_t)(uint32_t)64U >= (__uint128_t)128U ? (__uint128_t)0U : (__uint128_t)((__uint128_t)tmp_93900_1 << (__uint128_t)(uint32_t)64U);
tmp_93b00_1 = (__uint128_t)(uint64_t)rax_4;
tmp_93d00_1 = (__uint128_t)((__uint128_t)tmp_93a00_1 | (__uint128_t)tmp_93b00_1);
tmp_93f00_1 = (__uint128_t)tmp_93d00_1 == (__uint128_t)((__uint128_t)0x8000000000000000U << 64U | (__uint128_t)0U) && (__uint128_t)tmp_93800_1 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? r2sleigh_residual_u128(1) : (__uint128_t)((__int128_t)tmp_93d00_1 / (__int128_t)tmp_93800_1);
rax_5 = (uint64_t)((__uint128_t)tmp_93f00_1 >> 0U);
(void)((__uint128_t)tmp_93800_1 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0U) : (__uint128_t)((__int128_t)tmp_93d00_1 % (__int128_t)tmp_93800_1));
tmp_7ae00_2 = (__uint128_t)(int64_t)a;
rdx_4 = (uint64_t)((__uint128_t)tmp_7ae00_2 >> 64U);
tmp_93800_2 = (__uint128_t)(int64_t)b;
tmp_93900_2 = (__uint128_t)(uint64_t)rdx_4;
tmp_93a00_2 = (__uint128_t)(uint32_t)64U >= (__uint128_t)128U ? (__uint128_t)0U : (__uint128_t)((__uint128_t)tmp_93900_2 << (__uint128_t)(uint32_t)64U);
tmp_93b00_2 = (__uint128_t)(uint64_t)a;
tmp_93d00_2 = (__uint128_t)((__uint128_t)tmp_93a00_2 | (__uint128_t)tmp_93b00_2);
(void)((__uint128_t)tmp_93d00_2 == (__uint128_t)((__uint128_t)0x8000000000000000U << 64U | (__uint128_t)0U) && (__uint128_t)tmp_93800_2 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? r2sleigh_residual_u128(2) : (__uint128_t)((__int128_t)tmp_93d00_2 / (__int128_t)tmp_93800_2));
tmp_94200_2 = (__uint128_t)tmp_93800_2 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0U) : (__uint128_t)((__int128_t)tmp_93d00_2 % (__int128_t)tmp_93800_2);
rdx_5 = (uint64_t)((__uint128_t)tmp_94200_2 >> 0U);
rax_10 = (uint64_t)((uint64_t)rdx_5 + (uint64_t)rax_5);
} else {
rax_10 = 0;
@@ -513,15 +513,15 @@ CMDS=aa; pdd @ 0x000012ef
EXPECT=<<EOF
double avg(const double* v, int32_t n)
{
uint32_t tmp_11f00_1;
uint64_t tmp_6b00_6;
uint32_t tmp_23c00_1;
uint64_t tmp_d400_6;
__uint128_t xmm0_7;
double tmp_lane_1348_8_13_1;
__uint128_t xmm0_10;
uint32_t tmp_11f00_2;
uint64_t tmp_6b00_3;
uint64_t tmp_6b00_4;
uint32_t tmp_6a80_6;
uint32_t tmp_23c00_2;
uint64_t tmp_d400_3;
uint64_t tmp_d400_4;
uint32_t tmp_d300_6;
_Alignas(16) uint8_t frame[40];
/* r2dec proof: no individual construct is marked; 53 source obligations: 38 rendered, 15 elided, 0 refused; 19 statements rendered */
@@ -529,14 +529,14 @@ double avg(const double* v, int32_t n)
r2sleigh_store_u64((void*)(uint64_t)(frame + 24U), (uint64_t)0U);
r2sleigh_store_u32((void*)(uint64_t)(frame + 20U), (uint32_t)0U);
for (; ; ) {
tmp_11f00_1 = r2sleigh_load_u32((void*)(uint64_t)(frame + 20U));
if ((uint8_t)((int32_t)tmp_11f00_1 < (int32_t)n)) {
tmp_11f00_2 = r2sleigh_load_u32((void*)(uint64_t)(frame + 20U));
tmp_6b00_3 = r2sleigh_load_u64((void*)((uint64_t)v + (uint64_t)(int32_t)tmp_11f00_2 * 8U));
tmp_6b00_4 = r2sleigh_load_u64((void*)(uint64_t)(frame + 24U));
r2sleigh_store_u64((void*)(uint64_t)(frame + 24U), (uint64_t)r2sleigh_float_to_bits_64(r2sleigh_float_from_bits_64(tmp_6b00_3) + r2sleigh_float_from_bits_64(tmp_6b00_4)));
tmp_6a80_6 = r2sleigh_load_u32((void*)(uint64_t)(frame + 20U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 20U), (uint32_t)((uint32_t)tmp_6a80_6 + (uint32_t)1U));
tmp_23c00_1 = r2sleigh_load_u32((void*)(uint64_t)(frame + 20U));
if ((uint8_t)((int32_t)tmp_23c00_1 < (int32_t)n)) {
tmp_23c00_2 = r2sleigh_load_u32((void*)(uint64_t)(frame + 20U));
tmp_d400_3 = r2sleigh_load_u64((void*)((uint64_t)v + (uint64_t)(int32_t)tmp_23c00_2 * 8U));
tmp_d400_4 = r2sleigh_load_u64((void*)(uint64_t)(frame + 24U));
r2sleigh_store_u64((void*)(uint64_t)(frame + 24U), (uint64_t)r2sleigh_float_to_bits_64(r2sleigh_float_from_bits_64(tmp_d400_3) + r2sleigh_float_from_bits_64(tmp_d400_4)));
tmp_d300_6 = r2sleigh_load_u32((void*)(uint64_t)(frame + 20U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 20U), (uint32_t)((uint32_t)tmp_d300_6 + (uint32_t)1U));
} else {
break;
}
@@ -545,9 +545,9 @@ double avg(const double* v, int32_t n)
if ((uint8_t)((uint32_t)n == (uint32_t)0U)) {
xmm0_10 = 0;
} else {
tmp_6b00_6 = r2sleigh_load_u64((void*)(uint64_t)(frame + 24U));
tmp_d400_6 = r2sleigh_load_u64((void*)(uint64_t)(frame + 24U));
xmm0_7 = (__uint128_t)(((__uint128_t)0U & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffffffffffULL)) | ((__uint128_t)(uint64_t)0U & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffffffffffULL)) << 64U);
tmp_lane_1348_8_13_1 = r2sleigh_float_from_bits_64(tmp_6b00_6) / (double)(int32_t)n;
tmp_lane_1348_8_13_1 = r2sleigh_float_from_bits_64(tmp_d400_6) / (double)(int32_t)n;
xmm0_10 = (__uint128_t)(((__uint128_t)xmm0_7 & (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0U)) | ((__uint128_t)r2sleigh_float_to_bits_64(tmp_lane_1348_8_13_1) & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffffffffffULL)) << 0U);
}
{
@@ -599,24 +599,24 @@ void fill(int32_t v)
extern int32_t g_counter;
extern int32_t g_table[16];
uint32_t tmp_11f00_1;
uint32_t tmp_23c00_1;
uint32_t tmp_lane_13cf_0_7_1;
uint32_t tmp_11f00_3;
uint32_t tmp_11f00_4;
uint32_t tmp_6a80_6;
uint32_t tmp_23c00_3;
uint32_t tmp_23c00_4;
uint32_t tmp_d300_6;
_Alignas(16) uint8_t frame[40];
/* r2dec proof: no individual construct is marked; 41 source obligations: 28 rendered, 13 elided, 0 refused; 13 statements rendered; 2 data object types supplied by the source */
{
r2sleigh_store_u32((void*)(uint64_t)(frame + 28U), (uint32_t)0U);
for (; ; ) {
tmp_11f00_1 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
if ((uint8_t)((int32_t)tmp_11f00_1 <= (int32_t)15U)) {
tmp_11f00_3 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
tmp_11f00_4 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
r2sleigh_store_u32((void*)((uint64_t)((uint64_t)(int32_t)tmp_11f00_4 * (uint64_t)4U) + (uint64_t)&g_table), (uint32_t)((uint64_t)((uint64_t)(uint32_t)v + (uint64_t)(uint32_t)tmp_11f00_3) >> 0U));
tmp_6a80_6 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 28U), (uint32_t)((uint32_t)tmp_6a80_6 + (uint32_t)1U));
tmp_23c00_1 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
if ((uint8_t)((int32_t)tmp_23c00_1 <= (int32_t)15U)) {
tmp_23c00_3 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
tmp_23c00_4 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
r2sleigh_store_u32((void*)((uint64_t)((uint64_t)(int32_t)tmp_23c00_4 * (uint64_t)4U) + (uint64_t)&g_table), (uint32_t)((uint64_t)((uint64_t)(uint32_t)v + (uint64_t)(uint32_t)tmp_23c00_3) >> 0U));
tmp_d300_6 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 28U), (uint32_t)((uint32_t)tmp_d300_6 + (uint32_t)1U));
} else {
break;
}
@@ -644,28 +644,28 @@ uint64_t copy_name(char* dst, const char* src, uint64_t cap)
uint64_t strlen(const char*);
uint64_t rax_2;
uint64_t tmp_11f80_2;
uint64_t tmp_11f80_5;
uint64_t tmp_11f80_9;
uint64_t tmp_11f80_10;
uint64_t tmp_23d00_2;
uint64_t tmp_23d00_5;
uint64_t tmp_23d00_9;
uint64_t tmp_23d00_10;
_Alignas(16) uint8_t frame[72];
/* r2dec proof: no individual construct is marked; 52 source obligations: 33 rendered, 19 elided, 0 refused; 11 statements rendered; 2 callee prototypes supplied by the source */
{
rax_2 = strlen(src);
r2sleigh_store_u64((void*)(uint64_t)(frame + 56U), (uint64_t)rax_2);
tmp_11f80_2 = r2sleigh_load_u64((void*)(uint64_t)(frame + 56U));
if ((uint8_t)((uint64_t)tmp_11f80_2 < (uint64_t)cap)) {
tmp_23d00_2 = r2sleigh_load_u64((void*)(uint64_t)(frame + 56U));
if ((uint8_t)((uint64_t)tmp_23d00_2 < (uint64_t)cap)) {
} else {
r2sleigh_store_u64((void*)(uint64_t)(frame + 56U), (uint64_t)((uint64_t)cap - (uint64_t)1U));
}
{
tmp_11f80_5 = r2sleigh_load_u64((void*)(uint64_t)(frame + 56U));
memcpy((void*)(uint64_t)dst, (const void*)(uint64_t)src, tmp_11f80_5);
tmp_11f80_9 = r2sleigh_load_u64((void*)(uint64_t)(frame + 56U));
r2sleigh_store_u8((void*)((uint64_t)dst + (uint64_t)tmp_11f80_9 * 1U), (uint8_t)0U);
tmp_11f80_10 = r2sleigh_load_u64((void*)(uint64_t)(frame + 56U));
return (uint64_t)tmp_11f80_10;
tmp_23d00_5 = r2sleigh_load_u64((void*)(uint64_t)(frame + 56U));
memcpy((void*)(uint64_t)dst, (const void*)(uint64_t)src, tmp_23d00_5);
tmp_23d00_9 = r2sleigh_load_u64((void*)(uint64_t)(frame + 56U));
r2sleigh_store_u8((void*)((uint64_t)dst + (uint64_t)tmp_23d00_9 * 1U), (uint8_t)0U);
tmp_23d00_10 = r2sleigh_load_u64((void*)(uint64_t)(frame + 56U));
return (uint64_t)tmp_23d00_10;
}
}
}
@@ -683,7 +683,7 @@ int16_t sext(int8_t x)
{
uint64_t rdi_1;
uint64_t rax_1;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint16_t tmp_lane_144c_b_3_1;
uint64_t rax_2;
_Alignas(16) uint8_t frame[24];
@@ -693,8 +693,8 @@ int16_t sext(int8_t x)
rdi_1 = (uint64_t)(((uint64_t)r2sleigh_residual_u64(1) & (uint64_t)-0x100) | ((uint64_t)(uint8_t)x & (uint64_t)255U) << 0U);
rax_1 = (uint64_t)(uint32_t)((uint64_t)rdi_1 >> 0U);
r2sleigh_store_u8((void*)(uint64_t)(frame + 12U), (uint8_t)x);
tmp_11e00_1 = r2sleigh_load_u8((void*)(uint64_t)(frame + 12U));
tmp_lane_144c_b_3_1 = (uint16_t)(int8_t)tmp_11e00_1;
tmp_23a00_1 = r2sleigh_load_u8((void*)(uint64_t)(frame + 12U));
tmp_lane_144c_b_3_1 = (uint16_t)(int8_t)tmp_23a00_1;
rax_2 = (uint64_t)(((uint64_t)rax_1 & (uint64_t)0xffffffffffff0000U) | ((uint64_t)tmp_lane_144c_b_3_1 & (uint64_t)0xffffU) << 0U);
return (int16_t)((uint32_t)((uint64_t)rax_2 >> 0U) - (uint32_t)((uint64_t)((uint64_t)rax_2 * (uint64_t)4U) >> 0U));
}
@@ -711,12 +711,12 @@ CMDS=aa; pdd @ 0x0000146d
EXPECT=<<EOF
uint32_t rotl(uint32_t x, int32_t r)
{
uint8_t tmp_63380_1;
uint8_t tmp_c6100_1;
/* r2dec proof: no individual construct is marked; 15 source obligations: 8 rendered, 7 elided, 0 refused; 2 statements rendered */
{
tmp_63380_1 = (uint8_t)((uint32_t)(uint8_t)((uint32_t)r >> 0U) & (uint32_t)(uint8_t)31U);
return (uint32_t)((uint32_t)((uint32_t)tmp_63380_1 >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)x << (uint32_t)tmp_63380_1)) | (uint32_t)((uint32_t)(uint8_t)((uint32_t)(uint8_t)32U - (uint32_t)tmp_63380_1) >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)x >> (uint32_t)(uint8_t)((uint32_t)(uint8_t)32U - (uint32_t)tmp_63380_1))));
tmp_c6100_1 = (uint8_t)((uint32_t)(uint8_t)((uint32_t)r >> 0U) & (uint32_t)(uint8_t)31U);
return (uint32_t)((uint32_t)((uint32_t)tmp_c6100_1 >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)x << (uint32_t)tmp_c6100_1)) | (uint32_t)((uint32_t)(uint8_t)((uint32_t)(uint8_t)32U - (uint32_t)tmp_c6100_1) >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)x >> (uint32_t)(uint8_t)((uint32_t)(uint8_t)32U - (uint32_t)tmp_c6100_1))));
}
}
@@ -731,10 +731,10 @@ CMDS=aa; pdd @ 0x00001489
EXPECT=<<EOF
int32_t bit_count(uint32_t x)
{
uint32_t tmp_11f00_1;
uint32_t tmp_11f00_2;
uint32_t tmp_6a80_3;
uint32_t tmp_6a80_10;
uint32_t tmp_23c00_1;
uint32_t tmp_23c00_2;
uint32_t tmp_d300_3;
uint32_t tmp_d300_10;
_Alignas(16) uint8_t frame[40];
/* r2dec proof: no individual construct is marked; 38 source obligations: 24 rendered, 14 elided, 0 refused; 12 statements rendered */
@@ -742,13 +742,13 @@ int32_t bit_count(uint32_t x)
r2sleigh_store_u32((void*)(uint64_t)(frame + 12U), (uint32_t)x);
r2sleigh_store_u32((void*)(uint64_t)(frame + 28U), (uint32_t)0U);
for (; ; ) {
tmp_11f00_1 = r2sleigh_load_u32((void*)(uint64_t)(frame + 12U));
if ((uint8_t)((uint32_t)tmp_11f00_1 != (uint32_t)0U)) {
tmp_11f00_2 = r2sleigh_load_u32((void*)(uint64_t)(frame + 12U));
tmp_6a80_3 = r2sleigh_load_u32((void*)(uint64_t)(frame + 12U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 12U), (uint32_t)((uint32_t)((uint32_t)tmp_11f00_2 - (uint32_t)1U) & (uint32_t)tmp_6a80_3));
tmp_6a80_10 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 28U), (uint32_t)((uint32_t)tmp_6a80_10 + (uint32_t)1U));
tmp_23c00_1 = r2sleigh_load_u32((void*)(uint64_t)(frame + 12U));
if ((uint8_t)((uint32_t)tmp_23c00_1 != (uint32_t)0U)) {
tmp_23c00_2 = r2sleigh_load_u32((void*)(uint64_t)(frame + 12U));
tmp_d300_3 = r2sleigh_load_u32((void*)(uint64_t)(frame + 12U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 12U), (uint32_t)((uint32_t)((uint32_t)tmp_23c00_2 - (uint32_t)1U) & (uint32_t)tmp_d300_3));
tmp_d300_10 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 28U), (uint32_t)((uint32_t)tmp_d300_10 + (uint32_t)1U));
} else {
break;
}
@@ -770,13 +770,13 @@ CMDS=aa; pdd @ 0x000014b5
EXPECT=<<EOF
int32_t find(const int32_t* v, int32_t n, int32_t key)
{
uint32_t tmp_11f00_1;
uint32_t tmp_11f00_2;
uint32_t tmp_11f00_3;
uint32_t tmp_11f00_5;
uint32_t tmp_11f00_6;
uint32_t tmp_11f00_7;
uint32_t tmp_6a80_7;
uint32_t tmp_23c00_1;
uint32_t tmp_23c00_2;
uint32_t tmp_23c00_3;
uint32_t tmp_23c00_5;
uint32_t tmp_23c00_6;
uint32_t tmp_23c00_7;
uint32_t tmp_d300_7;
uint64_t rax_14;
_Alignas(16) uint8_t frame[40];
@@ -784,18 +784,18 @@ int32_t find(const int32_t* v, int32_t n, int32_t key)
{
r2sleigh_store_u32((void*)(uint64_t)(frame + 28U), (uint32_t)0U);
for (; ; ) {
tmp_11f00_1 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
if ((uint8_t)((int32_t)tmp_11f00_1 < (int32_t)n)) {
tmp_11f00_2 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
tmp_11f00_3 = r2sleigh_load_u32((void*)((uint64_t)v + (uint64_t)(int32_t)tmp_11f00_2 * 4U));
if ((uint8_t)((uint32_t)key != (uint32_t)tmp_11f00_3)) {
tmp_11f00_6 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
tmp_11f00_7 = r2sleigh_load_u32((void*)((uint64_t)v + (uint64_t)(int32_t)tmp_11f00_6 * 4U));
if ((uint8_t)((int32_t)key < (int32_t)tmp_11f00_7)) {
tmp_23c00_1 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
if ((uint8_t)((int32_t)tmp_23c00_1 < (int32_t)n)) {
tmp_23c00_2 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
tmp_23c00_3 = r2sleigh_load_u32((void*)((uint64_t)v + (uint64_t)(int32_t)tmp_23c00_2 * 4U));
if ((uint8_t)((uint32_t)key != (uint32_t)tmp_23c00_3)) {
tmp_23c00_6 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
tmp_23c00_7 = r2sleigh_load_u32((void*)((uint64_t)v + (uint64_t)(int32_t)tmp_23c00_6 * 4U));
if ((uint8_t)((int32_t)key < (int32_t)tmp_23c00_7)) {
goto L2;
} else {
tmp_6a80_7 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 28U), (uint32_t)((uint32_t)tmp_6a80_7 + (uint32_t)1U));
tmp_d300_7 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 28U), (uint32_t)((uint32_t)tmp_d300_7 + (uint32_t)1U));
}
} else {
goto L0;
@@ -809,8 +809,8 @@ int32_t find(const int32_t* v, int32_t n, int32_t key)
}
{
L0: ;
tmp_11f00_5 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_14 = (uint64_t)(uint32_t)tmp_11f00_5;
tmp_23c00_5 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_14 = (uint64_t)(uint32_t)tmp_23c00_5;
goto L4;
}
{
@@ -880,43 +880,43 @@ int32_t main(int32_t argc, char** argv)
uint32_t sum_array(const uint32_t*, int32_t);
extern const int8_t* g_msg;
uint32_t tmp_11f00_1;
uint32_t tmp_23c00_1;
uint64_t rax_6;
uint64_t rax_8;
uint32_t tmp_11f00_2;
uint32_t tmp_11f00_3;
uint32_t tmp_23c00_2;
uint32_t tmp_23c00_3;
uint64_t rax_11;
uint32_t tmp_6a80_13;
uint32_t tmp_d300_13;
uint64_t rax_13;
uint32_t tmp_6a80_20;
uint32_t tmp_11f00_4;
uint32_t tmp_d300_20;
uint32_t tmp_23c00_4;
uint64_t rax_16;
uint64_t rax_17;
uint32_t tmp_6a80_27;
uint32_t tmp_d300_27;
__uint128_t xmm0_7;
uint64_t tmp_lane_1549_e1_21_1;
uint32_t tmp_6a80_34;
uint32_t tmp_d300_34;
uint64_t rax_21;
uint32_t tmp_6a80_41;
uint32_t tmp_11f00_5;
uint32_t tmp_11f00_6;
uint64_t tmp_11f80_2;
uint64_t tmp_11f80_3;
uint32_t tmp_d300_41;
uint32_t tmp_23c00_5;
uint32_t tmp_23c00_6;
uint64_t tmp_23d00_2;
uint64_t tmp_23d00_3;
uint64_t rax_27;
uint64_t rax_28;
uint32_t tmp_6a80_48;
uint32_t tmp_11f00_7;
uint32_t tmp_d300_48;
uint32_t tmp_23c00_7;
uint64_t rax_31;
uint32_t tmp_11f00_8;
uint32_t tmp_23c00_8;
uint64_t rax_33;
uint64_t rax_34;
uint32_t tmp_11f00_9;
uint32_t tmp_23c00_9;
uint64_t rax_38;
uint32_t tmp_11f00_10;
uint32_t tmp_23c00_10;
uint64_t rax_41;
uint32_t tmp_6a80_56;
uint32_t tmp_11f00_11;
uint32_t tmp_11f00_12;
uint32_t tmp_d300_56;
uint32_t tmp_23c00_11;
uint32_t tmp_23c00_12;
uint32_t tmp_lane_16f0_94_4d_1;
_Alignas(16) uint8_t frame[248];
@@ -940,36 +940,36 @@ int32_t main(int32_t argc, char** argv)
r2sleigh_store_u64((void*)(uint64_t)(frame + 160U), (uint64_t)0x3ff0000000000000U);
r2sleigh_store_u64((void*)((uint64_t)(frame + 160U) + (uint64_t)8U), (uint64_t)0x4004000000000000U);
r2sleigh_store_u64((void*)((uint64_t)(frame + 160U) + (uint64_t)16U), (uint64_t)0x400c000000000000U);
tmp_11f00_1 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_6 = (uint64_t)(uint32_t)add((int32_t)tmp_11f00_1, 3);
tmp_23c00_1 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_6 = (uint64_t)(uint32_t)add((int32_t)tmp_23c00_1, 3);
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint64_t)rax_6 >> 0U));
rax_8 = (uint64_t)sum_array((const uint32_t*)(uint64_t)(frame + 48U), 4);
tmp_11f00_2 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_8 >> 0U) + (uint32_t)tmp_11f00_2));
tmp_11f00_3 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_11 = (uint64_t)(uint32_t)classify((int32_t)tmp_11f00_3);
tmp_23c00_2 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_8 >> 0U) + (uint32_t)tmp_23c00_2));
tmp_23c00_3 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_11 = (uint64_t)(uint32_t)classify((int32_t)tmp_23c00_3);
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_6a80_13 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_11 >> 0U) + (uint32_t)tmp_6a80_13));
tmp_d300_13 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_11 >> 0U) + (uint32_t)tmp_d300_13));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
rax_13 = (uint64_t)(uint32_t)list_len((const struct node*)(uint64_t)(frame + 128U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_6a80_20 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_13 >> 0U) + (uint32_t)tmp_6a80_20));
tmp_d300_20 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_13 >> 0U) + (uint32_t)tmp_d300_20));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_11f00_4 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_16 = (uint64_t)(int32_t)((uint64_t)((uint64_t)(int32_t)tmp_11f00_4 * (uint64_t)100U) >> 0U);
tmp_23c00_4 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_16 = (uint64_t)(int32_t)((uint64_t)((uint64_t)(int32_t)tmp_23c00_4 * (uint64_t)100U) >> 0U);
rax_17 = (uint64_t)mul_div((int64_t)rax_16, 3);
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_6a80_27 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_17 >> 0U) + (uint32_t)tmp_6a80_27));
tmp_d300_27 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_17 >> 0U) + (uint32_t)tmp_d300_27));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
@@ -977,59 +977,59 @@ int32_t main(int32_t argc, char** argv)
tmp_lane_1549_e1_21_1 = (uint64_t)((__uint128_t)xmm0_7 >> 0U);
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_6a80_34 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)(r2sleigh_float_from_bits_64(tmp_lane_1549_e1_21_1) > -2147483649.0 && r2sleigh_float_from_bits_64(tmp_lane_1549_e1_21_1) < 2147483648.0 ? (int32_t)r2sleigh_float_from_bits_64(tmp_lane_1549_e1_21_1) : r2sleigh_residual_i32(1)) + (uint32_t)tmp_6a80_34));
tmp_d300_34 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)(r2sleigh_float_from_bits_64(tmp_lane_1549_e1_21_1) > -2147483649.0 && r2sleigh_float_from_bits_64(tmp_lane_1549_e1_21_1) < 2147483648.0 ? (int32_t)r2sleigh_float_from_bits_64(tmp_lane_1549_e1_21_1) : r2sleigh_residual_i32(1)) + (uint32_t)tmp_d300_34));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
rax_21 = (uint64_t)(uint32_t)fact(5);
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_6a80_41 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_21 >> 0U) + (uint32_t)tmp_6a80_41));
tmp_d300_41 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_21 >> 0U) + (uint32_t)tmp_d300_41));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_11f00_5 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
fill((int32_t)tmp_11f00_5);
tmp_11f00_6 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
if ((uint8_t)((int32_t)tmp_11f00_6 <= (int32_t)1U)) {
tmp_23c00_5 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
fill((int32_t)tmp_23c00_5);
tmp_23c00_6 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
if ((uint8_t)((int32_t)tmp_23c00_6 <= (int32_t)1U)) {
rax_27 = (uint64_t)g_msg;
} else {
tmp_11f80_2 = r2sleigh_load_u64((void*)(uint64_t)(frame + 16U));
tmp_11f80_3 = r2sleigh_load_u64((void*)((uint64_t)tmp_11f80_2 + (uint64_t)1U * 8U));
rax_27 = tmp_11f80_3;
tmp_23d00_2 = r2sleigh_load_u64((void*)(uint64_t)(frame + 16U));
tmp_23d00_3 = r2sleigh_load_u64((void*)((uint64_t)tmp_23d00_2 + (uint64_t)1U * 8U));
rax_27 = tmp_23d00_3;
}
{
rax_28 = copy_name((char*)(uint64_t)(frame + 192U), (const char*)rax_27, 16);
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_6a80_48 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_28 >> 0U) + (uint32_t)tmp_6a80_48));
tmp_d300_48 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_28 >> 0U) + (uint32_t)tmp_d300_48));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_11f00_7 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_31 = (uint64_t)(uint16_t)sext((int8_t)((uint32_t)tmp_11f00_7 >> 0U));
tmp_11f00_8 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_33 = (uint64_t)rotl((uint32_t)tmp_11f00_8, 3);
tmp_23c00_7 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_31 = (uint64_t)(uint16_t)sext((int8_t)((uint32_t)tmp_23c00_7 >> 0U));
tmp_23c00_8 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_33 = (uint64_t)rotl((uint32_t)tmp_23c00_8, 3);
rax_34 = (uint64_t)(uint32_t)bit_count(0xf0f0);
tmp_11f00_9 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)((uint64_t)(uint32_t)((uint32_t)(int16_t)((uint64_t)rax_31 >> 0U) + (uint32_t)((uint64_t)rax_33 >> 0U)) + (uint64_t)rax_34) >> 0U) + (uint32_t)tmp_11f00_9));
tmp_23c00_9 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)((uint64_t)(uint32_t)((uint32_t)(int16_t)((uint64_t)rax_31 >> 0U) + (uint32_t)((uint64_t)rax_33 >> 0U)) + (uint64_t)rax_34) >> 0U) + (uint32_t)tmp_23c00_9));
rax_38 = (uint64_t)(uint32_t)find((const int32_t*)(uint64_t)0x4040U, 16, 7);
tmp_11f00_10 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_41 = (uint64_t)(uint32_t)dispatch((int32_t(*)(int32_t, int32_t))(uint64_t)0x11a9U, (int32_t)tmp_11f00_10);
tmp_23c00_10 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_41 = (uint64_t)(uint32_t)dispatch((int32_t(*)(int32_t, int32_t))(uint64_t)0x11a9U, (int32_t)tmp_23c00_10);
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_6a80_56 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)tmp_6a80_56 + (uint32_t)((uint32_t)((uint64_t)rax_38 >> 0U) + (uint32_t)((uint64_t)rax_41 >> 0U))));
tmp_d300_56 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)tmp_d300_56 + (uint32_t)((uint32_t)((uint64_t)rax_38 >> 0U) + (uint32_t)((uint64_t)rax_41 >> 0U))));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_11f00_11 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
printf("%d %s\n", (uint64_t)(uint32_t)tmp_11f00_11, (uint64_t)(frame + 192U));
tmp_11f00_12 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_lane_16f0_94_4d_1 = (uint32_t)(uint8_t)((uint32_t)tmp_11f00_12 >> 0U);
tmp_23c00_11 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
printf("%d %s\n", (uint64_t)(uint32_t)tmp_23c00_11, (uint64_t)(frame + 192U));
tmp_23c00_12 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_lane_16f0_94_4d_1 = (uint32_t)(uint8_t)((uint32_t)tmp_23c00_12 >> 0U);
{
return (int32_t)tmp_lane_16f0_94_4d_1;
}
+122 -122
View File
@@ -132,11 +132,11 @@ CMDS=aa; pdd @ 0x000010c0
EXPECT=<<EOF
void entry0(void)
{
uint64_t tmp_55400_2;
uint64_t tmp_aa300_2;
/* r2dec proof: 5 constructs are marked below; 28 source obligations: 0 rendered, 6 elided, 0 refused, 22 residual; 1 statements rendered; 1 held from entry, read as residuals (stack_p0) */
{
tmp_55400_2 = r2sleigh_residual_u64(1);
tmp_aa300_2 = r2sleigh_residual_u64(1);
r2sleigh_residual_void(2); /* r2dec gap: StoreNotSpelled at 0x10c0:29 covering 1 op (render::values) */
r2sleigh_residual_void(3); /* r2dec gap: StoreNotSpelled at 0x10c0:32 covering 1 op (render::values) */
r2sleigh_residual_void(4); /* r2dec gap: CallNotRendered at 0x10c0:68 covering 1 op (render::values): call to __libc_start_main: the import's declaration has an argument this convention does not place */
@@ -189,18 +189,18 @@ uint64_t entry_fini0(void)
{
void __cxa_finalize(void*);
uint8_t tmp_3e180_1;
uint64_t tmp_3ea80_1;
uint8_t tmp_7c100_1;
uint64_t tmp_7d300_1;
uint64_t rdi_1;
/* r2dec proof: 3 constructs are marked below; 40 source obligations: 16 rendered, 17 elided, 0 refused, 7 residual; 9 statements rendered; 1 callee prototype supplied by the source */
{
tmp_3e180_1 = r2sleigh_load_u8((void*)(uint64_t)0x4020U);
if ((uint8_t)((uint8_t)tmp_3e180_1 != (uint8_t)0U)) {
tmp_7c100_1 = r2sleigh_load_u8((void*)(uint64_t)0x4020U);
if ((uint8_t)((uint8_t)tmp_7c100_1 != (uint8_t)0U)) {
return r2sleigh_residual_u64(1);
} else {
tmp_3ea80_1 = r2sleigh_load_u64((void*)(uint64_t)0x3ff8U);
if ((uint8_t)((uint64_t)tmp_3ea80_1 == (uint64_t)0U)) {
tmp_7d300_1 = r2sleigh_load_u64((void*)(uint64_t)0x3ff8U);
if ((uint8_t)((uint64_t)tmp_7d300_1 == (uint64_t)0U)) {
} else {
rdi_1 = r2sleigh_load_u64((void*)(uint64_t)0x4008U);
__cxa_finalize((void*)rdi_1);
@@ -278,7 +278,7 @@ uint32_t fcn_11c1(uint32_t* arg0, uint32_t arg1)
{
uint32_t stack_m16_1;
uint32_t stack_m12_1;
uint32_t tmp_11f00_3;
uint32_t tmp_23c00_3;
/* r2dec proof: no individual construct is marked; 31 source obligations: 24 rendered, 7 elided, 0 refused; 9 statements rendered */
{
@@ -286,8 +286,8 @@ uint32_t fcn_11c1(uint32_t* arg0, uint32_t arg1)
stack_m12_1 = 0;
for (; ; ) {
if ((uint8_t)((int32_t)stack_m12_1 < (int32_t)arg1)) {
tmp_11f00_3 = r2sleigh_load_u32((void*)((uint64_t)arg0 + (uint64_t)(int32_t)stack_m12_1 * 4U));
stack_m16_1 = (uint32_t)((uint32_t)stack_m16_1 + (uint32_t)tmp_11f00_3);
tmp_23c00_3 = r2sleigh_load_u32((void*)((uint64_t)arg0 + (uint64_t)(int32_t)stack_m12_1 * 4U));
stack_m16_1 = (uint32_t)((uint32_t)stack_m16_1 + (uint32_t)tmp_23c00_3);
stack_m12_1 = (uint32_t)((uint32_t)stack_m12_1 + (uint32_t)1U);
} else {
break;
@@ -379,7 +379,7 @@ uint32_t fcn_1277(uint64_t arg0)
{
uint64_t stack_m32_1;
uint32_t stack_m12_1;
uint64_t tmp_11f80_3;
uint64_t tmp_23d00_3;
/* r2dec proof: no individual construct is marked; 28 source obligations: 21 rendered, 7 elided, 0 refused; 9 statements rendered */
{
@@ -387,8 +387,8 @@ uint32_t fcn_1277(uint64_t arg0)
stack_m12_1 = 0;
for (; ; ) {
if ((uint8_t)((uint64_t)stack_m32_1 != (uint64_t)0U)) {
tmp_11f80_3 = r2sleigh_load_u64((void*)(uint64_t)((uint64_t)stack_m32_1 + (uint64_t)8U));
stack_m32_1 = tmp_11f80_3;
tmp_23d00_3 = r2sleigh_load_u64((void*)(uint64_t)((uint64_t)stack_m32_1 + (uint64_t)8U));
stack_m32_1 = tmp_23d00_3;
stack_m12_1 = (uint32_t)((uint32_t)stack_m12_1 + (uint32_t)1U);
} else {
break;
@@ -412,23 +412,23 @@ EXPECT=<<EOF
uint64_t fcn_12a8(uint64_t arg0, uint64_t arg1)
{
uint64_t rax_4;
__uint128_t tmp_3d800_1;
__uint128_t tmp_7ae00_1;
uint64_t rdx_2;
__uint128_t tmp_49d00_1;
__uint128_t tmp_49d80_1;
__uint128_t tmp_49e00_1;
__uint128_t tmp_49e80_1;
__uint128_t tmp_49f80_1;
__uint128_t tmp_4a080_1;
__uint128_t tmp_93800_1;
__uint128_t tmp_93900_1;
__uint128_t tmp_93a00_1;
__uint128_t tmp_93b00_1;
__uint128_t tmp_93d00_1;
__uint128_t tmp_93f00_1;
uint64_t rax_5;
__uint128_t tmp_3d800_2;
__uint128_t tmp_7ae00_2;
uint64_t rdx_4;
__uint128_t tmp_49d00_2;
__uint128_t tmp_49d80_2;
__uint128_t tmp_49e00_2;
__uint128_t tmp_49e80_2;
__uint128_t tmp_49f80_2;
__uint128_t tmp_4a200_2;
__uint128_t tmp_93800_2;
__uint128_t tmp_93900_2;
__uint128_t tmp_93a00_2;
__uint128_t tmp_93b00_2;
__uint128_t tmp_93d00_2;
__uint128_t tmp_94200_2;
uint64_t rdx_5;
uint64_t rax_10;
@@ -436,26 +436,26 @@ uint64_t fcn_12a8(uint64_t arg0, uint64_t arg1)
{
if ((uint8_t)((uint64_t)arg1 != (uint64_t)0U)) {
rax_4 = (uint64_t)((uint64_t)((uint64_t)arg0 * (uint64_t)8U) - (uint64_t)arg0);
tmp_3d800_1 = (__uint128_t)(int64_t)rax_4;
rdx_2 = (uint64_t)((__uint128_t)tmp_3d800_1 >> 64U);
tmp_49d00_1 = (__uint128_t)(int64_t)arg1;
tmp_49d80_1 = (__uint128_t)(uint64_t)rdx_2;
tmp_49e00_1 = (__uint128_t)(uint32_t)64U >= (__uint128_t)128U ? (__uint128_t)0U : (__uint128_t)((__uint128_t)tmp_49d80_1 << (__uint128_t)(uint32_t)64U);
tmp_49e80_1 = (__uint128_t)(uint64_t)rax_4;
tmp_49f80_1 = (__uint128_t)((__uint128_t)tmp_49e00_1 | (__uint128_t)tmp_49e80_1);
tmp_4a080_1 = (__uint128_t)tmp_49f80_1 == (__uint128_t)((__uint128_t)0x8000000000000000U << 64U | (__uint128_t)0U) && (__uint128_t)tmp_49d00_1 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? r2sleigh_residual_u128(1) : (__uint128_t)((__int128_t)tmp_49f80_1 / (__int128_t)tmp_49d00_1);
rax_5 = (uint64_t)((__uint128_t)tmp_4a080_1 >> 0U);
(void)((__uint128_t)tmp_49d00_1 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0U) : (__uint128_t)((__int128_t)tmp_49f80_1 % (__int128_t)tmp_49d00_1));
tmp_3d800_2 = (__uint128_t)(int64_t)arg0;
rdx_4 = (uint64_t)((__uint128_t)tmp_3d800_2 >> 64U);
tmp_49d00_2 = (__uint128_t)(int64_t)arg1;
tmp_49d80_2 = (__uint128_t)(uint64_t)rdx_4;
tmp_49e00_2 = (__uint128_t)(uint32_t)64U >= (__uint128_t)128U ? (__uint128_t)0U : (__uint128_t)((__uint128_t)tmp_49d80_2 << (__uint128_t)(uint32_t)64U);
tmp_49e80_2 = (__uint128_t)(uint64_t)arg0;
tmp_49f80_2 = (__uint128_t)((__uint128_t)tmp_49e00_2 | (__uint128_t)tmp_49e80_2);
(void)((__uint128_t)tmp_49f80_2 == (__uint128_t)((__uint128_t)0x8000000000000000U << 64U | (__uint128_t)0U) && (__uint128_t)tmp_49d00_2 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? r2sleigh_residual_u128(2) : (__uint128_t)((__int128_t)tmp_49f80_2 / (__int128_t)tmp_49d00_2));
tmp_4a200_2 = (__uint128_t)tmp_49d00_2 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0U) : (__uint128_t)((__int128_t)tmp_49f80_2 % (__int128_t)tmp_49d00_2);
rdx_5 = (uint64_t)((__uint128_t)tmp_4a200_2 >> 0U);
tmp_7ae00_1 = (__uint128_t)(int64_t)rax_4;
rdx_2 = (uint64_t)((__uint128_t)tmp_7ae00_1 >> 64U);
tmp_93800_1 = (__uint128_t)(int64_t)arg1;
tmp_93900_1 = (__uint128_t)(uint64_t)rdx_2;
tmp_93a00_1 = (__uint128_t)(uint32_t)64U >= (__uint128_t)128U ? (__uint128_t)0U : (__uint128_t)((__uint128_t)tmp_93900_1 << (__uint128_t)(uint32_t)64U);
tmp_93b00_1 = (__uint128_t)(uint64_t)rax_4;
tmp_93d00_1 = (__uint128_t)((__uint128_t)tmp_93a00_1 | (__uint128_t)tmp_93b00_1);
tmp_93f00_1 = (__uint128_t)tmp_93d00_1 == (__uint128_t)((__uint128_t)0x8000000000000000U << 64U | (__uint128_t)0U) && (__uint128_t)tmp_93800_1 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? r2sleigh_residual_u128(1) : (__uint128_t)((__int128_t)tmp_93d00_1 / (__int128_t)tmp_93800_1);
rax_5 = (uint64_t)((__uint128_t)tmp_93f00_1 >> 0U);
(void)((__uint128_t)tmp_93800_1 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0U) : (__uint128_t)((__int128_t)tmp_93d00_1 % (__int128_t)tmp_93800_1));
tmp_7ae00_2 = (__uint128_t)(int64_t)arg0;
rdx_4 = (uint64_t)((__uint128_t)tmp_7ae00_2 >> 64U);
tmp_93800_2 = (__uint128_t)(int64_t)arg1;
tmp_93900_2 = (__uint128_t)(uint64_t)rdx_4;
tmp_93a00_2 = (__uint128_t)(uint32_t)64U >= (__uint128_t)128U ? (__uint128_t)0U : (__uint128_t)((__uint128_t)tmp_93900_2 << (__uint128_t)(uint32_t)64U);
tmp_93b00_2 = (__uint128_t)(uint64_t)arg0;
tmp_93d00_2 = (__uint128_t)((__uint128_t)tmp_93a00_2 | (__uint128_t)tmp_93b00_2);
(void)((__uint128_t)tmp_93d00_2 == (__uint128_t)((__uint128_t)0x8000000000000000U << 64U | (__uint128_t)0U) && (__uint128_t)tmp_93800_2 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? r2sleigh_residual_u128(2) : (__uint128_t)((__int128_t)tmp_93d00_2 / (__int128_t)tmp_93800_2));
tmp_94200_2 = (__uint128_t)tmp_93800_2 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0U) : (__uint128_t)((__int128_t)tmp_93d00_2 % (__int128_t)tmp_93800_2);
rdx_5 = (uint64_t)((__uint128_t)tmp_94200_2 >> 0U);
rax_10 = (uint64_t)((uint64_t)rdx_5 + (uint64_t)rax_5);
} else {
rax_10 = 0;
@@ -482,7 +482,7 @@ double fcn_12ef(uint64_t* arg0, uint32_t arg1)
__uint128_t xmm0_7;
double tmp_lane_1348_8_13_1;
__uint128_t xmm0_10;
uint64_t tmp_6b00_3;
uint64_t tmp_d400_3;
double tmp_lane_1310_1a_c_1;
/* r2dec proof: no individual construct is marked; 41 source obligations: 34 rendered, 7 elided, 0 refused; 15 statements rendered */
@@ -491,8 +491,8 @@ double fcn_12ef(uint64_t* arg0, uint32_t arg1)
stack_m16_1 = 0;
for (; ; ) {
if ((uint8_t)((int32_t)stack_m20_1 < (int32_t)arg1)) {
tmp_6b00_3 = r2sleigh_load_u64((void*)((uint64_t)arg0 + (uint64_t)(int32_t)stack_m20_1 * 8U));
tmp_lane_1310_1a_c_1 = r2sleigh_float_from_bits_64(tmp_6b00_3) + r2sleigh_float_from_bits_64(stack_m16_1);
tmp_d400_3 = r2sleigh_load_u64((void*)((uint64_t)arg0 + (uint64_t)(int32_t)stack_m20_1 * 8U));
tmp_lane_1310_1a_c_1 = r2sleigh_float_from_bits_64(tmp_d400_3) + r2sleigh_float_from_bits_64(stack_m16_1);
stack_m20_1 = (uint32_t)((uint32_t)stack_m20_1 + (uint32_t)1U);
stack_m16_1 = r2sleigh_float_to_bits_64(tmp_lane_1310_1a_c_1);
} else {
@@ -643,12 +643,12 @@ CMDS=aa; pdd @ 0x0000146d
EXPECT=<<EOF
uint32_t fcn_146d(uint32_t arg0, uint8_t arg1)
{
uint8_t tmp_63380_1;
uint8_t tmp_c6100_1;
/* r2dec proof: no individual construct is marked; 17 source obligations: 10 rendered, 7 elided, 0 refused; 2 statements rendered; the result's second register is open: no call read decides it */
{
tmp_63380_1 = (uint8_t)((uint32_t)arg1 & (uint32_t)(uint8_t)31U);
return (uint32_t)((uint32_t)((uint32_t)tmp_63380_1 >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)arg0 << (uint32_t)tmp_63380_1)) | (uint32_t)((uint32_t)(uint8_t)((uint32_t)(uint8_t)32U - (uint32_t)tmp_63380_1) >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)arg0 >> (uint32_t)(uint8_t)((uint32_t)(uint8_t)32U - (uint32_t)tmp_63380_1))));
tmp_c6100_1 = (uint8_t)((uint32_t)arg1 & (uint32_t)(uint8_t)31U);
return (uint32_t)((uint32_t)((uint32_t)tmp_c6100_1 >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)arg0 << (uint32_t)tmp_c6100_1)) | (uint32_t)((uint32_t)(uint8_t)((uint32_t)(uint8_t)32U - (uint32_t)tmp_c6100_1) >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)arg0 >> (uint32_t)(uint8_t)((uint32_t)(uint8_t)32U - (uint32_t)tmp_c6100_1))));
}
}
@@ -696,8 +696,8 @@ EXPECT=<<EOF
uint64_t fcn_14b5(uint32_t* arg0, uint32_t arg1, uint32_t arg2)
{
uint32_t stack_m12_1;
uint32_t tmp_11f00_3;
uint32_t tmp_11f00_7;
uint32_t tmp_23c00_3;
uint32_t tmp_23c00_7;
uint64_t rax_14;
/* r2dec proof: no individual construct is marked; 45 source obligations: 37 rendered, 8 elided, 0 refused; 20 statements rendered */
@@ -705,10 +705,10 @@ uint64_t fcn_14b5(uint32_t* arg0, uint32_t arg1, uint32_t arg2)
stack_m12_1 = 0;
for (; ; ) {
if ((uint8_t)((int32_t)stack_m12_1 < (int32_t)arg1)) {
tmp_11f00_3 = r2sleigh_load_u32((void*)((uint64_t)arg0 + (uint64_t)(int32_t)stack_m12_1 * 4U));
if ((uint8_t)((uint32_t)arg2 != (uint32_t)tmp_11f00_3)) {
tmp_11f00_7 = r2sleigh_load_u32((void*)((uint64_t)arg0 + (uint64_t)(int32_t)stack_m12_1 * 4U));
if ((uint8_t)((int32_t)arg2 < (int32_t)tmp_11f00_7)) {
tmp_23c00_3 = r2sleigh_load_u32((void*)((uint64_t)arg0 + (uint64_t)(int32_t)stack_m12_1 * 4U));
if ((uint8_t)((uint32_t)arg2 != (uint32_t)tmp_23c00_3)) {
tmp_23c00_7 = r2sleigh_load_u32((void*)((uint64_t)arg0 + (uint64_t)(int32_t)stack_m12_1 * 4U));
if ((uint8_t)((int32_t)arg2 < (int32_t)tmp_23c00_7)) {
goto L2;
} else {
stack_m12_1 = (uint32_t)((uint32_t)stack_m12_1 + (uint32_t)1U);
@@ -787,43 +787,43 @@ uint32_t fcn_1549(uint32_t arg0, uint64_t* arg1)
uint64_t fcn_1521(uint64_t, uint64_t);
int32_t printf(const char*, ...);
uint32_t tmp_11f00_1;
uint32_t tmp_23c00_1;
uint64_t rax_6;
uint64_t rax_8;
uint32_t tmp_11f00_2;
uint32_t tmp_11f00_3;
uint32_t tmp_23c00_2;
uint32_t tmp_23c00_3;
uint64_t rax_11;
uint32_t tmp_6a80_13;
uint32_t tmp_d300_13;
uint64_t rax_13;
uint32_t tmp_6a80_20;
uint32_t tmp_11f00_4;
uint32_t tmp_d300_20;
uint32_t tmp_23c00_4;
uint64_t rax_16;
uint64_t rax_17;
uint32_t tmp_6a80_27;
uint32_t tmp_d300_27;
__uint128_t xmm0_7;
uint64_t tmp_lane_1549_e1_21_1;
uint32_t tmp_6a80_34;
uint32_t tmp_d300_34;
uint64_t rax_21;
uint32_t tmp_6a80_41;
uint32_t tmp_11f00_5;
uint32_t tmp_11f00_6;
uint64_t tmp_11f80_2;
uint64_t tmp_11f80_3;
uint32_t tmp_d300_41;
uint32_t tmp_23c00_5;
uint32_t tmp_23c00_6;
uint64_t tmp_23d00_2;
uint64_t tmp_23d00_3;
uint64_t rax_27;
uint64_t rax_28;
uint32_t tmp_6a80_48;
uint32_t tmp_11f00_7;
uint32_t tmp_d300_48;
uint32_t tmp_23c00_7;
uint64_t rax_31;
uint32_t tmp_11f00_8;
uint32_t tmp_23c00_8;
uint64_t rax_33;
uint64_t rax_34;
uint32_t tmp_11f00_9;
uint32_t tmp_23c00_9;
uint64_t rax_38;
uint32_t tmp_11f00_10;
uint32_t tmp_23c00_10;
uint64_t rax_41;
uint32_t tmp_6a80_56;
uint32_t tmp_11f00_11;
uint32_t tmp_11f00_12;
uint32_t tmp_d300_56;
uint32_t tmp_23c00_11;
uint32_t tmp_23c00_12;
uint32_t tmp_lane_16f0_94_4d_1;
_Alignas(16) uint8_t frame[248];
@@ -847,36 +847,36 @@ uint32_t fcn_1549(uint32_t arg0, uint64_t* arg1)
r2sleigh_store_u64((void*)((uint64_t)(frame + 48U) + (uint64_t)112U), (uint64_t)0x3ff0000000000000U);
r2sleigh_store_u64((void*)((uint64_t)(frame + 48U) + (uint64_t)120U), (uint64_t)0x4004000000000000U);
r2sleigh_store_u64((void*)((uint64_t)(frame + 48U) + (uint64_t)128U), (uint64_t)0x400c000000000000U);
tmp_11f00_1 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_6 = (uint64_t)fcn_11a9((uint32_t)tmp_11f00_1, 3);
tmp_23c00_1 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_6 = (uint64_t)fcn_11a9((uint32_t)tmp_23c00_1, 3);
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint64_t)rax_6 >> 0U));
rax_8 = (uint64_t)fcn_11c1((uint64_t)(frame + 48U), 4);
tmp_11f00_2 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_8 >> 0U) + (uint32_t)tmp_11f00_2));
tmp_11f00_3 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_11 = fcn_120a((uint32_t)tmp_11f00_3);
tmp_23c00_2 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_8 >> 0U) + (uint32_t)tmp_23c00_2));
tmp_23c00_3 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_11 = fcn_120a((uint32_t)tmp_23c00_3);
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_6a80_13 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_11 >> 0U) + (uint32_t)tmp_6a80_13));
tmp_d300_13 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_11 >> 0U) + (uint32_t)tmp_d300_13));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
rax_13 = (uint64_t)fcn_1277((uint64_t)((uint64_t)(frame + 48U) + (uint64_t)80U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_6a80_20 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_13 >> 0U) + (uint32_t)tmp_6a80_20));
tmp_d300_20 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_13 >> 0U) + (uint32_t)tmp_d300_20));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_11f00_4 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_16 = (uint64_t)(int32_t)((uint64_t)((uint64_t)(int32_t)tmp_11f00_4 * (uint64_t)100U) >> 0U);
tmp_23c00_4 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_16 = (uint64_t)(int32_t)((uint64_t)((uint64_t)(int32_t)tmp_23c00_4 * (uint64_t)100U) >> 0U);
rax_17 = fcn_12a8(rax_16, 3);
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_6a80_27 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_17 >> 0U) + (uint32_t)tmp_6a80_27));
tmp_d300_27 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_17 >> 0U) + (uint32_t)tmp_d300_27));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
@@ -884,59 +884,59 @@ uint32_t fcn_1549(uint32_t arg0, uint64_t* arg1)
tmp_lane_1549_e1_21_1 = (uint64_t)((__uint128_t)xmm0_7 >> 0U);
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_6a80_34 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)(r2sleigh_float_from_bits_64(tmp_lane_1549_e1_21_1) > -2147483649.0 && r2sleigh_float_from_bits_64(tmp_lane_1549_e1_21_1) < 2147483648.0 ? (int32_t)r2sleigh_float_from_bits_64(tmp_lane_1549_e1_21_1) : r2sleigh_residual_i32(1)) + (uint32_t)tmp_6a80_34));
tmp_d300_34 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)(r2sleigh_float_from_bits_64(tmp_lane_1549_e1_21_1) > -2147483649.0 && r2sleigh_float_from_bits_64(tmp_lane_1549_e1_21_1) < 2147483648.0 ? (int32_t)r2sleigh_float_from_bits_64(tmp_lane_1549_e1_21_1) : r2sleigh_residual_i32(1)) + (uint32_t)tmp_d300_34));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
rax_21 = fcn_1362(5);
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_6a80_41 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_21 >> 0U) + (uint32_t)tmp_6a80_41));
tmp_d300_41 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_21 >> 0U) + (uint32_t)tmp_d300_41));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_11f00_5 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
fcn_1391((uint32_t)tmp_11f00_5);
tmp_11f00_6 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
if ((uint8_t)((int32_t)tmp_11f00_6 <= (int32_t)1U)) {
tmp_23c00_5 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
fcn_1391((uint32_t)tmp_23c00_5);
tmp_23c00_6 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
if ((uint8_t)((int32_t)tmp_23c00_6 <= (int32_t)1U)) {
rax_27 = r2sleigh_load_u64((void*)(uint64_t)0x4018U);
} else {
tmp_11f80_2 = r2sleigh_load_u64((void*)(uint64_t)(frame + 16U));
tmp_11f80_3 = r2sleigh_load_u64((void*)((uint64_t)tmp_11f80_2 + (uint64_t)1U * 8U));
rax_27 = tmp_11f80_3;
tmp_23d00_2 = r2sleigh_load_u64((void*)(uint64_t)(frame + 16U));
tmp_23d00_3 = r2sleigh_load_u64((void*)((uint64_t)tmp_23d00_2 + (uint64_t)1U * 8U));
rax_27 = tmp_23d00_3;
}
{
rax_28 = fcn_13e3((uint64_t)((uint64_t)(frame + 48U) + (uint64_t)144U), rax_27, 16);
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_6a80_48 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_28 >> 0U) + (uint32_t)tmp_6a80_48));
tmp_d300_48 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)rax_28 >> 0U) + (uint32_t)tmp_d300_48));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_11f00_7 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_31 = (uint64_t)fcn_144c((uint32_t)(int8_t)((uint32_t)tmp_11f00_7 >> 0U));
tmp_11f00_8 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_33 = (uint64_t)fcn_146d((uint32_t)tmp_11f00_8, 3);
tmp_23c00_7 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_31 = (uint64_t)fcn_144c((uint32_t)(int8_t)((uint32_t)tmp_23c00_7 >> 0U));
tmp_23c00_8 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_33 = (uint64_t)fcn_146d((uint32_t)tmp_23c00_8, 3);
rax_34 = (uint64_t)fcn_1489(0xf0f0);
tmp_11f00_9 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)((uint64_t)(uint32_t)((uint32_t)(int16_t)((uint64_t)rax_31 >> 0U) + (uint32_t)((uint64_t)rax_33 >> 0U)) + (uint64_t)rax_34) >> 0U) + (uint32_t)tmp_11f00_9));
tmp_23c00_9 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)((uint64_t)((uint64_t)(uint32_t)((uint32_t)(int16_t)((uint64_t)rax_31 >> 0U) + (uint32_t)((uint64_t)rax_33 >> 0U)) + (uint64_t)rax_34) >> 0U) + (uint32_t)tmp_23c00_9));
rax_38 = fcn_14b5(0x4040, 16, 7);
tmp_11f00_10 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_41 = fcn_1521(0x11a9, (uint64_t)(uint32_t)tmp_11f00_10);
tmp_23c00_10 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_41 = fcn_1521(0x11a9, (uint64_t)(uint32_t)tmp_23c00_10);
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_6a80_56 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)tmp_6a80_56 + (uint32_t)((uint32_t)((uint64_t)rax_38 >> 0U) + (uint32_t)((uint64_t)rax_41 >> 0U))));
tmp_d300_56 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
r2sleigh_store_u32((void*)(uint64_t)(frame + 44U), (uint32_t)((uint32_t)tmp_d300_56 + (uint32_t)((uint32_t)((uint64_t)rax_38 >> 0U) + (uint32_t)((uint64_t)rax_41 >> 0U))));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
(void)r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_11f00_11 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
printf("%d %s\n", (uint64_t)(uint32_t)tmp_11f00_11, (uint64_t)((uint64_t)(frame + 48U) + (uint64_t)144U));
tmp_11f00_12 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_lane_16f0_94_4d_1 = (uint32_t)(uint8_t)((uint32_t)tmp_11f00_12 >> 0U);
tmp_23c00_11 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
printf("%d %s\n", (uint64_t)(uint32_t)tmp_23c00_11, (uint64_t)((uint64_t)(frame + 48U) + (uint64_t)144U));
tmp_23c00_12 = r2sleigh_load_u32((void*)(uint64_t)(frame + 44U));
tmp_lane_16f0_94_4d_1 = (uint32_t)(uint8_t)((uint32_t)tmp_23c00_12 >> 0U);
{
return (uint32_t)tmp_lane_16f0_94_4d_1;
}
+81 -81
View File
@@ -151,7 +151,7 @@ uint32_t fcn_10c0(uint64_t arg0, uint64_t* arg1)
uint32_t tmp_lane_10c0_b_0_1;
__uint128_t xmm0_1;
__uint128_t tmp_8eb80_1;
__uint128_t tmp_117700_1;
uint64_t tmp_lane_10c0_3b_5_1;
__uint128_t xmm0_2;
uint64_t tmp_lane_10c0_3c_6_1;
@@ -165,7 +165,7 @@ uint32_t fcn_10c0(uint64_t arg0, uint64_t* arg1)
uint64_t tmp_lane_10c0_9f_1e_1;
uint64_t rbx_3;
uint64_t rsi_6;
uint64_t tmp_11f80_2;
uint64_t tmp_23d00_2;
uint64_t rsi_8;
uint64_t rax_14;
uint32_t tmp_lane_11c4_c_2d_1;
@@ -187,10 +187,10 @@ uint32_t fcn_10c0(uint64_t arg0, uint64_t* arg1)
r2sleigh_store_u64((void*)((uint64_t)(frame + 16U) + (uint64_t)56U), (uint64_t)((uint64_t)(frame + 16U) + (uint64_t)16U));
r2sleigh_store_u64((void*)((uint64_t)(frame + 16U) + (uint64_t)88U), (uint64_t)((uint64_t)(frame + 16U) + (uint64_t)48U));
r2sleigh_store_u128((void*)(uint64_t)(frame + 16U), (__uint128_t)xmm0_1);
tmp_8eb80_1 = r2sleigh_load_u128((void*)(uint64_t)0x2070U);
tmp_lane_10c0_3b_5_1 = (uint64_t)((__uint128_t)tmp_8eb80_1 >> 0U);
tmp_117700_1 = r2sleigh_load_u128((void*)(uint64_t)0x2070U);
tmp_lane_10c0_3b_5_1 = (uint64_t)((__uint128_t)tmp_117700_1 >> 0U);
xmm0_2 = (__uint128_t)(((__uint128_t)0U & (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0U)) | ((__uint128_t)tmp_lane_10c0_3b_5_1 & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffffffffffULL)) << 0U);
tmp_lane_10c0_3c_6_1 = (uint64_t)((__uint128_t)tmp_8eb80_1 >> 64U);
tmp_lane_10c0_3c_6_1 = (uint64_t)((__uint128_t)tmp_117700_1 >> 64U);
xmm0_3 = (__uint128_t)(((__uint128_t)xmm0_2 & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffffffffffULL)) | ((__uint128_t)tmp_lane_10c0_3c_6_1 & (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0xffffffffffffffffULL)) << 64U);
r2sleigh_store_u64((void*)((uint64_t)(frame + 16U) + (uint64_t)32U), (uint64_t)99U);
r2sleigh_store_u128((void*)(uint64_t)((uint64_t)(frame + 16U) + (uint64_t)112U), (__uint128_t)xmm0_3);
@@ -211,8 +211,8 @@ uint32_t fcn_10c0(uint64_t arg0, uint64_t* arg1)
if ((uint8_t)((int32_t)tmp_lane_10c0_b_0_1 <= (int32_t)1U)) {
rsi_8 = rsi_6;
} else {
tmp_11f80_2 = r2sleigh_load_u64((void*)((uint64_t)arg1 + (uint64_t)1U * 8U));
rsi_8 = tmp_11f80_2;
tmp_23d00_2 = r2sleigh_load_u64((void*)((uint64_t)arg1 + (uint64_t)1U * 8U));
rsi_8 = tmp_23d00_2;
}
{
rax_14 = copy_name((uint64_t)((uint64_t)(frame + 16U) + (uint64_t)144U), rsi_8, 16);
@@ -245,11 +245,11 @@ CMDS=aa; pdd @ 0x00001280
EXPECT=<<EOF
void _start(void)
{
uint64_t tmp_55400_2;
uint64_t tmp_aa300_2;
/* r2dec proof: 5 constructs are marked below; 28 source obligations: 0 rendered, 6 elided, 0 refused, 22 residual; 1 statements rendered; 1 held from entry, read as residuals (stack_p0) */
{
tmp_55400_2 = r2sleigh_residual_u64(1);
tmp_aa300_2 = r2sleigh_residual_u64(1);
r2sleigh_residual_void(2); /* r2dec gap: StoreNotSpelled at 0x1280:29 covering 1 op (render::values) */
r2sleigh_residual_void(3); /* r2dec gap: StoreNotSpelled at 0x1280:32 covering 1 op (render::values) */
r2sleigh_residual_void(4); /* r2dec gap: CallNotRendered at 0x1280:68 covering 1 op (render::values): call to __libc_start_main: the import's declaration has an argument this convention does not place */
@@ -336,18 +336,18 @@ uint64_t __do_global_dtors_aux(void)
extern char __dso_handle[];
extern char __TMC_END__[];
uint8_t tmp_3e180_1;
uint64_t tmp_3ea80_1;
uint8_t tmp_7c100_1;
uint64_t tmp_7d300_1;
uint64_t rdi_1;
/* r2dec proof: 3 constructs are marked below; 40 source obligations: 16 rendered, 17 elided, 0 refused, 7 residual; 9 statements rendered; 2 data object types refused; 1 callee prototype supplied by the source */
{
tmp_3e180_1 = r2sleigh_load_u8((void*)&__TMC_END__);
if ((uint8_t)((uint8_t)tmp_3e180_1 != (uint8_t)0U)) {
tmp_7c100_1 = r2sleigh_load_u8((void*)&__TMC_END__);
if ((uint8_t)((uint8_t)tmp_7c100_1 != (uint8_t)0U)) {
return r2sleigh_residual_u64(1);
} else {
tmp_3ea80_1 = r2sleigh_load_u64((void*)(uint64_t)0x3ff8U);
if ((uint8_t)((uint64_t)tmp_3ea80_1 == (uint64_t)0U)) {
tmp_7d300_1 = r2sleigh_load_u64((void*)(uint64_t)0x3ff8U);
if ((uint8_t)((uint64_t)tmp_7d300_1 == (uint64_t)0U)) {
} else {
rdi_1 = r2sleigh_load_u64((void*)&__dso_handle);
__cxa_finalize((void*)rdi_1);
@@ -408,30 +408,30 @@ CMDS=aa; pdd @ 0x00001380
EXPECT=<<EOF
uint32_t sum_array(uint64_t arg0, uint32_t arg1)
{
uint32_t tmp_70400_1;
uint64_t tmp_4a00_1;
uint32_t tmp_e0200_1;
uint64_t tmp_9400_1;
uint64_t rax_2;
uint64_t rdi_1;
uint32_t tmp_11f00_3;
uint32_t tmp_23c00_3;
uint32_t tmp_lane_1398_5_6_1;
uint64_t rdi_2;
/* r2dec proof: no individual construct is marked; 44 source obligations: 36 rendered, 8 elided, 0 refused; 17 statements rendered */
{
tmp_70400_1 = arg1;
if ((uint8_t)((int32_t)tmp_70400_1 <= (int32_t)0U)) {
tmp_e0200_1 = arg1;
if ((uint8_t)((int32_t)tmp_e0200_1 <= (int32_t)0U)) {
return 0;
} else {
tmp_4a00_1 = (uint64_t)((uint64_t)((uint64_t)(int32_t)arg1 * (uint64_t)4U) + (uint64_t)arg0);
tmp_9400_1 = (uint64_t)((uint64_t)((uint64_t)(int32_t)arg1 * (uint64_t)4U) + (uint64_t)arg0);
rax_2 = 0;
rdi_1 = arg0;
for (; ; ) {
(void)r2sleigh_load_u32((void*)rdi_1);
(void)r2sleigh_load_u32((void*)rdi_1);
tmp_11f00_3 = r2sleigh_load_u32((void*)rdi_1);
tmp_lane_1398_5_6_1 = (uint32_t)((uint32_t)((uint64_t)rax_2 >> 0U) + (uint32_t)tmp_11f00_3);
tmp_23c00_3 = r2sleigh_load_u32((void*)rdi_1);
tmp_lane_1398_5_6_1 = (uint32_t)((uint32_t)((uint64_t)rax_2 >> 0U) + (uint32_t)tmp_23c00_3);
rdi_2 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)4U);
if ((uint8_t)((uint64_t)rdi_2 != (uint64_t)tmp_4a00_1)) {
if ((uint8_t)((uint64_t)rdi_2 != (uint64_t)tmp_9400_1)) {
rax_2 = (uint64_t)(uint32_t)tmp_lane_1398_5_6_1;
rdi_1 = rdi_2;
} else {
@@ -458,7 +458,7 @@ uint64_t classify(uint32_t arg0)
{
extern char CSWTCH_12[];
uint32_t tmp_11f00_1;
uint32_t tmp_23c00_1;
uint64_t rax_4;
/* r2dec proof: no individual construct is marked; 19 source obligations: 15 rendered, 4 elided, 0 refused; 5 statements rendered; 1 data object type refused */
@@ -466,8 +466,8 @@ uint64_t classify(uint32_t arg0)
if ((uint8_t)((uint32_t)7U < (uint32_t)arg0)) {
rax_4 = (uint64_t)0xffffffffU;
} else {
tmp_11f00_1 = r2sleigh_load_u32((void*)((uint64_t)((uint64_t)(uint32_t)arg0 * (uint64_t)4U) + (uint64_t)&CSWTCH_12));
rax_4 = (uint64_t)(uint32_t)tmp_11f00_1;
tmp_23c00_1 = r2sleigh_load_u32((void*)((uint64_t)((uint64_t)(uint32_t)arg0 * (uint64_t)4U) + (uint64_t)&CSWTCH_12));
rax_4 = (uint64_t)(uint32_t)tmp_23c00_1;
}
{
return (uint64_t)rax_4;
@@ -488,7 +488,7 @@ uint32_t list_len(uint64_t arg0)
{
uint64_t rax_2;
uint64_t rdi_1;
uint64_t tmp_11f80_1;
uint64_t tmp_23d00_1;
uint64_t rdi_2;
uint32_t tmp_lane_13e0_5_4_1;
@@ -500,8 +500,8 @@ uint32_t list_len(uint64_t arg0)
rax_2 = 0;
rdi_1 = arg0;
for (; ; ) {
tmp_11f80_1 = r2sleigh_load_u64((void*)(uint64_t)((uint64_t)rdi_1 + (uint64_t)8U));
rdi_2 = tmp_11f80_1;
tmp_23d00_1 = r2sleigh_load_u64((void*)(uint64_t)((uint64_t)rdi_1 + (uint64_t)8U));
rdi_2 = tmp_23d00_1;
tmp_lane_13e0_5_4_1 = (uint32_t)((uint32_t)((uint64_t)rax_2 >> 0U) + (uint32_t)1U);
if ((uint8_t)((uint64_t)rdi_2 != (uint64_t)0U)) {
rax_2 = (uint64_t)(uint32_t)tmp_lane_13e0_5_4_1;
@@ -529,23 +529,23 @@ EXPECT=<<EOF
uint64_t mul_div(uint64_t arg0, uint64_t arg1)
{
uint64_t rax_3;
__uint128_t tmp_3d800_1;
__uint128_t tmp_7ae00_1;
uint64_t rdx_1;
__uint128_t tmp_49d00_1;
__uint128_t tmp_49d80_1;
__uint128_t tmp_49e00_1;
__uint128_t tmp_49e80_1;
__uint128_t tmp_49f80_1;
__uint128_t tmp_4a080_1;
__uint128_t tmp_93800_1;
__uint128_t tmp_93900_1;
__uint128_t tmp_93a00_1;
__uint128_t tmp_93b00_1;
__uint128_t tmp_93d00_1;
__uint128_t tmp_93f00_1;
uint64_t rax_4;
__uint128_t tmp_3d800_2;
__uint128_t tmp_7ae00_2;
uint64_t rdx_3;
__uint128_t tmp_49d00_2;
__uint128_t tmp_49d80_2;
__uint128_t tmp_49e00_2;
__uint128_t tmp_49e80_2;
__uint128_t tmp_49f80_2;
__uint128_t tmp_4a200_2;
__uint128_t tmp_93800_2;
__uint128_t tmp_93900_2;
__uint128_t tmp_93a00_2;
__uint128_t tmp_93b00_2;
__uint128_t tmp_93d00_2;
__uint128_t tmp_94200_2;
uint64_t rdx_4;
uint64_t rax_8;
@@ -555,26 +555,26 @@ uint64_t mul_div(uint64_t arg0, uint64_t arg1)
rax_8 = 0;
} else {
rax_3 = (uint64_t)((uint64_t)((uint64_t)arg0 * (uint64_t)8U) - (uint64_t)arg0);
tmp_3d800_1 = (__uint128_t)(int64_t)rax_3;
rdx_1 = (uint64_t)((__uint128_t)tmp_3d800_1 >> 64U);
tmp_49d00_1 = (__uint128_t)(int64_t)arg1;
tmp_49d80_1 = (__uint128_t)(uint64_t)rdx_1;
tmp_49e00_1 = (__uint128_t)(uint32_t)64U >= (__uint128_t)128U ? (__uint128_t)0U : (__uint128_t)((__uint128_t)tmp_49d80_1 << (__uint128_t)(uint32_t)64U);
tmp_49e80_1 = (__uint128_t)(uint64_t)rax_3;
tmp_49f80_1 = (__uint128_t)((__uint128_t)tmp_49e00_1 | (__uint128_t)tmp_49e80_1);
tmp_4a080_1 = (__uint128_t)tmp_49f80_1 == (__uint128_t)((__uint128_t)0x8000000000000000U << 64U | (__uint128_t)0U) && (__uint128_t)tmp_49d00_1 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? r2sleigh_residual_u128(1) : (__uint128_t)((__int128_t)tmp_49f80_1 / (__int128_t)tmp_49d00_1);
rax_4 = (uint64_t)((__uint128_t)tmp_4a080_1 >> 0U);
(void)((__uint128_t)tmp_49d00_1 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0U) : (__uint128_t)((__int128_t)tmp_49f80_1 % (__int128_t)tmp_49d00_1));
tmp_3d800_2 = (__uint128_t)(int64_t)arg0;
rdx_3 = (uint64_t)((__uint128_t)tmp_3d800_2 >> 64U);
tmp_49d00_2 = (__uint128_t)(int64_t)arg1;
tmp_49d80_2 = (__uint128_t)(uint64_t)rdx_3;
tmp_49e00_2 = (__uint128_t)(uint32_t)64U >= (__uint128_t)128U ? (__uint128_t)0U : (__uint128_t)((__uint128_t)tmp_49d80_2 << (__uint128_t)(uint32_t)64U);
tmp_49e80_2 = (__uint128_t)(uint64_t)arg0;
tmp_49f80_2 = (__uint128_t)((__uint128_t)tmp_49e00_2 | (__uint128_t)tmp_49e80_2);
(void)((__uint128_t)tmp_49f80_2 == (__uint128_t)((__uint128_t)0x8000000000000000U << 64U | (__uint128_t)0U) && (__uint128_t)tmp_49d00_2 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? r2sleigh_residual_u128(2) : (__uint128_t)((__int128_t)tmp_49f80_2 / (__int128_t)tmp_49d00_2));
tmp_4a200_2 = (__uint128_t)tmp_49d00_2 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0U) : (__uint128_t)((__int128_t)tmp_49f80_2 % (__int128_t)tmp_49d00_2);
rdx_4 = (uint64_t)((__uint128_t)tmp_4a200_2 >> 0U);
tmp_7ae00_1 = (__uint128_t)(int64_t)rax_3;
rdx_1 = (uint64_t)((__uint128_t)tmp_7ae00_1 >> 64U);
tmp_93800_1 = (__uint128_t)(int64_t)arg1;
tmp_93900_1 = (__uint128_t)(uint64_t)rdx_1;
tmp_93a00_1 = (__uint128_t)(uint32_t)64U >= (__uint128_t)128U ? (__uint128_t)0U : (__uint128_t)((__uint128_t)tmp_93900_1 << (__uint128_t)(uint32_t)64U);
tmp_93b00_1 = (__uint128_t)(uint64_t)rax_3;
tmp_93d00_1 = (__uint128_t)((__uint128_t)tmp_93a00_1 | (__uint128_t)tmp_93b00_1);
tmp_93f00_1 = (__uint128_t)tmp_93d00_1 == (__uint128_t)((__uint128_t)0x8000000000000000U << 64U | (__uint128_t)0U) && (__uint128_t)tmp_93800_1 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? r2sleigh_residual_u128(1) : (__uint128_t)((__int128_t)tmp_93d00_1 / (__int128_t)tmp_93800_1);
rax_4 = (uint64_t)((__uint128_t)tmp_93f00_1 >> 0U);
(void)((__uint128_t)tmp_93800_1 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0U) : (__uint128_t)((__int128_t)tmp_93d00_1 % (__int128_t)tmp_93800_1));
tmp_7ae00_2 = (__uint128_t)(int64_t)arg0;
rdx_3 = (uint64_t)((__uint128_t)tmp_7ae00_2 >> 64U);
tmp_93800_2 = (__uint128_t)(int64_t)arg1;
tmp_93900_2 = (__uint128_t)(uint64_t)rdx_3;
tmp_93a00_2 = (__uint128_t)(uint32_t)64U >= (__uint128_t)128U ? (__uint128_t)0U : (__uint128_t)((__uint128_t)tmp_93900_2 << (__uint128_t)(uint32_t)64U);
tmp_93b00_2 = (__uint128_t)(uint64_t)arg0;
tmp_93d00_2 = (__uint128_t)((__uint128_t)tmp_93a00_2 | (__uint128_t)tmp_93b00_2);
(void)((__uint128_t)tmp_93d00_2 == (__uint128_t)((__uint128_t)0x8000000000000000U << 64U | (__uint128_t)0U) && (__uint128_t)tmp_93800_2 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? r2sleigh_residual_u128(2) : (__uint128_t)((__int128_t)tmp_93d00_2 / (__int128_t)tmp_93800_2));
tmp_94200_2 = (__uint128_t)tmp_93800_2 == (__uint128_t)((__uint128_t)0xffffffffffffffffULL << 64U | (__uint128_t)0xffffffffffffffffULL) ? (__uint128_t)((__uint128_t)0U << 64U | (__uint128_t)0U) : (__uint128_t)((__int128_t)tmp_93d00_2 % (__int128_t)tmp_93800_2);
rdx_4 = (uint64_t)((__uint128_t)tmp_94200_2 >> 0U);
rax_8 = (uint64_t)((uint64_t)rax_4 + (uint64_t)rdx_4);
}
{
@@ -594,7 +594,7 @@ CMDS=aa; pdd @ 0x00001430
EXPECT=<<EOF
uint64_t avg(int64_t* arg0, uint32_t arg1)
{
uint32_t tmp_70400_1;
uint32_t tmp_e0200_1;
uint8_t zf_1;
uint64_t rax_1;
uint64_t rdi_1;
@@ -603,9 +603,9 @@ uint64_t avg(int64_t* arg0, uint32_t arg1)
/* r2dec proof: 2 constructs are marked below; 49 source obligations: 37 rendered, 8 elided, 0 refused, 4 residual; 22 statements rendered */
{
tmp_70400_1 = arg1;
zf_1 = (uint8_t)((uint32_t)tmp_70400_1 == (uint32_t)0U);
if ((uint8_t)((uint32_t)(uint8_t)((int32_t)tmp_70400_1 < (int32_t)0U) | (uint32_t)zf_1)) {
tmp_e0200_1 = arg1;
zf_1 = (uint8_t)((uint32_t)tmp_e0200_1 == (uint32_t)0U);
if ((uint8_t)((uint32_t)(uint8_t)((int32_t)tmp_e0200_1 < (int32_t)0U) | (uint32_t)zf_1)) {
if ((uint8_t)((uint32_t)zf_1 ^ (uint32_t)(uint8_t)1U)) {
} else {
return r2sleigh_residual_u64(1);
@@ -726,7 +726,7 @@ uint64_t fill(uint32_t arg0)
__uint128_t xmm0_4;
uint32_t tmp_lane_14e8_11_1e_1;
uint32_t tmp_lane_14e8_11_20_1;
uint32_t tmp_2c309_1;
uint32_t tmp_58409_1;
/* r2dec proof: 1 construct is marked below; 62 source obligations: 56 rendered, 4 elided, 0 refused, 2 residual; 44 statements rendered; 1 data object type refused */
{
@@ -772,8 +772,8 @@ uint64_t fill(uint32_t arg0)
{
(void)r2sleigh_load_u32((void*)&g_counter);
(void)r2sleigh_load_u32((void*)&g_counter);
tmp_2c309_1 = r2sleigh_load_u32((void*)&g_counter);
r2sleigh_store_u32((void*)&g_counter, (uint32_t)((uint32_t)tmp_2c309_1 + (uint32_t)arg0));
tmp_58409_1 = r2sleigh_load_u32((void*)&g_counter);
r2sleigh_store_u32((void*)&g_counter, (uint32_t)((uint32_t)tmp_58409_1 + (uint32_t)arg0));
(void)r2sleigh_load_u32((void*)&g_counter);
(void)r2sleigh_load_u32((void*)&g_counter);
(void)r2sleigh_load_u32((void*)&g_counter);
@@ -842,12 +842,12 @@ CMDS=aa; pdd @ 0x00001580
EXPECT=<<EOF
uint32_t rotl(uint32_t arg0, uint8_t arg1)
{
uint8_t tmp_63380_1;
uint8_t tmp_c6100_1;
/* r2dec proof: no individual construct is marked; 11 source obligations: 7 rendered, 4 elided, 0 refused; 2 statements rendered */
{
tmp_63380_1 = (uint8_t)((uint32_t)arg1 & (uint32_t)(uint8_t)31U);
return (uint32_t)((uint32_t)((uint32_t)tmp_63380_1 >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)arg0 << (uint32_t)tmp_63380_1)) | (uint32_t)((uint32_t)(uint8_t)((uint32_t)(uint8_t)32U - (uint32_t)tmp_63380_1) >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)arg0 >> (uint32_t)(uint8_t)((uint32_t)(uint8_t)32U - (uint32_t)tmp_63380_1))));
tmp_c6100_1 = (uint8_t)((uint32_t)arg1 & (uint32_t)(uint8_t)31U);
return (uint32_t)((uint32_t)((uint32_t)tmp_c6100_1 >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)arg0 << (uint32_t)tmp_c6100_1)) | (uint32_t)((uint32_t)(uint8_t)((uint32_t)(uint8_t)32U - (uint32_t)tmp_c6100_1) >= (uint32_t)32U ? (uint32_t)0U : (uint32_t)((uint32_t)arg0 >> (uint32_t)(uint8_t)((uint32_t)(uint8_t)32U - (uint32_t)tmp_c6100_1))));
}
}
@@ -906,23 +906,23 @@ CMDS=aa; pdd @ 0x000015b0
EXPECT=<<EOF
uint64_t find(uint32_t* arg0, uint32_t arg1, uint32_t arg2)
{
uint32_t tmp_70400_1;
uint32_t tmp_e0200_1;
uint64_t rsi_1;
uint64_t rax_2;
uint32_t tmp_11f00_1;
uint32_t tmp_23c00_1;
uint64_t rax_3;
/* r2dec proof: no individual construct is marked; 43 source obligations: 36 rendered, 7 elided, 0 refused; 17 statements rendered */
{
tmp_70400_1 = arg1;
if ((uint8_t)((int32_t)tmp_70400_1 <= (int32_t)0U)) {
tmp_e0200_1 = arg1;
if ((uint8_t)((int32_t)tmp_e0200_1 <= (int32_t)0U)) {
} else {
rsi_1 = (uint64_t)(int32_t)arg1;
rax_2 = 0;
for (; ; ) {
tmp_11f00_1 = r2sleigh_load_u32((void*)((uint64_t)arg0 + (uint64_t)rax_2 * 4U));
if ((uint8_t)((uint32_t)tmp_11f00_1 != (uint32_t)arg2)) {
if ((uint8_t)((int32_t)arg2 < (int32_t)tmp_11f00_1)) {
tmp_23c00_1 = r2sleigh_load_u32((void*)((uint64_t)arg0 + (uint64_t)rax_2 * 4U));
if ((uint8_t)((uint32_t)tmp_23c00_1 != (uint32_t)arg2)) {
if ((uint8_t)((int32_t)arg2 < (int32_t)tmp_23c00_1)) {
goto L1;
} else {
rax_3 = (uint64_t)((uint64_t)rax_2 + (uint64_t)1U);
File diff suppressed because it is too large. Load diff
+27 -27
View File
@@ -84,11 +84,11 @@ CMDS=aa; pdd @ 0x00001060
EXPECT=<<EOF
void _start(void)
{
uint64_t tmp_55400_2;
uint64_t tmp_aa300_2;
/* r2dec proof: 5 constructs are marked below; 28 source obligations: 0 rendered, 6 elided, 0 refused, 22 residual; 1 statements rendered; 1 held from entry, read as residuals (stack_p0) */
{
tmp_55400_2 = r2sleigh_residual_u64(1);
tmp_aa300_2 = r2sleigh_residual_u64(1);
r2sleigh_residual_void(2); /* r2dec gap: StoreNotSpelled at 0x1060:29 covering 1 op (render::values) */
r2sleigh_residual_void(3); /* r2dec gap: StoreNotSpelled at 0x1060:32 covering 1 op (render::values) */
r2sleigh_residual_void(4); /* r2dec gap: CallNotRendered at 0x1060:68 covering 1 op (render::values): call to __libc_start_main: the import's declaration has an argument this convention does not place */
@@ -175,18 +175,18 @@ uint64_t __do_global_dtors_aux(void)
extern char __dso_handle[];
extern char __TMC_END__[];
uint8_t tmp_3e180_1;
uint64_t tmp_3ea80_1;
uint8_t tmp_7c100_1;
uint64_t tmp_7d300_1;
uint64_t rdi_1;
/* r2dec proof: 3 constructs are marked below; 40 source obligations: 16 rendered, 17 elided, 0 refused, 7 residual; 9 statements rendered; 2 data object types refused; 1 callee prototype supplied by the source */
{
tmp_3e180_1 = r2sleigh_load_u8((void*)&__TMC_END__);
if ((uint8_t)((uint8_t)tmp_3e180_1 != (uint8_t)0U)) {
tmp_7c100_1 = r2sleigh_load_u8((void*)&__TMC_END__);
if ((uint8_t)((uint8_t)tmp_7c100_1 != (uint8_t)0U)) {
return r2sleigh_residual_u64(1);
} else {
tmp_3ea80_1 = r2sleigh_load_u64((void*)(uint64_t)0x3ff8U);
if ((uint8_t)((uint64_t)tmp_3ea80_1 == (uint64_t)0U)) {
tmp_7d300_1 = r2sleigh_load_u64((void*)(uint64_t)0x3ff8U);
if ((uint8_t)((uint64_t)tmp_7d300_1 == (uint64_t)0U)) {
} else {
rdi_1 = r2sleigh_load_u64((void*)&__dso_handle);
__cxa_finalize((void*)rdi_1);
@@ -272,11 +272,11 @@ CMDS=aa; pdd @ 0x0000117c
EXPECT=<<EOF
double helper(const double* values, int64_t count)
{
uint64_t tmp_11f80_1;
uint64_t tmp_11f80_3;
uint64_t tmp_6b00_5;
uint64_t tmp_6b00_6;
uint64_t tmp_6b00_10;
uint64_t tmp_23d00_1;
uint64_t tmp_23d00_3;
uint64_t tmp_d400_5;
uint64_t tmp_d400_6;
uint64_t tmp_d400_10;
_Alignas(16) uint8_t frame[40];
/* r2dec proof: no individual construct is marked; 42 source obligations: 27 rendered, 15 elided, 0 refused; 13 statements rendered */
@@ -284,14 +284,14 @@ double helper(const double* values, int64_t count)
r2sleigh_store_u64((void*)(uint64_t)(frame + 16U), (uint64_t)0U);
r2sleigh_store_u64((void*)(uint64_t)(frame + 24U), (uint64_t)0U);
for (; ; ) {
tmp_11f80_1 = r2sleigh_load_u64((void*)(uint64_t)(frame + 24U));
if ((uint8_t)((int64_t)tmp_11f80_1 < (int64_t)count)) {
tmp_11f80_3 = r2sleigh_load_u64((void*)(uint64_t)(frame + 24U));
tmp_6b00_5 = r2sleigh_load_u64((void*)((uint64_t)values + (uint64_t)tmp_11f80_3 * 8U));
tmp_6b00_6 = r2sleigh_load_u64((void*)(uint64_t)(frame + 16U));
r2sleigh_store_u64((void*)(uint64_t)(frame + 16U), (uint64_t)r2sleigh_float_to_bits_64(r2sleigh_float_from_bits_64(tmp_6b00_5) + r2sleigh_float_from_bits_64(tmp_6b00_6)));
tmp_6b00_10 = r2sleigh_load_u64((void*)(uint64_t)(frame + 24U));
r2sleigh_store_u64((void*)(uint64_t)(frame + 24U), (uint64_t)((uint64_t)tmp_6b00_10 + (uint64_t)1U));
tmp_23d00_1 = r2sleigh_load_u64((void*)(uint64_t)(frame + 24U));
if ((uint8_t)((int64_t)tmp_23d00_1 < (int64_t)count)) {
tmp_23d00_3 = r2sleigh_load_u64((void*)(uint64_t)(frame + 24U));
tmp_d400_5 = r2sleigh_load_u64((void*)((uint64_t)values + (uint64_t)tmp_23d00_3 * 8U));
tmp_d400_6 = r2sleigh_load_u64((void*)(uint64_t)(frame + 16U));
r2sleigh_store_u64((void*)(uint64_t)(frame + 16U), (uint64_t)r2sleigh_float_to_bits_64(r2sleigh_float_from_bits_64(tmp_d400_5) + r2sleigh_float_from_bits_64(tmp_d400_6)));
tmp_d400_10 = r2sleigh_load_u64((void*)(uint64_t)(frame + 24U));
r2sleigh_store_u64((void*)(uint64_t)(frame + 24U), (uint64_t)((uint64_t)tmp_d400_10 + (uint64_t)1U));
} else {
break;
}
@@ -338,8 +338,8 @@ int32_t main(int32_t argc, char** argv)
int32_t from_a(int32_t);
double from_b(const double*, int64_t);
uint32_t tmp_11f00_1;
uint32_t tmp_11f00_2;
uint32_t tmp_23c00_1;
uint32_t tmp_23c00_2;
uint64_t rax_4;
__uint128_t xmm0_6;
uint64_t tmp_lane_1203_44_e_1;
@@ -351,10 +351,10 @@ int32_t main(int32_t argc, char** argv)
r2sleigh_store_u32((void*)(uint64_t)(frame + 28U), (uint32_t)argc);
r2sleigh_store_u64((void*)(uint64_t)(frame + 16U), (uint64_t)argv);
r2sleigh_store_u64((void*)(uint64_t)(frame + 32U), (uint64_t)0x3ff0000000000000U);
tmp_11f00_1 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
r2sleigh_store_u64((void*)((uint64_t)(frame + 32U) + (uint64_t)8U), (uint64_t)r2sleigh_float_to_bits_64((double)(int32_t)tmp_11f00_1));
tmp_11f00_2 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_4 = (uint64_t)(uint32_t)from_a((int32_t)tmp_11f00_2);
tmp_23c00_1 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
r2sleigh_store_u64((void*)((uint64_t)(frame + 32U) + (uint64_t)8U), (uint64_t)r2sleigh_float_to_bits_64((double)(int32_t)tmp_23c00_1));
tmp_23c00_2 = r2sleigh_load_u32((void*)(uint64_t)(frame + 28U));
rax_4 = (uint64_t)(uint32_t)from_a((int32_t)tmp_23c00_2);
xmm0_6 = (__uint128_t)r2sleigh_float_to_bits_64(from_b((const double*)(uint64_t)(frame + 32U), 2));
tmp_lane_1203_44_e_1 = (uint64_t)((__uint128_t)xmm0_6 >> 0U);
tmp_lane_1203_48_12_1 = (uint32_t)((uint32_t)((uint64_t)rax_4 >> 0U) + (uint32_t)(r2sleigh_float_from_bits_64(tmp_lane_1203_44_e_1) > -2147483649.0 && r2sleigh_float_from_bits_64(tmp_lane_1203_44_e_1) < 2147483648.0 ? (int32_t)r2sleigh_float_from_bits_64(tmp_lane_1203_44_e_1) : r2sleigh_residual_i32(1)));
+43 -43
View File
@@ -11,13 +11,13 @@ Blocks: 5
Block 0x401330 (9 bytes, 10 ops)
0: CF = COPY 0x0:1
1: OF = COPY 0x0:1
2: uniq:0x70500[8] = RSI & RSI
3: SF = uniq:0x70500[8] s< 0x0:8
4: ZF = uniq:0x70500[8] == 0x0:8
5: uniq:0x2c200[8] = uniq:0x70500[8] & 0xff:8
6: uniq:0x2c280[1] = POPCOUNT(uniq:0x2c200[8])
7: uniq:0x2c300[1] = uniq:0x2c280[1] & 0x1:1
8: PF = uniq:0x2c300[1] == 0x0:1
2: uniq:0xe0400[8] = RSI & RSI
3: SF = uniq:0xe0400[8] s< 0x0:8
4: ZF = uniq:0xe0400[8] == 0x0:8
5: uniq:0x58200[8] = uniq:0xe0400[8] & 0xff:8
6: uniq:0x58300[1] = POPCOUNT(uniq:0x58200[8])
7: uniq:0x58400[1] = uniq:0x58300[1] & 0x1:1
8: PF = uniq:0x58400[1] == 0x0:1
9: CBRANCH ram:0x401360[8] if ZF
-> 0x401360 (Direct)
-> 0x401339 (Fallthrough)
@@ -28,57 +28,57 @@ Block 0x401339 (15 bytes, 10 ops)
2: RSI = RSI + RDI
3: SF = RSI s< 0x0:8
4: ZF = RSI == 0x0:8
5: uniq:0x2c200[8] = RSI & 0xff:8
6: uniq:0x2c280[1] = POPCOUNT(uniq:0x2c200[8])
7: uniq:0x2c300[1] = uniq:0x2c280[1] & 0x1:1
8: PF = uniq:0x2c300[1] == 0x0:1
5: uniq:0x58200[8] = RSI & 0xff:8
6: uniq:0x58300[1] = POPCOUNT(uniq:0x58200[8])
7: uniq:0x58400[1] = uniq:0x58300[1] & 0x1:1
8: PF = uniq:0x58400[1] == 0x0:1
9: RAX = COPY 0x811c9dc5:8
-> 0x401348 (Fallthrough)
Block 0x401348 (20 bytes, 43 ops)
0: uniq:0x11e00[1] = LOAD [ram]RDI
1: EDX = ZEXT(uniq:0x11e00[1])
0: uniq:0x23a00[1] = LOAD [ram]RDI
1: EDX = ZEXT(uniq:0x23a00[1])
2: RDX = ZEXT(EDX)
3: CF = CARRY(RDI, 0x1:8)
4: OF = SCARRY(RDI, 0x1:8)
5: RDI = RDI + 0x1:8
6: SF = RDI s< 0x0:8
7: ZF = RDI == 0x0:8
8: uniq:0x2c200[8] = RDI & 0xff:8
9: uniq:0x2c280[1] = POPCOUNT(uniq:0x2c200[8])
10: uniq:0x2c300[1] = uniq:0x2c280[1] & 0x1:1
11: PF = uniq:0x2c300[1] == 0x0:1
8: uniq:0x58200[8] = RDI & 0xff:8
9: uniq:0x58300[1] = POPCOUNT(uniq:0x58200[8])
10: uniq:0x58400[1] = uniq:0x58300[1] & 0x1:1
11: PF = uniq:0x58400[1] == 0x0:1
12: CF = COPY 0x0:1
13: OF = COPY 0x0:1
14: EAX = EAX ^ EDX
15: RAX = ZEXT(EAX)
16: SF = EAX s< 0x0:4
17: ZF = EAX == 0x0:4
18: uniq:0x2c200[4] = EAX & 0xff:4
19: uniq:0x2c280[1] = POPCOUNT(uniq:0x2c200[4])
20: uniq:0x2c300[1] = uniq:0x2c280[1] & 0x1:1
21: PF = uniq:0x2c300[1] == 0x0:1
22: uniq:0x4c600[8] = SEXT(EAX)
23: uniq:0x4c680[8] = SEXT(0x1000193:4)
24: uniq:0x4c780[8] = uniq:0x4c600[8] * uniq:0x4c680[8]
25: EAX = SUBPIECE(uniq:0x4c780[8], 0)
26: uniq:0x4c900[4] = SUBPIECE(uniq:0x4c780[8], 4)
27: uniq:0x2d180[8] = SEXT(EAX)
28: CF = uniq:0x2d180[8] != uniq:0x4c780[8]
18: uniq:0x58200[4] = EAX & 0xff:4
19: uniq:0x58300[1] = POPCOUNT(uniq:0x58200[4])
20: uniq:0x58400[1] = uniq:0x58300[1] & 0x1:1
21: PF = uniq:0x58400[1] == 0x0:1
22: uniq:0x98a00[8] = SEXT(EAX)
23: uniq:0x98b00[8] = SEXT(0x1000193:4)
24: uniq:0x98d00[8] = uniq:0x98a00[8] * uniq:0x98b00[8]
25: EAX = SUBPIECE(uniq:0x98d00[8], 0)
26: uniq:0x99000[4] = SUBPIECE(uniq:0x98d00[8], 4)
27: uniq:0x5a100[8] = SEXT(EAX)
28: CF = uniq:0x5a100[8] != uniq:0x98d00[8]
29: OF = COPY CF
30: RAX = ZEXT(EAX)
31: uniq:0x3f080[8] = COPY RSI
32: CF = uniq:0x3f080[8] < RDI
33: OF = SBORROW(uniq:0x3f080[8], RDI)
34: uniq:0x3f180[8] = uniq:0x3f080[8] - RDI
35: SF = uniq:0x3f180[8] s< 0x0:8
36: ZF = uniq:0x3f180[8] == 0x0:8
37: uniq:0x2c200[8] = uniq:0x3f180[8] & 0xff:8
38: uniq:0x2c280[1] = POPCOUNT(uniq:0x2c200[8])
39: uniq:0x2c300[1] = uniq:0x2c280[1] & 0x1:1
40: PF = uniq:0x2c300[1] == 0x0:1
41: uniq:0x12800[1] = !ZF
42: CBRANCH ram:0x401348[8] if uniq:0x12800[1]
31: uniq:0x7df00[8] = COPY RSI
32: CF = uniq:0x7df00[8] < RDI
33: OF = SBORROW(uniq:0x7df00[8], RDI)
34: uniq:0x7e100[8] = uniq:0x7df00[8] - RDI
35: SF = uniq:0x7e100[8] s< 0x0:8
36: ZF = uniq:0x7e100[8] == 0x0:8
37: uniq:0x58200[8] = uniq:0x7e100[8] & 0xff:8
38: uniq:0x58300[1] = POPCOUNT(uniq:0x58200[8])
39: uniq:0x58400[1] = uniq:0x58300[1] & 0x1:1
40: PF = uniq:0x58400[1] == 0x0:1
41: uniq:0x24e00[1] = !ZF
42: CBRANCH ram:0x401348[8] if uniq:0x24e00[1]
-> 0x401348 (Direct)
-> 0x40135c (Fallthrough)
@@ -105,7 +105,7 @@ uint64_t fnv1a32(uint64_t arg0, uint64_t arg1)
uint64_t rsi_1;
uint64_t rax_2;
uint64_t rdi_1;
uint8_t tmp_11e00_1;
uint8_t tmp_23a00_1;
uint64_t rdi_2;
uint64_t rax_4;
@@ -118,9 +118,9 @@ uint64_t fnv1a32(uint64_t arg0, uint64_t arg1)
rax_2 = (uint64_t)0x811c9dc5U;
rdi_1 = arg0;
for (; ; ) {
tmp_11e00_1 = r2sleigh_load_u8((void*)rdi_1);
tmp_23a00_1 = r2sleigh_load_u8((void*)rdi_1);
rdi_2 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)1U);
rax_4 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)(uint8_t)tmp_11e00_1 ^ (uint32_t)((uint64_t)rax_2 >> 0U)) * (uint64_t)0x1000193U) >> 0U);
rax_4 = (uint64_t)(uint32_t)((uint64_t)((uint64_t)(int32_t)((uint32_t)(uint8_t)tmp_23a00_1 ^ (uint32_t)((uint64_t)rax_2 >> 0U)) * (uint64_t)0x1000193U) >> 0U);
if ((uint8_t)((uint64_t)rsi_1 != (uint64_t)rdi_2)) {
rax_2 = rax_4;
rdi_1 = rdi_2;
+2 -1
View File
@@ -5,7 +5,7 @@ fn main() {
// The following sources were pulled from the Makefile
const LIBSLA_SOURCE_FILES: &[&str] = &[
// CORE= xml marshal space float address pcoderaw translate opcodes globalcontext
// CORE= xml marshal space float address pcoderaw translate opcodes metatype globalcontext
"xml.cc",
"marshal.cc",
"space.cc",
@@ -14,6 +14,7 @@ fn main() {
"pcoderaw.cc",
"translate.cc",
"opcodes.cc",
"metatype.cc",
"globalcontext.cc",
// SLEIGH= sleigh pcodeparse pcodecompile sleighbase slghsymbol \
// slghpatexpress slghpattern semantics context slaformat compression filemanage
@@ -7,7 +7,7 @@ decomp_dbg
decomp_opt
ghidra_dbg
ghidra_opt
ghidra_test_dbg
decomp_test_dbg
sleigh_dbg
com_dbg
com_opt
@@ -457,7 +457,7 @@ RECURSIVE = NO
# excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag.
EXCLUDE = unify.hh unify.cc rulecompile.hh rulecompile.cc slghparse.cc slghparse.hh slghscan.cc slghpattern.hh slghpattern.cc slghpatexpress.hh slghpatexpress.cc slghsymbol.hh slghsymbol.cc codedata.hh codedata.cc semantics.hh semantics.cc grammar.hh grammar.cc callgraph.hh callgraph.cc filemanage.hh filemanage.cc graph.hh graph.cc loadimage_bfd.hh loadimage_bfd.cc pcodecompile.cc pcodecompile.hh pcodeparse.hh pcodeparse.cc inject_sleigh.hh inject_sleigh.cc context.hh context.cc consolemain.cc sleighexample.cc xml.cc double.hh double.cc paramid.hh paramid.cc prefersplit.hh prefersplit.cc
EXCLUDE = unify.hh unify.cc rulecompile.hh rulecompile.cc slghparse.cc slghparse.hh slghscan.cc slghpattern.hh slghpattern.cc slghpatexpress.hh slghpatexpress.cc slghsymbol.hh slghsymbol.cc codedata.hh codedata.cc grammar.hh grammar.cc callgraph.hh callgraph.cc filemanage.hh filemanage.cc graph.hh graph.cc loadimage_bfd.hh loadimage_bfd.cc pcodeparse.hh pcodeparse.cc consolemain.cc sleighexample.cc xml.cc double.hh double.cc paramid.hh paramid.cc
# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
# directories that are symbolic links (a Unix filesystem feature) are excluded
@@ -589,12 +589,6 @@ VERBATIM_HEADERS = NO
ALPHABETICAL_INDEX = NO
# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
# in which this list will be split (can be a number in the range [1..20])
COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all
# classes will be put under the same header in the alphabetical index.
# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
@@ -744,7 +738,7 @@ COMPACT_LATEX = NO
# by the printer. Possible values are: a4, a4wide, letter, legal and
# executive. If left blank a4wide will be used.
PAPER_TYPE = a4wide
PAPER_TYPE = a4
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
# packages that should be included in the LaTeX output.
@@ -35,6 +35,13 @@ ifeq ($(OS),Darwin)
OSDIR=mac_x86_64
endif
ifeq ($(OS),OpenBSD)
ifeq ($(ARCH),amd64)
ARCH_TYPE=-m64
OSDIR=openbsd_x86_64
endif
endif
CXX=g++ -std=c++11
# Debug flags
@@ -54,6 +61,9 @@ BFDLIB=-lbfd
LNK=-lz
.PHONY: all
all: ghidra_opt decomp_opt sleigh_opt
# Source files
ALL_SOURCE= $(wildcard *.cc)
ALL_NAMES=$(subst .cc,,$(ALL_SOURCE))
@@ -76,14 +86,14 @@ EXTERNAL_CONSOLEEXT_NAMES=$(subst .cc,,$(notdir $(EXTERNAL_CONSOLEEXT_SOURCE)))
# The following macros partition all the source files, there should be no overlaps
# Some core source files used in all projects
CORE= xml marshal space float address pcoderaw translate opcodes globalcontext
CORE= xml marshal space float address pcoderaw translate opcodes metatype globalcontext
# Additional core files for any projects that decompile
DECCORE=capability architecture options graph cover block cast typeop database cpool \
comment stringmanage modelrules fspec action loadimage grammar varnode op \
type variable varmap jumptable emulate emulateutil flow userop multiprecision \
comment stringmanage modelrules fspec action loadimage grammar varnode op type \
variable varmap jumptable emulate emulateutil flow userop expression multiprecision \
funcdata funcdata_block funcdata_op funcdata_varnode unionresolve pcodeinject \
heritage prefersplit rangeutil ruleaction subflow blockaction merge double \
transform constseq coreaction condexe override dynamic crc32 prettyprint \
transform constseq bitfield coreaction condexe override dynamic crc32 prettyprint \
printlanguage printc printjava memstate opbehavior paramid signature $(COREEXT_NAMES)
# Files used for any project that use the sleigh decoder
SLEIGH= sleigh pcodeparse pcodecompile sleighbase slghsymbol \
@@ -99,7 +109,7 @@ SPECIAL=consolemain sleighexample test
# Any additional modules for the command line decompiler
EXTRA= $(filter-out $(CORE) $(DECCORE) $(SLEIGH) $(GHIDRA) $(SLACOMP) $(SPECIAL),$(ALL_NAMES))
EXECS=decomp_dbg decomp_opt ghidra_test_dbg ghidra_dbg ghidra_opt sleigh_dbg sleigh_opt libdecomp_dbg.a libdecomp.a
EXECS=decomp_dbg decomp_opt decomp_test_dbg ghidra_dbg ghidra_opt sleigh_dbg sleigh_opt libdecomp_dbg.a libdecomp.a
# Possible conditional compilation flags
# __TERMINAL__ # Turn on terminal support for console mode
@@ -118,7 +128,7 @@ COMMANDLINE_NAMES=$(CORE) $(DECCORE) $(EXTRA) $(SLEIGH) consolemain
COMMANDLINE_DEBUG=-DCPUI_DEBUG -D__TERMINAL__
COMMANDLINE_OPT=-D__TERMINAL__
TEST_NAMES=$(CORE) $(DECCORE) $(SLEIGH) $(EXTRA) test
TEST_NAMES=$(CORE) $(DECCORE) $(SLEIGH) $(EXTRA) test
TEST_DEBUG=-D__TERMINAL__
GHIDRA_NAMES=$(CORE) $(DECCORE) $(GHIDRA)
@@ -153,82 +163,54 @@ LIBSLA_SOURCE=$(LIBSLA_NAMES:%=%.cc) $(LIBSLA_NAMES:%=%.hh) \
LIBDECOMP_DBG_OBJS=$(LIBDECOMP_NAMES:%=com_dbg/%.o)
LIBDECOMP_OPT_OBJS=$(LIBDECOMP_NAMES:%=com_opt/%.o)
# conditionals to determine which dependency files to build
DEPNAMES=com_dbg/depend com_opt/depend
ifeq ($(MAKECMDGOALS),install_ghidraopt)
DEPNAMES=ghi_opt/depend
endif
ifeq ($(MAKECMDGOALS),install_ghidradbg)
DEPNAMES=ghi_dbg/depend
endif
ifeq ($(MAKECMDGOALS),ghidra_opt)
DEPNAMES=ghi_opt/depend
endif
ifeq ($(MAKECMDGOALS),ghidra_opt_mac)
DEPNAMES=ghi_opt/depend
endif
ifeq ($(MAKECMDGOALS),ghidra_dbg)
DEPNAMES=ghi_dbg/depend
endif
ifeq ($(MAKECMDGOALS),sleigh_opt)
DEPNAMES=sla_opt/depend
endif
ifeq ($(MAKECMDGOALS),sleigh_opt_mac)
DEPNAMES=sla_opt/depend
endif
ifeq ($(MAKECMDGOALS),sleigh_dbg)
DEPNAMES=sla_dbg/depend
endif
ifeq ($(MAKECMDGOALS),libsla.a)
DEPNAMES=com_opt/depend.lib_sla
endif
ifeq ($(MAKECMDGOALS),libsla_dbg.a)
DEPNAMES=com_dbg/depend.lib_sla
endif
ifeq ($(MAKECMDGOALS),decomp_dbg)
DEPNAMES=com_dbg/depend
endif
ifeq ($(MAKECMDGOALS),decomp_opt)
DEPNAMES=com_opt/depend
endif
ifneq (,$(filter $(MAKECMDGOALS),ghidra_test_dbg test))
DEPNAMES=test_dbg/depend
endif
ifeq ($(MAKECMDGOALS),reallyclean)
DEPNAMES=
endif
ifeq ($(MAKECMDGOALS),clean)
DEPNAMES=
endif
ifeq ($(MAKECMDGOALS),doc)
DEPNAMES=
endif
ifeq ($(MAKECMDGOALS),tags)
DEPNAMES=
endif
ifeq ($(MAKECMDGOALS),link_extensions)
DEPNAMES=
endif
ifeq ($(MAKECMDGOALS),link_extensions_hard)
DEPNAMES=
endif
-include $(COMMANDLINE_DBG_OBJS:.o=.d)
-include $(COMMANDLINE_OPT_OBJS:.o=.d)
-include $(TEST_DEBUG_OBJS:.o=.d)
-include $(GHIDRA_DBG_OBJS:.o=.d)
-include $(GHIDRA_OPT_OBJS:.o=.d)
-include $(SLEIGH_DBG_OBJS:.o=.d)
-include $(SLEIGH_OPT_OBJS:.o=.d)
-include $(LIBSLA_DBG_OBJS:.o=.d)
-include $(LIBSLA_OPT_OBJS:.o=.d)
-include $(LIBDECOMP_DBG_OBJS:.o=.d)
-include $(LIBDECOMP_OPT_OBJS:.o=.d)
com_dbg/%.o: %.cc
$(CXX) $(ARCH_TYPE) -c $(DBG_CXXFLAGS) $(ADDITIONAL_FLAGS) $(COMMANDLINE_DEBUG) $< -o $@
com_opt/%.o: %.cc
$(CXX) $(ARCH_TYPE) -c $(OPT_CXXFLAGS) $(ADDITIONAL_FLAGS) $(COMMANDLINE_OPT) $< -o $@
test_dbg/%.o: %.cc
$(CXX) $(ARCH_TYPE) -c $(DBG_CXXFLAGS) $(ADDITIONAL_FLAGS) $(TEST_DEBUG) $< -o $@
test_dbg/%.o: ../unittests/%.cc
$(CXX) -I. $(ARCH_TYPE) -c $(DBG_CXXFLAGS) $(ADDITIONAL_FLAGS) $(TEST_DEBUG) $< -o $@
ghi_dbg/%.o: %.cc
$(CXX) $(ARCH_TYPE) -c $(DBG_CXXFLAGS) $(ADDITIONAL_FLAGS) $(GHIDRA_DEBUG) $< -o $@
ghi_opt/%.o: %.cc
$(CXX) $(ARCH_TYPE) -c $(OPT_CXXFLAGS) $(ADDITIONAL_FLAGS) $(GHIDRA_OPT) $< -o $@
sla_dbg/%.o: %.cc
$(CXX) $(ARCH_TYPE) -c $(DBG_CXXFLAGS) $(ADDITIONAL_FLAGS) $(SLEIGH_DEBUG) $< -o $@
sla_opt/%.o: %.cc
$(CXX) $(ARCH_TYPE) -c $(OPT_CXXFLAGS) $(ADDITIONAL_FLAGS) $(SLEIGH_OPT) $< -o $@
com_dbg/%.o: %.cc | com_dbg
$(CXX) $(ARCH_TYPE) $(DBG_CXXFLAGS) $(ADDITIONAL_FLAGS) $(COMMANDLINE_DEBUG) \
-MMD -MP -MF $(@:.o=.d) -c $< -o $@
com_opt/%.o: %.cc | com_opt
$(CXX) $(ARCH_TYPE) $(OPT_CXXFLAGS) $(ADDITIONAL_FLAGS) $(COMMANDLINE_OPT) \
-MMD -MP -MF $(@:.o=.d) -c $< -o $@
test_dbg/%.o: %.cc | test_dbg
$(CXX) $(ARCH_TYPE) $(DBG_CXXFLAGS) $(ADDITIONAL_FLAGS) $(TEST_DEBUG) \
-MMD -MP -MF $(@:.o=.d) -c $< -o $@
test_dbg/%.o: ../unittests/%.cc | test_dbg
$(CXX) -I. $(ARCH_TYPE) $(DBG_CXXFLAGS) $(ADDITIONAL_FLAGS) $(TEST_DEBUG) \
-MMD -MP -MF $(@:.o=.d) -c $< -o $@
ghi_dbg/%.o: %.cc | ghi_dbg
$(CXX) $(ARCH_TYPE) $(DBG_CXXFLAGS) $(ADDITIONAL_FLAGS) $(GHIDRA_DEBUG) \
-MMD -MP -MF $(@:.o=.d) -c $< -o $@
ghi_opt/%.o: %.cc | ghi_opt
$(CXX) $(ARCH_TYPE) $(OPT_CXXFLAGS) $(ADDITIONAL_FLAGS) $(GHIDRA_OPT) \
-MMD -MP -MF $(@:.o=.d) -c $< -o $@
sla_dbg/%.o: %.cc | sla_dbg
$(CXX) $(ARCH_TYPE) $(DBG_CXXFLAGS) $(ADDITIONAL_FLAGS) $(SLEIGH_DEBUG) \
-MMD -MP -MF $(@:.o=.d) -c $< -o $@
sla_opt/%.o: %.cc | sla_opt
$(CXX) $(ARCH_TYPE) $(OPT_CXXFLAGS) $(ADDITIONAL_FLAGS) $(SLEIGH_OPT) \
-MMD -MP -MF $(@:.o=.d) -c $< -o $@
OBJDIRS := com_dbg com_opt test_dbg ghi_dbg ghi_opt sla_dbg sla_opt
$(OBJDIRS):
mkdir -p $@
grammar.cc: grammar.y
$(YACC) -l -o $@ $<
@@ -253,11 +235,12 @@ decomp_dbg: $(COMMANDLINE_DBG_OBJS)
decomp_opt: $(COMMANDLINE_OPT_OBJS)
$(CXX) $(OPT_CXXFLAGS) $(ARCH_TYPE) -o decomp_opt $(COMMANDLINE_OPT_OBJS) $(BFDLIB) $(LNK)
ghidra_test_dbg: $(TEST_DEBUG_OBJS)
$(CXX) $(DBG_CXXFLAGS) $(ARCH_TYPE) -o ghidra_test_dbg $(TEST_DEBUG_OBJS) $(BFDLIB) $(LNK)
#decomp_test_dbg: DBG_CXXFLAGS += -D_GLIBCXX_ASSERTIONS -fsanitize=address,undefined
decomp_test_dbg: $(TEST_DEBUG_OBJS)
$(CXX) $(DBG_CXXFLAGS) $(ARCH_TYPE) -o decomp_test_dbg $(TEST_DEBUG_OBJS) $(BFDLIB) $(LNK)
test: ghidra_test_dbg
./ghidra_test_dbg
test: decomp_test_dbg
./decomp_test_dbg
ghidra_dbg: $(GHIDRA_DBG_OBJS)
$(CXX) $(DBG_CXXFLAGS) $(ADDITIONAL_FLAGS) $(MAKE_STATIC) $(ARCH_TYPE) -o ghidra_dbg $(GHIDRA_DBG_OBJS)
@@ -330,77 +313,17 @@ link_extensions_hard:
tags:
etags *.c *.h *.cc *.hh
# Rules to build the different dependency files
com_dbg/depend: $(COMMANDLINE_NAMES:%=%.cc)
mkdir -p com_dbg
@set -e; rm -f $@; \
$(CXX) -MM $(COMMANDLINE_DEBUG) $^ > $@.$$$$; \
sed 's,\(.*\)\.o[ :]*,com_dbg/\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
com_opt/depend: $(COMMANDLINE_NAMES:%=%.cc)
mkdir -p com_opt
@set -e; rm -f $@; \
$(CXX) -MM $(COMMANDLINE_OPT) $^ > $@.$$$$; \
sed 's,\(.*\)\.o[ :]*,com_opt/\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
test_dbg/depend: $(TEST_NAMES:%=%.cc) $(UNITTEST_NAMES:%=%.cc)
mkdir -p test_dbg
@set -e; rm -f $@; \
$(CXX) -I. -MM $(TEST_DEBUG) $^ > $@.$$$$; \
sed 's,\(.*\)\.o[ :]*,test_dbg/\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
ghi_dbg/depend: $(GHIDRA_NAMES_DBG:%=%.cc)
mkdir -p ghi_dbg
@set -e; rm -f $@; \
$(CXX) -MM $(GHIDRA_DEBUG) $^ > $@.$$$$; \
sed 's,\(.*\)\.o[ :]*,ghi_dbg/\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
ghi_opt/depend: $(GHIDRA_NAMES:%=%.cc)
mkdir -p ghi_opt
@set -e; rm -f $@; \
$(CXX) -MM $(GHIDRA_OPT) $^ > $@.$$$$; \
sed 's,\(.*\)\.o[ :]*,ghi_opt/\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
sla_dbg/depend: $(SLEIGH_NAMES:%=%.cc)
mkdir -p sla_dbg
@set -e; rm -f $@; \
$(CXX) -MM $(SLEIGH_DEBUG) $^ > $@.$$$$; \
sed 's,\(.*\)\.o[ :]*,sla_dbg/\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
sla_opt/depend: $(SLEIGH_NAMES:%=%.cc)
mkdir -p sla_opt
@set -e; rm -f $@; \
$(CXX) -MM $(SLEIGH_OPT) $^ > $@.$$$$; \
sed 's,\(.*\)\.o[ :]*,sla_opt/\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
com_opt/depend.lib_sla: $(LIBSLA_NAMES:%=%.cc)
mkdir -p com_opt
@set -e; rm -f $@; \
$(CXX) -MM $(COMMANDLINE_OPT) $^ > $@.$$$$; \
sed 's,\(.*\)\.o[ :]*,com_opt/\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
com_dbg/depend.lib_sla: $(LIBSLA_NAMES:%=%.cc)
mkdir -p com_dbg
@set -e; rm -f $@; \
$(CXX) -MM $(COMMANDLINE_DEBUG) $^ > $@.$$$$; \
sed 's,\(.*\)\.o[ :]*,com_dbg/\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
include $(DEPNAMES)
doc:
doxygen Doxyfile
clean:
rm -f com_dbg/*.o com_opt/*.o test_dbg/*.o ghi_dbg/*.o ghi_opt/*.o sla_dbg/*.o sla_opt/*.o
rm -f com_dbg/*.o com_dbg/*.d
rm -f com_opt/*.o com_opt/*.d
rm -f test_dbg/*.o test_dbg/*.d
rm -f ghi_dbg/*.o ghi_dbg/*.d
rm -f ghi_opt/*.o ghi_opt/*.d
rm -f sla_dbg/*.o sla_dbg/*.d
rm -f sla_opt/*.o sla_opt/*.d
rm -f *.gcov com_dbg/*.gcno com_dbg/*.gcda
resetgcov:
@@ -411,3 +334,22 @@ reallyclean: clean
rm -rf com_dbg com_opt test_dbg ghi_dbg ghi_opt sla_dbg sla_opt
rm -f $(EXECS) TAGS *~
.PHONY: \
decomp_dbg \
decomp_opt \
decomp_test_dbg \
test \
ghidra_dbg \
ghidra_opt \
sleigh_dbg \
sleigh_opt \
install_ghidradbg \
install_ghidraopt \
sleighexamp_dir \
link_extensions \
link_extensions_hard \
tags \
doc \
clean \
resetgcov \
reallyclean
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -43,7 +43,7 @@ void Action::issueWarning(Architecture *glb)
{
if ((flags&(rule_warnings_on|rule_warnings_given)) == rule_warnings_on) {
flags |= rule_warnings_given;
glb->printMessage("WARNING: Applied action "+name);
glb->printWarning("Applied action "+name);
}
}
@@ -640,7 +640,7 @@ void Rule::issueWarning(Architecture *glb)
{
if ((flags&(warnings_on|warnings_given)) == warnings_on) {
flags |= warnings_given;
glb->printMessage("WARNING: Applied rule "+name);
glb->printWarning("Applied rule "+name);
}
}
@@ -700,18 +700,6 @@ void Rule::printStatistics(ostream &s) const
s << name << dec << " Tested=" << count_tests << " Applied=" << count_apply << endl;
}
/// Populate the given array with all possible OpCodes this Rule might apply to.
/// By default, this method returns all possible OpCodes
/// \param oplist is the array to populate
void Rule::getOpList(vector<uint4> &oplist) const
{
uint4 i;
for(i=0;i<CPUI_MAX;++i)
oplist.push_back(i);
}
/// This method is called every time the Rule successfully applies. If it returns
/// \b true, this indicates to the system that an action breakpoint has occurred.
/// \return true if an action breakpoint should occur because of this Rule
@@ -862,11 +850,11 @@ int4 ActionPool::processOp(PcodeOp *op,Funcdata &data)
rule_index = 0;
}
}
#ifdef CPUI_DEBUG
else if (opc != op->code()) {
data.getArch()->printMessage("ERROR: Rule " + rl->getName() + " changed op without returning result of 1!");
opc = op->code();
rule_index = 0;
throw LowlevelError("ERROR: Rule " + rl->getName() + " changed op without returning result of 1!");
}
#endif
}
op_state++;
rule_index = 0;
@@ -878,11 +866,11 @@ int4 ActionPool::apply(Funcdata &data)
{
if (status != status_mid) {
op_state = data.beginOpAll(); // Initialize the derived action
op_state = data.beginOpMain(); // Initialize the derived action
rule_index = 0;
}
for(;op_state!=data.endOpAll();)
if (0!=processOp((*op_state).second,data)) return -1;
for(;op_state!=data.endOpMain();)
if (0!=processOp((*op_state).second,data)) return -1;
return 0; // Indicate successful completion
}
@@ -234,7 +234,10 @@ public:
/// \param grouplist is the list of groups being cloned
/// \return the cloned Rule or NULL
virtual Rule *clone(const ActionGroupList &grouplist) const=0;
virtual void getOpList(vector<uint4> &oplist) const; ///< List of op codes this rule operates on
/// Populate the given array with all possible OpCodes this Rule might apply to.
/// \param oplist is the array to populate
virtual void getOpList(vector<uint4> &oplist) const=0; ///< Provide OpCodes \b this rule operates on
/// \brief Attempt to apply \b this Rule
///
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -101,6 +101,35 @@ Address::Address(mach_extreme ex)
}
}
/// If there is a register container of the given region print a description of the region
/// using the register name. Otherwise just print region as an address.
/// Return the size of the register or the \e expected size for the region.
/// \param s is the stream to print to
/// \param size is the number of bytes in the region
/// \return the size of the expected size
int4 Address::printRaw(ostream &s,int4 size) const
{
const Translate *trans = base->getTrans();
int4 expect;
string name = trans->getRegisterName(base, offset, size);
if (name.size() != 0) {
const VarnodeData &point(trans->getRegister(name));
uintb off = offset - point.offset;
s << name;
expect = point.size;
if (off != 0)
s << '+' << dec << off;
}
else {
s << base->getShortcut();
expect = trans->getDefaultSize();
base->printRaw(s,offset);
}
return expect;
}
/// Return \b true if the range starting at \b this extending the given number of bytes
/// is contained by the second given range.
/// \param sz is the given number of bytes in \b this range
@@ -185,12 +214,21 @@ bool Address::isContiguous(int4 sz,const Address &loaddr,int4 losz) const
return false;
}
/// If pointers are possible anywhere within the \b size byte region return \b true, \b false otherwise.
/// \param size is the number bytes in the region
/// \return \b true if pointers into the region are possible
bool Address::highPtrPossible(int4 size) const
{
return base->manage->highPtrPossible(*this, size);
}
/// If \b this is (originally) a \e join address, reevaluate it in terms of its new
/// \e offset and \e size, changing the space and offset if necessary.
/// \param size is the new size in bytes of the underlying object
void Address::renormalize(int4 size) {
if (base->getType() == IPTR_JOIN)
base->getManager()->renormalizeJoinAddress(*this,size);
base->manage->renormalizeJoinAddress(*this,size);
}
/// This is usually used to decode an address from an \b \<addr\>
@@ -457,15 +495,15 @@ void RangeList::merge(const RangeList &op2)
while(iter1 != iter2) {
const Range &range( *iter1 );
++iter1;
insertRange(range.spc, range.first, range.last);
insertRange(range);
}
}
/// Make sure indicated range of addresses is \e contained in \b this RangeList
/// \param addr is the first Address in the target range
/// \param size is the number of bytes in the target range
/// \return \b true is the range is fully contained by this RangeList
bool RangeList::inRange(const Address &addr,int4 size) const
/// \return \b true if the range is fully contained by this RangeList
bool RangeList::inRange(const Address &addr,uintb size) const
{
set<Range>::const_iterator iter;
@@ -481,11 +519,32 @@ bool RangeList::inRange(const Address &addr,int4 size) const
// if (iter == tree.end()) // iter can't be end if non-empty
// return false;
if ((*iter).spc != addr.getSpace()) return false;
if ((*iter).last >= addr.getOffset()+size-1)
uintb end = addr.getOffset()+size-1;
if (end < addr.getOffset())
return false; // size causes overflow
if ((*iter).last >= end)
return true;
return false;
}
/// \param rng is the target range
/// \return \b true if the range is fully contained by this RangeList
bool RangeList::inRange(const Range &rng) const
{
set<Range>::const_iterator iter;
if (tree.empty()) return false;
// iter = first range with its first > rng.first
iter = tree.upper_bound(rng);
if (iter == tree.begin()) return false;
// Set iter to last range with range.first <= rng.first
--iter;
if ((*iter).spc != rng.getSpace()) return false;
return ((*iter).last >= rng.last);
}
/// If \b this RangeList contains the specific address (spaceid,offset), return it
/// \return the containing Range or NULL
const Range *RangeList::getRange(AddrSpace *spaceid,uintb offset) const
@@ -504,6 +563,37 @@ const Range *RangeList::getRange(AddrSpace *spaceid,uintb offset) const
return (const Range *)0;
}
/// If \b this contains no Range in the given address space, null is returned.
/// If a range contains \b offset, it is returned.
/// Otherwise the range with a boundary point closest to \b offset is returned.
/// If two ranges are equidistant to \b offset, the earlier Range is returned.
/// \param spaceid is the given address space
/// \param offset is the given offset
/// \return the nearest Range in the same address space or null
const Range *RangeList::getNearestRange(AddrSpace *spaceid,uintb offset) const
{
if (tree.empty()) return (const Range *)0;
set<Range>::const_iterator iter = tree.upper_bound(Range(spaceid,offset,offset));
const Range *after = (const Range *)0;
if (iter != tree.end()) {
after = &(*iter);
if (after->spc != spaceid)
after = (const Range *)0;
}
if (iter == tree.begin()) return after; // nothing earlier, after is closest
--iter;
const Range *before = &(*iter);
if (before->spc != spaceid) return after;
if (after == (const Range *)0) return before;
if (before->last >= offset) return before; // Range contains offset, it is closest
uint8 distafter = after->first - offset;
uint8 distbefore = offset - before->last;
return (distafter < distbefore) ? after : before;
}
/// Return the size of the biggest contiguous sequence of addresses in
/// \b this RangeList which contain the given address
/// \param addr is the given address
@@ -627,6 +717,246 @@ void RangeList::decode(Decoder &decoder)
decoder.closeElement(elemId);
}
BitRange::BitRange(const BitRange &op2,int4 off,int4 sz)
{
byteOffset = off;
byteSize = sz;
numBits = op2.numBits;
isBigEndian = op2.isBigEndian;
leastSigBit = translateLSB(op2);
}
/// Both the byte container and the bit range are compared and must be equal to return 0.
/// \param op2 is the other bit range to compare with
/// \return -1, 0, or 1 to establish ordering the two ranges
int4 BitRange::compare(const BitRange &op2) const
{
if (byteOffset != op2.byteOffset)
return (byteOffset < op2.byteOffset) ? -1:1;
if (byteSize != op2.byteSize)
return (byteSize < op2.byteSize) ? -1 : 1;
if (leastSigBit != op2.leastSigBit)
return (leastSigBit < op2.leastSigBit) ? -1:1;
if (numBits != op2.numBits)
return (numBits < op2.numBits) ? -1:1;
return 0;
}
/// The returned result is directly comparable with \b leastSigBit for determining order/overlap.
/// \param op2 is the other BitRange to translate into \b this frame
/// \return the translated value of op2.leastSigBit
int4 BitRange::translateLSB(const BitRange &op2) const
{
int4 op2Sig = op2.leastSigBit;
if (isBigEndian) {
int4 thisPos = byteOffset + byteSize;
int4 op2Pos = op2.byteOffset + op2.byteSize;
op2Sig += 8 * (thisPos - op2Pos);
}
else {
op2Sig += 8 * (op2.byteOffset - byteOffset);
}
return op2Sig;
}
/// Return:
/// - -1 if \b this should come before (no intersection)
/// - 0 if \b this and op2 are the same bitrange
/// - 1 if \b this should come after (no intersection)
/// - 2 if \b this is contained in op2
/// - 3 if op2 is contained in \b this
/// - 4 if partial overlap
///
/// \param op2 is the other range to compare
/// \return the intersection code
int4 BitRange::overlapTest(const BitRange &op2) const
{
int4 op2Sig = translateLSB(op2);
int4 thisMost = leastSigBit + numBits;
int4 op2Most = op2Sig + op2.numBits;
if (isBigEndian) {
if (leastSigBit >= op2Most) return -1;
if (op2Sig >= thisMost) return 1;
}
else {
if (thisMost <= op2Sig) return -1;
if (op2Most <= leastSigBit) return 1;
}
// Reaching here we have some kind of intersection
if (leastSigBit == op2Sig && thisMost == op2Most) return 0;
if (op2Sig <= leastSigBit && op2Most >= thisMost) return 2; /// this contained in op2
if (leastSigBit <= op2Sig && thisMost >= op2Most) return 3; /// op2 contained in this
return 4;
}
/// The byte container for \b this does not change only \b leastSigBit and \b numBits.
/// If the intersection is empty, \b numBits is set to 0.
/// \param op2 is the bit range to intersect with \b this.
void BitRange::intersection(const BitRange &op2)
{
int4 op2Sig = translateLSB(op2);
int4 op2Most = op2Sig + op2.numBits;
int4 thisMost = leastSigBit + numBits;
if (op2Sig > leastSigBit) {
numBits -= (op2Sig - leastSigBit);
leastSigBit = op2Sig;
}
if (op2Most < thisMost) {
numBits -= (thisMost - op2Most);
}
if (numBits < 0) {
leastSigBit = 0;
numBits = 0;
}
}
/// The range of bits is intersected with the 1-bits of the mask. The resulting
/// range is the minimal cover of the bits in the intersection.
/// \param mask is the mask to intersect with
void BitRange::intersectMask(uintb mask)
{
mask &= getMask();
if (mask == 0) {
leastSigBit = 0;
numBits = 0;
return;
}
int4 newLeastSig = leastsigbit_set(mask);
int4 newMostSig = mostsigbit_set(mask) + 1;
int4 thisMost = leastSigBit + numBits;
if (newLeastSig > leastSigBit) {
numBits -= (newLeastSig - leastSigBit);
leastSigBit = newLeastSig;
}
if (newMostSig < thisMost) {
numBits -= (thisMost - newMostSig);
}
}
/// The bit range is shifted to the left by the given amount.
/// \param leftShiftAmount is the amount to shift the range by
void BitRange::shift(int4 leftShiftAmount)
{
leastSigBit += leftShiftAmount;
int4 most = leastSigBit + numBits;
if (leastSigBit < 0) {
numBits += leastSigBit;
leastSigBit = 0;
}
else if (most > byteSize * 8) {
numBits -= (most - byteSize * 8);
}
if (numBits < 0) {
leastSigBit = 0;
numBits = 0;
}
}
/// The number of bits may be affected.
/// \param num is the number of bytes to truncate
void BitRange::truncateMostSigBytes(int4 num)
{
if (isBigEndian) {
byteOffset += num;
}
byteSize -= num;
int4 maxOffset = leastSigBit + numBits;
if (maxOffset > byteSize * 8)
numBits -= (maxOffset - byteSize * 8);
if (numBits < 0)
numBits = 0;
}
/// \param num is the number of bytes to truncate
void BitRange::truncateLeastSigBytes(int4 num)
{
if (!isBigEndian)
byteOffset += num;
byteSize -= num;
leastSigBit -= num * 8;
if (leastSigBit < 0) {
numBits = numBits + leastSigBit;
leastSigBit = 0;
if (numBits < 0)
numBits = 0;
}
}
/// Only the container is affected, the bit range itself does not change.
/// \param num is the number of bytes to add
void BitRange::extendBytes(int4 num)
{
if (isBigEndian)
byteOffset -= num;
byteSize += num;
}
/// The bit-mask is aligned with the byte container.
/// \return the bit-mask describing \b this range
uintb BitRange::getMask(void) const
{
uintb res;
if (numBits >= sizeof(uintb)*8)
res = 0;
else {
res = 1;
res <<= numBits;
}
res -= 1;
res <<= leastSigBit;
return res;
}
/// \return \b true if the beginning and end of the range fall on byte boundaries
bool BitRange::isByteRange(void) const
{
if ((numBits & 7) != 0) return false;
if ((leastSigBit & 7) != 0) return false;
return true;
}
/// \return \b true if the most significant bit of the field and the container are the same
bool BitRange::isMostSignificant(void) const
{
return 8*byteSize == leastSigBit + numBits;
}
void BitRange::minimizeContainer(void)
{
int4 trunc = leastSigBit / 8;
if (isBigEndian)
byteSize -= trunc;
else
byteOffset += trunc;
leastSigBit &= 7;
int4 num = byteSize - ((leastSigBit + numBits + 7) / 8);
if (num > 0) {
if (isBigEndian)
byteOffset += num;
byteSize -= num;
}
}
void BitRange::expandToMost(void)
{
numBits = 8*byteSize - leastSigBit; // Increase number of bits to maximum that still fits
}
#ifdef UINTB4
uintb uintbmasks[9] = { 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff };
#else
@@ -666,6 +996,8 @@ uintb uintb_negate(uintb in,int4 size)
uintb sign_extend(uintb in,int4 sizein,int4 sizeout)
{
sizein = (sizein < sizeof(uintb)) ? sizein : sizeof(uintb);
sizeout = (sizeout < sizeof(uintb)) ? sizeout : sizeof(uintb);
intb sval = in;
sval <<= (sizeof(intb) - sizein) * 8;
uintb res = (uintb)(sval >> (sizeout - sizein) * 8);
@@ -673,6 +1005,22 @@ uintb sign_extend(uintb in,int4 sizein,int4 sizeout)
return res;
}
/// \param val is the value to extend
/// \param numbits is the number of bits in the value
/// \param size is the integer size in bytes
/// \return the extended value
uintb extend_signbit(uintb val,int4 numbits,int4 size)
{
if (numbits < size * 8) {
int4 sa = 8*sizeof(intb) - numbits;
intb sval = val;
val = (sval << sa) >> sa;
val &= calc_mask(size);
}
return val;
}
/// Swap the least significant \b size bytes in \b val
/// \param val is a reference to the value to swap
/// \param size is the number of bytes to swap
@@ -74,7 +74,8 @@ public:
bool isInvalid(void) const; ///< Is the address invalid?
int4 getAddrSize(void) const; ///< Get the number of bytes in the address
bool isBigEndian(void) const; ///< Is data at this address big endian encoded
void printRaw(ostream &s) const; ///< Write a raw version of the address to a stream
void printRaw(ostream &s) const; ///< Write a raw version of the address to a stream for debugging/logging
int4 printRaw(ostream &s,int4 size) const; ///< Write a (small) region to a stream for debugging/logging
int4 read(const string &s); ///< Read in the address from a string
AddrSpace *getSpace(void) const; ///< Get the address space
uintb getOffset(void) const; ///< Get the address offset
@@ -87,12 +88,14 @@ public:
Address operator+(int8 off) const; ///< Increment address by a number of bytes
Address operator-(int8 off) const; ///< Decrement address by a number of bytes
friend ostream &operator<<(ostream &s,const Address &addr); ///< Write out an address to stream
bool isValidRange(uint8 size) const; ///< Is the range properly contained in its address space
bool containedBy(int4 sz,const Address &op2,int4 sz2) const; ///< Determine if \e op2 range contains \b this range
int4 justifiedContain(int4 sz,const Address &op2,int4 sz2,bool forceleft) const; ///< Determine if \e op2 is the least significant part of \e this.
int4 overlap(int4 skip,const Address &op,int4 size) const; ///< Determine how \b this address falls in a given address range
int4 overlapJoin(int4 skip,const Address &op,int4 size) const; ///< Determine how \b this falls in a possible \e join space address range
bool isContiguous(int4 sz,const Address &loaddr,int4 losz) const; ///< Does \e this form a contiguous range with \e loaddr
bool isConstant(void) const; ///< Is this a \e constant \e value
bool highPtrPossible(int4 size) const; ///< Are pointers possible to \b this address
void renormalize(int4 size); ///< Make sure there is a backing JoinRecord if \b this is in the \e join space
bool isJoin(void) const; ///< Is this a \e join \e value
void encode(Encoder &encoder) const; ///< Encode \b this to a stream
@@ -243,16 +246,51 @@ public:
const Range *getLastRange(void) const; ///< Get the last Range
const Range *getLastSignedRange(AddrSpace *spaceid) const; ///< Get the last Range viewing offsets as signed
const Range *getRange(AddrSpace *spaceid,uintb offset) const; ///< Get Range containing the given byte
const Range *getNearestRange(AddrSpace *spaceid,uintb offset) const; ///< Get the nearest Range to the given byte
void insertRange(AddrSpace *spc,uintb first,uintb last); ///< Insert a range of addresses
void insertRange(const Range &rng) { insertRange(rng.getSpace(),rng.getFirst(),rng.getLast()); } ///< Insert a range
void removeRange(AddrSpace *spc,uintb first,uintb last); ///< Remove a range of addresses
void removeRange(const Range &rng) { removeRange(rng.getSpace(),rng.getFirst(),rng.getLast()); } ///< Remove a range
void merge(const RangeList &op2); ///< Merge another RangeList into \b this
bool inRange(const Address &addr,int4 size) const; ///< Check containment an address range
bool inRange(const Address &addr,uintb size) const; ///< Check containment an address range
bool inRange(const Range &rng) const; ///< Check containment of given range
uintb longestFit(const Address &addr,uintb maxsize) const; ///< Find size of biggest Range containing given address
void printBounds(ostream &s) const; ///< Print a description of \b this RangeList to stream
void encode(Encoder &encoder) const; ///< Encode \b this RangeList to a stream
void decode(Decoder &decoder); ///< Decode \b this RangeList from a \<rangelist> element
};
/// \brief An endian aware range of bits contained in a contiguous set of bytes
class BitRange {
public:
int4 byteOffset; ///< Byte offset of the region containing the range
int4 byteSize; ///< Size of the region in bytes
int4 leastSigBit; ///< Least significant bit of the bit-range within its region
int4 numBits; ///< Number of bits in the range
bool isBigEndian; ///< Is the underlying encoding big endian
BitRange(void) { byteOffset = -1; byteSize = -1; leastSigBit = -1; numBits = -1; isBigEndian = false; } ///< Construct \e undefined range
BitRange(int4 bOff,int4 bSize,bool bigEndian) {
byteOffset = bOff; byteSize = bSize; leastSigBit = 0; numBits = bSize * 8; isBigEndian = bigEndian; } ///< Construct byte range
BitRange(const BitRange &op2,int4 off,int4 sz); ///< Constructor, copy range into new container
BitRange(int4 bOff,int4 bSize,int4 least,int4 num,bool bigEndian) { byteOffset = bOff; byteSize = bSize; leastSigBit = least;
numBits = num; isBigEndian = bigEndian; } ///< Constructor
bool empty(void) const { return (numBits <= 0); } ///< Return \b true if \b this is an empty bit range (zero bits)
int4 compare(const BitRange &op2) const; ///< Compare \b this with another as containers
int4 translateLSB(const BitRange &op2) const; ///< Translate the \b leastSigBit of the given range into \b this reference frame
int4 overlapTest(const BitRange &op2) const; ///< Characterize the type of overlap between \b this and another range
void intersection(const BitRange &op2); ///< Replace \b this with the intersection of \b this with another BitRange
void intersectMask(uintb mask); ///< Restrict \b this with a mask that lines up with the container
void shift(int4 leftShiftAmount); ///< Replace \b this with the shifted range
void truncateMostSigBytes(int4 num); ///< Truncate the most significant bytes in the byte container
void truncateLeastSigBytes(int4 num); ///< Truncate the least significant bytes in the byte container
void extendBytes(int4 num); ///< Add most significant bytes to the container
uintb getMask(void) const; ///< Get mask representing \b this range
bool isByteRange(void) const; ///< Return \b true if \b this bit range is also a byte range
bool isMostSignificant(void) const; ///< Return \b true if the bit range occupies the most significant bits of the container
void minimizeContainer(void); ///< Shrink the container to fit the bit range
void expandToMost(void); ///< Expand the bitrange until it includes the most significant bits of the container
};
/// Precalculated masks indexed by size
extern uintb uintbmasks[];
@@ -434,6 +472,14 @@ inline Address Address::operator-(int8 off) const {
return Address(base,base->wrapOffset(offset-off));
}
/// If the range starting at \b this address and extending for \b size bytes, encompasses bytes beyond
/// the edge of the address space (or wraps), then return \b false.
/// \param size is the number of bytes in the range (must be non-zero)
/// \return \b true if the range is properly contained in the address space
inline bool Address::isValidRange(uint8 size) const {
return (size-1) <= (base->getHighest() - offset);
}
/// This method is equivalent to Address::overlap, but a range in the \e join space can be
/// considered overlapped with its constituent pieces.
/// If \e this + \e skip falls in the range, \e op to \e op + \e size, then a non-negative integer is
@@ -498,6 +544,18 @@ inline bool Range::contains(const Address &addr) const {
/// \return a value appropriate for masking off the first \e size bytes
inline uintb calc_mask(int4 size) { return uintbmasks[((uint4)size) < 8 ? size : 8]; }
/// \param size of the integer in bytes
/// \return largest unsigned integer value for given size
inline uintb calc_uint_max(int4 size) { return calc_mask(size); }
/// \param size of the integer in bytes
/// \return largest signed integer value for given size
inline uintb calc_int_max(int4 size) { return calc_mask(size) >> 1; }
/// \param size of the integer in bytes
/// \return smallest signed integer value for given size
inline uintb calc_int_min(int4 size) { return (uintb)1 << (size * 8 - 1); }
/// Perform a CPUI_INT_RIGHT on the given val
/// \param val is the value to shift
/// \param sa is the number of bits to shift
@@ -558,13 +616,14 @@ inline intb zero_extend(intb val,int4 bit)
{
int4 sa = sizeof(intb)*8 - (bit+1);
return (intb)((uintb)(val << sa) >> sa);
return (intb)(((uintb)val << sa) >> sa);
}
extern bool signbit_negative(uintb val,int4 size); ///< Return true if the sign-bit is set
extern uintb calc_mask(int4 size); ///< Calculate a mask for a given byte size
extern uintb uintb_negate(uintb in,int4 size); ///< Negate the \e sized value
extern uintb sign_extend(uintb in,int4 sizein,int4 sizeout); ///< Sign-extend a value between two byte sizes
extern uintb extend_signbit(uintb val,int4 numbits,int4 size); ///< Extend a signed value of given number of bits to a full integer
extern void byte_swap(intb &val,int4 size); ///< Swap bytes in the given value
@@ -33,7 +33,7 @@ using std::sqrt;
vector<ArchitectureCapability *> ArchitectureCapability::thelist;
const uint4 ArchitectureCapability::majorversion = 6;
const uint4 ArchitectureCapability::minorversion = 1;
const uint4 ArchitectureCapability::minorversion = 2;
AttributeId ATTRIB_ADDRESS = AttributeId("address",148);
AttributeId ATTRIB_ADJUSTVMA = AttributeId("adjustvma",103);
@@ -342,8 +342,7 @@ void Architecture::clearAnalysis(Funcdata *fd)
/// Symbols do not necessarily need to be available for the decompiler.
/// This routine loads all the \e load \e image knows about into the symbol table
/// \param delim is the delimiter separating namespaces from symbol base names
void Architecture::readLoaderSymbols(const string &delim)
void Architecture::readLoaderSymbols(void)
{
if (loadersymbols_parsed) return; // already read
@@ -352,7 +351,7 @@ void Architecture::readLoaderSymbols(const string &delim)
LoadImageFunc record;
while(loader->getNextSymbol(record)) {
string basename;
Scope *scope = symboltab->findCreateScopeFromSymbolName(record.name, delim, basename, (Scope *)0);
Scope *scope = symboltab->findCreateScopeFromSymbolName(record.name, basename, (Scope *)0);
scope->addFunction(record.address,basename);
}
loader->closeSymbols();
@@ -393,7 +392,7 @@ void Architecture::setPrototype(const PrototypePieces &pieces)
{
string basename;
Scope *scope = symboltab->resolveScopeFromSymbolName(pieces.name, "::", basename, (Scope *)0);
Scope *scope = symboltab->resolveScopeFromSymbolName(pieces.name, basename, (Scope *)0);
if (scope == (Scope *)0)
throw ParseError("Unknown namespace: " + pieces.name);
Funcdata *fd = scope->queryFunction( basename );
@@ -456,14 +455,27 @@ void Architecture::decodeFlowOverride(Decoder &decoder)
uint4 elemId = decoder.openElement(ELEM_FLOWOVERRIDELIST);
for(;;) {
uint4 subId = decoder.openElement();
if (subId != ELEM_FLOW) break;
string flowType = decoder.readString(ATTRIB_TYPE);
Address funcaddr = Address::decode(decoder);
Address overaddr = Address::decode(decoder);
Funcdata *fd = symboltab->getGlobalScope()->queryFunction(funcaddr);
if (fd != (Funcdata *)0)
fd->getOverride().insertFlowOverride(overaddr,Override::stringToType(flowType));
decoder.closeElement(subId);
if (subId == ELEM_FLOW) {
string flowType = decoder.readString(ATTRIB_TYPE);
Address funcaddr = Address::decode(decoder);
Address overaddr = Address::decode(decoder);
Funcdata *fd = symboltab->getGlobalScope()->queryFunction(funcaddr);
if (fd != (Funcdata *)0)
fd->getOverride().insertFlowOverride(overaddr,flowType);
decoder.closeElement(subId);
}
else if (subId == ELEM_CALLDEST) {
string flowType = decoder.readString(ATTRIB_TYPE);
Address funcaddr = Address::decode(decoder);
Address overaddr = Address::decode(decoder);
Address destaddr = Address::decode(decoder);
Funcdata *fd = symboltab->getGlobalScope()->queryFunction(funcaddr);
if (fd != (Funcdata *)0)
fd->getOverride().insertDestinationOverride(overaddr, destaddr, flowType);
decoder.closeElement(subId);
}
else
break;
}
decoder.closeElement(elemId);
}
@@ -569,16 +581,6 @@ void Architecture::addSpacebase(AddrSpace *basespace,const string &nm,const Varn
addSpacebasePointer(spc,ptrdata,truncSize,stackGrowth);
}
/// This routine is used by the initialization process to add
/// address ranges to which there is never an (indirect) pointer
/// Should only be called during initialization
/// \param rng is the new range with no aliases to be added
void Architecture::addNoHighPtr(const Range &rng)
{
nohighptr.insertRange(rng.getSpace(),rng.getFirst(),rng.getLast());
}
/// This builds the \e universal Action for function transformation
/// and instantiates the "decompile" root Action
/// \param store may hold configuration information
@@ -624,8 +626,9 @@ void Architecture::postSpecFile(void)
void Architecture::restoreFromSpec(DocumentStorage &store)
{
Translate *newtrans = buildTranslator(store); // Once language is described we can build translator
newtrans->initialize(store);
unique_ptr<Translate> utrans(buildTranslator(store)); // Once language is described we can build translator
utrans->initialize(store);
Translate *newtrans = utrans.release();
translate = newtrans;
modifySpaces(newtrans); // Give architecture chance to modify spaces, before copying
copySpaces(newtrans);
@@ -675,7 +678,7 @@ void Architecture::cacheAddrSpaceProperties(void)
AddrSpace *spc = copyList[i];
if (spc == lastSpace) continue;
lastSpace = spc;
if (spc->getDelay() == 0) continue; // Don't put in a register space
if (spc->noHighPtrPossible()) continue; // Don't put in a register space
if (spc->getType() == IPTR_SPACEBASE) continue;
if (spc->isOtherSpace()) continue;
if (spc->isOverlay()) continue;
@@ -741,23 +744,21 @@ void Architecture::decodeDynamicRule(Decoder &decoder)
ProtoModel *Architecture::decodeProto(Decoder &decoder)
{
ProtoModel *res;
unique_ptr<ProtoModel> model;
uint4 elemId = decoder.peekElement();
if (elemId == ELEM_PROTOTYPE)
res = new ProtoModel(this);
model.reset(new ProtoModel(this));
else if (elemId == ELEM_RESOLVEPROTOTYPE)
res = new ProtoModelMerged(this);
model.reset(new ProtoModelMerged(this));
else
throw LowlevelError("Expecting <prototype> or <resolveprototype> tag");
res->decode(decoder);
model->decode(decoder);
ProtoModel *other = getModel(res->getName());
if (other != (ProtoModel *)0) {
string errMsg = "Duplicate ProtoModel name: " + res->getName();
delete res;
throw LowlevelError(errMsg);
}
ProtoModel *other = getModel(model->getName());
if (other != (ProtoModel *)0)
throw LowlevelError("Duplicate ProtoModel name: " + model->getName());
ProtoModel *res = model.release();
protoModels[res->getName()] = res;
return res;
}
@@ -1422,6 +1423,7 @@ void Architecture::resetDefaultsInternal(void)
max_basetype_size = 10; // Needs to be 8 or bigger
flowoptions = FlowInfo::error_toomanyinstructions;
max_instructions = 100000;
max_baddata = 4;
infer_pointers = true;
analyze_for_loops = true;
readonlypropagate = false;
@@ -1452,7 +1454,7 @@ Address SegmentedResolver::resolve(uintb val,int4 sz,const Address &point,uintb
// In this case the address offset is not fully specified
// we check if the rest is stored in a context variable
// (as with near pointers)
if (segop->getResolve().space != (AddrSpace *)0) {
if (segop->getResolve().space != (AddrSpace *)0 && !point.isInvalid()) {
uintb base = glb->context->getTrackedValue(segop->getResolve(),point);
fullEncoding = (base << 8 * innersz) + (val & calc_mask(innersz));
vector<uintb> seginput;
@@ -183,6 +183,7 @@ public:
int4 funcptr_align; ///< How many bits of alignment a function ptr has
uint4 flowoptions; ///< options passed to flow following engine
uint4 max_instructions; ///< Maximum instructions that can be processed in one function
uint4 max_baddata; ///< Maximum number of bad instructions that one function can encounter
int4 alias_block_level; ///< Aliases blocked by 0=none, 1=struct, 2=array, 3=all
uint4 split_datatype_config; ///< Toggle for data-types splitting: Bit 0=structs, 1=arrays, 2=pointers
vector<Rule *> extra_pool_rules; ///< Extra rules that go in the main pool (cpu specific, experimental)
@@ -198,7 +199,6 @@ public:
const Translate *translate; ///< Translation method for this binary
LoadImage *loader; ///< Method for loading portions of binary
PcodeInjectLibrary *pcodeinjectlib; ///< Pcode injection manager
RangeList nohighptr; ///< Ranges for which high-level pointers are not possible
CommentDatabase *commentdb; ///< Comments for this architecture
StringManager *stringManager; ///< Manager of decoded strings
ConstantPool *cpool; ///< Deferred constant values
@@ -224,13 +224,12 @@ public:
ProtoModel *getModel(const string &nm) const; ///< Get a specific PrototypeModel
bool hasModel(const string &nm) const; ///< Does this Architecture have a specific PrototypeModel
ProtoModel *createUnknownModel(const string &modelName); ///< Create a model for an unrecognized name
bool highPtrPossible(const Address &loc,int4 size) const; ///< Are pointers possible to the given location?
AddrSpace *getSpaceBySpacebase(const Address &loc,int4 size) const; ///< Get space associated with a \e spacebase register
const LanedRegister *getLanedRegister(const Address &loc,int4 size) const; ///< Get LanedRegister associated with storage
int4 getMinimumLanedRegisterSize(void) const; ///< Get the minimum size of a laned register in bytes
void setDefaultModel(ProtoModel *model); ///< Set the default PrototypeModel
void clearAnalysis(Funcdata *fd); ///< Clear analysis specific to a function
void readLoaderSymbols(const string &delim); ///< Read any symbols from loader into database
void readLoaderSymbols(void); ///< Read any symbols from loader into database
void collectBehaviors(vector<OpBehavior *> &behave) const; ///< Provide a list of OpBehavior objects
SegmentOp *getSegmentOp(AddrSpace *spc) const; ///< Retrieve the \e segment op for the given space if any
void setPrototype(const PrototypePieces &pieces); ///< Set the prototype for a particular function
@@ -243,14 +242,15 @@ public:
/// \return the description
virtual string getDescription(void) const { return archid; }
/// \brief Print an error message to console
/// \brief Print a warning message to console
///
/// Write the given message to whatever the registered error stream is
/// Write the given message to a registered stream.
/// \param message is the error message
virtual void printMessage(const string &message) const=0;
virtual void printWarning(const string &message) const=0;
virtual void encode(Encoder &encoder) const; ///< Encode \b this architecture to a stream
virtual void restoreXml(DocumentStorage &store); ///< Restore the Architecture state from XML documents
virtual void nameFunction(const Address &addr,string &name) const; ///< Pick a default name for a function
string getScopeDelimiter(void) const { return print->getScopeDelimiter(); } ///< Get the character string separating scope names
#ifdef OPACTION_DEBUG
void setDebugStream(ostream *s) { debugstream = s; } ///< Establish the debug console stream
void printDebug(const string &message) const { *debugstream << message << endl; } ///< Print message to the debug stream
@@ -258,7 +258,6 @@ public:
protected:
void addSpacebase(AddrSpace *basespace,const string &nm,const VarnodeData &ptrdata,
int4 truncSize,bool isreversejustified,bool stackGrowth,bool isFormal);
void addNoHighPtr(const Range &rng); ///< Add a new region where pointers do not exist
// Factory routines for building this architecture
virtual Scope *buildDatabase(DocumentStorage &store); ///< Build the database and global scope for this executable
@@ -397,18 +396,5 @@ public:
virtual Address resolve(uintb val,int4 sz,const Address &point,uintb &fullEncoding);
};
/// The Translate object keeps track of address ranges for which
/// it is effectively impossible to have a pointer into. This is
/// used for pointer aliasing calculations. This routine returns
/// \b true if it is \e possible to have pointers into the indicated
/// range.
/// \param loc is the starting address of the range
/// \param size is the size of the range in bytes
/// \return \b true if pointers are possible
inline bool Architecture::highPtrPossible(const Address &loc,int4 size) const {
if (loc.getSpace()->getType() == IPTR_INTERNAL) return false;
return !nohighptr.inRange(loc,size);
}
} // End namespace ghidra
#endif
@@ -5,9 +5,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -67,19 +67,19 @@ bool BfdArchitectureCapability::isXmlMatch(Document *doc) const
void BfdArchitecture::buildLoader(DocumentStorage &store)
{
LoadImageBfd *ldr;
unique_ptr<LoadImageBfd> ldr;
collectSpecFiles(*errorstream);
if (getTarget().find("binary")==0)
ldr = new LoadImageBfd(getFilename(),"binary");
ldr.reset(new LoadImageBfd(getFilename(),"binary"));
else if (getTarget().find("default")==0)
ldr = new LoadImageBfd(getFilename(),"default");
ldr.reset(new LoadImageBfd(getFilename(),"default"));
else
ldr = new LoadImageBfd(getFilename(),getTarget());
ldr.reset(new LoadImageBfd(getFilename(),getTarget()));
ldr->open();
if (adjustvma!=0)
ldr->adjustVma(adjustvma);
loader = ldr;
loader = ldr.release();
}
void BfdArchitecture::resolveArchitecture(void)
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,268 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// \file bitfield.hh
/// \brief Classes for transforming bitfield expressions
#ifndef __BITFIELD_HH__
#define __BITFIELD_HH__
#include "ruleaction.hh"
namespace ghidra {
/// \brief Description of the bitfields covered by a Varnode
class BitFieldNodeState {
public:
BitRange bitsUsed; ///< Bits being used from \b this Varnode
BitRange bitsField; ///< Bits from bit-field being followed
Varnode *node; ///< Varnode holding bitfields
const TypeBitField *field; ///< Bit-field being followed
int4 origLeastSigBit; ///< Original position of least significant bit
bool isSignExtended; ///< Bitfield has been sign-extended into node
BitFieldNodeState(const BitRange &used,Varnode *vn,const TypeBitField *fld); ///< Constructor to follow a field
BitFieldNodeState(const BitRange &used,Varnode *vn,int4 leastSig,int4 numBits); ///< Constructor for a hole
BitFieldNodeState(const BitFieldNodeState &copy,const BitRange &newField,Varnode *vn,bool sgnExt); ///< Copy constructor with new \b bitsField
/// \brief Can the current Varnode be treated as the isolated bitfield
bool isFieldAligned(void) const { return (bitsField.leastSigBit == 0 && bitsField.numBits == bitsUsed.numBits); }
/// \brief Return \b true if the signedness of the field matches the extension used to extract it
bool doesSignExtensionMatch(void) const { return isSignExtended == (field->type->getMetatype() == TYPE_INT); }
};
/// \brief Class for transforming bitfield expressions
///
/// For both insertion and extraction, establish the bitfields that need to be traced.
class BitFieldTransform {
protected:
Funcdata *func; ///< The containing function
TypeStruct *parentStruct; ///< Structure owning the bitfields
list<BitFieldNodeState> workList; ///< Fields that are being followed
int4 initialOffset; ///< Byte offset into parent structure
int4 containerSize; ///< Size of Varnode containing bitfields
bool isBigEndian; ///< Endianness associated with bitfields
void establishFields(Varnode *vn,bool followHoles); ///< Build worklist for each bitfield overlapped by given Varnode
Datatype *buildPartialType(void); ///< Build the (partial) data-type associated with the root bitfield container
static bool findOverwrite(Varnode *vn,BlockBasic *bl,const BitRange &range);
public:
BitFieldTransform(Funcdata *f,Datatype *dt,int4 off); ///< Constructor setting up basic info about bitfield data-type
};
/// \brief Class that converts bitfield insertion expressions into explicit INSERT operations
///
/// The doTrace() method traces backward from a root Varnode that contains bitfields to find points that
/// can be treated as a value written to an individual bitfield, creating an InsertRecord at each point.
/// If all bits of the Varnode are accounted for, the apply() method transforms expressions based on any InsertRecord.
class BitFieldInsertTransform : public BitFieldTransform {
/// \brief Info about a Varnode that can be treated as a write to a single bitfield
class InsertRecord {
friend class BitFieldInsertTransform;
Varnode *vn; ///< Value being inserted (or null)
uintb constVal; ///< Constant value being inserted
Datatype *dt; ///< Data-type associated with value
int4 pos; ///< Position being inserted to
int4 numBits; ///< Number of bits being inserted
int4 shiftAmount; ///< Amount that value needs to be right shifted
public:
InsertRecord(Varnode *v,Datatype *d,int4 p,int4 sz,int4 sa) { vn = v; dt = d; constVal = 0; pos = p; numBits = sz; shiftAmount = sa; } ///< Constructor for Varnode
InsertRecord(uintb val,Datatype *d,int4 p,int4 sz) { vn = (Varnode *)0; dt = d; constVal = val; pos = p; numBits = sz; shiftAmount = 0; } ///< Constructor for constant
};
PcodeOp *finalWriteOp; ///< STORE to bitfields or op outputing to bitfields
Varnode *originalValue; ///< Value prior to insertion
Varnode *mappedVn; ///< Bitfield container written to
list<InsertRecord> insertList; ///< Insertion actions
bool verifyLoadStoreOriginalValue(uintb mask) const; ///< Test for other STORE ops interfering with the \e original \e value
bool verifyMappedOriginalValue(uintb mask) const; ///< Test for other ops interfering with the mapped \e original \e value
uintb constructOriginalValueMask(void) const; ///< Calculate mask where 1 bits represent all the bits being preserved
bool verifyOriginalValueBits(void) const; ///< Do final check that unINSERTed bits come from the \e original \e value
bool isOverwrittenPartial(const BitFieldNodeState &state); ///< Is given state a partial field that is overwritten later
bool checkPulledOriginalValue(BitFieldNodeState &state); ///< Is this an original value defined by ZPULL or SPULL
bool checkOriginalBase(Varnode *vn); ///< Check if the given Varnode is the original LOAD or mapped value
bool isOriginalValue(BitFieldNodeState &state); ///< Is the given Varnode a (partial) copy of the original value being INSERTed into
bool addConstantWrite(BitFieldNodeState &state); ///< Create InsertRecord writing a constant into the field
bool addZeroOut(BitFieldNodeState &state); ///< Create InsertRecord writing 0 into the field
void addFieldWrite(BitFieldNodeState &state); ///< Create InsertRecord writing Varnode into the field
bool handleAndBack(BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield back through INT_AND with a mask
bool handleOrBack(BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield back through one branch of INT_OR
bool handleAddBack(BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield back through one branch of INT_AND
bool handleLeftBack(BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield back through INT_LEFT by a constant
bool handleRightBack(BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield back through INT_SRIGHT by a constant
bool handleZextBack(BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield back through INT_ZEXT
bool handleMultBack(BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield back through INT_MULT
bool handleSubpieceBack(BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield back through SUBPIECE
bool testCallOriginal(BitFieldNodeState &state,PcodeOp *op); ///< Test if a call is producing the \e original \e value
bool processBackward(BitFieldNodeState &state); ///< Follow field back, creating an InsertRecord if possible
PcodeOp *setInsertInputs(PcodeOp *op,const InsertRecord &rec); ///< Fill-in INSERT inputs based on given InsertRecord
void addFieldShift(PcodeOp *insertOp,const InsertRecord &rec); ///< Create any shift p-code op specified by given InsertRecord
bool foldLoad(PcodeOp *loadOp) const; ///< Try to mark LOAD as part of INSERT
void foldPtrsub(PcodeOp *loadOp) const; ///< Try to mark PTRSUB as part of INSERT
void checkRedundancy(const InsertRecord &rec); ///< Check if value is getting INSERTed twice and remove second
public:
BitFieldInsertTransform(Funcdata *f,PcodeOp *op,Datatype *dt,int4 off); ///< Construct from a terminating op
bool doTrace(void); ///< Trace bitfields backward from the terminating op
void apply(void); ///< Transform recovered expressions into INSERT operations
static const vector<uint4> allowedFinalWrites; ///< List of opcodes allowed for finalWriteOp (must be sorted)
};
/// \brief Class that converts bitfield pull expressions into explicit ZPULL and SPULL operations
///
/// The doTrace() method traces forward from a root Varnode that contains bitfields to find points where
/// an individual bitfield has been fully isolated, creating an PullRecord at each point.
/// If all bits of the Varnode are accounted for, the apply() method transforms expressions based on any PullRecord.
class BitFieldPullTransform : public BitFieldTransform {
/// \brief During final transformation, this is the state maintained between processing individual PullRecords
class TransformState {
friend class BitFieldPullTransform;
vector<PcodeOp *> deadScratch; ///< Scratch space for opDestroyRecursive method
Datatype *partialType; ///< Partial data-type of the root container
int4 count; ///< Number of PullRecords processed
};
/// \brief Info about a single read by a PcodeOp that can be treated as a \e pull of 1 or more bitfields
class PullRecord {
enum {
normal = 0, ///< A single field pull
equal = 1, ///< Pull for INT_EQUAL or INT_NOTEQUAL
aborted = 2 ///< Code to indicate that the pull for the entire PcodeOp should be aborted
};
friend class BitFieldPullTransform;
Varnode *readVn; ///< Varnode holding pulled value
PcodeOp *readOp; ///< Op reading the pulled value, or null if readVn itself is redefined
Datatype *dt; ///< Data-type associated with the pulled value
int4 type; ///< Type of pull
int4 pos; ///< Bit position of field being pulled
int4 numBits; ///< Number of bits in field being pulled
int4 leftShift; ///< Amount final field is left shifted
uintb mask; ///< Mask representing the bitfield within the Varnode
public:
PullRecord(const BitFieldNodeState &state,PcodeOp *op); ///< Construct pull record for a specific PcodeOp read
PullRecord(const BitFieldNodeState &state,PcodeOp *op,uintb val); ///< Construct record for a pull into an INT_EQUAL or INT_NOTEQUAL
PullRecord(PcodeOp *op); ///< Construct record representing an abort
bool operator<(const PullRecord &op2) const; ///< Compare records
};
Varnode *root; ///< Value being pulled from
PcodeOp *loadOp; ///< LOAD op producing root (if non-null)
list<PullRecord> pullList; ///< Pull actions
static bool testConsumed(Varnode *vn,const BitRange &bitField); ///< Test if all consumed bits are in the given bitfield
void handleLeftForward(const BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield forward through INT_LEFT
void handleRightForward(const BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield forward through INT_RIGHT
void handleAndForward(const BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield forward through INT_AND
void handleExtForward(const BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield forward through INT_ZEXT
void handleMultForward(const BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield forward through INT_MULT
void handleSubpieceForward(const BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield forward through SUBPIECE
void handleInsertForward(const BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield forward into INSERT
void handleLessForward(const BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield forward through INT_LESS, INT_SLESS
void handleLeastSigOp(const BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield into INT_ADD, INT_MULT, INT_OR, INT_XOR
void handleEqualForward(const BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield into INT_EQUAL or INT_NOTEQUAL
void processForward(BitFieldNodeState &state); ///< Follow bitfield forward one level through all its descendants
list<PullRecord>::iterator testCompareGroup(list<PullRecord>::iterator iter);
void applyRecord(PullRecord &rec,TransformState &state); ///< Perform transform corresponding to the given PullRecord
void applyCompareRecord(const PullRecord &rec); ///< Perform transform on an INT_EQUAL or INT_NOTEQUAL
bool foldLoad(PcodeOp *loadOp) const; ///< Try to mark LOAD as part of ZPULL or SPULL
void foldPtrsub(PcodeOp *loadOp) const; ///< Try to mark PTRSUB as part of ZPULL or SPULL
public:
BitFieldPullTransform(Funcdata *f,Varnode *r,Datatype *dt,int4 off); ///< Construct from Varnode containing bitfields
bool doTrace(void); ///< Trace bitfields from \b root to points where they are pulled
void apply(void); ///< Transform recovered expressions into ZPULL or SPULL operations
};
/// \brief Collapse bitfield insertion ending in a CPUI_STORE
class RuleBitFieldStore : public Rule {
public:
RuleBitFieldStore(const string &g) : Rule( g, 0, "bitfield_store") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleBitFieldStore(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Collapse bitfield insertion ending in a write to a mapped Varnode
class RuleBitFieldOut : public Rule {
public:
RuleBitFieldOut(const string &g) : Rule( g, 0, "bitfield_out") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleBitFieldOut(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Collapse bitfield pulls starting with a CPUI_LOAD
class RuleBitFieldLoad : public Rule {
public:
RuleBitFieldLoad(const string &g) : Rule( g, 0, "bitfield_load") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleBitFieldLoad(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Collapse bitfield pulls starting with mapped Varnodes
class RuleBitFieldIn : public Rule {
public:
RuleBitFieldIn(const string &g) : Rule( g, 0, "bitfield_in") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleBitFieldIn(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Simplify expressions explicitly using ZPULL and SPULL p-code ops
class RulePullAbsorb : public Rule {
int4 absorbRight(Funcdata &data,PcodeOp *rightOp,PcodeOp *pullOp);
int4 absorbRightAndCompZero(Funcdata &data,PcodeOp *rightOp,PcodeOp *andOp,PcodeOp *pullOp);
int4 absorbLeft(Funcdata &data,PcodeOp *leftOp,PcodeOp *pullOp);
int4 absorbLeftRight(Funcdata &data,PcodeOp *rightOp,PcodeOp *leftOp,PcodeOp *pullOp);
int4 absorbLeftAnd(Funcdata &data,PcodeOp *andOp,PcodeOp *leftOp,PcodeOp *pullOp);
int4 absorbAnd(Funcdata &data,PcodeOp *andOp,PcodeOp *pullOp);
int4 absorbCompare(Funcdata &data,PcodeOp *compOp,PcodeOp *leftOp,PcodeOp *pullOp);
int4 absorbExt(Funcdata &data,PcodeOp *extOp,PcodeOp *pullOp);
int4 absorbSubpiece(Funcdata &data,PcodeOp *subOp,PcodeOp *pullOp);
int4 absorbCompZero(Funcdata &data,PcodeOp *compOp,PcodeOp *pullOp);
public:
RulePullAbsorb(const string &g) : Rule( g, 0, "pull_absorb") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RulePullAbsorb(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Simplify expressions explicitly using the INSERT p-code op
class RuleInsertAbsorb : public Rule {
static Varnode *leftShiftVarnode(Varnode *vn,int4 sa); ///< Test if a Varnode is left-shifted by the given amount
int4 absorbAnd(Funcdata &data,PcodeOp *andOp,PcodeOp *insertOp);
int4 absorbRightLeft(Funcdata &data,PcodeOp *nextOp,PcodeOp *rightOp,PcodeOp *insertOp);
int4 absorbShiftAdd(Funcdata &data,PcodeOp *rightOp,PcodeOp *addOp,PcodeOp *insertOp);
int4 absorbNestedAnd(Funcdata &data,PcodeOp *baseOp,PcodeOp *insertOp);
public:
RuleInsertAbsorb(const string &g) : Rule( g, 0, "insert_absorb") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleInsertAbsorb(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
} // End namespace ghidra
#endif
@@ -64,8 +64,12 @@ FlowBlock::FlowBlock(void)
flags = 0;
index = 0;
visitcount = 0;
numdesc = 0;
leafCount = 1;
structureDepth = 0;
parent = (FlowBlock *)0;
immed_dom = (FlowBlock *)0;
copymap = (FlowBlock *)0;
}
/// \param b is the FlowBlock coming in
@@ -638,6 +642,17 @@ JumpTable *FlowBlock::getJumptable(void) const
return jt;
}
/// Print a single unique identifier for \b this block
/// \param s is the output stream
void FlowBlock::printShortHeader(ostream &s) const
{
s << "Block_" << dec << index;
if (!getStart().isInvalid()) {
s << ':' << getStart();
}
}
/// Given a string describing a FlowBlock type, return the block_type.
/// This is currently only used by the decode() process.
/// TODO: Fill in the remaining names and types
@@ -679,6 +694,11 @@ string FlowBlock::typeToName(FlowBlock::block_type bt)
return "condition";
case t_if:
return "properif";
case t_ifelse:
case t_ifnoexit:
return "ifelse";
case t_ifgoto:
return "ifgoto";
case t_whiledo:
return "whiledo";
case t_dowhile:
@@ -861,6 +881,10 @@ void BlockGraph::addBlock(FlowBlock *bl)
}
bl->parent = this;
list.push_back(bl);
leafCount += bl->getBasicCount();
int4 depth = bl->getStructureDepth() + 1;
if (depth > structureDepth)
structureDepth = depth;
}
/// Force \b this FlowBlock to have the indicated number of outputs.
@@ -1031,7 +1055,7 @@ void BlockGraph::findSpanningTree(vector<FlowBlock *> &preorder,vector<FlowBlock
bool extraroots = false;
int4 rpostcount = list.size();
int4 rootindex = 0;
clearEdgeFlags(~((uint4)0)); // Clear all edge flags
clearEdgeFlags(f_irreducible|f_tree_edge|f_forward_edge|f_cross_edge|f_back_edge|f_loop_edge|f_loop_exit_edge); // Clear spanning tree
while(preorder.size() < list.size()) {
FlowBlock *startbl = (FlowBlock *)0;
while(rootindex<rootlist.size()) { // Go thru blocks with no in edges
@@ -1233,6 +1257,7 @@ void BlockGraph::clear(void)
for(iter=list.begin();iter!=list.end();++iter)
delete *iter;
list.clear();
clearAllFlags();
}
void BlockGraph::markUnstructured(void)
@@ -1293,8 +1318,24 @@ void BlockGraph::printRaw(ostream &s) const
printHeader(s);
s << endl;
for(iter=list.begin();iter!=list.end();++iter)
(*iter)->printRaw(s);
if (list.empty()) return;
iter = list.begin();
FlowBlock *lastBl = *iter;
++iter;
lastBl->printRaw(s);
for(;iter!=list.end();++iter) {
FlowBlock *curBl = *iter;
lastBl->printRawImpliedGoto(s, curBl);
curBl->printRaw(s);
lastBl = curBl;
}
}
void BlockGraph::printRawImpliedGoto(ostream &s,const FlowBlock *nextBlock) const
{
if (list.empty()) return;
list.back()->printRawImpliedGoto(s, nextBlock);
}
PcodeOp *BlockGraph::firstOp(void) const
@@ -1325,13 +1366,16 @@ FlowBlock *BlockGraph::nextFlowAfter(const FlowBlock *bl) const
return nextbl;
}
void BlockGraph::finalTransform(Funcdata &data)
void BlockGraph::finalTransform(Funcdata &data,bool allowOpMoves)
{
if (hasFinalTransform())
return; // Already performed
// Recurse into all the substructures
vector<FlowBlock *>::const_iterator iter;
for(iter=list.begin();iter!=list.end();++iter)
(*iter)->finalTransform(data);
(*iter)->finalTransform(data,allowOpMoves);
setFlag(f_final_transform); // Mark that transform has been performed
}
void BlockGraph::finalizePrinting(Funcdata &data) const
@@ -1352,18 +1396,7 @@ void BlockGraph::encodeBody(Encoder &encoder) const
encoder.openElement(ELEM_BHEAD);
encoder.writeSignedInteger(ATTRIB_INDEX, bl->getIndex());
FlowBlock::block_type bt = bl->getType();
string nm;
if (bt == FlowBlock::t_if) {
int4 sz = ((BlockGraph *)bl)->getSize();
if (sz == 1)
nm = "ifgoto";
else if (sz == 2)
nm = "properif";
else
nm = "ifelse";
}
else
nm = FlowBlock::typeToName(bt);
string nm = FlowBlock::typeToName(bt);
encoder.writeString(ATTRIB_TYPE, nm);
encoder.closeElement(ELEM_BHEAD);
}
@@ -1375,7 +1408,7 @@ void BlockGraph::decodeBody(Decoder &decoder)
{
BlockMap newresolver;
vector<FlowBlock *> tmplist;
vector<unique_ptr<FlowBlock> > tmplist;
for(;;) {
uint4 subId = decoder.peekElement();
@@ -1384,15 +1417,14 @@ void BlockGraph::decodeBody(Decoder &decoder)
int4 newindex = decoder.readSignedInteger(ATTRIB_INDEX);
FlowBlock *bl = newresolver.createBlock(decoder.readString(ATTRIB_TYPE));
bl->index = newindex; // Need to set index here for sort
tmplist.push_back(bl);
tmplist.push_back(unique_ptr<FlowBlock>(bl));
decoder.closeElement(subId);
}
newresolver.sortList();
for(int4 i=0;i<tmplist.size();++i) {
FlowBlock *bl = tmplist[i];
bl->decode(decoder,newresolver);
addBlock(bl);
tmplist[i]->decode(decoder,newresolver);
addBlock(tmplist[i].release());
}
}
@@ -1769,7 +1801,7 @@ BlockCondition *BlockGraph::newBlockCondition(FlowBlock *b1,FlowBlock *b2)
/// Add the new BlockIfGoto to \b this, collapsing the given condition FlowBlock into it.
/// \param cond is the given condition FlowBlock
/// \return the new BlockIfGoto
BlockIf *BlockGraph::newBlockIfGoto(FlowBlock *cond)
BlockIfGoto *BlockGraph::newBlockIfGoto(FlowBlock *cond)
{
if (!cond->isGotoOut(1)) // True branch must be a goto branch
@@ -1777,8 +1809,7 @@ BlockIf *BlockGraph::newBlockIfGoto(FlowBlock *cond)
const FlowBlock *out0 = cond->getOut(0);
vector<FlowBlock *> nodes;
BlockIf *ret = new BlockIf();
ret->setGotoTarget(cond->getOut(1)); // Store the target
BlockIfGoto *ret = new BlockIfGoto(cond->getOut(1)); // Goto block with specific target
nodes.push_back(cond);
identifyInternal(ret,nodes);
addBlock(ret);
@@ -1809,12 +1840,12 @@ BlockIf *BlockGraph::newBlockIf(FlowBlock *cond,FlowBlock *tc)
/// \param cond is the condition FlowBlock
/// \param tc is the true clause FlowBlock
/// \param fc is the false clause FlowBlock
/// \return the new BlockIf
BlockIf *BlockGraph::newBlockIfElse(FlowBlock *cond,FlowBlock *tc,FlowBlock *fc)
/// \return the new BlockIfElse
BlockIfElse *BlockGraph::newBlockIfElse(FlowBlock *cond,FlowBlock *tc,FlowBlock *fc)
{
vector<FlowBlock *> nodes;
BlockIf *ret = new BlockIf();
BlockIfElse *ret = new BlockIfElse();
nodes.push_back(cond);
nodes.push_back(tc);
nodes.push_back(fc);
@@ -1824,6 +1855,19 @@ BlockIf *BlockGraph::newBlockIfElse(FlowBlock *cond,FlowBlock *tc,FlowBlock *fc)
return ret;
}
BlockIfNoExit *BlockGraph::newBlockIfNoExit(FlowBlock *cond,FlowBlock *tc,FlowBlock *fc)
{
vector<FlowBlock *> nodes;
BlockIfNoExit *ret = new BlockIfNoExit();
nodes.push_back(cond);
nodes.push_back(tc);
nodes.push_back(fc);
identifyInternal(ret,nodes);
addBlock(ret);
return ret;
}
/// Add the new BlockWhileDo to \b this, collapsing the condition and clause into it.
/// \param cond is the condition FlowBlock
/// \param cl is the clause FlowBlock
@@ -1878,12 +1922,13 @@ BlockSwitch *BlockGraph::newBlockSwitch(const vector<FlowBlock *> &cs,bool hasEx
{
FlowBlock *rootbl = cs[0];
BlockSwitch *ret = new BlockSwitch(rootbl);
unique_ptr<BlockSwitch> uret( new BlockSwitch(rootbl) );
const FlowBlock *leafbl = rootbl->getExitLeaf();
if ((leafbl == (const FlowBlock *)0)||(leafbl->getType() != FlowBlock::t_copy))
throw LowlevelError("Could not get switch leaf");
ret->grabCaseBasic(leafbl->subBlock(0),cs); // Must be called before the identifyInternal
identifyInternal(ret,cs);
uret->grabCaseBasic(leafbl->subBlock(0),cs); // Must be called before the identifyInternal
identifyInternal(uret.get(),cs);
BlockSwitch *ret = uret.release();
addBlock(ret);
if (hasExit)
ret->forceOutputNum(1); // If there is an exit, there should be exactly 1 out edge
@@ -2338,14 +2383,23 @@ FlowBlock *BlockBasic::getSplitPoint(void)
return this;
}
int4 BlockBasic::flipInPlaceTest(vector<PcodeOp *> &fliplist) const
int4 BlockBasic::flipInPlaceTest(vector<PcodeOp *> &fliplist,bool allowOpRemoval) const
{
if (op.empty()) return 2;
PcodeOp *lastop = op.back();
if (lastop->code() != CPUI_CBRANCH)
return 2;
return Funcdata::opFlipInPlaceTest(lastop,fliplist);
int4 res;
if (lastop->isBooleanFlip()) {
// If the flip bit is set, don't change any ops to accomplish flip
vector<PcodeOp *> unusedOps;
res = Funcdata::opFlipInPlaceTest(lastop,unusedOps,allowOpRemoval);
}
else {
res = Funcdata::opFlipInPlaceTest(lastop,fliplist,allowOpRemoval);
}
return res;
}
void BlockBasic::flipInPlaceExecute(void)
@@ -2354,7 +2408,9 @@ void BlockBasic::flipInPlaceExecute(void)
PcodeOp *lastop = op.back();
// This is similar to negateCondition but we don't need to set the boolean_flip flag on lastop
// because it is getting explicitly changed
lastop->flipFlag(PcodeOp::fallthru_true); // Flip whether the fallthru block is true/false
lastop->flipFlag(PcodeOp::fallthru_true); // Flip whether the fallthru block is true/false
if (lastop->isBooleanFlip()) // If the flip flag is set
lastop->flipFlag(PcodeOp::boolean_flip); // unflip it (instead of flipping ops)
FlowBlock::negateCondition(true); // Flip the order of outof this
}
@@ -2416,6 +2472,18 @@ bool BlockBasic::isComplex(void) const
return false;
}
void BlockBasic::finalTransform(Funcdata &data,bool allowOpMoves)
{
if (sizeOut() != 2) return;
PcodeOp *cbranch = lastOp();
if (cbranch == (PcodeOp *)0 || cbranch->code() != CPUI_CBRANCH)
return;
if (!cbranch->isBooleanFlip())
return;
data.opNormalizeFlip(cbranch);
}
/// \param encoder is the stream encoder
void FlowBlock::encodeHeader(Encoder &encoder) const
@@ -2525,13 +2593,14 @@ bool BlockBasic::unblockedMulti(int4 outslot) const
// outlists
}
if (redundlist.empty()) return true;
int4 inIndexToThis = blout->getInIndex(this);
for(iter=blout->op.begin();iter!=blout->op.end();++iter) {
multiop = *iter;
if (multiop->code() != CPUI_MULTIEQUAL) continue;
for(vector<const FlowBlock *>::iterator biter=redundlist.begin();biter!=redundlist.end();++biter) {
bl = *biter;
vnredund = multiop->getIn(blout->getInIndex(bl)); // One of the redundant varnodes
vnremove = multiop->getIn(blout->getInIndex(this));
vnremove = multiop->getIn(inIndexToThis);
if (vnremove->isWritten()) {
othermulti = vnremove->getDef();
if ((othermulti->code()==CPUI_MULTIEQUAL)&&(othermulti->getParent()==this))
@@ -2543,6 +2612,26 @@ bool BlockBasic::unblockedMulti(int4 outslot) const
return true;
}
/// Was there copy propagation directly out of \b this block into a MULTIEQUAL in the immediate \e out block?
/// If so, \b this block shouldn't be removed as the COPY may need to be put back during merge.
/// \param outslot is the output edge to search along
/// \return \b true if there was no immediate copy propagation, \b false otherwise
bool BlockBasic::hasNoImmediateCopy(int4 outslot) const
{
if (!hasImmedCopyEdge(outslot)) return true;
const BlockBasic *blout = (const BlockBasic *)getOut(outslot);
int4 inIndexToThis = blout->getInIndex(this);
list<PcodeOp *>::const_iterator iter;
for(iter=blout->op.begin();iter!=blout->op.end();++iter) {
PcodeOp *multiop = *iter;
if (multiop->code() != CPUI_MULTIEQUAL) continue;
if (multiop->hasCopyImmed(inIndexToThis))
return false;
}
return true;
}
/// This is a crucial test for whether \b this block is doing anything substantial
/// or is a candidate for removal. Even blocks that "do nothing" have some kind of branch
/// and placeholder operations (MULTIEQUAL and INDIRECT) for data flowing through the block.
@@ -2658,6 +2747,24 @@ void BlockBasic::printRaw(ostream &s) const
}
}
void BlockBasic::printRawImpliedGoto(ostream &s,const FlowBlock *nextBlock) const
{
if (sizeOut() != 1) return;
const FlowBlock *outBlock = getOut(0);
if (nextBlock->getType() != t_basic) {
nextBlock = nextBlock->getFrontLeaf();
if (nextBlock == (const FlowBlock *)0) return;
nextBlock = nextBlock->subBlock(0);
}
if (getOut(0) == nextBlock) return;
if (!op.empty() && op.back()->isBranch()) return;
getStop().printRaw(s);
s << ": \t[ goto ";
outBlock->printShortHeader(s);
s << " ]" << endl;
}
/// \brief Check for values created in \b this block that flow outside the block.
///
/// The block can calculate a value for a BRANCHIND or CBRANCH and can copy values and this method will still
@@ -2942,7 +3049,7 @@ void BlockList::printHeader(ostream &s) const
FlowBlock::printHeader(s);
}
int4 BlockCondition::flipInPlaceTest(vector<PcodeOp *> &fliplist) const
int4 BlockCondition::flipInPlaceTest(vector<PcodeOp *> &fliplist,bool allowOpRemoval) const
{
FlowBlock *split1 = getBlock(0)->getSplitPoint();
@@ -2951,10 +3058,10 @@ int4 BlockCondition::flipInPlaceTest(vector<PcodeOp *> &fliplist) const
FlowBlock *split2 = getBlock(1)->getSplitPoint();
if (split2 == (FlowBlock *)0)
return 2;
int4 subtest1 = split1->flipInPlaceTest(fliplist);
int4 subtest1 = split1->flipInPlaceTest(fliplist,allowOpRemoval);
if (subtest1 == 2)
return 2;
int4 subtest2 = split2->flipInPlaceTest(fliplist);
int4 subtest2 = split2->flipInPlaceTest(fliplist,allowOpRemoval);
if (subtest2 == 2)
return 2;
return subtest1;
@@ -3019,23 +3126,11 @@ void BlockCondition::encodeHeader(Encoder &encoder) const
encoder.writeString(ATTRIB_OPCODE, nm);
}
void BlockIf::markUnstructured(void)
{
BlockGraph::markUnstructured(); // Recurse
if ((gototarget != (FlowBlock *)0)&&(gototype==f_goto_goto))
markCopyBlock(gototarget,f_unstructured_targ);
}
void BlockIf::scopeBreak(int4 curexit,int4 curloopexit)
{
getBlock(0)->scopeBreak(-1,curloopexit); // Condition block has multiple exits
// Blocks don't flow into one another, but share same exit block
for(int4 i=1;i<getSize();++i)
getBlock(i)->scopeBreak(curexit,curloopexit);
if ((gototarget != (FlowBlock *)0)&&(gototarget->getIndex() == curloopexit))
gototype = f_break_goto;
getBlock(1)->scopeBreak(curexit,curloopexit);
}
void BlockIf::printHeader(ostream &s) const
@@ -3045,40 +3140,6 @@ void BlockIf::printHeader(ostream &s) const
FlowBlock::printHeader(s);
}
bool BlockIf::preferComplement(Funcdata &data)
{
if (getSize()!=3) // If we are an if/else
return false;
FlowBlock *split = getBlock(0)->getSplitPoint();
if (split == (FlowBlock *)0)
return false;
vector<PcodeOp *> fliplist;
if (0 != split->flipInPlaceTest(fliplist))
return false;
split->flipInPlaceExecute();
data.opFlipInPlaceExecute(fliplist);
swapBlocks(1,2);
return true;
}
const FlowBlock *BlockIf::getExitLeaf(void) const
{ // In the special case of an ifgoto block, we do have an exit leaf
if (getSize() == 1)
return getBlock(0)->getExitLeaf();
return (FlowBlock *)0;
}
PcodeOp *BlockIf::lastOp(void) const
{ // In the special case of an ifgoto block, we do have a last op, otherwise we don't
if (getSize() == 1)
return getBlock(0)->lastOp();
return (PcodeOp *)0;
}
FlowBlock *BlockIf::nextFlowAfter(const FlowBlock *bl) const
{
@@ -3089,19 +3150,123 @@ FlowBlock *BlockIf::nextFlowAfter(const FlowBlock *bl) const
return getParent()->nextFlowAfter(this);
}
void BlockIf::encodeBody(Encoder &encoder) const
void BlockIfElse::scopeBreak(int4 curexit,int4 curloopexit)
{
getBlock(0)->scopeBreak(-1,curloopexit); // Condition block has multiple exits
// Blocks don't flow into one another, but share same exit block
getBlock(1)->scopeBreak(curexit,curloopexit);
getBlock(2)->scopeBreak(curexit,curloopexit);
}
void BlockIfElse::printHeader(ostream &s) const
{
s << "If/else block ";
FlowBlock::printHeader(s);
}
bool BlockIfElse::preferComplement(Funcdata &data,bool allowOpRemoval)
{
FlowBlock *split = getBlock(0)->getSplitPoint();
if (split == (FlowBlock *)0)
return false;
vector<PcodeOp *> fliplist;
if (0 != split->flipInPlaceTest(fliplist,allowOpRemoval))
return false;
split->flipInPlaceExecute();
data.opFlipInPlaceExecute(fliplist);
swapBlocks(1,2);
return true;
}
void BlockIfNoExit::scopeBreak(int4 curexit,int4 curloopexit)
{
getBlock(0)->scopeBreak(-1,curloopexit); // No fixed exit for condition block
FlowBlock *followBlock = getBlock(2);
getBlock(1)->scopeBreak(followBlock->getIndex(),curloopexit); // First body: followBlock acts as "exit"
followBlock->scopeBreak(curexit,curloopexit);
}
void BlockIfNoExit::printHeader(ostream &s) const
{
s << "If (no exit) block ";
FlowBlock::printHeader(s);
}
bool BlockIfNoExit::preferComplement(Funcdata &data,bool allowOpRemoval)
{
FlowBlock *body1 = getBlock(1);
FlowBlock *body2 = getBlock(2);
int4 diff = body1->getStructureDepth() - body2->getStructureDepth();
if (diff < 0) return false;
if (diff == 0) {
diff = body1->getBasicCount() - body2->getBasicCount();
if (diff < 0) return false;
if (diff == 0) {
uint4 halt1 = body1->getHaltType();
uint4 halt2 = body2->getHaltType();
if (halt1 > halt2)
return false;
if (halt1 < halt2)
diff = 1;
}
}
FlowBlock *split = getBlock(0)->getSplitPoint();
if (split == (FlowBlock *)0)
return false;
vector<PcodeOp *> fliplist;
int4 testResult = split->flipInPlaceTest(fliplist,allowOpRemoval);
if (2 == testResult)
return false;
if (diff == 0 && testResult != 0)
return false;
split->flipInPlaceExecute();
data.opFlipInPlaceExecute(fliplist);
swapBlocks(1,2);
return true;
}
void BlockIfGoto::scopeBreak(int4 curexit,int4 curloopexit)
{
getBlock(0)->scopeBreak(-1,curloopexit); // Condition has multiple exits
if ((gototarget != (FlowBlock *)0)&&(gototarget->getIndex() == curloopexit))
gototype = f_break_goto;
}
void BlockIfGoto::printHeader(ostream &s) const
{
s << "If goto block ";
FlowBlock::printHeader(s);
}
void BlockIfGoto::markUnstructured(void)
{
BlockGraph::markUnstructured(); // Recurse
if ((gototarget != (FlowBlock *)0)&&(gototype==f_goto_goto))
markCopyBlock(gototarget,f_unstructured_targ);
}
void BlockIfGoto::encodeBody(Encoder &encoder) const
{
BlockGraph::encodeBody(encoder);
if (getSize() == 1) { // If this is a if GOTO block
const FlowBlock *leaf = gototarget->getFrontLeaf();
int4 depth = gototarget->calcDepth(leaf);
encoder.openElement(ELEM_TARGET);
encoder.writeSignedInteger(ATTRIB_INDEX, leaf->getIndex());
encoder.writeSignedInteger(ATTRIB_DEPTH, depth);
encoder.writeUnsignedInteger(ATTRIB_TYPE, gototype);
encoder.closeElement(ELEM_TARGET);
}
const FlowBlock *leaf = gototarget->getFrontLeaf();
int4 depth = gototarget->calcDepth(leaf);
encoder.openElement(ELEM_TARGET);
encoder.writeSignedInteger(ATTRIB_INDEX, leaf->getIndex());
encoder.writeSignedInteger(ATTRIB_DEPTH, depth);
encoder.writeUnsignedInteger(ATTRIB_TYPE, gototype);
encoder.closeElement(ELEM_TARGET);
}
/// Try to find a Varnode that represents the controlling \e loop \e variable for \b this loop.
@@ -3308,10 +3473,11 @@ FlowBlock *BlockWhileDo::nextFlowAfter(const FlowBlock *bl) const
/// Determine if \b this block can be printed as a \e for loop, with an \e initializer statement
/// extracted from the previous block, and an \e iterator statement extracted from the body.
/// \param data is the function containing \b this loop
void BlockWhileDo::finalTransform(Funcdata &data)
/// \param allowOpMoves is \b true if iterator and initializer ops can be moved
void BlockWhileDo::finalTransform(Funcdata &data,bool allowOpMoves)
{
BlockGraph::finalTransform(data);
BlockGraph::finalTransform(data,allowOpMoves);
if (!data.getArch()->analyze_for_loops) return;
if (hasOverflowSyntax()) return;
FlowBlock *copyBl = getFrontLeaf();
@@ -3334,6 +3500,7 @@ void BlockWhileDo::finalTransform(Funcdata &data)
if (iterateOp == (PcodeOp *)0) return;
if (iterateOp != lastOp) {
if (!allowOpMoves) return;
data.opUninsert(iterateOp);
data.opInsertAfter(iterateOp, lastOp);
}
@@ -3346,6 +3513,7 @@ void BlockWhileDo::finalTransform(Funcdata &data)
return;
}
if (initializeOp != lastOp) {
if (!allowOpMoves) return;
data.opUninsert(initializeOp);
data.opInsertAfter(initializeOp, lastOp);
}
@@ -30,6 +30,9 @@ class BlockGoto;
class BlockMultiGoto;
class BlockCondition;
class BlockIf;
class BlockIfElse;
class BlockIfNoExit;
class BlockIfGoto;
class BlockWhileDo;
class BlockDoWhile;
class BlockInfLoop;
@@ -76,7 +79,7 @@ public:
/// \brief The possible block types
enum block_type {
t_plain, t_basic, t_graph, t_copy, t_goto, t_multigoto, t_ls,
t_condition, t_if, t_whiledo, t_dowhile, t_switch, t_infloop
t_condition, t_if, t_ifelse, t_ifnoexit, t_ifgoto, t_whiledo, t_dowhile, t_switch, t_infloop
};
/// \brief Boolean properties of blocks
///
@@ -102,7 +105,9 @@ public:
f_whiledo_overflow = 0x8000,///< Set if the conditional block of a whiledo is too big to print as while(cond) { ...
f_flip_path = 0x10000, ///< If true, out edges have been flipped since last time path was traced
f_joined_block = 0x20000, ///< Block is a merged form of original basic blocks
f_duplicate_block = 0x40000 ///< Block is a duplicated version of an original basic block
f_duplicate_block = 0x40000, ///< Block is a duplicated version of an original basic block
f_delayed_donothing = 0x80000, ///< Potential \e do \e nothing block whose removal has been delayed
f_final_transform = 0x100000 ///< Has the final transform been run
};
/// \brief Boolean properties on edges
enum edge_flags {
@@ -114,22 +119,25 @@ public:
f_forward_edge = 0x20, ///< An edge that jumps forward in the spanning tree
f_cross_edge = 0x40, ///< An edge that crosses subtrees in the spanning tree
f_back_edge = 0x80, ///< Within (reducible) graph, a back edge defining a loop
f_loop_exit_edge = 0x100 ///< Edge exits the body of a loop
f_loop_exit_edge = 0x100, ///< Edge exits the body of a loop
f_immed_copy = 0x200 ///< Copy propagation has happened across the edge
};
private:
uint4 flags; ///< Collection of block_flags
FlowBlock *parent; ///< The parent block to which \b this belongs
FlowBlock *immed_dom; ///< Immediate dominating block
FlowBlock *copymap; ///< Back reference to a BlockCopy of \b this
int4 index; ///< Reference index for this block (reverse post order)
int4 visitcount; ///< A count of visits of this node for various algorithms
int4 numdesc; ///< Number of descendants of this block in spanning tree (+1)
vector<BlockEdge> intothis; ///< Blocks which (can) fall into this block
vector<BlockEdge> outofthis; ///< Blocks into which this block (can) fall
// If there are two possible outputs as the
// result of a conditional branch
// the first block in outofthis should be
// the result of the condition being false
uint4 flags; ///< Collection of block_flags
int4 index; ///< Reference index for this block (reverse post order)
int4 visitcount; ///< A count of visits of this node for various algorithms
int4 numdesc; ///< Number of descendants of this block in spanning tree (+1)
int4 leafCount; ///< Number of leaf blocks contained in \b this
int4 structureDepth; ///< Amount of nesting in structure rooted at \b this
static void replaceEdgeMap(vector<BlockEdge> &vec); ///< Update block references in edges with copy map
void addInEdge(FlowBlock *b,uint4 lab); ///< Add an edge coming into \b this
void decodeNextInEdge(Decoder &decoder,BlockMap &resolver); ///< Decode the next input edge from stream
@@ -154,6 +162,7 @@ private:
protected:
void setFlag(uint4 fl) { flags |= fl; } ///< Set a boolean property
void clearFlag(uint4 fl) { flags &= ~fl; } ///< Clear a boolean property
void clearAllFlags(void) { flags = 0; } ///< Clear all properties of \b this block
public:
FlowBlock(void); ///< Construct a block with no edges
virtual ~FlowBlock(void) {} ///< Destructor
@@ -210,6 +219,14 @@ public:
/// \param s is the given stream to write to
virtual void printRaw(ostream &s) const {}
/// \brief If the \e out block of \b this is not the given next block, print an implied \b goto to the out block
///
/// In order to see where \b this block is flowing to, if there is no explicit branch op, and if the next block
/// being printed is \e not the fallthru branch, print the destination block as an implied \b goto op.
/// \param s is the output stream
/// \param nextBlock is the given nextBlock being printed
virtual void printRawImpliedGoto(ostream &s,const FlowBlock *nextBlock) const {}
virtual void emit(PrintLanguage *lng) const; ///<Emit the instructions in \b this FlowBlock as structured code
/// \brief Get the leaf block from which \b this block exits
@@ -231,9 +248,9 @@ public:
virtual PcodeOp *lastOp(void) const { return (PcodeOp *)0; }
virtual bool negateCondition(bool toporbottom); ///< Flip the condition computed by \b this
virtual bool preferComplement(Funcdata &data); ///< Rearrange \b this hierarchy to simplify boolean expressions
virtual bool preferComplement(Funcdata &data,bool allowOpRemoval); ///< Rearrange \b this hierarchy to simplify boolean expressions
virtual FlowBlock *getSplitPoint(void); ///< Get the leaf splitting block
virtual int4 flipInPlaceTest(vector<PcodeOp *> &fliplist) const;
virtual int4 flipInPlaceTest(vector<PcodeOp *> &fliplist,bool allowOpRemoval) const;
virtual void flipInPlaceExecute(void);
/// \brief Is \b this too complex to be a condition (BlockCondition)
@@ -246,7 +263,8 @@ public:
/// \brief Do any structure driven final transforms
///
/// \param data is the function to transform
virtual void finalTransform(Funcdata &data) {}
/// \param allowOpMoves is \b true if ops may be moved within their basic block
virtual void finalTransform(Funcdata &data,bool allowOpMoves) {}
/// \brief Make any final configurations necessary to emit the block
///
@@ -286,6 +304,8 @@ public:
void setLoopExit(int4 i) { setOutEdgeFlag(i,f_loop_exit_edge); } ///< Label the edge exiting \b this as a loop
void clearLoopExit(int4 i) { clearOutEdgeFlag(i,f_loop_exit_edge); } ///< Clear the loop exit edge
void setBackEdge(int4 i) { setOutEdgeFlag(i,f_back_edge); } ///< Label the \e back edge of a loop
void setImmedCopyEdge(int4 i) { setOutEdgeFlag(i,f_immed_copy); } ///< Mark that an immediate COPY has propagated across the edge
bool hasImmedCopyEdge(int4 i) const { return ((outofthis[i].label & f_immed_copy)!=0); } ///< Has an immediate COPY propagated across the edge
bool getFlipPath(void) const { return ((flags & f_flip_path)!=0); } ///< Have out edges been flipped
bool isJumpTarget(void) const; ///< Return \b true if non-fallthru jump flows into \b this
FlowBlock *getFalseOut(void) const { return outofthis[0].point; } ///< Get the \b false output FlowBlock
@@ -338,6 +358,10 @@ public:
bool isGotoIn(int4 i) const { return ((intothis[i].label & (f_irreducible|f_goto_edge))!=0); } ///< Is the i-th incoming edge unstructured
bool isGotoOut(int4 i) const { return ((outofthis[i].label & (f_irreducible|f_goto_edge))!=0); } ///< Is the i-th outgoing edge unstructured
JumpTable *getJumptable(void) const; ///< Get the JumpTable associated \b this block
int4 getBasicCount(void) const { return leafCount; } ///< Get the number of basic blocks under the structure at \b this point
int4 getStructureDepth(void) const { return structureDepth; } ///< Get the nesting depth of the structure rooted at \b this point
uint4 getHaltType(void) const; ///< Get the \e halt type of the last PcodeOp in \b this
void printShortHeader(ostream &s) const; ///< Print a short identifier for the block
static block_type nameToType(const string &name); ///< Get the block_type associated with a name string
static string typeToName(block_type bt); ///< Get the name string associated with a block_type
static bool compareBlockIndex(const FlowBlock *bl1,const FlowBlock *bl2); ///< Compare FlowBlock by index
@@ -368,6 +392,7 @@ protected:
void swapBlocks(int4 i,int4 j); ///< Swap the positions two component FlowBlocks
static void markCopyBlock(FlowBlock *bl,uint4 fl); ///< Set properties on the first leaf FlowBlock
public:
BlockGraph(void) { leafCount = 0; } ///< Construct empty structure
void clear(void); ///< Clear all component FlowBlock objects
virtual ~BlockGraph(void) { clear(); } ///< Destructor
const vector<FlowBlock *> &getList(void) const { return list; } ///< Get the list of component FlowBlock objects
@@ -380,10 +405,11 @@ public:
virtual void scopeBreak(int4 curexit,int4 curloopexit);
virtual void printTree(ostream &s,int4 level) const;
virtual void printRaw(ostream &s) const;
void printRawImpliedGoto(ostream &s,const FlowBlock *nextBlock) const;
virtual void emit(PrintLanguage *lng) const { lng->emitBlockGraph(this); }
virtual PcodeOp *firstOp(void) const;
virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const;
virtual void finalTransform(Funcdata &data);
virtual void finalTransform(Funcdata &data,bool allowOpMoves);
virtual void finalizePrinting(Funcdata &data) const;
virtual void encodeBody(Encoder &encoder) const;
virtual void decodeBody(Decoder &decoder);
@@ -409,9 +435,10 @@ public:
BlockMultiGoto *newBlockMultiGoto(FlowBlock *bl,int4 outedge); ///< Build a new BlockMultiGoto
BlockList *newBlockList(const vector<FlowBlock *> &nodes); ///< Build a new BlockList
BlockCondition *newBlockCondition(FlowBlock *b1,FlowBlock *b2); ///< Build a new BlockCondition
BlockIf *newBlockIfGoto(FlowBlock *cond); ///< Build a new BlockIfGoto
BlockIfGoto *newBlockIfGoto(FlowBlock *cond); ///< Build a new BlockIfGoto
BlockIf *newBlockIf(FlowBlock *cond,FlowBlock *tc); ///< Build a new BlockIf
BlockIf *newBlockIfElse(FlowBlock *cond,FlowBlock *tc,FlowBlock *fc); ///< Build a new BlockIfElse
BlockIfElse *newBlockIfElse(FlowBlock *cond,FlowBlock *tc,FlowBlock *fc); ///< Build a new BlockIfElse
BlockIfNoExit *newBlockIfNoExit(FlowBlock *cond,FlowBlock *tc,FlowBlock *fc); ///< Build a new BlockIfNoExit
BlockWhileDo *newBlockWhileDo(FlowBlock *cond,FlowBlock *cl); ///< Build a new BlockWhileDo
BlockDoWhile *newBlockDoWhile(FlowBlock *condcl); ///< Build a new BlockDoWhile
BlockInfLoop *newBlockInfLoop(FlowBlock *body); ///< Build a new BlockInfLoop
@@ -428,6 +455,7 @@ public:
void calcLoop(void); ///< Calculate loop edges
void collectReachable(vector<FlowBlock *> &res,FlowBlock *bl,bool un) const; ///< Collect reachable/unreachable FlowBlocks from a given start FlowBlock
void structureLoops(vector<FlowBlock *> &rootlist); ///< Label loop edges
bool hasFinalTransform(void) const { return ((getFlags() & f_final_transform) != 0); } ///< Return \b true if finalTransform() has been run on \b this
#ifdef BLOCKCONSISTENT_DEBUG
bool isConsistent(void) const; ///< Check consistency of \b this BlockGraph
#endif
@@ -473,16 +501,19 @@ public:
virtual void decodeBody(Decoder &decoder);
virtual void printHeader(ostream &s) const;
virtual void printRaw(ostream &s) const;
virtual void printRawImpliedGoto(ostream &s,const FlowBlock *nextBlock) const;
virtual void emit(PrintLanguage *lng) const { lng->emitBlockBasic(this); }
virtual const FlowBlock *getExitLeaf(void) const { return this; }
virtual PcodeOp *firstOp(void) const;
virtual PcodeOp *lastOp(void) const;
virtual bool negateCondition(bool toporbottom);
virtual FlowBlock *getSplitPoint(void);
virtual int4 flipInPlaceTest(vector<PcodeOp *> &fliplist) const;
virtual int4 flipInPlaceTest(vector<PcodeOp *> &fliplist,bool allowOpRemoval) const;
virtual void flipInPlaceExecute(void);
virtual bool isComplex(void) const;
bool unblockedMulti(int4 outslot) const; ///< Check if \b this block can be removed without introducing inconsistencies
virtual void finalTransform(Funcdata &data,bool allowOpMoves);
bool unblockedMulti(int4 outslot) const; ///< Check if \b this block can be removed without introducing inconsistencies
bool hasNoImmediateCopy(int4 outslot) const; ///< Check if there have been immediate COPYs out of \b this block
bool hasOnlyMarkers(void) const; ///< Does \b this block contain only MULTIEQUAL and INDIRECT ops
bool isDoNothing(void) const; ///< Should \b this block should be removed
list<PcodeOp *>::iterator beginOp(void) { return op.begin(); } ///< Return an iterator to the beginning of the PcodeOps
@@ -493,6 +524,9 @@ public:
bool noInterveningStatement(void) const;
PcodeOp *findMultiequal(const vector<Varnode *> &varArray); ///< Find MULTIEQUAL with given inputs
PcodeOp *earliestUse(Varnode *vn);
void setDelayedDonothing(void) { setFlag(f_delayed_donothing); } ///< Mark as \e do \e nothing block with delayed removal
void clearDelayedDonothing(void) { clearFlag(f_delayed_donothing); } ///< Clear mark for delayed removal
bool isDelayedDonothing(void) const { return ((getFlags() & f_delayed_donothing) != 0); } ///< Is block marked for delayed removal
static bool liftVerifyUnroll(vector<Varnode *> &varArray,int4 slot); ///< Verify given Varnodes are defined with same PcodeOp
};
@@ -515,6 +549,7 @@ public:
virtual void printHeader(ostream &s) const;
virtual void printTree(ostream &s,int4 level) const;
virtual void printRaw(ostream &s) const { copy->printRaw(s); }
virtual void printRawImpliedGoto(ostream &s,const FlowBlock *nextBlock) const { copy->printRawImpliedGoto(s, nextBlock); }
virtual void emit(PrintLanguage *lng) const { lng->emitBlockCopy(this); }
virtual const FlowBlock *getExitLeaf(void) const { return this; }
virtual PcodeOp *firstOp(void) const { return copy->firstOp(); }
@@ -522,6 +557,7 @@ public:
virtual bool negateCondition(bool toporbottom) { bool res = copy->negateCondition(true); FlowBlock::negateCondition(toporbottom); return res; }
virtual FlowBlock *getSplitPoint(void) { return copy->getSplitPoint(); }
virtual bool isComplex(void) const { return copy->isComplex(); }
virtual void finalTransform(Funcdata &data,bool allowOpMoves) { return copy->finalTransform(data,allowOpMoves); }
virtual void encodeHeader(Encoder &encoder) const;
};
@@ -617,7 +653,7 @@ public:
virtual void emit(PrintLanguage *lng) const { lng->emitBlockCondition(this); }
virtual bool negateCondition(bool toporbottom);
virtual FlowBlock *getSplitPoint(void) { return this; }
virtual int4 flipInPlaceTest(vector<PcodeOp *> &fliplist) const;
virtual int4 flipInPlaceTest(vector<PcodeOp *> &fliplist,bool allowOpRemoval) const;
virtual void flipInPlaceExecute(void);
virtual PcodeOp *lastOp(void) const;
virtual bool isComplex(void) const { return getBlock(0)->isComplex(); }
@@ -633,10 +669,6 @@ public:
/// the block of code executed when the condition is true. If there is a third component, it
/// is the "else" block, executed when the condition is false.
///
/// If there is only one component, this represents the case where the conditionally executed
/// branch is unstructured. This is generally emitted where the conditionally executed body
/// is the single \e goto statement.
///
/// A BlockIf will always have at most one (structured) exit edge. With one component, one of the edges of
/// the conditional component is unstructured. With two components, one of the conditional block
/// edges flows to the body block, and the body's out edge and the remaining conditional block out
@@ -644,22 +676,58 @@ public:
/// \e true body block, the other conditional edge flows to the \e false body block, and outgoing
/// edges from the body blocks, if they exist, flow to the same exit block.
class BlockIf : public BlockGraph {
uint4 gototype; ///< The type of unstructured edge (if present)
FlowBlock *gototarget; ///< The target FlowBlock of the unstructured edge (if present)
public:
BlockIf(void) { gototype = f_goto_goto; gototarget = (FlowBlock *)0; } ///< Constructor
void setGotoTarget(FlowBlock *bl) { gototarget = bl; } ///< Mark the target of the unstructured edge
FlowBlock *getGotoTarget(void) const { return gototarget; } ///< Get the target of the unstructured edge
uint4 getGotoType(void) const { return gototype; } ///< Get the type of unstructured edge
virtual block_type getType(void) const { return t_if; }
virtual void markUnstructured(void);
virtual void scopeBreak(int4 curexit,int4 curloopexit);
virtual void printHeader(ostream &s) const;
virtual void emit(PrintLanguage *lng) const { lng->emitBlockIf(this); }
virtual bool preferComplement(Funcdata &data);
virtual const FlowBlock *getExitLeaf(void) const;
virtual PcodeOp *lastOp(void) const;
virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const;
};
/// \brief An "if" with two bodies of conditionally executed code
///
/// The first component is the \e conditional block. The second component is executed if the condition is \b true.
/// The third component is the "else" clause. Both bodies have at most one \e out edge.
class BlockIfElse : public BlockIf {
public:
virtual block_type getType(void) const { return t_ifelse; }
virtual void scopeBreak(int4 curexit,int4 curloopexit);
virtual void printHeader(ostream &s) const;
virtual bool preferComplement(Funcdata &data,bool allowOpRemoval);
};
/// \brief An "if" with two bodies of executed code, neither of which has an exit
///
/// This always has three components, the \e conditional block, and two bodies. If the condition is \b true,
/// the first body is executed. The second "else" body is treated as if it were \e following the first body,
/// and it is rendered without explicit "else" syntax.
class BlockIfNoExit : public BlockIfElse {
public:
virtual block_type getType(void) const { return t_ifnoexit; }
virtual void scopeBreak(int4 curexit,int4 curloopexit);
virtual void printHeader(ostream &s) const;
virtual bool preferComplement(Funcdata &data,bool allowOpRemoval);
virtual PcodeOp *lastOp(void) const { return getBlock(2)->lastOp(); }
};
/// \brief An "if" with one unstructured \e goto branch
///
/// This always has one component, the condition. One of the two branches is executed as a \e goto statement,
/// the target of which is stored internally.
/// The other branch is the (structured) exit.
class BlockIfGoto : public BlockIf {
uint4 gototype; ///< The type of unstructured edge (if present)
FlowBlock *gototarget; ///< The target FlowBlock of the unstructured edge (if present)
public:
BlockIfGoto(FlowBlock *target) { gototype = f_goto_goto; gototarget = target; } ///< Constructor
FlowBlock *getGotoTarget(void) const { return gototarget; } ///< Get the target of the unstructured edge
uint4 getGotoType(void) const { return gototype; } ///< Get the type of unstructured edge
virtual block_type getType(void) const { return t_ifgoto; }
virtual void scopeBreak(int4 curexit,int4 curloopexit);
virtual void printHeader(ostream &s) const;
virtual void markUnstructured(void);
virtual const FlowBlock *getExitLeaf(void) const { return getBlock(0)->getExitLeaf(); }
virtual PcodeOp *lastOp(void) const { return getBlock(0)->lastOp(); }
virtual void encodeBody(Encoder &encoder) const;
};
@@ -698,7 +766,7 @@ public:
virtual void printHeader(ostream &s) const;
virtual void emit(PrintLanguage *lng) const { lng->emitBlockWhileDo(this); }
virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const;
virtual void finalTransform(Funcdata &data);
virtual void finalTransform(Funcdata &data,bool allowOpMoves);
virtual void finalizePrinting(Funcdata &data) const;
};
@@ -778,6 +846,7 @@ public:
uint4 getGotoType(int4 i) const { return caseblocks[i].gototype; } ///< Get the edge type for the i-th \e case block
bool isExit(int4 i) const { return caseblocks[i].isexit; } ///< Does the i-th \e case block exit the switch?
const Datatype *getSwitchType(void) const; ///< Get the data-type of the switch variable
uint4 getDisplayFormat(void) const { return jump->getDisplayFormat(); } ///< Get any integer display format for cases
virtual block_type getType(void) const { return t_switch; }
virtual void markUnstructured(void);
virtual void scopeBreak(int4 curexit,int4 curloopexit);
@@ -818,8 +887,9 @@ inline void FlowBlock::emit(PrintLanguage *lng) const
/// For the instructions in this block, decide if the control-flow structure
/// can be rearranged so that boolean expressions come out more naturally.
/// \param data is the function to analyze
/// \param allowOpRemoval if \b true, changes can include removal of ops
/// \return \b true if a change was made
inline bool FlowBlock::preferComplement(Funcdata &data)
inline bool FlowBlock::preferComplement(Funcdata &data,bool allowOpRemoval)
{
return false;
@@ -838,15 +908,17 @@ inline FlowBlock *FlowBlock::getSplitPoint(void)
/// \brief Test normalizing the conditional branch in \b this
///
/// Find the set of PcodeOp objects that need to be adjusted to flip
/// the condition \b this FlowBlock calculates.
/// the condition \b this FlowBlock calculates. If \b allowOpRemoval is set,
/// the adjustment can include the removal of (BOOL_NEGATE) ops.
///
/// Return:
/// - 0 if the flip would normalize the condition
/// - 1 if the flip doesn't affect normalization of the condition
/// - 2 if the flip produces an unnormalized condition
/// - 1 if the flip denormalizes (or doesn't affect normalization)
/// - 2 if a flip is not possible
/// \param fliplist will contain the PcodeOps that need to be adjusted
/// \param allowOpRemoval if \b true adjustments can include removal of ops
/// \return 0 if the condition will be normalized, 1 or 2 otherwise
inline int4 FlowBlock::flipInPlaceTest(vector<PcodeOp *> &fliplist) const
inline int4 FlowBlock::flipInPlaceTest(vector<PcodeOp *> &fliplist,bool allowOpRemoval) const
{
return 2; // By default a block will not normalize
@@ -875,6 +947,16 @@ inline FlowBlock *FlowBlock::nextFlowAfter(const FlowBlock *bl) const
return (FlowBlock *)0;
}
/// If the last op is a halt of execution of some form, we return its code: \b halt, \b noreturn, \b badinstruction etc.
/// If it is not a halt, or if there is no last op, 0 is returned.
/// \return the \e halt code or 0
inline uint4 FlowBlock::getHaltType(void) const
{
PcodeOp *op = lastOp();
return (op != (PcodeOp *)0) ? op->getHaltType() : 0;
}
/// \param bl1 is the first FlowBlock to compare
/// \param bl2 is the second FlowBlock to compare
/// \return true if the first comes before the second
@@ -1496,11 +1496,19 @@ bool CollapseStructure::ruleBlockIfNoExit(FlowBlock *bl)
if (clauseblock->sizeOut() != 0) continue; // Must be no way out of clause
if (clauseblock->isSwitchOut()) continue;
if (!bl->isDecisionOut(i)) continue;
// if (clauseblock->isInteriorGotoTarget()) {
// bl->setGotoBranch(i);
// return true;
// }
if (i == 0) {
FlowBlock *otherblock = bl->getOut(1);
if (otherblock->sizeIn() == 1 &&
otherblock->sizeOut() == 0 &&
!otherblock->isSwitchOut() &&
bl->isDecisionOut(1)) {
// Both out edges go to "no exit" blocks
if (bl->negateCondition(true))
dataflow_changecount += 1;
graph.newBlockIfNoExit(bl,clauseblock,otherblock);
return true;
}
}
if (i==0) { // clause must be true out of bl
if (bl->negateCondition(true))
dataflow_changecount += 1;
@@ -2074,18 +2082,10 @@ bool ConditionalJoin::match(BlockBasic *b1,BlockBasic *b2)
exita = (BlockBasic *)block1->getOut(0);
exitb = (BlockBasic *)block1->getOut(1);
if (exita == exitb) return false;
if (block2->getOut(0) == exita) {
if (block2->getOut(1) != exitb) return false;
a_in2 = block2->getOutRevIndex(0);
b_in2 = block2->getOutRevIndex(1);
}
else if (block2->getOut(0) == exitb) {
if (block2->getOut(1) != exita) return false;
a_in2 = block2->getOutRevIndex(1);
b_in2 = block2->getOutRevIndex(0);
}
else
return false;
if (block2->getOut(0) != exita) return false; // False exits must match
if (block2->getOut(1) != exitb) return false; // True exits must match
a_in2 = block2->getOutRevIndex(0);
b_in2 = block2->getOutRevIndex(1);
a_in1 = block1->getOutRevIndex(0);
b_in1 = block1->getOutRevIndex(1);
@@ -2118,7 +2118,7 @@ void ConditionalJoin::clear(void)
int4 ActionStructureTransform::apply(Funcdata &data)
{
data.getStructure().finalTransform(data);
data.getStructure().finalTransform(data,allowOpMoves);
return 0;
}
@@ -2135,7 +2135,7 @@ int4 ActionNormalizeBranches::apply(Funcdata &data)
if (cbranch == (PcodeOp *)0) continue;
if (cbranch->code() != CPUI_CBRANCH) continue;
fliplist.clear();
if (Funcdata::opFlipInPlaceTest(cbranch,fliplist) != 0)
if (Funcdata::opFlipInPlaceTest(cbranch,fliplist,true) != 0)
continue;
data.opFlipInPlaceExecute(fliplist);
bb->flipInPlaceExecute();
@@ -2151,6 +2151,7 @@ int4 ActionPreferComplement::apply(Funcdata &data)
BlockGraph &graph(data.getStructure());
if (graph.getSize() == 0) return 0;
if (graph.hasFinalTransform()) return 0;
vector<BlockGraph *> vec;
vec.push_back(&graph);
int4 pos = 0;
@@ -2167,7 +2168,7 @@ int4 ActionPreferComplement::apply(Funcdata &data)
continue;
vec.push_back((BlockGraph *)childbl);
}
if (curbl->preferComplement(data))
if (curbl->preferComplement(data,allowOpMods))
count += 1;
}
data.clearDeadOps(); // Clear any ops deleted during this action
@@ -2224,9 +2225,9 @@ void ActionReturnSplit::gatherReturnGotos(FlowBlock *parent,vector<FlowBlock *>
if (((BlockGoto *)bl)->gotoPrints())
ret = ((BlockGoto *)bl)->getGotoTarget();
}
else if (bl->getType() == FlowBlock::t_if)
else if (bl->getType() == FlowBlock::t_ifgoto)
// if this is an ifgoto block, get target, otherwise null
ret = ((BlockIf *)bl)->getGotoTarget();
ret = ((BlockIfGoto *)bl)->getGotoTarget();
if (ret != (FlowBlock *)0) {
while(ret->getType() != FlowBlock::t_basic)
ret = ret->subBlock(0);
@@ -2325,7 +2326,7 @@ int4 ActionReturnSplit::apply(Funcdata &data)
count += 1;
#ifdef BLOCKCONSISTENT_DEBUG
if (!data.getBasicBlocks().isConsistent())
data.getArch()->printMessage("Block structure is not consistent");
data.getArch()->printWarning("Block structure is not consistent");
#endif
}
return 0;
@@ -268,11 +268,12 @@ public:
///
/// This is currently used to set up \e for loops via BlockWhileDo
class ActionStructureTransform : public Action {
bool allowOpMoves; ///< Are p-code ops allowed to be moved by \b this action
public:
ActionStructureTransform(const string &g) : Action(0,"structuretransform",g) {} ///< Constructor
ActionStructureTransform(const string &g,bool allowMoves) : Action(0,"structuretransform",g) { allowOpMoves = allowMoves; } ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionStructureTransform(getGroup());
return new ActionStructureTransform(getGroup(),allowOpMoves);
}
virtual int4 apply(Funcdata &data);
};
@@ -298,11 +299,12 @@ public:
/// This uses the preferComplement() method on structured FlowBlocks to choose between symmetric
/// structurings, such as an if/else where the \b true and \b false blocks can be swapped.
class ActionPreferComplement : public Action {
bool allowOpMods; ///< Are p-code ops allowed to be modified by \b this action
public:
ActionPreferComplement(const string &g) : Action(0,"prefercomplement",g) {} ///< Constructor
ActionPreferComplement(const string &g,bool allowMods) : Action(0,"prefercomplement",g) { allowOpMods = allowMods; } ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionPreferComplement(getGroup());
return new ActionPreferComplement(getGroup(),allowOpMods);
}
virtual int4 apply(Funcdata &data);
};
@@ -302,6 +302,8 @@ Datatype *CastStrategyC::castStandard(Datatype *reqtype,Datatype *curtype,
{ // Generic casting rules that apply for most ops
if (curtype == reqtype) return (Datatype *)0; // Types are equal, no cast required
if (curtype->getMetatype()==TYPE_VOID)
return reqtype; // If coming from "void" (as a dereferenced pointer) we need a cast
Datatype *reqbase = reqtype;
Datatype *curbase = curtype;
bool isptr = false;
@@ -325,8 +327,9 @@ Datatype *CastStrategyC::castStandard(Datatype *reqtype,Datatype *curtype,
while(curbase->getTypedef() != (Datatype *)0)
curbase = curbase->getTypedef();
if (curbase == reqbase) return (Datatype *)0; // Different typedefs could point to the same type
if ((reqbase->getMetatype()==TYPE_VOID)||(curtype->getMetatype()==TYPE_VOID))
return (Datatype *)0; // Don't cast from or to VOID
if (reqbase->getMetatype()==TYPE_VOID || curbase->getMetatype()==TYPE_VOID) {
return (Datatype *)0; // Don't cast to or from a void pointer
}
if (reqbase->getSize() != curbase->getSize()) {
if (reqbase->isVariableLength() && isptr && reqbase->hasSameVariableBase(curbase)) {
return (Datatype *)0; // Don't need a cast
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -280,9 +280,9 @@ bool CommentSorter::findPosition(Subsort &subsort,Comment *comm,const Funcdata *
// Try to find block containing comment
// Find op at lowest address greater or equal to comment's address
PcodeOpTree::const_iterator opiter = fd->beginOp(comm->getAddr());
PcodeOpTree::const_iterator opiter = fd->beginOpMain(comm->getAddr());
PcodeOp *backupOp = (PcodeOp *)0;
if (opiter != fd->endOpAll()) { // If there is an op at or after the comment
if (opiter != fd->endOpMain()) { // If there is an op at or after the comment
PcodeOp *op = (*opiter).second;
BlockBasic *block = op->getParent();
if (block == (BlockBasic *)0)
@@ -295,7 +295,7 @@ bool CommentSorter::findPosition(Subsort &subsort,Comment *comm,const Funcdata *
if (comm->getAddr() == op->getAddr())
backupOp = op;
}
if (opiter != fd->beginOpAll()) { // If there is a previous op
if (opiter != fd->beginOpMain()) { // If there is a previous op
--opiter;
PcodeOp *op = (*opiter).second;
BlockBasic *block = op->getParent();
@@ -313,7 +313,7 @@ bool CommentSorter::findPosition(Subsort &subsort,Comment *comm,const Funcdata *
subsort.setBlock(backupOp->getParent()->getIndex(),(uint4)backupOp->getSeqNum().getOrder());
return true;
}
if (fd->beginOpAll() == fd->endOpAll()) { // If there are no ops at all
if (fd->beginOpMain() == fd->endOpMain()) { // If there are no ops at all
subsort.setBlock(0,0); // Put comment at the beginning of the first block
return true;
}
@@ -17,22 +17,6 @@
namespace ghidra {
const int4 BooleanExpressionMatch::maxDepth = 1;
bool BooleanExpressionMatch::verifyCondition(PcodeOp *op, PcodeOp *iop)
{
int4 res = BooleanMatch::evaluate(op->getIn(1), iop->getIn(1), maxDepth);
if (res == BooleanMatch::uncorrelated)
return false;
matchflip = (res == BooleanMatch::complementary);
if (op->isBooleanFlip())
matchflip = !matchflip;
if (iop->isBooleanFlip())
matchflip = !matchflip;
return true;
}
/// \brief Calculate boolean array of all address spaces that have had a heritage pass run.
///
/// Used to test if all the links out of the iblock have been calculated.
@@ -106,14 +90,6 @@ bool ConditionalExecution::verifySameCondition(void)
if (tester.getFlip())
init2a_true = !init2a_true;
int4 multislot = tester.getMultiSlot();
if (multislot != -1) {
// This is a direct split
directsplit = true;
posta_outslot = (multislot == prea_inslot) ? 0 : 1;
if (init2a_true)
posta_outslot = 1 - posta_outslot;
}
return true;
}
@@ -126,15 +102,12 @@ bool ConditionalExecution::testMultiRead(Varnode *vn,PcodeOp *op)
{
if (op->getParent() == iblock) {
if (!directsplit) {
if (op->code() == CPUI_COPY) // The COPY is tested separately
return true; // If the COPY's output reads can be altered, then -vn- can be altered
return false;
}
if (op->code() == CPUI_COPY || op->code() == CPUI_SUBPIECE) // The copy-like tested separately
return true; // If the COPY's output reads can be altered, then -vn- can be altered
return false;
}
if (op->code() == CPUI_RETURN) {
if ((op->numInput() < 2)||(op->getIn(1) != vn)) return false; // Only test for flow thru to return value
returnop.push_back(op); // mark that CPUI_RETURN needs special handling
}
return true;
}
@@ -148,78 +121,72 @@ bool ConditionalExecution::testOpRead(Varnode *vn,PcodeOp *op)
{
if (op->getParent() == iblock) return true;
if ((op->code() == CPUI_RETURN)&&(!directsplit)) {
if ((op->numInput() < 2)||(op->getIn(1) != vn)) return false; // Only test for flow thru to return value
PcodeOp *copyop = vn->getDef();
if (copyop->code() == CPUI_COPY) {
// Ordinarily, if -vn- is produced by a COPY we want to return false here because the propagation
// hasn't had time to happen here. But if the flow is into a RETURN this can't propagate, so
// we allow this as a read that can be altered. (We have to move the COPY)
Varnode *invn = copyop->getIn(0);
if (!invn->isWritten()) return false;
PcodeOp *writeOp = vn->getDef();
OpCode opc = writeOp->code();
if (opc == CPUI_COPY || opc == CPUI_SUBPIECE || opc == CPUI_INT_ADD || opc == CPUI_PTRSUB) {
if (opc == CPUI_INT_ADD || opc == CPUI_PTRSUB) {
if (!writeOp->getIn(1)->isConstant())
return false;
}
Varnode *invn = writeOp->getIn(0);
if (invn->isWritten()) {
PcodeOp *upop = invn->getDef();
if ((upop->getParent() == iblock)&&(upop->code() != CPUI_MULTIEQUAL))
return false;
returnop.push_back(op);
return true;
}
else if (invn->isFree())
return false;
return true;
}
return false;
}
/// \brief Prebuild a replacement MULTIEQUAL for output Varnode of the given PcodeOp in \b posta_block
///
/// The new op will hold the same data-flow as the original Varnode once a new
/// edge into \b posta_block is created.
/// \param op is the given PcodeOp
void ConditionalExecution::predefineDirectMulti(PcodeOp *op)
/// \param inbranch is the iblock incoming branch to pullback through
/// \return the output of the previous pullback op, or null
Varnode *ConditionalExecution::findPullback(int4 inbranch)
{
PcodeOp *newop = fd->newOp(posta_block->sizeIn()+1,posta_block->getStart());
Varnode *outvn = op->getOut();
Varnode *newoutvn;
newoutvn = fd->newVarnodeOut(outvn->getSize(),outvn->getAddr(),newop);
fd->opSetOpcode(newop,CPUI_MULTIEQUAL);
Varnode *vn;
int4 inslot = iblock->getOutRevIndex(posta_outslot);
for(int4 i=0;i<posta_block->sizeIn();++i) {
if (i==inslot)
vn = op->getIn(1-camethruposta_slot);
else
vn = newoutvn;
fd->opSetInput(newop,vn,i);
}
fd->opSetInput(newop,op->getIn(camethruposta_slot),posta_block->sizeIn());
fd->opInsertBegin(newop,posta_block);
// Cache this new data flow holder
replacement[posta_block->getIndex()] = newoutvn;
while(pullback.size() <= inbranch)
pullback.push_back((Varnode *)0);
return pullback[inbranch];
}
/// In the \e direct \e split case, MULTIEQUALs in the body block (\b posta_block)
/// must update their flow to account for \b iblock being removed and a new
/// block flowing into the body block.
void ConditionalExecution::adjustDirectMulti(void)
/// Create a duplicate PcodeOp outside the iblock. The first input to the PcodeOp can
/// be defined by a MULTIEQUAL in the iblock, in which case the duplicate's input will be
/// selected from the MULTIEQUAL input. Any other inputs must be constants.
/// \param op is the PcodeOp in the iblock being replaced
/// \param inbranch is the direction to pullback from
/// \return the output Varnode of the new op
Varnode *ConditionalExecution::pullbackOp(PcodeOp *op,int4 inbranch)
{
list<PcodeOp *>::const_iterator iter;
PcodeOp *op;
iter = posta_block->beginOp();
int4 inslot = iblock->getOutRevIndex(posta_outslot);
while(iter != posta_block->endOp()) {
op = *iter++;
if (op->code() != CPUI_MULTIEQUAL) continue;
Varnode *vn = op->getIn(inslot);
if (vn->isWritten()&&(vn->getDef()->getParent() == iblock)) {
if (vn->getDef()->code() != CPUI_MULTIEQUAL)
throw LowlevelError("Cannot push non-trivial operation");
// Flow that stays in iblock, comes from modified side
fd->opSetInput(op,vn->getDef()->getIn(1-camethruposta_slot),inslot);
// Flow from unmodified side, forms new branch
vn = vn->getDef()->getIn(camethruposta_slot);
Varnode *invn = findPullback(inbranch); // Look for pullback constructed for a previous read
if (invn != (Varnode *)0)
return invn;
invn = op->getIn(0);
BlockBasic *bl;
if (invn->isWritten()) {
PcodeOp *defOp = invn->getDef();
if (defOp->getParent() == iblock) {
bl = (BlockBasic *)iblock->getIn(inbranch);
invn = defOp->getIn(inbranch); // defOp must by MULTIEQUAL
}
fd->opInsertInput(op,vn,op->numInput());
else
bl = (BlockBasic *)iblock->getImmedDom();
}
else {
bl = (BlockBasic *)iblock->getImmedDom();
}
PcodeOp *newOp = fd->newOp(op->numInput(),op->getAddr());
Varnode *origOutVn = op->getOut();
Varnode *outVn = fd->newVarnodeOut(origOutVn->getSize(),origOutVn->getAddr(),newOp);
fd->opSetOpcode(newOp,op->code());
fd->opSetInput(newOp,invn,0);
for(int4 i=1;i<op->numInput();++i)
fd->opSetInput(newOp,op->getIn(i),i);
fd->opInsertEnd(newOp, bl);
pullback[inbranch] = outVn; // Cache pullback in case there are other reads
return outVn;
}
/// \brief Create a MULTIEQUAL in the given block that will hold data-flow from the given PcodeOp
@@ -249,6 +216,68 @@ Varnode *ConditionalExecution::getNewMulti(PcodeOp *op,BlockBasic *bl)
return newoutvn;
}
/// Given an op in the \b iblock and the basic block of another op that reads the output Varnode,
/// calculate the replacement Varnode for the read.
/// \param op is the given op in the \b iblock
/// \param bl is the basic block of the read
/// \return the replacement Varnode
Varnode *ConditionalExecution::resolveRead(PcodeOp *op,BlockBasic *bl)
{
Varnode *res;
if (bl->sizeIn()==1) {
// Since dominator is iblock, In(0) must be iblock
// Figure what side of -iblock- we came through
int4 slot = (bl->getInRevIndex(0) == posta_outslot) ? camethruposta_slot : 1-camethruposta_slot;
res = resolveIblockRead(op,slot);
}
else
res = getNewMulti(op,bl);
return res;
}
/// \param op is the \b iblock op whose output is being read
/// \param inbranch is the known direction of the reading op
/// \return the replacement Varnode to use for the read
Varnode *ConditionalExecution::resolveIblockRead(PcodeOp *op,int4 inbranch)
{
if (op->code() == CPUI_COPY) {
Varnode *vn = op->getIn(0);
if (!vn->isWritten())
return vn;
PcodeOp *defOp = vn->getDef();
if (defOp->code() == CPUI_MULTIEQUAL && defOp->getParent() == iblock)
op = defOp;
else
return vn; // We know defOp is not in iblock
}
OpCode opc = op->code();
if (opc == CPUI_MULTIEQUAL)
return op->getIn(inbranch);
else if (opc == CPUI_SUBPIECE || opc == CPUI_INT_ADD || opc == CPUI_PTRSUB) {
return pullbackOp(op, inbranch);
}
throw LowlevelError("Conditional execution: Illegal op in iblock");
}
/// \brief Get the replacement Varnode for the output of a MULTIEQUAL in the \b iblock, given the op reading it
///
/// \param op is the MULTIEQUAL from \b iblock
/// \param readop is the PcodeOp reading the output Varnode
/// \param slot is the input slot being read
/// \return the Varnode to use as a replacement
Varnode *ConditionalExecution::getMultiequalRead(PcodeOp *op,PcodeOp *readop,int4 slot)
{
BlockBasic *bl = readop->getParent();
BlockBasic *inbl = (BlockBasic *)bl->getIn(slot);
if (inbl != iblock)
return getReplacementRead(op, inbl);
int4 s = (bl->getInRevIndex(slot) == posta_outslot) ? camethruposta_slot : 1-camethruposta_slot;
return resolveIblockRead(op,s);
}
/// \brief Find a replacement Varnode for the output of the given PcodeOp that is read in the given block
///
/// The replacement Varnode must be valid for everything below (dominated) by the block.
@@ -278,15 +307,7 @@ Varnode *ConditionalExecution::getReplacementRead(PcodeOp *op,BlockBasic *bl)
replacement[bl->getIndex()] = (*iter).second;
return (*iter).second;
}
Varnode *res;
if (curbl->sizeIn()==1) {
// Since dominator is iblock, In(0) must be iblock
// Figure what side of -iblock- we came through
int4 slot = (curbl->getInRevIndex(0) == posta_outslot) ? camethruposta_slot : 1-camethruposta_slot;
res = op->getIn(slot);
}
else
res = getNewMulti(op,curbl);
Varnode *res = resolveRead(op,curbl);
replacement[curbl->getIndex()] = res;
if (curbl != bl)
replacement[bl->getIndex()] = res;
@@ -299,14 +320,8 @@ Varnode *ConditionalExecution::getReplacementRead(PcodeOp *op,BlockBasic *bl)
void ConditionalExecution::doReplacement(PcodeOp *op)
{
if (op->code() == CPUI_COPY) {
if (op->getOut()->hasNoDescend()) // Verify that this has been dealt with by fixReturnOp
return;
// It could be a COPY internal to iblock, we need to remove it like any other op
}
replacement.clear();
if (directsplit)
predefineDirectMulti(op);
pullback.clear();
Varnode *vn = op->getOut();
list<PcodeOp *>::const_iterator iter = vn->beginDescend();
while(iter != vn->endDescend()) {
@@ -315,20 +330,21 @@ void ConditionalExecution::doReplacement(PcodeOp *op)
BlockBasic *bl = readop->getParent();
Varnode *rvn;
if (bl == iblock) {
if (directsplit)
fd->opSetInput(readop,op->getIn(1-camethruposta_slot),slot); // We know op is MULTIEQUAL
else
fd->opUnsetInput(readop,slot);
fd->opUnsetInput(readop,slot);
}
else {
if (readop->code() == CPUI_MULTIEQUAL) {
BlockBasic *inbl = (BlockBasic *)bl->getIn(slot);
if (inbl == iblock) {
int4 s = (bl->getInRevIndex(slot) == posta_outslot) ? camethruposta_slot : 1-camethruposta_slot;
rvn = op->getIn(s);
}
else
rvn = getReplacementRead(op,inbl);
rvn = getMultiequalRead(op, readop, slot);
}
else if (readop->code() == CPUI_RETURN && slot > 0) { // Cannot replace input of RETURN directly, create COPY to hold input
PcodeOp *newcopyop = fd->newOp(1,readop->getAddr());
fd->opSetOpcode(newcopyop,CPUI_COPY);
Varnode *outvn = fd->newVarnodeOut(vn->getSize(),vn->getAddr(),newcopyop); // Preserve the Varnode's storage address
fd->opSetInput(readop,outvn,slot);
fd->opInsertBefore(newcopyop,readop);
readop = newcopyop;
slot = 0;
rvn = getReplacementRead(op,bl); // COPY gets the replacement read
}
else
rvn = getReplacementRead(op,bl);
@@ -339,28 +355,6 @@ void ConditionalExecution::doReplacement(PcodeOp *op)
}
}
/// \brief Reproduce COPY data-flow into RETURN ops affected by the removal of \b iblock
void ConditionalExecution::fixReturnOp(void)
{
for(int4 i=0;i<returnop.size();++i) {
PcodeOp *retop = returnop[i];
Varnode *retvn = retop->getIn(1);
PcodeOp *iblockop = retvn->getDef();
Varnode *invn;
if (iblockop->code() == CPUI_COPY)
invn = iblockop->getIn(0); // This must either be from MULTIEQUAL or something written outside of iblock
else
invn = retvn;
PcodeOp *newcopyop = fd->newOp(1,retop->getAddr());
fd->opSetOpcode(newcopyop,CPUI_COPY);
Varnode *outvn = fd->newVarnodeOut(retvn->getSize(),retvn->getAddr(),newcopyop); // Preserve the CPUI_RETURN storage address
fd->opSetInput(newcopyop,invn,0);
fd->opSetInput(retop,outvn,1);
fd->opInsertBefore(newcopyop,retop);
}
}
/// \param op is the PcodeOp within \b iblock to test
/// \return \b true if it is removable
bool ConditionalExecution::testRemovability(PcodeOp *op)
@@ -385,6 +379,7 @@ bool ConditionalExecution::testRemovability(PcodeOp *op)
if (op->code()==CPUI_INDIRECT) return false;
vn = op->getOut();
if (vn->isAddrTied()) return false;
if (vn != (Varnode *)0) {
bool hasnodescend = true;
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
@@ -408,7 +403,6 @@ bool ConditionalExecution::verify(void)
{
prea_inslot = 0;
posta_outslot = 0;
directsplit = false;
if (!testIBlock()) return false;
if (!findInitPre()) return false;
@@ -420,7 +414,6 @@ bool ConditionalExecution::verify(void)
posta_block = (BlockBasic *)iblock->getOut(posta_outslot);
postb_block = (BlockBasic *)iblock->getOut(1-posta_outslot);
returnop.clear();
list<PcodeOp *>::const_iterator iter;
iter = iblock->endOp();
if (iter != iblock->beginOp())
@@ -456,50 +449,7 @@ bool ConditionalExecution::trial(BlockBasic *ib)
{
iblock = ib;
if (!verify()) return false;
PcodeOp *cbranch_copy;
BlockBasic *initblock_copy;
BlockBasic *iblock_copy;
int4 prea_inslot_copy;
bool init2a_true_copy;
bool iblock2posta_true_copy;
int4 camethruposta_slot_copy;
int4 posta_outslot_copy;
BlockBasic *posta_block_copy;
BlockBasic *postb_block_copy;
bool directsplit_copy;
for(;;) {
if (!directsplit) return true;
// Save off the data for current iblock
cbranch_copy = cbranch;
initblock_copy = initblock;
iblock_copy = iblock;
prea_inslot_copy = prea_inslot;
init2a_true_copy = init2a_true;
iblock2posta_true_copy = iblock2posta_true;
camethruposta_slot_copy = camethruposta_slot;
posta_outslot_copy = posta_outslot;
posta_block_copy = posta_block;
postb_block_copy = postb_block;
directsplit_copy = directsplit;
iblock = posta_block;
if (!verify()) {
cbranch = cbranch_copy;
initblock = initblock_copy;
iblock = iblock_copy;
prea_inslot = prea_inslot_copy;
init2a_true = init2a_true_copy;
iblock2posta_true = iblock2posta_true_copy;
camethruposta_slot = camethruposta_slot_copy;
posta_outslot = posta_outslot_copy;
posta_block = posta_block_copy;
postb_block = postb_block_copy;
directsplit = directsplit_copy;
return true;
}
}
return true;
}
/// We assume the last call to verify() returned \b true
@@ -508,31 +458,20 @@ void ConditionalExecution::execute(void)
{
list<PcodeOp *>::iterator iter;
PcodeOp *op;
bool notdone;
fixReturnOp(); // Patch any data-flow thru to CPUI_RETURN
if (!directsplit) {
iter = iblock->beginOp();
while(iter != iblock->endOp()) {
op = *iter++;
if (!op->isBranch())
doReplacement(op); // Remove all read refs of op
fd->opDestroy(op); // Then destroy op
}
fd->removeFromFlowSplit(iblock,(posta_outslot != camethruposta_slot));
}
else {
adjustDirectMulti();
iter = iblock->beginOp();
while(iter != iblock->endOp()) {
op = *iter++;
if (op->code() == CPUI_MULTIEQUAL) { // Only adjust MULTIEQUALs
doReplacement(op);
fd->opDestroy(op);
}
// Branch stays, other operations stay
}
fd->switchEdge(iblock->getIn(camethruposta_slot),iblock,posta_block);
}
iter = iblock->endOp(); // Remove ops in reverse order
--iter;
do {
op = *iter;
notdone = iter != iblock->beginOp();
if (notdone)
--iter;
if (!op->isBranch())
doReplacement(op); // Remove all read refs of op
fd->opDestroy(op); // Then destroy op
} while(notdone);
fd->removeFromFlowSplit(iblock,(posta_outslot != camethruposta_slot));
}
int4 ActionConditionalExe::apply(Funcdata &data)
@@ -22,19 +22,6 @@
namespace ghidra {
/// \brief A helper class for describing the similarity of the boolean condition between 2 CBRANCH operations
///
/// This class determines if two CBRANCHs share the same condition. It also determines if the conditions
/// are complements of each other, and/or they are shared along only one path.
class BooleanExpressionMatch {
static const int4 maxDepth; ///< Maximum depth to trace a boolean expression
bool matchflip; ///< True if the compared CBRANCH keys on the opposite boolean value of the root
public:
bool verifyCondition(PcodeOp *op, PcodeOp *iop); ///< Perform the correlation test on two CBRANCH operations
int4 getMultiSlot(void) const { return -1; } ///< Get the MULTIEQUAL slot in the critical path
bool getFlip(void) const { return matchflip; } ///< Return \b true if the expressions are anti-correlated
};
/// \brief A class for simplifying a series of conditionally executed statements.
///
/// This class tries to perform transformations like the following:
@@ -113,9 +100,8 @@ class ConditionalExecution {
int4 posta_outslot; ///< The \b out edge from iblock to posta
BlockBasic *posta_block; ///< First block in posta path
BlockBasic *postb_block; ///< First block in postb path
bool directsplit; ///< True if this the \e direct \e split variation
map<int4,Varnode *> replacement; ///< Map from block to replacement Varnode for (current) Varnode
vector<PcodeOp *> returnop; ///< RETURN ops that have flow coming out of the iblock
vector<Varnode *> pullback; ///< Outputs of ops that have been pulled back from \b iblock for (current) Varnode
vector<bool> heritageyes; ///< Boolean array indexed by address space indicating whether the space is heritaged
void buildHeritageArray(void);
@@ -123,14 +109,16 @@ class ConditionalExecution {
bool findInitPre(void); ///< Find \b initblock, based on \b iblock
bool verifySameCondition(void); ///< Verify that \b initblock and \b iblock branch on the same condition
bool testOpRead(Varnode *vn,PcodeOp *op); ///< Can we move the (non MULTIEQUAL) defining p-code of the given Varnode
bool testMultiRead(Varnode *vn,PcodeOp *op); ///< Can we mave the MULTIEQUAL defining p-code of the given Varnode
bool testMultiRead(Varnode *vn,PcodeOp *op); ///< Can we move the MULTIEQUAL defining p-code of the given Varnode
bool testRemovability(PcodeOp *op); ///< Test if the given PcodeOp can be removed from \b iblock
void predefineDirectMulti(PcodeOp *op);
void adjustDirectMulti(void); ///< Update inputs to any MULTIEQUAL in the direct block
Varnode *findPullback(int4 inbranch); ///< Find previously constructed pull-back op
Varnode *pullbackOp(PcodeOp *op,int4 inbranch); ///< Pull-back PcodeOp out of the iblock
Varnode *getNewMulti(PcodeOp *op,BlockBasic *bl);
Varnode *resolveRead(PcodeOp *op,BlockBasic *bl); ///< Resolve a read op coming through an arbitrary block
Varnode *resolveIblockRead(PcodeOp *op,int4 inbranch); ///< Resolve a read op coming through the \b iblock
Varnode *getMultiequalRead(PcodeOp *op,PcodeOp *readop,int4 slot);
Varnode *getReplacementRead(PcodeOp *op,BlockBasic *bl);
void doReplacement(PcodeOp *op); ///< Replace the data-flow for the given PcodeOp in \b iblock
void fixReturnOp(void);
bool verify(void); ///< Verify that we have a removable \b iblock
public:
ConditionalExecution(Funcdata *f); ///< Constructor
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -101,7 +101,7 @@ void IfcLoadFile::execute(istream &s)
return;
}
if (capa->getName() == "xml") // If file is xml
dcp->conf->readLoaderSymbols("::"); // Read in loader symbols
dcp->conf->readLoaderSymbols(); // Read in loader symbols
#ifdef OPACTION_DEBUG
dcp->conf->setDebugStream(status->fileoptr);
#endif
@@ -206,43 +206,38 @@ int main(int argc,char **argv)
startDecompilerLibrary(ghidraroot.c_str(), extrapaths);
}
IfaceStatus *status;
int4 retval = 2;
try {
status = new IfaceTerm("[decomp]> ",cin,cout); // Set up interface
} catch(IfaceError &err) {
cerr << "Interface error during setup: " << err.explain << endl;
exit(1);
}
IfaceCapability::registerAllCommands(status); // Register commands for decompiler and all modules
unique_ptr<IfaceStatus> status(new IfaceTerm("[decomp]> ",cin,cout)); // Set up interface
IfaceCapability::registerAllCommands(status.get()); // Register commands for decompiler and all modules
// Extra commands specific to the console application
status->registerCom(new IfcLoadFile(),"load","file");
status->registerCom(new IfcAddpath(),"addpath");
status->registerCom(new IfcSave(),"save");
status->registerCom(new IfcRestore(),"restore");
// Extra commands specific to the console application
status->registerCom(new IfcLoadFile(),"load","file");
status->registerCom(new IfcAddpath(),"addpath");
status->registerCom(new IfcSave(),"save");
status->registerCom(new IfcRestore(),"restore");
if (initscript != (const char *)0) {
try {
status->pushScript(initscript,"init> ");
} catch(IfaceParseError &err) {
*status->optr << err.explain << endl;
status->done = true;
if (initscript != (const char *)0) {
try {
status->pushScript(initscript,"init> ");
} catch(IfaceParseError &err) {
*status->optr << err.explain << endl;
status->done = true;
}
}
}
if (!status->done)
mainloop(status);
int4 retval = status->isInError() ? 1 : 0;
if (!status->done)
mainloop(status.get());
retval = status->isInError() ? 1 : 0;
#ifdef CPUI_STATISTICS
IfaceDecompData *decompdata = (IfaceDecompData *)status->getData("decompile");
decompdata->conf->stats->printResults(cout);
IfaceDecompData *decompdata = (IfaceDecompData *)status->getData("decompile");
decompdata->conf->stats->printResults(cout);
#endif
try {
delete status;
} catch(IfaceError &err) {
cerr << err.explain << endl;
cerr << "Interface error: " << err.explain << endl;
retval = 2;
}
shutdownDecompilerLibrary();
@@ -185,7 +185,7 @@ uint4 ArraySequence::selectStringCopyFunction(int4 &index)
/// \param ent is the given Symbol
/// \param root is the COPY holding the constant
/// \param addr is the Address being COPYed into
StringSequence::StringSequence(Funcdata &fdata,Datatype *ct,SymbolEntry *ent,PcodeOp *root,const Address &addr)
StringSequence::StringSequence(Funcdata &fdata,Datatype *ct,MapEntry *ent,PcodeOp *root,const Address &addr)
: ArraySequence(fdata,ct,root)
{
rootAddr = addr;
@@ -205,7 +205,13 @@ StringSequence::StringSequence(Funcdata &fdata,Datatype *ct,SymbolEntry *ent,Pco
break;
arrayType = parentType;
lastOff = off;
parentType = parentType->getSubType(off, &off);
if (parentType->needsResolution()) {
const TypeField *field = parentType->resolveTruncation(off, root, -1, off); // Resolve thru the specific COPY
if (field == (const TypeField *)0) break;
parentType = field->type;
}
else
parentType = parentType->getSubType(off, &off);
} while(parentType != (Datatype *)0);
if (parentType != ct || arrayType == (Datatype *)0 || arrayType->getMetatype() != TYPE_ARRAY)
return;
@@ -296,8 +302,20 @@ Varnode *StringSequence::constructTypedPointer(PcodeOp *insertPoint)
if (baseType->getMetatype() == TYPE_ARRAY)
elSize = ((TypeArray *)baseType)->getBase()->getAlignSize();
int8 newOff;
baseType = baseType->getSubType(curOff, &newOff );
if (baseType == (Datatype *)0) break;
if (baseType->needsResolution()) {
const TypeField *field = baseType->resolveTruncation(curOff, insertPoint, -1, newOff);
if (field != (const TypeField *)0) {
baseType = field->type;
curOff = newOff;
continue; // Do not create PTRSUB for union resolution here
}
else
break;
}
else {
baseType = baseType->getSubType(curOff, &newOff );
if (baseType == (Datatype *)0) break;
}
curOff -= newOff;
baseOff = AddrSpace::byteToAddress(curOff, spc->getWordSize());
if (elSize >= 0) {
@@ -318,6 +336,8 @@ Varnode *StringSequence::constructTypedPointer(PcodeOp *insertPoint)
data.opSetInput(ptrsub,data.newConstant(spacePtr->getSize(), baseOff), 1);
}
data.opSetInput(ptrsub,spacePtr,0);
if (curType->needsResolution())
data.inheritUnionFieldPtr(curType, ptrsub, 0, insertPoint, -1);
spacePtr = data.newUniqueOut(spacePtr->getSize(), ptrsub);
data.opInsertBefore(ptrsub, insertPoint);
curType = types->getTypePointerStripArray(spacePtr->getSize(), baseType, spc->getWordSize());
@@ -364,6 +384,8 @@ PcodeOp *StringSequence::buildStringCopy(void)
Varnode *destPtr = constructTypedPointer(insertPoint);
data.opSetInput(copyOp, destPtr, 1);
data.opSetInput(copyOp, srcPtr, 2);
if (destPtr->getType()->needsResolution())
data.inheritUnionFieldPtr(destPtr->getType(), copyOp, 1, insertPoint, -1);
Varnode *lenVn = data.newConstant(4,index);
lenVn->updateType(copyOp->inputTypeLocal(3));
data.opSetInput(copyOp, lenVn, 3);
@@ -431,10 +453,8 @@ void StringSequence::removeCopyOps(PcodeOp *replaceOp)
Varnode *vn = op->getIn((*iter).slot);
if (vn->getDef()->code() != CPUI_INDIRECT) {
Varnode *newIn = data.newConstant(vn->getSize(),0);
PcodeOp *indOp = data.newOp(2, replaceOp->getAddr());
data.opSetOpcode(indOp,CPUI_INDIRECT);
PcodeOp *indOp = data.newIndirect(replaceOp);
data.opSetInput(indOp,newIn,0);
data.opSetInput(indOp,data.newVarnodeIop(replaceOp),1);
data.opSetOutput(indOp, vn);
data.markIndirectCreation(indOp, false);
data.opInsertBefore(indOp,replaceOp);
@@ -460,12 +480,12 @@ bool StringSequence::transform(void)
return true;
}
/// From a starting pointer, backtrack through PTRADDs and COPYs to a putative root Varnode pointer.
/// \param initPtr is pointer Varnode into the root STORE
void HeapSequence::findBasePointer(Varnode *initPtr)
/// From a starting pointer to \b rootOp, backtrack through PTRADDs and COPYs to a putative root Varnode pointer.
void HeapSequence::findBasePointer(void)
{
basePointer = initPtr;
basePointer = rootOp->getIn(1);
immedRead = rootOp;
while(basePointer->isWritten()) {
PcodeOp *op = basePointer->getDef();
OpCode opc = op->code();
@@ -476,6 +496,7 @@ void HeapSequence::findBasePointer(Varnode *initPtr)
else if (opc != CPUI_COPY)
break;
basePointer = op->getIn(0);
immedRead = op;
}
}
@@ -507,7 +528,7 @@ void HeapSequence::findDuplicateBases(vector<Varnode *> &duplist)
if (!copyRoot->isWritten()) break;
op = copyRoot->getDef();
opc = op->code();
if (opc != CPUI_PTRSUB && opc != CPUI_INT_ADD && opc != CPUI_PTRSUB)
if (opc != CPUI_PTRSUB && opc != CPUI_INT_ADD && opc != CPUI_PTRADD)
break;
} while(op->getIn(1)->isConstant());
@@ -523,7 +544,7 @@ void HeapSequence::findDuplicateBases(vector<Varnode *> &duplist)
op = *iter;
++iter;
opc = op->code();
if (opc != CPUI_PTRSUB && opc != CPUI_INT_ADD && opc != CPUI_PTRSUB)
if (opc != CPUI_PTRSUB && opc != CPUI_INT_ADD && opc != CPUI_PTRADD)
continue;
if (op->getIn(0) != vn || !op->getIn(1)->isConstant())
continue;
@@ -745,6 +766,8 @@ PcodeOp *HeapSequence::buildStringCopy(void)
data.opSetInput(ptrAdd,data.newConstant(basePointer->getSize(), charType->getAlignSize()),2);
destPtr->updateType(charPtrType);
data.opInsertBefore(ptrAdd, insertPoint);
if (basePointer->getType()->needsResolution())
data.inheritUnionField(basePointer->getType(), ptrAdd, 0, immedRead, immedRead->getSlot(basePointer));
}
int4 index;
uint4 builtInId = selectStringCopyFunction(index);
@@ -758,6 +781,8 @@ PcodeOp *HeapSequence::buildStringCopy(void)
lenVn->updateType(copyOp->inputTypeLocal(3));
data.opSetInput(copyOp, lenVn, 3);
data.opInsertBefore(copyOp, insertPoint);
if (destPtr->getType()->needsResolution())
data.inheritUnionField(destPtr->getType(), copyOp, 1, immedRead, immedRead->getSlot(destPtr));
return copyOp;
}
@@ -767,7 +792,7 @@ PcodeOp *HeapSequence::buildStringCopy(void)
/// the initial input and final output are gathered.
/// \param indirects will hold the INDIRECT ops attached to sequence STOREs
/// \param pairs will hold Varnode pairs where the first in the pair is the input and the second is the output
void HeapSequence::gatherIndirectPairs(vector<PcodeOp *> &indirects,vector<Varnode *> &pairs)
void HeapSequence::gatherIndirectPairs(vector<PcodeOp *> &indirects,vector<IndirectPair> &pairs)
{
for(int4 i=0;i<moveOps.size();++i) {
@@ -798,26 +823,83 @@ void HeapSequence::gatherIndirectPairs(vector<PcodeOp *> &indirects,vector<Varno
if (!defOp->isMark()) break;
invn = defOp->getIn(0);
}
pairs.push_back(invn);
pairs.push_back(outvn);
data.opUnsetOutput(op);
pairs.emplace_back(invn,outvn);
}
}
for(int4 i=0;i<indirects.size();++i)
indirects[i]->clearMark();
}
bool HeapSequence::IndirectPair::compareOutput(const IndirectPair *a,const IndirectPair *b)
{
Varnode *vn1 = a->outVn;
Varnode *vn2 = b->outVn;
if (vn1->getSpace() != vn2->getSpace())
return vn1->getSpace()->getIndex() < vn2->getSpace()->getIndex();
if (vn1->getOffset() != vn2->getOffset())
return vn1->getOffset() < vn2->getOffset();
if (vn1->getSize() != vn2->getSize())
return vn1->getSize() < vn2->getSize();
return false;
}
/// Its possible that INDIRECTs collected from different \e effect ops may share
/// the same output storage. Find any output Varnodes that share storage and
/// replace all their reads with a single representative Varnode.
/// \param pairs is the list of INDIRECT pairs
/// \return \b true if the deduplication succeeded
bool HeapSequence::deduplicatePairs(vector<IndirectPair> &pairs)
{
if (pairs.empty()) return true;
vector<IndirectPair *> copy(pairs.size(),(IndirectPair *)0);
for(int4 i=0;i<pairs.size();++i)
copy[i] = &pairs[i];
sort(copy.begin(),copy.end(),IndirectPair::compareOutput);
IndirectPair *head = copy[0];
int4 dupCount = 0;
for(int4 i=1;i<copy.size();++i) {
Varnode *vn = copy[i]->outVn;
int4 overlap = head->outVn->characterizeOverlap(*vn);
if (overlap == 1)
return false; // Partial overlap
if (overlap == 2) {
if (copy[i]->inVn != head->inVn) {
return false; // Same storage coming from different sources
}
copy[i]->markDuplicate();
dupCount += 1; // Found a duplicate, keep the same head for next iteration
}
else // No overlap, move to next headVn
head = copy[i];
}
if (dupCount > 0) {
head = copy[0];
for(int4 i=1;i<copy.size();++i) {
if (copy[i]->isDuplicate()) {
data.totalReplace(copy[i]->outVn, head->outVn);
}
else
head = copy[i];
}
}
return true;
}
/// If the STORE pointer no longer has any other uses, remove the PTRADD producing it, recursively,
/// up to the base pointer. INDIRECT ops surrounding any STORE that is removed are replaced with
/// INDIRECTs around the user-op replacing the STOREs.
/// \param indirects are the list of INDIRECTs cause by the STOREs
/// \param indirectPairs are the flow pairs across the STOREs that need to be preserved
/// \param replaceOp is the user-op replacement for the STOREs
void HeapSequence::removeStoreOps(PcodeOp *replaceOp)
void HeapSequence::removeStoreOps(vector<PcodeOp *> &indirects,vector<IndirectPair> &indirectPairs,PcodeOp *replaceOp)
{
vector<PcodeOp *> indirects;
vector<Varnode *> indirectPairs;
vector<PcodeOp *> scratch;
gatherIndirectPairs(indirects, indirectPairs);
for(int4 i=0;i<indirectPairs.size();++i) { // Unhook Varnodes we don't want destroyed
data.opUnsetOutput(indirectPairs[i].outVn->getDef());
}
for(int4 i=0;i<moveOps.size();++i) {
PcodeOp *op = moveOps[i].op;
data.opDestroyRecursive(op, scratch);
@@ -825,14 +907,11 @@ void HeapSequence::removeStoreOps(PcodeOp *replaceOp)
for(int4 i=0;i<indirects.size();++i) {
data.opDestroy(indirects[i]);
}
for(int4 i=0;i<indirectPairs.size();i+=2) {
Varnode *invn = indirectPairs[i];
Varnode *outvn = indirectPairs[i+1];
PcodeOp *newInd = data.newOp(2,replaceOp->getAddr());
data.opSetOpcode(newInd, CPUI_INDIRECT);
data.opSetOutput(newInd,outvn);
data.opSetInput(newInd,invn,0);
data.opSetInput(newInd,data.newVarnodeIop(replaceOp),1);
for(int4 i=0;i<indirectPairs.size();++i) {
if (indirectPairs[i].isDuplicate()) continue;
PcodeOp *newInd = data.newIndirect(replaceOp);
data.opSetOutput(newInd,indirectPairs[i].outVn);
data.opSetInput(newInd,indirectPairs[i].inVn,0);
data.opInsertBefore(newInd, replaceOp);
}
}
@@ -854,7 +933,7 @@ HeapSequence::HeapSequence(Funcdata &fdata,Datatype *ct,PcodeOp *root)
baseOffset = 0;
storeSpace = root->getIn(0)->getSpaceFromConst();
ptrAddMult = AddrSpace::byteToAddressInt(charType->getAlignSize(), storeSpace->getWordSize());
findBasePointer(rootOp->getIn(1));
findBasePointer();
if (!collectStoreOps())
return;
if (!checkInterference())
@@ -871,10 +950,15 @@ HeapSequence::HeapSequence(Funcdata &fdata,Datatype *ct,PcodeOp *root)
bool HeapSequence::transform(void)
{
vector<PcodeOp *> indirects;
vector<IndirectPair> indirectPairs;
gatherIndirectPairs(indirects, indirectPairs);
if (!deduplicatePairs(indirectPairs))
return false;
PcodeOp *memCpyOp = buildStringCopy();
if (memCpyOp == (PcodeOp *)0)
return false;
removeStoreOps(memCpyOp);
removeStoreOps(indirects,indirectPairs,memCpyOp);
return true;
}
@@ -895,12 +979,12 @@ int4 RuleStringCopy::applyOp(PcodeOp *op,Funcdata &data)
{
if (!op->getIn(0)->isConstant()) return 0; // Constant
Varnode *outvn = op->getOut();
Datatype *ct = outvn->getType();
Datatype *ct = outvn->getTypeDefFacing();
if (!ct->isCharPrint()) return 0; // Copied to a "char" data-type Varnode
if (ct->isOpaqueString()) return 0;
if (!outvn->isAddrTied()) return 0;
SymbolEntry *entry = data.getScopeLocal()->queryContainer(outvn->getAddr(), outvn->getSize(), op->getAddr());
if (entry == (SymbolEntry *)0)
MapEntry *entry = data.getScopeLocal()->queryContainer(outvn->getAddr(), outvn->getSize(), op->getAddr());
if (entry == (MapEntry *)0)
return 0;
StringSequence sequence(data,ct,entry,op,outvn->getAddr());
if (!sequence.isValid())
@@ -22,6 +22,8 @@
namespace ghidra {
class MapEntry;
/// \brief A sequence of PcodeOps that move data in-to/out-of an array data-type.
///
/// A container for a sequence of PcodeOps within a basic block where we are trying to determine if the sequence
@@ -66,7 +68,7 @@ public:
class StringSequence : public ArraySequence {
Address rootAddr; ///< Address within the memory region associated with the root PcodeOp
Address startAddr; ///< Starting address of the memory region
SymbolEntry *entry; ///< Symbol at the root Address
MapEntry *entry; ///< Symbol at the root Address
bool collectCopyOps(int size); ///< Collect ops COPYing constants into the memory region
PcodeOp *buildStringCopy(void); ///< Build the strncpy,wcsncpy, or memcpy function with string as input
static void removeForward(const WriteNode &curNode,map<PcodeOp *,list<WriteNode>::iterator> &xref,
@@ -74,7 +76,7 @@ class StringSequence : public ArraySequence {
void removeCopyOps(PcodeOp *replaceOp); ///< Remove all the COPY ops from the basic block
Varnode *constructTypedPointer(PcodeOp *insertPoint);
public:
StringSequence(Funcdata &fdata,Datatype *ct,SymbolEntry *ent,PcodeOp *root,const Address &addr);
StringSequence(Funcdata &fdata,Datatype *ct,MapEntry *ent,PcodeOp *root,const Address &addr);
bool transform(void); ///< Transform COPYs into a single memcpy user-op
};
@@ -84,12 +86,23 @@ public:
/// a single string into memory. If the transform() method is called, an explicit string is constructed, and
/// the STOREs are replaced with a \b strncpy or similar CALLOTHER that takes the string as its source input.
class HeapSequence : public ArraySequence {
/// \brief Helper class containing Varnode pairs that flow across a sequence of INDIRECTs
class IndirectPair {
public:
Varnode *inVn; ///< Input to INDIRECTs
Varnode *outVn; ///< Output of INDIRECTs
IndirectPair(Varnode *in,Varnode *out) { inVn = in; outVn = out; } ///< Constructor
void markDuplicate(void) { inVn = (Varnode *)0; } ///< Note that \b this is a duplicate of another pair
bool isDuplicate(void) const { return (inVn == (Varnode *)0); } ///< Return \b true if \b this is marked as a duplicate
static bool compareOutput(const IndirectPair *a,const IndirectPair *b); ///< Compare pairs by output storage
};
Varnode *basePointer; ///< Pointer that sequence is stored to
PcodeOp *immedRead; ///< Op immediately reading basePointer
uint8 baseOffset; ///< Offset relative to pointer to root STORE
AddrSpace *storeSpace; ///< Address space being STOREed to
int4 ptrAddMult; ///< Required multiplier for PTRADD ops
vector<Varnode *> nonConstAdds; ///< non-constant Varnodes being added into pointer calculation
void findBasePointer(Varnode *initPtr); ///< Find the base pointer for the sequence
void findBasePointer(void); ///< Find the base pointer for the sequence
void findDuplicateBases(vector<Varnode *> &duplist); ///< Find any duplicates of \b basePointer
void findInitialStores(vector<PcodeOp *> &stores);
static uint8 calcAddElements(Varnode *vn,vector<Varnode *> &nonConst,int4 maxDepth);
@@ -98,8 +111,9 @@ class HeapSequence : public ArraySequence {
bool testValue(PcodeOp *op); ///< Test if a STORE value has the matching form for the sequence
bool collectStoreOps(void); ///< Collect ops STOREing into a memory region from the same root pointer
PcodeOp *buildStringCopy(void); ///< Build the strncpy,wcsncpy, or memcpy function with string as input
void gatherIndirectPairs(vector<PcodeOp *> &indirects,vector<Varnode *> &pairs);
void removeStoreOps(PcodeOp *replaceOp); ///< Remove all STORE ops from the basic block
void gatherIndirectPairs(vector<PcodeOp *> &indirects,vector<IndirectPair> &pairs);
bool deduplicatePairs(vector<IndirectPair> &pairs); ///< Find and eliminate duplicate INDIRECT pairs
void removeStoreOps(vector<PcodeOp *> &indirects,vector<IndirectPair> &indirectPairs,PcodeOp *replaceOp); ///< Remove all STORE ops from the basic block
public:
HeapSequence(Funcdata &fdata,Datatype *ct,PcodeOp *root);
bool transform(void); ///< Transform STOREs into a single memcpy user-op
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -19,6 +19,39 @@
namespace ghidra {
ConstructState::ConstructState(void)
{
ct = (Constructor *)0;
resolve = (ConstructState **)0;
parent = (ConstructState *)0;
length = 0;
offset = 0;
}
/// The array holding pointers to child nodes is preallocated.
/// \param numOperands is maximum number of children this node can have
ConstructState::ConstructState(int4 numOperands)
{
ct = (Constructor *)0;
parent = (ConstructState *)0;
length = 0;
offset = 0;
resolve = new ConstructState *[numOperands];
for(int4 i=0;i<numOperands;++i)
resolve[i] = (ConstructState *)0;
}
ConstructState::~ConstructState(void)
{
if (resolve != (ConstructState **)0)
delete [] resolve;
}
/// \param ccache is the cache to use for formal context changes
/// \param trans is the parent parser
ParserContext::ParserContext(ContextCache *ccache,Translate *trans)
{
@@ -35,15 +68,25 @@ ParserContext::ParserContext(ContextCache *ccache,Translate *trans)
}
}
void ParserContext::initialize(int4 maxstate,int4 maxparam,AddrSpace *spc)
ParserContext::~ParserContext(void)
{
if (context != (uintm *)0)
delete [] context;
for(int4 i=0;i<state.size();++i)
delete state[i];
}
/// \param spc is the address space used for constants
/// \param maxstate is the number of nodes to allocate (initially)
void ParserContext::initialize(AddrSpace *spc,int4 maxstate)
{
const_space = spc;
state.resize(maxstate);
state[0].parent = (ConstructState *)0;
for(int4 i=0;i<maxstate;++i)
state[i].resolve.resize(maxparam);
base_state = &state[0];
state[i] = new ConstructState(MAX_OPERAND);
base_state = state[maxstate-1];
}
const Address &ParserContext::getN2addr(void) const
@@ -58,13 +101,17 @@ const Address &ParserContext::getN2addr(void) const
return n2addr;
}
/// Get bytes from the instruction stream into a packed value assuming a big endian encoding.
/// \param bytestart is the number of bytes to skip
/// \param size is the number of bytes to pack
/// \param off is the number of bytes in the instruction already read
/// \return the packed bytes from the instruction
uintm ParserContext::getInstructionBytes(int4 bytestart,int4 size,uint4 off) const
{ // Get bytes from the instruction stream into a intm
// (assuming big endian format)
{
off += bytestart;
if (off >=16)
throw BadDataError("Instruction is using more than 16 bytes");
if (off >= MAX_INSTRUCTION_LEN)
throw BadDataError("Instruction is using more than " + to_string(MAX_INSTRUCTION_LEN) + " bytes");
const uint1 *ptr = buf + off;
uintm res = 0;
for(int4 i=0;i<size;++i) {
@@ -74,12 +121,17 @@ uintm ParserContext::getInstructionBytes(int4 bytestart,int4 size,uint4 off) con
return res;
}
/// Get bits from the instruction stream assuming big endian encoding.
/// \param startbit is the offset of the first bit (within the instruction stream)
/// \param size is the number of bits to grab
/// \param off is the number of bytes in the instruction already read
/// \return the requested range of bits (in the least significant positions and padded out with zero bits)
uintm ParserContext::getInstructionBits(int4 startbit,int4 size,uint4 off) const
{
off += (startbit/8);
if (off >= 16)
throw BadDataError("Instruction is using more than 16 bytes");
if (off >= MAX_INSTRUCTION_LEN)
throw BadDataError("Instruction is using more than " + to_string(MAX_INSTRUCTION_LEN) + " bytes");
const uint1 *ptr = buf + off;
startbit = startbit % 8;
int4 bytesize = (startbit+size-1)/8 + 1;
@@ -93,9 +145,12 @@ uintm ParserContext::getInstructionBits(int4 startbit,int4 size,uint4 off) const
return res;
}
/// \param bytestart is the offset of the first byte to grab
/// \param size is the number of bytes to grab
/// \return the context bytes in a packed value
uintm ParserContext::getContextBytes(int4 bytestart,int4 size) const
{ // Get bytes from context into a uintm
{
int4 intstart = bytestart / sizeof(uintm);
uintm res = context[ intstart ];
int4 byteOffset = bytestart % sizeof(uintm);
@@ -112,6 +167,9 @@ uintm ParserContext::getContextBytes(int4 bytestart,int4 size) const
return res;
}
/// \param startbit is the offset of the first bit
/// \param size is the number of bits to return
/// \return the requested range of bits (in the least significant positions and padded out with zero bits)
uintm ParserContext::getContextBits(int4 startbit,int4 size) const
{
@@ -131,6 +189,11 @@ uintm ParserContext::getContextBits(int4 startbit,int4 size) const
return res;
}
/// \param sym is a symbol that resolves to the address where the setting takes effect
/// \param num is the index of the context word being affected
/// \param mask indicates the bits within the context word that are affected
/// \param flow is \b true if the context change \e flows forward from the point where it is set
/// \param point is the parse point where the change was made
void ParserContext::addCommit(TripleSymbol *sym,int4 num,uintm mask,bool flow,ConstructState *point)
{
@@ -206,9 +269,29 @@ bool ParserContext::applyCommits(vector<ContextTarget> &elsewhere)
return committed;
}
/// This can be called in the middle of a parse to accommodate larger constructor trees.
/// \param amount is the number of additional nodes to add
void ParserContext::expandState(int4 amount)
{
state.insert(state.begin(),amount,(ConstructState *)0);
for(int4 i=0;i<amount;++i)
state[i] = new ConstructState(MAX_OPERAND);
alloc += amount;
}
/// \brief Initialize \b this from another walker assuming a given constructor and operand is the current position in the walk
///
/// The constructor tree state is simulated using only a single provided node.
/// This allows TokenField to behave as if it were just parsed so its getValue() will return the correct value.
/// \param ct is the given constructor
/// \param index is the index of the operand
/// \param tempstate is provided storage used to simulate the mid-walk tree node
/// \param otherwalker is the walker with the complete parse state
void ParserWalker::setOutOfBandState(Constructor *ct,int4 index,ConstructState *tempstate,const ParserWalker &otherwalker)
{ // Initialize walker for future calls into getInstructionBytes assuming -ct- is the current position in the walk
{
const ConstructState *pt = otherwalker.point;
int4 curdepth = otherwalker.depth;
while(pt->ct != ct) {
@@ -235,17 +318,18 @@ void ParserWalker::setOutOfBandState(Constructor *ct,int4 index,ConstructState *
breadcrumb[0] = 0;
}
/// This assumes all the current nodes operands have been parsed into the tree.
/// \param length is the minimum length of the current constructor
/// \param numopers is the number of operands
void ParserWalkerChange::calcCurrentLength(int4 length,int4 numopers)
{ // Calculate the length of the current constructor
// state assuming all its operands are constructed
{
length += point->offset; // Convert relative length to absolute length
for(int4 i=0;i<numopers;++i) {
ConstructState *subpoint = point->resolve[i];
int4 sublength = subpoint->length + subpoint->offset;
// Since subpoint->offset is an absolute offset
// (relative to beginning of instruction) sublength
if (sublength > length) // is absolute and must be compared to absolute length
// Since subpoint->offset is an absolutee (relative to beginning of instruction)
if (sublength > length) // sublength is absolute and must be compared to absolute length
length = sublength;
}
point->length = length - point->offset; // Convert back to relative length
@@ -4,65 +4,82 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// \file context.hh
/// \brief Objects for describing the context around the parsing of an instruction by the SLEIGH engine
#ifndef __CONTEXT_HH__
#define __CONTEXT_HH__
#include "globalcontext.hh"
#include "opcodes.hh"
#include "translate.hh"
namespace ghidra {
class Token { // A multiple-byte sized chunk of pattern in a bitstream
string name;
int4 size; // Number of bytes in token;
int4 index; // Index of this token, for resolving offsets
bool bigendian;
/// \brief A multiple-byte sized chunk of pattern in the instruction byte stream
class Token {
string name; ///< Name of the token
int4 size; ///< Number of bytes in token
int4 index; ///< Index of \b this token, for resolving offsets
bool bigendian; ///< Set to \b true if encodings within \b this token are big endian
public:
Token(const string &nm,int4 sz,bool be,int4 ind) : name(nm) { size = sz; bigendian=be; index = ind; }
int4 getSize(void) const { return size; }
bool isBigEndian(void) const { return bigendian; }
int4 getIndex(void) const { return index; }
const string &getName(void) const { return name; }
Token(const string &nm,int4 sz,bool be,int4 ind) : name(nm) { size = sz; bigendian=be; index = ind; } ///< Constructor
int4 getSize(void) const { return size; } ///< Get the size in bytes
bool isBigEndian(void) const { return bigendian; } ///< Return \b true if encodings within \b this are big endian
int4 getIndex(void) const { return index; } ///< Get the index associated with \b this token
const string &getName(void) const { return name; } ///< Get the name of the token
};
struct FixedHandle { // A handle that is fully resolved
AddrSpace *space;
uint4 size;
AddrSpace *offset_space; // Either null or where dynamic offset is stored
uintb offset_offset; // Either static offset or ptr offset
uint4 offset_size; // Size of pointer
AddrSpace *temp_space; // Consistent temporary location for value
uintb temp_offset;
/// \brief A resolved version of (or pointer to) a SLEIGH defined Varnode
///
/// For a static Varnode, this is the triple (address space, offset, size) for the Varnode.
/// For a dynamic Varnode, this also encodes the pointer Varnode containing the dynamic offset
/// and a temporary storage location for the dereferenced value.
struct FixedHandle {
AddrSpace *space; ///< The address space of the Varnode
uint4 size; ///< Number of bytes in the Varnode
AddrSpace *offset_space; ///< Null \e or the space where the dynamic offset is stored
uintb offset_offset; ///< The offset for the static Varnode \e or the offset for the pointer
uint4 offset_size; ///< Size of pointer
AddrSpace *temp_space; ///< Address space for temporary location for value
uintb temp_offset; ///< Offset of the temporary location
};
class Constructor;
/// \brief A node in a tree of subconstructors
///
/// This knows its position in the tree (parent node, child nodes) and the underlying SLEIGH constructor that was matched.
/// Child nodes correspond to the operands for the specific constructor.
struct ConstructState {
Constructor *ct;
FixedHandle hand;
vector<ConstructState *> resolve;
ConstructState *parent;
int4 length; // Length of this instantiation of the constructor
uint4 offset; // Absolute offset (from start of instruction)
Constructor *ct; ///< The matched Constructor
FixedHandle hand; ///< Resolved Varnode associated with the Constructor
ConstructState **resolve; ///< An array of pointers to child nodes
ConstructState *parent; ///< Pointer to parent node
int4 length; ///< Length of this instantiation of the constructor
uint4 offset; ///< Absolute offset (from start of instruction)
ConstructState(void); ///< Construct a node with no children
ConstructState(int4 numOperands); ///< Construct a node with given number of possible children
~ConstructState(void); ///< Destructor
};
class TripleSymbol;
struct ContextSet { // Instructions for setting a global context value
TripleSymbol *sym; // Resolves to address where setting takes effect
ConstructState *point; // Point at which context set was made
int4 num; // Number of context word affected
uintm mask; // Bits within word affected
uintm value; // New setting for bits
bool flow; // Does the new context flow from its set point
/// \brief Command for globally setting a formal SLEIGH context value
struct ContextSet {
TripleSymbol *sym; ///< Symbol resolving to address where setting takes effect
ConstructState *point; ///< Point at which context set was made
int4 num; ///< Index of the specific context word affected
uintm mask; ///< Bits within word affected
uintm value; ///< New setting for bits
bool flow; ///< Does the new context flow from its set point
};
/// \brief A global context value committed at an address other than the instruction's fall-through
@@ -81,141 +98,209 @@ class ParserWalker; // Forward declaration
class ParserWalkerChange;
class Translate;
/// \brief Context maintained while parsing a single instruction
///
/// This contains:
/// - the bytes encoding the instruction
/// - the tree structure of the SLEIGH Constructors encountered while parsing the instruction
/// - any formal named SLEIGH context values referenced by the instruction
class ParserContext {
friend class ParserWalker;
friend class ParserWalkerChange;
public:
enum { // Possible states of the ParserContext
uninitialized = 0, // Instruction has not been parsed at all
disassembly = 1, // Instruction is parsed in preparation for disassembly
pcode = 2 // Instruction is parsed in preparation for generating p-code
static constexpr int4 MAX_DEPTH = 32; ///< Maximum subconstructor depth in a single instruction
static constexpr int4 MAX_OPERAND = 20; ///< Maximum operands for a single constructor
static constexpr int4 MAX_INSTRUCTION_LEN = 16; ///< Maximum number of bytes in a single instruction
static constexpr int4 INITIAL_STATE_NUM = 64; ///< Recommended number of initial states
static constexpr int4 STATE_GROWTH = 64; ///< Number of states to add for each expansion
/// \brief Possible states of the ParserContext
enum parse_state {
uninitialized = 0, ///< Instruction has not been parsed at all
disassembly = 1, ///< Instruction is parsed in preparation for disassembly
pcode = 2 ///< Instruction is parsed in preparation for generating p-code
};
private:
Translate *translate; // Instruction parser
int4 parsestate;
AddrSpace *const_space;
uint1 buf[16]; // Buffer of bytes in the instruction stream
uintm *context; // Pointer to local context
int4 contextsize; // Number of entries in context array
ContextCache *contcache; // Interface for getting/setting context
vector<ContextSet> contextcommit;
Address addr; // Address of start of instruction
Address naddr; // Address of next instruction
mutable Address n2addr; // Address of instruction after the next
Address calladdr; // For injections, this is the address of the call being overridden
vector<ConstructState> state; // Current resolved instruction
ConstructState *base_state;
int4 alloc; // Number of ConstructState's allocated
int4 delayslot; // delayslot depth
Translate *translate; ///< The parent instruction parser
parse_state parsestate; ///< Overall state of the parse
AddrSpace *const_space; ///< Address space for constants
uint1 buf[MAX_INSTRUCTION_LEN]; ///< Buffer of bytes in the instruction stream
uintm *context; ///< Pointer to local context
int4 contextsize; ///< Number of entries in local context array
ContextCache *contcache; ///< Interface for getting/setting context
vector<ContextSet> contextcommit; ///< Changes to SLEIGH context slated by this instruction
Address addr; ///< Address of start of instruction
Address naddr; ///< Address of next instruction
mutable Address n2addr; ///< Address of instruction after the next
Address calladdr; ///< For injections, this is the address of the call being overridden
vector<ConstructState *> state; ///< Available nodes for the constructor tree
ConstructState *base_state; ///< Root node of the constructor tree
int4 alloc; ///< Number of unallocated ConstructState nodes remaining
int4 delayslot; ///< delayslot depth
public:
ParserContext(ContextCache *ccache,Translate *trans);
~ParserContext(void) { if (context != (uintm *)0) delete [] context; }
uint1 *getBuffer(void) { return buf; }
void initialize(int4 maxstate,int4 maxparam,AddrSpace *spc);
int4 getParserState(void) const { return parsestate; }
void setParserState(int4 st) { parsestate = st; }
void deallocateState(ParserWalkerChange &walker);
void allocateOperand(int4 i,ParserWalkerChange &walker);
void setAddr(const Address &ad) { addr = ad; n2addr = Address(); }
void setNaddr(const Address &ad) { naddr = ad; }
void setCalladdr(const Address &ad) { calladdr = ad; }
void addCommit(TripleSymbol *sym,int4 num,uintm mask,bool flow,ConstructState *point);
void clearCommits(void) { contextcommit.clear(); }
bool applyCommits(vector<ContextTarget> &elsewhere); ///< Commit fall-through context changes (\b true if there were any)
const Address &getAddr(void) const { return addr; }
const Address &getNaddr(void) const { return naddr; }
const Address &getN2addr(void) const;
const Address &getDestAddr(void) const { return calladdr; }
const Address &getRefAddr(void) const { return calladdr; }
AddrSpace *getCurSpace(void) const { return addr.getSpace(); }
AddrSpace *getConstSpace(void) const { return const_space; }
uintm getInstructionBytes(int4 byteoff,int4 numbytes,uint4 off) const;
uintm getContextBytes(int4 byteoff,int4 numbytes) const;
uintm getInstructionBits(int4 startbit,int4 size,uint4 off) const;
uintm getContextBits(int4 startbit,int4 size) const;
void setContextWord(int4 i,uintm val,uintm mask) { context[i] = (context[i]&(~mask))|(mask&val); }
void loadContext(void) { contcache->getContext(addr,context); }
int4 getLength(void) const { return base_state->length; }
void setDelaySlot(int4 val) { delayslot = val; }
int4 getDelaySlot(void) const { return delayslot; }
ParserContext(ContextCache *ccache,Translate *trans); ///< Constructor
~ParserContext(void); ///< Destructor
uint1 *getBuffer(void) { return buf; } ///< Get bytes in the stream at the point this instruction is encoded
void initialize(AddrSpace *spc,int4 maxstate = INITIAL_STATE_NUM); ///< Preallocate nodes for constructor trees
parse_state getParserState(void) const { return parsestate; } ///< Get the overall state of the parse
void setParserState(parse_state st) { parsestate = st; } ///< Update the overall parse state
void deallocateState(ParserWalkerChange &walker); ///< Clear any existing constructor tree
void allocateOperand(int4 i,ParserWalkerChange &walker); ///< Allocate a new child node in the constructor tree
void setAddr(const Address &ad) { addr = ad; n2addr = Address(); } ///< Set the starting address of the instruction
void setNaddr(const Address &ad) { naddr = ad; } ///< Set the ending address of the instruction
void setCalladdr(const Address &ad) { calladdr = ad; } ///< Set the address of the call being overridden
void addCommit(TripleSymbol *sym,int4 num,uintm mask,bool flow,ConstructState *point); ///< Add a formal SLEIGH context change command
void clearCommits(void) { contextcommit.clear(); } ///< Clear all context commits
bool applyCommits(vector<ContextTarget> &elsewhere); ///< Commit fall-through context changes (\b true if there were any)
const Address &getAddr(void) const { return addr; } ///< Get the starting address of the current instruction
const Address &getNaddr(void) const { return naddr; } ///< Get the address of the next instruction
const Address &getN2addr(void) const; ///< Get the address of the instruction after the next
const Address &getDestAddr(void) const { return calladdr; } ///< Get the destination address (inst_dest) for the overriden call
const Address &getRefAddr(void) const { return calladdr; } ///< Get the reference address (inst_ref) for the p-code snippet
AddrSpace *getCurSpace(void) const { return addr.getSpace(); } ///< Get the address space of the current instruction
AddrSpace *getConstSpace(void) const { return const_space; } ///< Get the address space for constants
uintm getInstructionBytes(int4 byteoff,int4 numbytes,uint4 off) const; ///< Get the specified instruction bytes
uintm getContextBytes(int4 byteoff,int4 numbytes) const; ///< Get bytes from the local context
uintm getInstructionBits(int4 startbit,int4 size,uint4 off) const; ///< Get the specific range of bits from the instruction stream
uintm getContextBits(int4 startbit,int4 size) const; ///< Get the specific range of bits from the local context
void setContextWord(int4 i,uintm val,uintm mask) { context[i] = (context[i]&(~mask))|(mask&val); } ///< Modify a context word, using given mask and value
void loadContext(void) { contcache->getContext(addr,context); } ///< Pull context words associated with the starting address into the local array
int4 getLength(void) const { return base_state->length; } ///< Get the length of the current instruction
void setDelaySlot(int4 val) { delayslot = val; } ///< Set (the number of instruction bytes) in the delay slot
int4 getDelaySlot(void) const { return delayslot; } ///< Get the number of instruction bytes in the delay slot
void expandState(int4 amount); ///< Expand the number of available nodes for the constructor tree
};
class ParserWalker { // A class for walking the ParserContext
const ParserContext *const_context;
const ParserContext *cross_context;
/// \brief A class for walking the constructor tree (ParserContext)
class ParserWalker {
private:
const ParserContext *const_context; ///< Context for the main instruction parse
const ParserContext *cross_context; ///< Context for an additional instruction parse needed to resolve a \e crossbuild
protected:
ConstructState *point; // The current node being visited
int4 depth; // Depth of the current node
int4 breadcrumb[32]; // Path of operands from root
ConstructState *point; ///< The current node being visited
int4 depth; ///< Depth of the current node
int4 breadcrumb[ParserContext::MAX_DEPTH]; ///< Path of operands from root
public:
ParserWalker(const ParserContext *c) { const_context = c; cross_context = (const ParserContext *)0; }
ParserWalker(const ParserContext *c,const ParserContext *cross) { const_context = c; cross_context = cross; }
const ParserContext *getParserContext(void) const { return const_context; }
void baseState(void) { point = const_context->base_state; depth=0; breadcrumb[0] = 0; }
ParserWalker(const ParserContext *c) { const_context = c; cross_context = (const ParserContext *)0; } ///< Constructor
ParserWalker(const ParserContext *c,const ParserContext *cross) { const_context = c; cross_context = cross; } ///< Constructor for crossbuilds
const ParserContext *getParserContext(void) const { return const_context; } ///< Get the current context
void baseState(void) { point = const_context->base_state; depth=0; breadcrumb[0] = 0; } ///< Initialize for a new walk
void setOutOfBandState(Constructor *ct,int4 index,ConstructState *tempstate,const ParserWalker &otherwalker);
bool isState(void) const { return (point != (ConstructState *)0); }
void pushOperand(int4 i) { breadcrumb[depth++] = i+1; point = point->resolve[i]; breadcrumb[depth] = 0; }
void popOperand(void) { point = point->parent; depth-= 1; }
bool isState(void) const { return (point != (ConstructState *)0); } ///< Return \b true if there are more nodes to traverse
void pushOperand(int4 i); ///< Make the indicated child (operand) the current node
void popOperand(void) { point = point->parent; depth-= 1; } ///< Make the parent constructor the current node
uint4 getOffset(int4 i) const { if (i<0) return point->offset;
ConstructState *op=point->resolve[i]; return op->offset + op->length; }
Constructor *getConstructor(void) const { return point->ct; }
int4 getOperand(void) const { return breadcrumb[depth]; }
FixedHandle &getParentHandle(void) { return point->hand; }
const FixedHandle &getFixedHandle(int4 i) const { return point->resolve[i]->hand; }
AddrSpace *getCurSpace(void) const { return const_context->getCurSpace(); }
AddrSpace *getConstSpace(void) const { return const_context->getConstSpace(); }
ConstructState *op=point->resolve[i]; return op->offset + op->length; } ///< Get the byte offset of the indicated operand within the instruction stream
Constructor *getConstructor(void) const { return point->ct; } ///< Get the current constructor
int4 getOperand(void) const { return breadcrumb[depth]; } ///< Get the operand index of the next constructor in the walk
FixedHandle &getParentHandle(void) { return point->hand; } ///< Get the resolved value associated with the current constructor
const FixedHandle &getFixedHandle(int4 i) const { return point->resolve[i]->hand; } ///< Get the resolved value associated with the indicated child operand
AddrSpace *getCurSpace(void) const { return const_context->getCurSpace(); } ///< Get the address space associated with the instruction stream
AddrSpace *getConstSpace(void) const { return const_context->getConstSpace(); } ///< Get the constant address space
/// \brief Get the starting address of the instruction
const Address &getAddr(void) const { if (cross_context != (const ParserContext *)0) { return cross_context->getAddr(); } return const_context->getAddr(); }
/// \brief Get the address of the next instruction
const Address &getNaddr(void) const { if (cross_context != (const ParserContext *)0) { return cross_context->getNaddr();} return const_context->getNaddr(); }
/// \brief Get the address of the instruction after next
const Address &getN2addr(void) const { if (cross_context != (const ParserContext *)0) { return cross_context->getN2addr();} return const_context->getN2addr(); }
/// \brief Get the reference address (inst_ref) for the p-code snippet
const Address &getRefAddr(void) const { if (cross_context != (const ParserContext *)0) { return cross_context->getRefAddr();} return const_context->getRefAddr(); }
/// \brief Get the destination address (inst_dest) for the overridden call
const Address &getDestAddr(void) const { if (cross_context != (const ParserContext *)0) { return cross_context->getDestAddr();} return const_context->getDestAddr(); }
int4 getLength(void) const { return const_context->getLength(); }
int4 getLength(void) const { return const_context->getLength(); } ///< Get the length of the instruction in bytes
/// \brief Get packed instruction bytes associated with the current constructor
///
/// \param byteoff is an offset from the starting point associated with the constructor
/// \param numbytes is the number of bytes to pack
/// \return the packed instruction bytes in big endian encoding
uintm getInstructionBytes(int4 byteoff,int4 numbytes) const {
return const_context->getInstructionBytes(byteoff,numbytes,point->offset); }
/// \brief Get packed context bytes from the local context
///
/// \param byteoff is the offset of the first byte to grab
/// \param numbytes is the number of bytes to grab
/// \return the context bytes in a packed value
uintm getContextBytes(int4 byteoff,int4 numbytes) const {
return const_context->getContextBytes(byteoff,numbytes); }
/// \brief Get bits from the instruction stream associated with the current constructor
///
/// \param startbit is the offset of the first bit (relative to the starting point associated with the constructor)
/// \param size is the number of bits to grab
/// \return the requested range of bits (in the least significant positions and padded out with zero bits)
uintm getInstructionBits(int4 startbit,int4 size) const {
return const_context->getInstructionBits(startbit,size,point->offset); }
uintm getContextBits(int4 startbit,int4 size) const {
/// \brief Get a range of bits from the local context
///
/// \param startbit is the offset of the first bit
/// \param size is the number of bits to return
/// \return the requested range of bits (in the least significant positions and padded out with zero bits)
uintm getContextBits(int4 startbit,int4 size) const {
return const_context->getContextBits(startbit,size); }
};
class ParserWalkerChange : public ParserWalker { // Extension to walker that allows for on the fly modifications to tree
/// \brief A walker extension that allows for on the fly modifications to the constructor tree
///
/// This is used to build the constructor tree as the instruction is parsed (Sleigh::resolve)
class ParserWalkerChange : public ParserWalker {
friend class ParserContext;
ParserContext *context;
ParserContext *context; ///< The (currently active) context
public:
ParserWalkerChange(ParserContext *c) : ParserWalker(c) { context = c; }
ParserContext *getParserContext(void) { return context; }
ConstructState *getPoint(void) { return point; }
void setOffset(uint4 off) { point->offset = off; }
void setConstructor(Constructor *c) { point->ct = c; }
void setCurrentLength(int4 len) { point->length = len; }
void calcCurrentLength(int4 length,int4 numopers);
ParserWalkerChange(ParserContext *c) : ParserWalker(c) { context = c; } ///< Constructor
ParserContext *getParserContext(void) { return context; } ///< Get the currently active context
ConstructState *getPoint(void) { return point; } ///< Get the current
void setOffset(uint4 off) { point->offset = off; } ///< Get the current node in the constructor tree
void setConstructor(Constructor *c) { point->ct = c; } ///< Set the underlying Constructor for the current node
void setCurrentLength(int4 len) { point->length = len; } ///< Set the length associated with the current constructor
void calcCurrentLength(int4 length,int4 numopers); ///< Calculate the length of the current constructor
};
/// \brief Exception thrown by the SLEIGH engine
struct SleighError : public LowlevelError {
SleighError(const string &s) : LowlevelError(s) {}
SleighError(const string &s) : LowlevelError(s) {} ///< Constructor
};
/// The tree is reset to a single root node and the walker is prepared for a new parse
/// \param walker is the walker to initialize for a traversal
inline void ParserContext::deallocateState(ParserWalkerChange &walker) {
alloc = 1;
alloc = state.size() - 2; // Number of allocations left
walker.context=this;
walker.baseState();
}
/// \throw BadDataError when the parse is deeper than \b state or the walker's path holds
/// The next available node is linked to the current active node in the walker at the given operand index.
/// The child node becomes the new active node for the walker. The underlying constructor is not yet assigned.
/// \param i is the operand index of the new child
/// \param walker is the walker for the parse
inline void ParserContext::allocateOperand(int4 i,ParserWalkerChange &walker) {
if ((uint4)alloc >= state.size() || (uint4)walker.depth + 1 >= sizeof(walker.breadcrumb)/sizeof(int4)
|| (uint4)i >= walker.point->resolve.size())
throw BadDataError("Instruction parse is deeper than the parser context holds");
ConstructState *opstate = &state[alloc++];
if (i >= MAX_OPERAND)
throw LowlevelError("SLEIGH parser out of state space");
if (alloc < 0)
expandState(STATE_GROWTH);
ConstructState *opstate = state[alloc--];
opstate->parent = walker.point;
opstate->ct = (Constructor *)0;
walker.point->resolve[i] = opstate;
if (walker.depth > MAX_DEPTH-2)
throw LowlevelError("SLEIGH exceeded maximum parse depth");
walker.breadcrumb[walker.depth++] += 1;
walker.point = opstate;
walker.breadcrumb[walker.depth] = 0;
}
/// \param i is the index of child/operand
inline void ParserWalker::pushOperand(int4 i) {
if (depth > ParserContext::MAX_DEPTH-2)
throw LowlevelError("SLEIGH exceeded maximum parse depth");
breadcrumb[depth++] = i+1;
point = point->resolve[i];
breadcrumb[depth] = 0;
}
} // End namespace ghidra
#endif
File diff suppressed because it is too large. Load diff
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -190,8 +190,8 @@ class ActionConstantPtr : public Action {
static AddrSpace *searchForSpaceAttribute(Varnode *vn,PcodeOp *op);
static AddrSpace *selectInferSpace(Varnode *vn,PcodeOp *op,const vector<AddrSpace *> &spaceList);
static bool checkCopy(PcodeOp *op,Funcdata &data);
static SymbolEntry *isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op,int4 slot,
Address &rampoint,uintb &fullEncoding,Funcdata &data);
static MapEntry *isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op,int4 slot,
Address &rampoint,uintb &fullEncoding,Funcdata &data);
public:
ActionConstantPtr(const string &g) : Action(0,"constantptr",g) {} ///< Constructor
virtual void reset(Funcdata &data) { localcount = 0; }
@@ -220,6 +220,7 @@ public:
/// - Volatile Varnodes are converted read/write functions
/// - Varnodes whose values are not consumed are replaced with constant 0 Varnodes
class ActionVarnodeProps : public Action {
void handleExtendedZero(Varnode *vn,Funcdata &data);
public:
ActionVarnodeProps(const string &g) : Action(0,"varnodeprops",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
@@ -320,9 +321,10 @@ public:
class ActionSetCasts : public Action {
static void checkPointerIssues(PcodeOp *op,Varnode *vn,Funcdata &data);
static bool testStructOffset0(Datatype *reqtype,Datatype *curtype,CastStrategy *castStrategy);
static bool tryResolutionAdjustment(PcodeOp *op,int4 slot,Funcdata &data);
static bool tryResolutionAdjustment(Datatype *dt,PcodeOp *op,int4 slot,Funcdata &data);
static bool tryResolutionCopy(PcodeOp *op,Funcdata &data);
static bool isOpIdentical(Datatype *ct1,Datatype *ct2);
static int4 resolveUnion(PcodeOp *op,int4 slot,Funcdata &data);
static int4 resolveUnion(PcodeOp *op,int4 slot,Funcdata &data,CastStrategy *castStrategy);
static int4 castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStrategy);
static int4 castInput(PcodeOp *op,int4 slot,Funcdata &data,CastStrategy *castStrategy);
static PcodeOp *insertPtrsubZero(PcodeOp *op,int4 slot,Datatype *ct,Funcdata &data);
@@ -509,6 +511,18 @@ public:
virtual int4 apply(Funcdata &data);
};
/// \brief Remove blocks that do nothing after variable merging has occurred
class ActionLateDoNothing : public Action {
static bool removingCreatesRedundancy(FlowBlock *bl); ///< Does removing the given block create a redundant branch point
public:
ActionLateDoNothing(const string &g) : Action(0,"latedonothing",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionLateDoNothing(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Get rid of \b redundant branches: duplicate edges between the same input and output block
class ActionRedundBranch : public Action {
public:
@@ -567,14 +581,30 @@ public:
/// \brief Propagate conditional constants
class ActionConditionalConst : public Action {
/// \brief Description of a point in control-flow where a Varnode can propagate as a constant down a conditional branch
struct ConstPoint {
Varnode *vn; ///< Varnode that is constant for some reads
Varnode *constVn; ///< Representative of the constant (may be null)
uintb value; ///< The constant value
FlowBlock *constBlock; ///< Block that dominates all reads where vn is constant
int4 inSlot; ///< Input edge from condition block
bool blockIsDom; ///< Is \b true if block is dominated by constant path
ConstPoint(Varnode *v,Varnode *c,FlowBlock *bl,int4 slot,bool isDom) {
vn = v; constVn = c; value = c->getOffset(); constBlock = bl; inSlot = slot; blockIsDom = isDom; } ///< Construct from constant Varnode
ConstPoint(Varnode *v,uintb val,FlowBlock *bl,int4 slot,bool isDom) {
vn = v; constVn = (Varnode *)0; value = val; constBlock = bl; inSlot = slot; blockIsDom = isDom; } ///< Construct from constant value
};
static void clearMarks(const vector<PcodeOp *> &opList);
static void collectReachable(Varnode *vn,vector<PcodeOpNode> &phiNodeEdges,vector<PcodeOp *> &reachable);
static bool flowToAlternatePath(PcodeOp *op);
static bool flowTogether(const vector<PcodeOpNode> &edges,int4 i,vector<int4> &result);
static Varnode *placeCopy(PcodeOp *op,BlockBasic *bl,Varnode *constVn,Funcdata &data);
static void findConstCompare(list<ConstPoint> &points,Varnode *boolVn,FlowBlock *bl,bool *blockDom,bool flipEdge);
static void pushConstant(list<ConstPoint> &points,PcodeOp *op);
static void placeMultipleConstants(vector<PcodeOpNode> &phiNodeEdges,vector<int4> &marks,Varnode *constVn,Funcdata &data);
void handlePhiNodes(Varnode *varVn,Varnode *constVn,vector<PcodeOpNode> &phiNodeEdges,Funcdata &data);
void propagateConstant(Varnode *varVn,Varnode *constVn,FlowBlock *constBlock,bool useMultiequal,Funcdata &data);
bool testAlternatePath(Varnode *vn,PcodeOp *op,int4 slot,int4 depth);
void propagateConstant(list<ConstPoint> &points,bool useMultiequal,Funcdata &data);
public:
ActionConditionalConst(const string &g) : Action(0,"condconst",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
@@ -612,6 +642,7 @@ public:
class ActionNormalizeSetup : public Action {
public:
ActionNormalizeSetup(const string &g) : Action(rule_onceperfunc,"normalizesetup",g) {} ///< Constructor
virtual void reset(Funcdata &data) { data.setNormalization(true); }
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionNormalizeSetup(getGroup());
@@ -831,6 +862,7 @@ public:
/// This produces on intermediate view of symbols on the stack.
class ActionRestructureVarnode : public Action {
int4 numpass; ///< Number of passes performed for this function
static bool isCopyConstant(Varnode *vn); ///< Is the given Varnode a constant or a COPY of a constant
static bool isDelayedConstant(Varnode *vn); ///< Determine if given Varnode is or will be a constant
static void protectSwitchPathIndirects(PcodeOp *op); ///< Protect path to the given switch from INDIRECT collapse
static void protectSwitchPaths(Funcdata &data); ///< Look for switches and protect path of switch variable
@@ -873,6 +905,18 @@ public:
/// If the prototype wasn't originally known, the discovered input Varnodes are analyzed
/// to determine a prototype based on the prototype model.
class ActionInputPrototype : public Action {
/// \brief A reference into the stack
class InputRef {
public:
Address addr; ///< Address of region being referenced
Datatype *dataType; ///< Data-type associated with the region
InputRef(Address &ad,Datatype *dt) : addr(ad) { dataType = dt; } ///< Constructor
bool operator<(const InputRef &op2) const; ///< Compare \b this with another reference
static void dedup(list<InputRef> &refs); ///< Deduplicate a (sorted) list of references
};
void gatherParamSpacebaseRefs(list<InputRef> &refs,Funcdata &data);
void markActiveInputRefs(ParamActive &active,list<InputRef> &refs,vector<Datatype *> &typeList,Funcdata &data);
void addRefOnlySymbols(list<InputRef> &refs,Funcdata &data);
public:
ActionInputPrototype(const string &g) : Action(rule_onceperfunc,"inputprototype",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
@@ -999,7 +1043,8 @@ public:
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionCopyMarker(getGroup());
}
virtual int4 apply(Funcdata &data) { data.getMerge().markInternalCopies(); return 0; }
virtual int4 apply(Funcdata &data) {
data.getMerge().markInternalCopies(); data.getMerge().markPurePaddingCopies(); return 0; }
};
/// \brief Attach \e dynamically mapped symbols to Varnodes in time for data-type propagation
@@ -1064,47 +1109,5 @@ public:
bool valid(void) const { return (op != (PcodeOp *)0); } ///< Return \b true if there are edges left to iterate
};
/// Class representing a \e term in an additive expression
class AdditiveEdge {
PcodeOp *op; ///< Lone descendant reading the term
int4 slot; ///< The input slot of the term
Varnode *vn; ///< The term Varnode
PcodeOp *mult; ///< The (optional) multiplier being applied to the term
public:
AdditiveEdge(PcodeOp *o,int4 s,PcodeOp *m) { op = o; slot = s; vn = op->getIn(slot); mult=m; } ///< Constructor
PcodeOp *getMultiplier(void) const { return mult; } ///< Get the multiplier PcodeOp
PcodeOp *getOp(void) const { return op; } ///< Get the component PcodeOp adding in the term
int4 getSlot(void) const { return slot; } ///< Get the slot reading the term
Varnode *getVarnode(void) const { return vn; } ///< Get the Varnode term
};
/// \brief A class for ordering Varnode terms in an additive expression.
///
/// Given the final PcodeOp in a data-flow expression that sums 2 or more
/// Varnode \e terms, this class collects all the terms then allows
/// sorting of the terms to facilitate constant collapse and factoring simplifications.
class TermOrder {
PcodeOp *root; ///< The final PcodeOp in the expression
vector<AdditiveEdge> terms; ///< Collected terms
vector<AdditiveEdge *> sorter; ///< An array of references to terms for quick sorting
static bool additiveCompare(const AdditiveEdge *op1,const AdditiveEdge *op2);
public:
TermOrder(PcodeOp *rt) { root = rt; } ///< Construct given root PcodeOp
int4 getSize(void) const { return terms.size(); } ///< Get the number of terms in the expression
void collect(void); ///< Collect all the terms in the expression
void sortTerms(void); ///< Sort the terms using additiveCompare()
const vector<AdditiveEdge *> &getSort(void) { return sorter; } ///< Get the sorted list of references
};
/// \brief A comparison operator for ordering terms in a sum
///
/// This is based on Varnode::termOrder which groups constants terms and
/// ignores multiplicative coefficients.
/// \param op1 is the first term to compare
/// \param op2 is the second term
/// \return \b true if the first term is less than the second
inline bool TermOrder::additiveCompare(const AdditiveEdge *op1,const AdditiveEdge *op2) {
return (-1 == op1->getVarnode()->termOrder(op2->getVarnode())); }
} // End namespace ghidra
#endif
@@ -132,7 +132,10 @@ void CPoolRecord::decode(Decoder &decoder,TypeFactory &typegrp)
if (subId == ELEM_TOKEN)
token = decoder.readString(ATTRIB_CONTENT);
else {
byteDataLen = decoder.readSignedInteger(ATTRIB_LENGTH);
int8 val = decoder.readSignedInteger(ATTRIB_LENGTH);
if (val < 0 || val >= MAX_STRING_SIZE)
throw LowlevelError("Bad constant pool record: bad <data> size");
byteDataLen = val;
istringstream s3(decoder.readString(ATTRIB_CONTENT));
byteData = new uint1[byteDataLen];
for(int4 i=0;i<byteDataLen;++i) {
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -79,6 +79,7 @@ private:
Datatype *type; ///< Data-type associated with the object
uint1 *byteData; ///< For string literals, the raw byte data of the string
int4 byteDataLen; ///< The number of bytes in the data for a string literal
static constexpr int8 MAX_STRING_SIZE = 0x100000; ///< Maximum allowed bytes of string in pool
public:
CPoolRecord(void) { type = (Datatype *)0; byteData = (uint1 *)0; } ///< Construct an empty record
~CPoolRecord(void) { if (byteData != (uint1 *)0) delete [] byteData; } ///< Destructor
File diff suppressed because it is too large. Load diff
@@ -32,6 +32,7 @@ namespace ghidra {
class Architecture;
class Funcdata;
class Scope;
class MapEntry;
class Database;
class Symbol;
class PrintLanguage;
@@ -58,54 +59,18 @@ extern ElementId ELEM_RANGEEQUALSSYMBOLS; ///< Marshaling element \<rangeequalss
extern ElementId ELEM_SCOPE; ///< Marshaling element \<scope>
extern ElementId ELEM_SYMBOLLIST; ///< Marshaling element \<symbollist>
/// \brief A storage location for a particular Symbol
///
/// Where a Symbol is stored, as a byte address and a size, is of particular importance
/// to the decompiler. This class encapsulates this storage meta-data. A single Symbol split
/// across multiple storage locations is supported by the \b offset and \b size fields. The
/// \b hash field supports \e dynamic storage, where a Symbol is represented by a constant
/// or a temporary register. In this case, storage must be tied to the particular p-code
/// operators using the value.
///
/// A particular memory address does \b not have to represent the symbol across all code. Storage
/// may get recycled for different Symbols at different points in the code. The \b uselimit object
/// defines the range of instruction addresses over which a particular memory address does
/// represent a Symbol, with the convention that an empty \b uselimit indicates the storage
/// holds the Symbol across \e all code.
class SymbolEntry {
friend class Scope;
Symbol *symbol; ///< Symbol object being mapped
uint4 extraflags; ///< Varnode flags specific to this storage location
Address addr; ///< Starting address of the storage location
uint8 hash; ///< A dynamic storage address (an alternative to \b addr for dynamic symbols)
int4 offset; ///< Offset into the Symbol that \b this covers
int4 size; ///< Number of bytes consumed by \b this (piece of the) storage
RangeList uselimit; ///< Code address ranges where this storage is valid
SymbolEntry(Symbol *sym); ///< Construct a mapping for a Symbol without an address
/// \brief A helper class for storing MapEntry objects in an interval map
class SymbolRange {
public:
/// \brief Initialization data for a SymbolEntry to facilitate a rangemap
///
/// This is all the raw pieces of a SymbolEntry for a (non-dynamic) Symbol except
/// the offset of the main address and the size, which are provided by the
/// (rangemap compatible) SymbolEntry constructor.
class EntryInitData {
friend class SymbolEntry;
AddrSpace *space; ///< The address space of the main SymbolEntry starting address
Symbol *symbol; ///< The symbol being mapped
uint4 extraflags; ///< Varnode flags specific to the storage location
int4 offset; ///< Starting offset of the portion of the Symbol being covered
const RangeList &uselimit; ///< Reference to the range of code addresses for which the storage is valid
public:
EntryInitData(Symbol *sym,uint4 exfl,AddrSpace *spc,int4 off,const RangeList &ul)
: uselimit(ul) { symbol = sym; extraflags=exfl; space = spc; offset = off; } ///< Constructor
};
uintb first; ///< Starting offset of range covered by the MapEntry
uintb last; ///< Last offset of range
MapEntry *entry; ///< Pointer to the MapEntry
/// \brief Class for sub-sorting different SymbolEntry objects at the same address
///
/// This is built from the SymbolEntry \b uselimit object (see SymbolEntry::getSubsort())
/// This is built from the SymbolEntry \b uselimit object
/// Relevant portions of an Address object or pulled out for smaller storage and quick comparisons.
class EntrySubsort {
friend class SymbolEntry;
friend class SymbolRange;
int4 useindex; ///< Index of the sub-sorting address space
uintb useoffset; ///< Offset into the sub-sorting address space
public:
@@ -132,23 +97,65 @@ public:
return (useoffset < op2.useoffset);
}
};
typedef uintb linetype; ///< The linear element for a rangemap of SymbolEntry
typedef EntrySubsort subsorttype; ///< The sub-sort object for a rangemap
typedef EntryInitData inittype; ///< Initialization data for a SymbolEntry in a rangemap
typedef MapEntry *inittype; ///< Initialization data for a SymbolEntry in a rangemap
SymbolEntry(const EntryInitData &data,uintb a,uintb b); ///< Fully initialize \b this
SymbolEntry(Symbol *sym,uint4 exfl,uint8 h,int4 off,int4 sz,const RangeList &rnglist); ///< Construct a dynamic SymbolEntry
bool isPiece(void) const { return ((extraflags&(Varnode::precislo|Varnode::precishi))!=0); } ///< Is \b this a high or low piece of the whole Symbol
bool isDynamic(void) const { return addr.isInvalid(); } ///< Is \b storage \e dynamic
bool isInvalid(void) const { return (addr.isInvalid() && (hash==0)); } ///< Is \b this storage \e invalid
SymbolRange(MapEntry *e,uintb f,uintb l) { entry=e; first = f; last = l; } ///< Constructor
uintb getFirst(void) const { return first; } ///< Get the first offset of \b this storage location
uintb getLast(void) const { return last; } ///< Get the last offset of \b this storage location
subsorttype getSubsort(void) const;
};
/// \brief A storage location for a particular Symbol
///
/// Storage can be a fixed Address or a dynamically located Varnode representing the Symbol.
/// Storage may get recycled for different Symbols at different points in the code. The \b uselimit object
/// defines the range of instruction addresses over which a particular SymbolEntry does
/// represent a Symbol, with the convention that an empty \b uselimit indicates the storage
/// holds the Symbol across \e all code.
class SymbolEntry {
friend class Scope;
friend class ScopeInternal;
/// \brief The type (derived class) of SymbolEntry
protected:
enum {
map_entry = 1, ///< Is a MapEntry
conflict_entry = 2, ///< Is a MapEntryConflict
dynamic_entry = 4, ///< Is a DynamicEntry
unassigned_entry = 8, ///< Is an UnassignedEntry
piece = 16 ///< Is a proper piece of whole Symbol
};
Symbol *symbol; ///< Symbol object being mapped
RangeList uselimit; ///< Code address ranges where this storage is valid
uint4 properties; ///< Boolean properties of \b this entry
uint4 extraflags; ///< Varnode flags specific to this storage location
int4 offset; ///< Offset into the Symbol that \b this covers
int4 size; ///< Number of bytes consumed by \b this (piece of the) storage
public:
SymbolEntry(Symbol *sym); ///< Construct an uninitialized SymbolEntry
SymbolEntry(Symbol *sym,uint4 exflags,int4 sz,int4 off,const RangeList &use); ///< Constructor
virtual ~SymbolEntry(void) {}
bool isPiece(void) const { return ((properties & piece)!=0); } ///< Is \b this a proper piece of the whole Symbol
bool isMapEntry(void) const { return ((properties & map_entry)!=0); } ///< Is \b this a MapEntry
bool isDynamic(void) const { return ((properties & dynamic_entry)!=0); } ///< Is \b this a DynamicEntry
bool isConflict(void) const { return ((properties & conflict_entry)!=0); } ///< Does storage have potential Symbol conflicts
/// \brief Get the data-type associated with (a piece of) \b this
///
/// Return the data-type that matches the given size and address within \b this storage.
/// NULL is returned if there is no valid sub-type matching the size.
/// \param addr is the given address
/// \param sz is the given size (in bytes)
/// \return the matching data-type or NULL
virtual Datatype *getSizedType(const Address &addr,int4 sz) const=0;
virtual void printEntry(ostream &s) const=0; ///< Print a one-line description of \b this to a debug stream
virtual void encode(Encoder &encoder) const=0; ///< Encode storage element internal to \<mapsym>
virtual void decode(Decoder &decoder)=0; ///< Decode storage element internal to \<mapsym>
uint4 getAllFlags(void) const; ///< Get all Varnode flags for \b this storage
int4 getOffset(void) const { return offset; } ///< Get offset of \b this within the Symbol
uintb getFirst(void) const { return addr.getOffset(); } ///< Get the first offset of \b this storage location
uintb getLast(void) const { return (addr.getOffset()+size-1); } ///< Get the last offset of \b this storage location
subsorttype getSubsort(void) const; ///< Get the sub-sort object
Symbol *getSymbol(void) const { return symbol; } ///< Get the Symbol associated with \b this
const Address &getAddr(void) const { return addr; } ///< Get the starting address of \b this storage
uint8 getHash(void) const { return hash; } ///< Get the hash used to identify \b this storage
int4 getSize(void) const { return size; } ///< Get the number of bytes consumed by \b this storage
bool inUse(const Address &usepoint) const; ///< Is \b this storage valid for the given code address
const RangeList &getUseLimit(void) const { return uselimit; } ///< Get the set of valid code addresses for \b this storage
@@ -156,12 +163,77 @@ public:
void setUseLimit(const RangeList &uselim) { uselimit = uselim; } ///< Set the range of code addresses where \b this is valid
bool isAddrTied(void) const; ///< Is \b this storage address tied
bool updateType(Varnode *vn) const; ///< Update a Varnode data-type from \b this
Datatype *getSizedType(const Address &addr,int4 sz) const; ///< Get the data-type associated with (a piece of) \b this
void printEntry(ostream &s) const; ///< Dump a description of \b this to a stream
void encode(Encoder &encoder) const; ///< Encode \b this to a stream
void decode(Decoder &decoder); ///< Decode \b this from a stream
};
typedef rangemap<SymbolRange> EntryMap; ///< A rangemap of MapEntry
/// \brief A mapping from a Symbol to storage Address
///
/// This object holds a (starting) Address of the Symbol and can be integrated into an EntryMap.
/// A single Symbol split across multiple storage locations is supported by the \b offset and \b size fields.
class MapEntry : public SymbolEntry {
friend class Scope;
friend class ScopeInternal;
protected:
Address addr; ///< Starting address of the storage location
list<SymbolRange>::iterator mapIterator; ///< Position within container
public:
MapEntry(Symbol *sym,uint4 exflags,const Address &ad,int4 sz,int4 off,const RangeList &use); ///< Constructor
MapEntry(Symbol *sym) : SymbolEntry(sym) { properties |= map_entry; } ///< Construct and uninitialized MapEntry for use with decode()
virtual Datatype *getSizedType(const Address &addr,int4 sz) const;
virtual void printEntry(ostream &s) const;
virtual void encode(Encoder &encoder) const;
virtual void decode(Decoder &decoder);
uintb getFirst(void) const { return addr.getOffset(); } ///< Get the first offset of \b this storage location
uintb getLast(void) const { return (addr.getOffset()+size-1); } ///< Get the last offset of \b this storage location
const Address &getAddr(void) const { return addr; } ///< Get the starting address of \b this storage
};
/// \brief A mapping from Symbol to Address when there are conflicting uses of the Address
///
/// If storage is (potentially) used by other Symbols at the same code point (\b uselimit),
/// the Varnode is mapped using \b this, which allows potential deconfliction later,
/// by converting to a DynamicEntry.
class MapEntryConflict : public MapEntry {
uintm uniq; ///< Unique id of PcodeOp defining mapped Varnode
public:
MapEntryConflict(Symbol *sym,Varnode *vn); ///< Constructor
uintm getUnique(void) const { return uniq; } ///< Get id of PcodeOp defining the conflicting Varnode
virtual void printEntry(ostream &s) const;
virtual void encode(Encoder &encoder) const;
virtual void decode(Decoder &decoder);
};
/// \brief A mapping from a Symbol to a specific Varnode
///
/// For a constant or temporary register that is not strongly linked to a particular storage address,
/// \b this allows a representative Varnode to be discovered dynamically.
/// Storage for the Symbol is tied to the particular Varnode and p-code operator using the value.
class DynamicEntry : public SymbolEntry {
friend class Scope;
friend class ScopeInternal;
uint8 hash; ///< A dynamic storage address
list<DynamicEntry *>::iterator dynIterator; ///< Position within container
public:
DynamicEntry(Symbol *sym,uint4 exfl,uint8 h,int4 off,int4 sz,const RangeList &rnglist); ///< Constructor
DynamicEntry(Symbol *sym) : SymbolEntry(sym) { hash = 0; properties |= dynamic_entry; } ///< Constructor for use with decode()
virtual Datatype *getSizedType(const Address &addr,int4 sz) const;
virtual void printEntry(ostream &s) const;
virtual void encode(Encoder &encoder) const;
virtual void decode(Decoder &decoder);
uint8 getHash(void) const { return hash; } ///< Get the hash used to identify \b this storage
};
/// \brief A placeholder mapping for a Symbol that is not mapped or \e unassigned
///
class UnassignedEntry : public SymbolEntry {
public:
UnassignedEntry(Symbol *sym); ///< Constructor
virtual Datatype *getSizedType(const Address &addr,int4 sz) const;
virtual void printEntry(ostream &s) const;
virtual void encode(Encoder &encoder) const;
virtual void decode(Decoder &decoder);
};
typedef rangemap<SymbolEntry> EntryMap; ///< A rangemap of SymbolEntry
/// \brief The base class for a symbol in a symbol table or scope
///
@@ -186,11 +258,11 @@ protected:
int2 category; ///< Special category (\b function_parameter, \b equate, etc.)
uint2 catindex; ///< Index within category
uint8 symbolId; ///< Unique id, 0=unassigned
vector<list<SymbolEntry>::iterator> mapentry; ///< List of storage locations labeled with \b this Symbol
vector<SymbolEntry *> mapentry; ///< List of storage locations labeled with \b this Symbol
mutable const Scope *depthScope; ///< Scope associated with current depth resolution
mutable int4 depthResolution; ///< Number of namespace elements required to resolve symbol in current scope
uint4 wholeCount; ///< Number of SymbolEntries that map to the whole Symbol
virtual ~Symbol(void) {} ///< Destructor
virtual ~Symbol(void); ///< Destructor
void setDisplayFormat(uint4 val); ///< Set the display format for \b this Symbol
void checkSizeTypeLock(void); ///< Calculate if \b size_typelock property is on
void setThisPointer(bool val); ///< Toggle whether \b this is the "this" pointer for a class method
@@ -242,7 +314,7 @@ public:
void setIsolated(bool val); ///< Set whether \b this Symbol should be speculatively merged
Scope *getScope(void) const { return scope; } ///< Get the scope owning \b this Symbol
SymbolEntry *getFirstWholeMap(void) const; ///< Get the first entire mapping of the symbol
SymbolEntry *getMapEntry(const Address &addr) const; ///< Get first mapping of the symbol that contains the given Address
MapEntry *getMapEntry(const Address &addr) const; ///< Get first mapping of the symbol that contains the given Address
int4 numEntries(void) const { return mapentry.size(); } ///< Return the number of SymbolEntrys
SymbolEntry *getMapEntry(int4 i) const { return &(*mapentry[i]); } ///< Return the i-th SymbolEntry for \b this Symbol
int4 getMapEntryPosition(const SymbolEntry *entry) const; ///< Position of given SymbolEntry within \b this multi-entry Symbol
@@ -318,10 +390,12 @@ public:
/// different symbols attached. The Symbol's associated data-type will be the desired \e union to force.
class UnionFacetSymbol : public Symbol {
int4 fieldNum; ///< Particular field to associate with Symbol access
bool addrBased; ///< Set to \b true if facet matches any PcodeOp at the address
public:
UnionFacetSymbol(Scope *sc,const string &nm,Datatype *unionDt,int4 fldNum); ///< Constructor from components
UnionFacetSymbol(Scope *sc) : Symbol(sc) { fieldNum = -1; category = union_facet; } ///< Constructor for decode
UnionFacetSymbol(Scope *sc,const string &nm,Datatype *unionDt,int4 fldNum,bool isAddr=false); ///< Constructor from components
UnionFacetSymbol(Scope *sc) : Symbol(sc) { fieldNum = -1; category = union_facet; addrBased = false; } ///< Constructor for decode
int4 getFieldNumber(void) const { return fieldNum; } ///< Get the particular field associate with \b this
bool isAddrBased(void) const { return addrBased; } ///< Return \b true if facet matches any PcodeOp at the address
virtual void encode(Encoder &encoder) const;
virtual void decode(Decoder &decoder);
};
@@ -379,7 +453,7 @@ typedef set<Symbol *,SymbolCompareName> SymbolNameTree; ///< A set of Symbol ob
class MapIterator {
const vector<EntryMap *> *map; ///< The list of EntryMaps, one per address space
vector<EntryMap *>::const_iterator curmap; ///< Current EntryMap being iterated
list<SymbolEntry>::const_iterator curiter; ///< Current SymbolEntry being iterated
list<SymbolRange>::const_iterator curiter; ///< Current SymbolEntry being iterated
public:
MapIterator(void) { map = (const vector<EntryMap *> *)0; } ///< Construct an uninitialized iterator
@@ -390,7 +464,7 @@ public:
/// \param ci is the position of the iterator within the specific EntryMap
MapIterator(const vector<EntryMap *> *m,
vector<EntryMap *>::const_iterator cm,
list<SymbolEntry>::const_iterator ci) {
list<SymbolRange>::const_iterator ci) {
map = m; curmap = cm; curiter = ci;
}
@@ -398,7 +472,7 @@ public:
MapIterator(const MapIterator &op2) {
map = op2.map; curmap = op2.curmap; curiter = op2.curiter;
}
const SymbolEntry *operator*(void) const { return &(*curiter); } ///< Return the SymbolEntry being pointed at
const MapEntry *operator*(void) const { return (*curiter).entry; } ///< Return the SymbolEntry being pointed at
MapIterator &operator++(void); ///< Pre-increment the iterator
MapIterator operator++(int4 i); ///< Post-increment the iterator
@@ -479,17 +553,17 @@ protected:
const Scope *scope2,
const Address &addr,
const Address &usepoint,
SymbolEntry **addrmatch);
MapEntry **addrmatch);
static const Scope *stackContainer(const Scope *scope1,
const Scope *scope2,
const Address &addr,int4 size,
const Address &usepoint,
SymbolEntry **addrmatch);
MapEntry **addrmatch);
static const Scope *stackClosestFit(const Scope *scope1,
const Scope *scope2,
const Address &addr,int4 size,
const Address &usepoint,
SymbolEntry **addrmatch);
MapEntry **addrmatch);
static const Scope *stackFunction(const Scope *scope1,
const Scope *scope2,
const Address &addr,
@@ -526,34 +600,21 @@ protected:
/// \param sym is the preconstructed Symbol
virtual void addSymbolInternal(Symbol *sym)=0;
/// \brief Create a new SymbolEntry for a Symbol given a memory range
/// \brief Add a new MapEntry to a Symbol, update the map from Address to Symbol
///
/// The SymbolEntry is specified in terms of a memory range and \b usepoint
/// \param sym is the given Symbol being mapped
/// \param exfl are any boolean Varnode properties specific to the memory range
/// \param addr is the starting address of the given memory range
/// \param off is the byte offset of the new SymbolEntry (relative to the whole Symbol)
/// \param sz is the number of bytes in the range
/// \param uselim is the given \b usepoint (which may be \e invalid)
/// \return the newly created SymbolEntry
virtual SymbolEntry *addMapInternal(Symbol *sym,uint4 exfl,const Address &addr,int4 off,int4 sz,
const RangeList &uselim)=0;
/// \param entry is the MapEntry to add
virtual void addMapInternal(Symbol *sym,MapEntry *entry)=0;
/// \brief Create a new SymbolEntry for a Symbol given a dynamic hash
/// \brief Add a new DynamicEntry to a Symbol
///
/// The SymbolEntry is specified in terms of a \b hash and \b usepoint, which describe how
/// to find the temporary Varnode holding the symbol value.
/// \param sym is the given Symbol being mapped
/// \param exfl are any boolean Varnode properties
/// \param hash is the given dynamic hash
/// \param off is the byte offset of the new SymbolEntry (relative to the whole Symbol)
/// \param sz is the number of bytes occupied by the Varnode
/// \param uselim is the given \b usepoint
/// \return the newly created SymbolEntry
virtual SymbolEntry *addDynamicMapInternal(Symbol *sym,uint4 exfl,uint8 hash,int4 off,int4 sz,
const RangeList &uselim)=0;
SymbolEntry *addMap(SymbolEntry &entry); ///< Integrate a SymbolEntry into the range maps
/// \param entry is the DynamicEntry to add
virtual void addDynamicMapInternal(Symbol *sym,DynamicEntry *entry)=0;
void addMap(MapEntry *entry); ///< Integrate a MapEntry into the range maps
void addDynamic(DynamicEntry *entry); ///< Integrate a DynamicEntry into the Scope
void addUnassigned(MapEntry *entry); ///< Mark a symbol as unassigned
void setSymbolId(Symbol *sym,uint8 id) const { sym->symbolId = id; } ///< Adjust the id associated with a symbol
void setDisplayName(const string &nm) { displayName = nm; } ///< Change name displayed in output
public:
@@ -572,10 +633,10 @@ public:
virtual ~Scope(void); ///< Destructor
virtual MapIterator begin(void) const=0; ///< Beginning iterator to mapped SymbolEntrys
virtual MapIterator end(void) const=0; ///< Ending iterator to mapped SymbolEntrys
virtual list<SymbolEntry>::const_iterator beginDynamic(void) const=0; ///< Beginning iterator to dynamic SymbolEntrys
virtual list<SymbolEntry>::const_iterator endDynamic(void) const=0; ///< Ending iterator to dynamic SymbolEntrys
virtual list<SymbolEntry>::iterator beginDynamic(void)=0; ///< Beginning iterator to dynamic SymbolEntrys
virtual list<SymbolEntry>::iterator endDynamic(void)=0; ///< Ending iterator to dynamic SymbolEntrys
virtual list<DynamicEntry *>::const_iterator beginDynamic(void) const=0; ///< Beginning iterator to dynamic SymbolEntrys
virtual list<DynamicEntry *>::const_iterator endDynamic(void) const=0; ///< Ending iterator to dynamic SymbolEntrys
virtual list<DynamicEntry *>::iterator beginDynamic(void)=0; ///< Beginning iterator to dynamic SymbolEntrys
virtual list<DynamicEntry *>::iterator endDynamic(void)=0; ///< Ending iterator to dynamic SymbolEntrys
virtual void clear(void)=0; ///< Clear all symbols from \b this scope
virtual void clearCategory(int4 cat)=0; ///< Clear all symbols of the given category from \b this scope
virtual void clearUnlocked(void)=0; ///< Clear all unlocked symbols from \b this scope
@@ -618,7 +679,7 @@ public:
/// \param addr is the given address
/// \param usepoint is the point at which the Symbol is accessed (may be \e invalid)
/// \return the matching SymbolEntry or NULL
virtual SymbolEntry *findAddr(const Address &addr,const Address &usepoint) const=0;
virtual MapEntry *findAddr(const Address &addr,const Address &usepoint) const=0;
/// \brief Find the smallest Symbol containing the given memory range
///
@@ -626,8 +687,7 @@ public:
/// \param size is the number of bytes in the range
/// \param usepoint is the point at which the Symbol is accessed (may be \e invalid)
/// \return the matching SymbolEntry or NULL
virtual SymbolEntry *findContainer(const Address &addr,int4 size,
const Address &usepoint) const=0;
virtual MapEntry *findContainer(const Address &addr,int4 size,const Address &usepoint) const=0;
/// \brief Find Symbol which is the closest fit to the given memory range
///
@@ -635,8 +695,7 @@ public:
/// \param size is the number of bytes in the range
/// \param usepoint is the point at which the Symbol is accessed (may be \e invalid)
/// \return the matching SymbolEntry or NULL
virtual SymbolEntry *findClosestFit(const Address &addr,int4 size,
const Address &usepoint) const=0;
virtual MapEntry *findClosestFit(const Address &addr,int4 size,const Address &usepoint) const=0;
/// \brief Find the function starting at the given address
///
@@ -661,7 +720,21 @@ public:
/// \param addr is the starting address of the given range
/// \param size is the number of bytes in the range
/// \return an overlapping SymbolEntry or NULL if none exists
virtual SymbolEntry *findOverlap(const Address &addr,int4 size) const=0;
virtual MapEntry *findOverlap(const Address &addr,int4 size) const=0;
/// \brief Find the last Symbol whose range ends before the given address
///
/// \param addr is the given address
/// \param usepoint is the point at which the Symbol is being accessed
/// \return the matching MapEntry or NULL
virtual MapEntry *findSymbolBefore(const Address &addr,const Address &usepoint) const=0;
/// \brief Find the first Symbol whose range begins after the given address
///
/// \param addr is the given address
/// \param usepoint is the point at which the Symbol is being accessed
/// \return the matching MapEntry or NULL
virtual MapEntry *findSymbolAfter(const Address &addr,const Address &usepoint) const=0;
/// \brief Find a Symbol by name within \b this Scope
///
@@ -739,23 +812,22 @@ public:
/// \param ind is, for the function_parameter category, the index position to set, and is unused for other categories
virtual void setCategory(Symbol *sym,int4 cat,int4 ind)=0;
virtual SymbolEntry *addSymbol(const string &nm,Datatype *ct,
const Address &addr,const Address &usepoint);
virtual MapEntry *addSymbol(const string &nm,Datatype *ct,const Address &addr,const Address &usepoint);
const string &getName(void) const { return name; } ///< Get the name of the Scope
const string &getDisplayName(void) const { return displayName; } ///< Get name displayed in output
uint8 getId(void) const { return uniqueId; } ///< Get the globally unique id
bool isGlobal(void) const { return (fd == (Funcdata *)0); } ///< Return \b true if \b this scope is global
Funcdata *getFunction(void) const { return fd; } ///< Get function \b this is attached to, or null
// The main global querying routines
void queryByName(const string &nm,vector<Symbol *> &res) const; ///< Look-up symbols by name
Funcdata *queryFunction(const string &nm) const; ///< Look-up a function by name
SymbolEntry *queryByAddr(const Address &addr,
const Address &usepoint) const; ///< Get Symbol with matching address
SymbolEntry *queryContainer(const Address &addr,int4 size,
const Address &usepoint) const; ///< Find the smallest containing Symbol
SymbolEntry *queryProperties(const Address &addr,int4 size,
const Address &usepoint,uint4 &flags) const; ///< Find a Symbol or properties at the given address
MapEntry *queryByAddr(const Address &addr,const Address &usepoint) const; ///< Get Symbol with matching address
MapEntry *queryContainer(const Address &addr,int4 size,
const Address &usepoint) const; ///< Find the smallest containing Symbol
MapEntry *queryProperties(const Address &addr,int4 size,
const Address &usepoint,uint4 &flags) const; ///< Find a Symbol or properties at the given address
Funcdata *queryFunction(const Address &addr) const; ///< Look-up a function by address
Funcdata *queryExternalRefFunction(const Address &addr) const; ///< Look-up a function thru an \e external \e reference
LabSymbol *queryCodeLabel(const Address &addr) const; ///< Look-up a code label by address
@@ -775,8 +847,7 @@ public:
Architecture *getArch(void) const { return glb; } ///< Get the Architecture associated with \b this
Scope *getParent(void) const { return parent; } ///< Get the parent Scope (or NULL if \b this is the global Scope)
Symbol *addSymbol(const string &nm,Datatype *ct); ///< Add a new Symbol \e without mapping it to an address
SymbolEntry *addMapPoint(Symbol *sym,const Address &addr,
const Address &usepoint); ///< Map a Symbol to a specific address
MapEntry *addMapPoint(Symbol *sym,const Address &addr,const Address &usepoint); ///< Map a Symbol to a specific address
Symbol *addMapSym(Decoder &decoder); ///< Parse a mapped Symbol from a \<mapsym> element
FunctionSymbol *addFunction(const Address &addr,const string &nm);
ExternRefSymbol *addExternalRef(const Address &addr,const Address &refaddr,const string &nm);
@@ -784,6 +855,7 @@ public:
Symbol *addDynamicSymbol(const string &nm,Datatype *ct,const Address &caddr,uint8 hash);
Symbol *addEquateSymbol(const string &nm,uint4 format,uintb value,const Address &addr,uint8 hash);
Symbol *addUnionFacetSymbol(const string &nm,Datatype *dt,int4 fieldNum,const Address &addr,uint8 hash);
SymbolEntry *addSymbolWithConflict(const string &nm,Datatype *ct,Varnode *vn);
string buildDefaultName(Symbol *sym,int4 &base,Varnode *vn) const; ///< Create a default name for the given Symbol
bool isReadOnly(const Address &addr,int4 size,const Address &usepoint) const;
void printBounds(ostream &s) const { rangetree.printBounds(s); } ///< Print a description of \b this Scope's \e owned memory ranges
@@ -803,13 +875,12 @@ class ScopeInternal : public Scope {
protected:
virtual Scope *buildSubScope(uint8 id,const string &nm); ///< Build an unattached Scope to be associated as a sub-scope of \b this
virtual void addSymbolInternal(Symbol *sym);
virtual SymbolEntry *addMapInternal(Symbol *sym,uint4 exfl,const Address &addr,int4 off,int4 sz,const RangeList &uselim);
virtual SymbolEntry *addDynamicMapInternal(Symbol *sym,uint4 exfl,uint8 hash,int4 off,int4 sz,
const RangeList &uselim);
virtual void addMapInternal(Symbol *sym,MapEntry *entry);
virtual void addDynamicMapInternal(Symbol *sym,DynamicEntry *entry);
SymbolNameTree nametree; ///< The set of Symbol objects, sorted by name
vector<EntryMap *> maptable; ///< Rangemaps of SymbolEntry, one map for each address space
vector<vector<Symbol *> > category; ///< References to Symbol objects organized by category
list<SymbolEntry> dynamicentry; ///< Dynamic symbol entries
list<DynamicEntry *> dynamicentry; ///< Dynamic symbol entries
SymbolNameTree multiEntrySet; ///< Set of symbols with multiple entries
uint8 nextUniqueId; ///< Next available symbol id
public:
@@ -824,10 +895,10 @@ public:
virtual ~ScopeInternal(void);
virtual MapIterator begin(void) const;
virtual MapIterator end(void) const;
virtual list<SymbolEntry>::const_iterator beginDynamic(void) const;
virtual list<SymbolEntry>::const_iterator endDynamic(void) const;
virtual list<SymbolEntry>::iterator beginDynamic(void);
virtual list<SymbolEntry>::iterator endDynamic(void);
virtual list<DynamicEntry *>::const_iterator beginDynamic(void) const;
virtual list<DynamicEntry *>::const_iterator endDynamic(void) const;
virtual list<DynamicEntry *>::iterator beginDynamic(void);
virtual list<DynamicEntry *>::iterator endDynamic(void);
virtual void removeSymbolMappings(Symbol *symbol);
virtual void removeSymbol(Symbol *symbol);
virtual void renameSymbol(Symbol *sym,const string &newname);
@@ -836,15 +907,15 @@ public:
virtual void clearAttribute(Symbol *sym,uint4 attr);
virtual void setDisplayFormat(Symbol *sym,uint4 attr);
virtual SymbolEntry *findAddr(const Address &addr,const Address &usepoint) const;
virtual SymbolEntry *findContainer(const Address &addr,int4 size,
const Address &usepoint) const;
virtual SymbolEntry *findClosestFit(const Address &addr,int4 size,
const Address &usepoint) const;
virtual MapEntry *findAddr(const Address &addr,const Address &usepoint) const;
virtual MapEntry *findContainer(const Address &addr,int4 size,const Address &usepoint) const;
virtual MapEntry *findClosestFit(const Address &addr,int4 size,const Address &usepoint) const;
virtual Funcdata *findFunction(const Address &addr) const;
virtual ExternRefSymbol *findExternalRef(const Address &addr) const;
virtual LabSymbol *findCodeLabel(const Address &addr) const;
virtual SymbolEntry *findOverlap(const Address &addr,int4 size) const;
virtual MapEntry *findOverlap(const Address &addr,int4 size) const;
virtual MapEntry *findSymbolBefore(const Address &addr,const Address &usepoint) const;
virtual MapEntry *findSymbolAfter(const Address &addr,const Address &usepoint) const;
virtual void findByName(const string &nm,vector<Symbol *> &res) const;
virtual bool isNameUsed(const string &nm,const Scope *op2) const;
@@ -938,9 +1009,9 @@ public:
void removeRange(Scope *scope,AddrSpace *spc,uintb first,uintb last); ///< Remove an address range from \e ownership of a Scope
Scope *getGlobalScope(void) const { return globalscope; } ///< Get the global Scope
Scope *resolveScope(uint8 id) const; ///< Look-up a Scope by id
Scope *resolveScopeFromSymbolName(const string &fullname,const string &delim,string &basename,Scope *start) const;
Scope *resolveScopeFromSymbolName(const string &fullname,string &basename,Scope *start) const;
Scope *findCreateScope(uint8,const string &nm,Scope *parent); /// Find (and if not found create) a specific subscope
Scope *findCreateScopeFromSymbolName(const string &fullname,const string &delim,string &basename,Scope *start);
Scope *findCreateScopeFromSymbolName(const string &fullname,string &basename,Scope *start);
const Scope *mapScope(const Scope *qpoint,const Address &addr,const Address &usepoint) const;
Scope *mapScope(Scope *qpoint,const Address &addr,const Address &usepoint);
uint4 getProperty(const Address &addr) const { return flagbase.getValue(addr); } ///< Get boolean properties at the given address
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -85,7 +85,7 @@ void ScopeGhidra::decodeHole(Decoder &decoder) const
else if (attribId==ATTRIB_VOLATILE && decoder.readBool())
flags |= Varnode::volatil;
}
holes.insertRange(range.getSpace(),range.getFirst(),range.getLast());
holes.insertRange(range);
decoder.closeElement(elemId);
if (flags != 0) {
ghidra->symboltab->setPropertyRange(flags,range);
@@ -141,8 +141,9 @@ Symbol *ScopeGhidra::dump2Cache(Decoder &decoder) const
throw LowlevelError("DuplicateFunctionError, but could not recover original symbol");
}
if (sym != (Symbol *)0) {
SymbolEntry *entry = sym->getFirstWholeMap();
if (entry != (SymbolEntry *)0) {
SymbolEntry *ent = sym->getFirstWholeMap();
if (ent != (SymbolEntry *)0 && ent->isMapEntry()) {
MapEntry *entry = (MapEntry *)ent;
if (scope != cache) { // We have a namespace cache
// With a global namespace, mark the address range as a "hole", so the same query won't
// go up again. With this limitation, a function can only refer to a single global symbol at a
@@ -230,45 +231,45 @@ void ScopeGhidra::clear(void)
}
}
SymbolEntry *ScopeGhidra::findAddr(const Address &addr,
const Address &usepoint) const
MapEntry *ScopeGhidra::findAddr(const Address &addr,const Address &usepoint) const
{
SymbolEntry *entry;
MapEntry *entry;
entry = cache->findAddr(addr,usepoint);
if (entry == (SymbolEntry *)0) { // Didn't find symbol
if (entry == (MapEntry *)0) { // Didn't find symbol
entry = cache->findContainer(addr,1,Address());
if (entry != (SymbolEntry *)0)
return (SymbolEntry *)0; // Address is already queried, but symbol doesn't start at our address
if (entry != (MapEntry *)0)
return (MapEntry *)0; // Address is already queried, but symbol doesn't start at our address
Symbol *sym = removeQuery(addr); // Query server
if (sym != (Symbol *)0)
entry = sym->getMapEntry(addr);
// entry may be null for certain queries, ghidra may return symbol of size <8 with
// address equal to START of function, even though the query was for an address INTERNAL to the function
}
if ((entry != (SymbolEntry *)0)&&(entry->getAddr()==addr))
if ((entry != (MapEntry *)0)&&(entry->getAddr()==addr))
return entry;
return (SymbolEntry *)0;
return (MapEntry *)0;
}
SymbolEntry *ScopeGhidra::findContainer(const Address &addr,int4 size,
const Address &usepoint) const
MapEntry *ScopeGhidra::findContainer(const Address &addr,int4 size,const Address &usepoint) const
{
SymbolEntry *entry;
MapEntry *entry;
entry = cache->findClosestFit(addr,size,usepoint);
if (entry == (SymbolEntry *)0) {
if (entry == (MapEntry *)0) {
Symbol *sym = removeQuery(addr);
if (sym != (Symbol *)0)
entry = sym->getMapEntry(addr);
// entry may be null for certain queries, ghidra may return symbol of size <8 with
// address equal to START of function, even though the query was for an address INTERNAL to the function
}
if (entry != (SymbolEntry *)0) {
if (entry != (MapEntry *)0) {
// Entry contains addr, does it contain addr+size
uintb last = entry->getAddr().getOffset() + entry->getSize() -1;
if (last >= addr.getOffset() + size-1)
return entry;
}
return (SymbolEntry *)0;
return (MapEntry *)0;
}
ExternRefSymbol *ScopeGhidra::findExternalRef(const Address &addr) const
@@ -340,7 +341,7 @@ Funcdata *ScopeGhidra::resolveExternalRefFunction(ExternRefSymbol *sym) const
// If the function isn't in cache, we use the special
// getExternalRefXML interface to recover the external function
PackedDecode decoder(ghidra);
SymbolEntry *entry = sym->getFirstWholeMap();
MapEntry *entry = (MapEntry *)sym->getFirstWholeMap();
if (ghidra->getExternalRef(entry->getAddr(),decoder)) {
FunctionSymbol *funcSym;
// Make sure referenced function is cached
@@ -352,8 +353,41 @@ Funcdata *ScopeGhidra::resolveExternalRefFunction(ExternRefSymbol *sym) const
return resFd;
}
SymbolEntry *ScopeGhidra::addSymbol(const string &nm,Datatype *ct,
const Address &addr,const Address &usepoint)
MapEntry *ScopeGhidra::findSymbolBefore(const Address &addr,const Address &usepoint) const
{
uintb off = addr.getOffset();
MapEntry *res = findContainer(addr, 1, usepoint);
if (res != (MapEntry *)0)
off = res->getAddr().getOffset();
if (off == 0)
return (MapEntry *)0;
if ((off & 7) == 0)
off -= 8;
else
off -= off & 7;
Address curAddr(addr.getSpace(),off);
return findContainer(curAddr,1,usepoint);
}
MapEntry *ScopeGhidra::findSymbolAfter(const Address &addr,const Address &usepoint) const
{
uintb off = addr.getOffset();
MapEntry *res = findContainer(addr, 1, usepoint);
if (res != (MapEntry *)0)
off = res->getAddr().getOffset() + res->getSize() - 1;
if ((off & 7) != 0)
off -= off & 7;
off += 8;
if (off < addr.getOffset() || off > addr.getSpace()->getHighest())
return (MapEntry *)0;
Address curAddr(addr.getSpace(),off);
return findContainer(curAddr,1,usepoint);
}
MapEntry *ScopeGhidra::addSymbol(const string &nm,Datatype *ct,const Address &addr,const Address &usepoint)
{
// We do not inform Ghidra of the new symbol, we just
// stick it in the cache. This allows the mapglobals action
@@ -361,13 +395,10 @@ SymbolEntry *ScopeGhidra::addSymbol(const string &nm,Datatype *ct,
return cache->addSymbol(nm,ct,addr,usepoint);
}
SymbolEntry *ScopeGhidraNamespace::addMapInternal(Symbol *sym,uint4 exfl,const Address &addr,int4 off,int4 sz,
const RangeList &uselim)
void ScopeGhidraNamespace::addMapInternal(Symbol *sym,MapEntry *entry)
{
SymbolEntry *res;
res = ScopeInternal::addMapInternal(sym,exfl,addr,off,sz,uselim);
glb->symboltab->addRange(this,res->getAddr().getSpace(),res->getFirst(),res->getLast());
return res;
ScopeInternal::addMapInternal(sym,entry);
glb->symboltab->addRange(this,entry->getAddr().getSpace(),entry->getFirst(),entry->getLast());
}
bool ScopeGhidraNamespace::isNameUsed(const string &nm,const Scope *op2) const
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -50,11 +50,9 @@ class ScopeGhidra : public Scope {
throw LowlevelError("remove_range should not be performed on ghidra scope");
}
virtual Scope *buildSubScope(uint8 id,const string &nm);
virtual void addSymbolInternal(Symbol *sym) { throw LowlevelError("add_symbol_internal unimplemented"); }
virtual SymbolEntry *addMapInternal(Symbol *sym,uint4 exfl,const Address &addr,int4 off,int4 sz,
const RangeList &uselim) { throw LowlevelError("addMap unimplemented"); }
virtual SymbolEntry *addDynamicMapInternal(Symbol *sym,uint4 exfl,uint8 hash,int4 off,int4 sz,
const RangeList &uselim) { throw LowlevelError("addMap unimplemented"); }
virtual void addSymbolInternal(Symbol *sym) { throw LowlevelError("addSymbolInternal unimplemented"); }
virtual void addMapInternal(Symbol *sym,MapEntry *entry) { throw LowlevelError("addMapInternal unimplemented"); }
virtual void addDynamicMapInternal(Symbol *sym,DynamicEntry *entry) { throw LowlevelError("addMapInternal unimplemented"); }
public:
ScopeGhidra(ArchitectureGhidra *g); ///< Constructor
@@ -67,8 +65,7 @@ public:
void lockDefaultProperties(void) { flagbaseDefault = ghidra->symboltab->getProperties(); cacheDirty = false; }
virtual ~ScopeGhidra(void);
virtual void clear(void);
virtual SymbolEntry *addSymbol(const string &nm,Datatype *ct,
const Address &addr,const Address &usepoint);
virtual MapEntry *addSymbol(const string &nm,Datatype *ct,const Address &addr,const Address &usepoint);
virtual string buildVariableName(const Address &addr,
const Address &pc,
Datatype *ct,int4 &index,uint4 flags) const {
@@ -79,10 +76,10 @@ public:
virtual void setDisplayFormat(Symbol *sym,uint4 attr) { cache->setDisplayFormat(sym,attr); }
virtual void adjustCaches(void) { cache->adjustCaches(); }
virtual SymbolEntry *findAddr(const Address &addr,const Address &usepoint) const;
virtual SymbolEntry *findContainer(const Address &addr,int4 size,
virtual MapEntry *findAddr(const Address &addr,const Address &usepoint) const;
virtual MapEntry *findContainer(const Address &addr,int4 size,
const Address &usepoint) const;
virtual SymbolEntry *findClosestFit(const Address &addr,int4 size,
virtual MapEntry *findClosestFit(const Address &addr,int4 size,
const Address &usepoint) const {
throw LowlevelError("findClosestFit unimplemented"); }
virtual Funcdata *findFunction(const Address &addr) const;
@@ -90,16 +87,18 @@ public:
virtual LabSymbol *findCodeLabel(const Address &addr) const;
virtual Funcdata *resolveExternalRefFunction(ExternRefSymbol *sym) const;
virtual SymbolEntry *findOverlap(const Address &addr,int4 size) const { throw LowlevelError("findOverlap unimplemented"); }
virtual MapEntry *findOverlap(const Address &addr,int4 size) const { throw LowlevelError("findOverlap unimplemented"); }
virtual MapEntry *findSymbolBefore(const Address &addr,const Address &usepoint) const;
virtual MapEntry *findSymbolAfter(const Address &addr,const Address &usepoint) const;
virtual void findByName(const string &nm,vector<Symbol *> &res) const { throw LowlevelError("findByName unimplemented"); }
virtual bool isNameUsed(const string &nm,const Scope *op2) const { throw LowlevelError("isNameUsed unimplemented"); }
virtual MapIterator begin(void) const { throw LowlevelError("begin unimplemented"); }
virtual MapIterator end(void) const { throw LowlevelError("end unimplemented"); }
virtual list<SymbolEntry>::const_iterator beginDynamic(void) const { throw LowlevelError("beginDynamic unimplemented"); }
virtual list<SymbolEntry>::const_iterator endDynamic(void) const { throw LowlevelError("endDynamic unimplemented"); }
virtual list<SymbolEntry>::iterator beginDynamic(void) { throw LowlevelError("beginDynamic unimplemented"); }
virtual list<SymbolEntry>::iterator endDynamic(void) { throw LowlevelError("endDynamic unimplemented"); }
virtual list<DynamicEntry *>::const_iterator beginDynamic(void) const { throw LowlevelError("beginDynamic unimplemented"); }
virtual list<DynamicEntry *>::const_iterator endDynamic(void) const { throw LowlevelError("endDynamic unimplemented"); }
virtual list<DynamicEntry *>::iterator beginDynamic(void) { throw LowlevelError("beginDynamic unimplemented"); }
virtual list<DynamicEntry *>::iterator endDynamic(void) { throw LowlevelError("endDynamic unimplemented"); }
virtual void clearCategory(int4 cat) { throw LowlevelError("clearCategory unimplemented"); }
virtual void clearUnlockedCategory(int4 cat) { throw LowlevelError("clearUnlockedCategory unimplemented"); }
virtual void clearUnlocked(void) { throw LowlevelError("clearUnlocked unimplemented"); }
@@ -130,8 +129,7 @@ class ScopeGhidraNamespace : public ScopeInternal {
friend class ScopeGhidra;
ArchitectureGhidra *ghidra; ///< Connection to the Ghidra client
protected:
virtual SymbolEntry *addMapInternal(Symbol *sym,uint4 exfl,const Address &addr,int4 off,int4 sz,
const RangeList &uselim);
virtual void addMapInternal(Symbol *sym,MapEntry *entry);
public:
ScopeGhidraNamespace(uint8 id,const string &nm,ArchitectureGhidra *g)
: ScopeInternal(id,nm,g) { ghidra = g; } ///< Constructor
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -75,7 +75,6 @@
prototype, and local symbol information.
- \ref classfuncdata
.
.
\b Translation
- \ref classloadimage
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -21,10 +21,8 @@
- \ref capabilities
- \ref design
- \ref workflow
- \ref ghidraimpl
- \subpage sleigh
- \subpage coreclasses
- \subpage termrewriting
\section overview Overview
@@ -957,21 +957,6 @@ bool SplitVarnode::otherwiseEmpty(PcodeOp *branchop)
return true;
}
/// \brief Verify that the given PcodeOp is a CPUI_INT_MULT by -1
///
/// The PcodeOp must be a CPUI_INT_MULT and the second operand must be a constant -1.
/// \param op is the given PcodeOp
/// \return \b true if the PcodeOp is a multiple by -1
bool SplitVarnode::verifyMultNegOne(PcodeOp *op)
{
if (op->code() != CPUI_INT_MULT) return false;
Varnode *in1 = op->getIn(1);
if (!in1->isConstant()) return false;
if (in1->getOffset() != calc_mask(in1->getSize())) return false;
return true;
}
/// \brief Check that the logical version of a (generic) binary double-precision operation can be created
///
/// This checks only the most generic aspects of the calculation. The input and output whole Varnodes
@@ -1379,11 +1364,9 @@ void SplitVarnode::replaceIndirectOp(Funcdata &data,SplitVarnode &out,SplitVarno
out.createJoinedWhole(data);
in.findCreateWhole(data);
PcodeOp *newop = data.newOp(2,affector->getAddr());
data.opSetOpcode(newop,CPUI_INDIRECT);
PcodeOp *newop = data.newIndirect(affector);
data.opSetOutput(newop,out.getWhole());
data.opSetInput(newop,in.getWhole(),0);
data.opSetInput(newop,data.newVarnodeIop(affector),1);
data.opInsertBefore(newop,affector);
out.buildLoFromWhole(data);
out.buildHiFromWhole(data);
@@ -1640,8 +1623,8 @@ bool SubForm::verify(Varnode *h,Varnode *l,PcodeOp *op)
}
if (!hineg1->isWritten()) continue;
if (!hineg2->isWritten()) continue;
if (!SplitVarnode::verifyMultNegOne(hineg1->getDef())) continue;
if (!SplitVarnode::verifyMultNegOne(hineg2->getDef())) continue;
if (!hineg1->getDef()->verifyMultNegOne()) continue;
if (!hineg2->getDef()->verifyMultNegOne()) continue;
hizext1 = hineg1->getDef()->getIn(0);
hizext2 = hineg2->getDef()->getIn(0);
for(int4 j=0;j<2;++j) {
@@ -1670,7 +1653,7 @@ bool SubForm::verify(Varnode *h,Varnode *l,PcodeOp *op)
Varnode *tmpvn = loadd->getIn(1-loadd->getSlot(lo1));
if (!tmpvn->isWritten()) continue;
negop = tmpvn->getDef();
if (!SplitVarnode::verifyMultNegOne(negop)) continue;
if (!negop->verifyMultNegOne()) continue;
if (negop->getIn(0) != lo2) continue;
reslo = loadd->getOut();
return true;
@@ -2169,6 +2152,7 @@ bool LessThreeWay::normalizeHi(void)
}
hiconstform = false;
if (vnhil2->isConstant()) {
if (in.getSize() > sizeof(uintb)) return false; // Must have enough precision for constant
hiconstform = true;
hival = vnhil2->getOffset();
SplitVarnode::getTrueFalse(hilessbool,hiflip,hilesstrue,hilessfalse);
@@ -78,7 +78,6 @@ public:
static void findCopies(const SplitVarnode &in,vector<SplitVarnode> &splitvec);
static void getTrueFalse(PcodeOp *boolop,bool flip,BlockBasic *&trueout,BlockBasic *&falseout);
static bool otherwiseEmpty(PcodeOp *branchop);
static bool verifyMultNegOne(PcodeOp *op);
static PcodeOp *prepareBinaryOp(SplitVarnode &out,SplitVarnode &in1,SplitVarnode &in2);
static void createBinaryOp(Funcdata &data,SplitVarnode &out,SplitVarnode &in1,SplitVarnode &in2,
PcodeOp *existop,OpCode opc);
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -57,8 +57,8 @@ const uint4 DynamicHash::transtable[] = {
0, // CAST is skipped
CPUI_INT_ADD, CPUI_INT_ADD, // PTRADD and PTRSUB hash same as INT_ADD
CPUI_SEGMENTOP, CPUI_CPOOLREF, CPUI_NEW, CPUI_INSERT, CPUI_EXTRACT,
CPUI_POPCOUNT, CPUI_LZCOUNT
CPUI_SEGMENTOP, CPUI_CPOOLREF, CPUI_NEW, CPUI_INSERT, CPUI_ZPULL,
CPUI_POPCOUNT, CPUI_LZCOUNT, CPUI_SPULL
};
@@ -499,7 +499,7 @@ void DynamicHash::uniqueHash(const PcodeOp *op,int4 slot,Funcdata *fd)
addrresult = Address(); // Hash cannot be calculated
return;
}
gatherOpsAtAddress(oplist,fd,op->getAddr());
fd->listOps(oplist,op->getAddr());
for(method=4;method<7;++method) {
clear();
calcHash(op,slot,method);
@@ -600,7 +600,7 @@ PcodeOp *DynamicHash::findOp(const Funcdata *fd,const Address &addr,uint8 h)
clearTotalPosition(h);
vector<PcodeOp *> oplist;
vector<PcodeOp *> oplist2;
gatherOpsAtAddress(oplist,fd,addr);
fd->listOps(oplist, addr);
for(uint4 i=0;i<oplist.size();++i) {
PcodeOp *tmpop = oplist[i];
if (slot >= tmpop->numInput()) continue;
@@ -648,12 +648,11 @@ void DynamicHash::gatherFirstLevelVars(vector<Varnode *> &varlist,const Funcdata
uint4 opcVal = getOpCodeFromHash(h);
int4 slot = getSlotFromHash(h);
bool isnotattached = getIsNotAttached(h);
PcodeOpTree::const_iterator iter = fd->beginOp(addr);
PcodeOpTree::const_iterator enditer = fd->endOp(addr);
vector<PcodeOp *> opList;
fd->listOps(opList, addr);
while(iter!=enditer) {
PcodeOp *op = (*iter).second;
++iter;
for(int4 i=0;i<opList.size();++i) {
PcodeOp *op = opList[i];
if (op->isDead()) continue;
if (transtable[op->code()] != opcVal) continue;
if (slot <0) {
@@ -684,23 +683,6 @@ void DynamicHash::gatherFirstLevelVars(vector<Varnode *> &varlist,const Funcdata
dedupVarnodes(varlist);
}
/// \brief Place all PcodeOps at the given address in the provided container
///
/// \param opList is the container to hold the PcodeOps
/// \param fd is the function
/// \param addr is the given address
void DynamicHash::gatherOpsAtAddress(vector<PcodeOp *> &opList,const Funcdata *fd,const Address &addr)
{
PcodeOpTree::const_iterator iter,enditer;
enditer = fd->endOp(addr);
for(iter = fd->beginOp(addr); iter != enditer; ++iter) {
PcodeOp *op = (*iter).second;
if (op->isDead()) continue;
opList.push_back(op);
}
}
/// The hash encodes the input \e slot the root Varnode was attached to in its PcodeOp.
/// \param h is the hash value
/// \return the slot index or -1 if the Varnode was attached as output
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -92,7 +92,6 @@ public:
const Address &getAddress(void) const { return addrresult; } ///< Get the (current) address
static void gatherFirstLevelVars(vector<Varnode *> &varlist,const Funcdata *fd,const Address &addr,uint8 h);
static void gatherOpsAtAddress(vector<PcodeOp *> &opList,const Funcdata *fd,const Address &addr);
static int4 getSlotFromHash(uint8 h); ///< Retrieve the encoded slot from a hash
static uint4 getMethodFromHash(uint8 h); ///< Retrieve the encoded method from a hash
static uint4 getOpCodeFromHash(uint8 h); ///< Retrieve the encoded op-code from a hash
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -29,9 +29,11 @@
#include <set>
#include <list>
#include <vector>
#include <deque>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <memory>
namespace ghidra {
@@ -40,6 +42,7 @@ using std::map;
using std::set;
using std::list;
using std::vector;
using std::deque;
using std::pair;
using std::make_pair;
using std::ostream;
@@ -63,6 +66,7 @@ using std::max;
using std::to_string;
using std::piecewise_construct;
using std::forward_as_tuple;
using std::unique_ptr;
/// \brief The lowest level error generated by the decompiler
@@ -0,0 +1,804 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "expression.hh"
#include "database.hh"
namespace ghidra {
/// \brief Return \b true if the alternate path looks more valid than the main path.
///
/// Two different paths from a common Varnode each terminate at a CALL, CALLIND, or RETURN.
/// Evaluate which path most likely represents actual parameter/return value passing,
/// based on traversal information about each path.
/// \param vn is the Varnode terminating the \e alternate path
/// \param flags indicates traversals for both paths
/// \return \b true if the alternate path is preferred
bool TraverseNode::isAlternatePathValid(const Varnode *vn,uint4 flags)
{
if ((flags & (indirect | indirectalt)) == indirect)
// If main path traversed an INDIRECT but the alternate did not
return true; // Main path traversed INDIRECT, alternate did not
if ((flags & (indirect | indirectalt)) == indirectalt)
return false; // Alternate path traversed INDIRECT, main did not
if ((flags & actionalt) != 0)
return true; // Alternate path traversed a dedicated COPY
if (vn->loneDescend() == (PcodeOp*)0) return false;
const PcodeOp *op = vn->getDef();
if (op == (PcodeOp*)0) return true;
while(op->isIncidentalCopy() && op->code() == CPUI_COPY) { // Skip any incidental COPY
vn = op->getIn(0);
if (vn->loneDescend() == (PcodeOp *)0) return false;
op = vn->getDef();
if (op == (PcodeOp *)0) return true;
}
return !op->isMarker(); // MULTIEQUAL or INDIRECT indicates multiple values
}
/// \brief Test if two operations with same opcode produce complementary boolean values
///
/// This only tests for cases where the opcode is INT_LESS or INT_SLESS and one of the
/// inputs is constant.
/// \param bin1op is the first p-code op to compare
/// \param bin2op is the second p-code op to compare
/// \return \b true if the two operations always produce complementary values
bool BooleanMatch::sameOpComplement(PcodeOp *bin1op,PcodeOp *bin2op)
{
OpCode opcode = bin1op->code();
if ((opcode == CPUI_INT_SLESS)||(opcode==CPUI_INT_LESS)) {
// Basically we test for the scenario like: x < 9 8 < x
int4 constslot = 0;
if (bin1op->getIn(1)->isConstant())
constslot = 1;
if (!bin1op->getIn(constslot)->isConstant()) return false;
if (!bin2op->getIn(1-constslot)->isConstant()) return false;
if (!varnodeSame(bin1op->getIn(1-constslot),bin2op->getIn(constslot))) return false;
uintb val1 = bin1op->getIn(constslot)->getOffset();
uintb val2 = bin2op->getIn(1-constslot)->getOffset();
if (constslot!=0) {
uintb tmp = val2;
val2 = val1;
val1 = tmp;
}
if (val1 + 1 != val2) return false;
if ((val2 == 0)&&(opcode==CPUI_INT_LESS)) return false; // Corner case for unsigned
if (opcode==CPUI_INT_SLESS) { // Corner case for signed
int4 sz = bin1op->getIn(constslot)->getSize();
if (signbit_negative(val2,sz) && (!signbit_negative(val1,sz)))
return false;
}
return true;
}
return false;
}
/// \brief Do the given Varnodes hold the same value, possibly as constants
///
/// \param a is the first Varnode to compare
/// \param b is the second Varnode
/// \return \b true if the Varnodes (always) hold the same value
bool BooleanMatch::varnodeSame(Varnode *a,Varnode *b)
{
if (a == b) return true;
if (a->isConstant() && b->isConstant())
return (a->getOffset() == b->getOffset());
return false;
}
/// \brief Determine if two boolean Varnodes hold related values
///
/// The values may be the \e same, or opposite of each other (\e complementary).
/// Otherwise the values are \e uncorrelated. The trees constructing each Varnode
/// are examined up to a maximum \b depth. If this is exceeded \e uncorrelated is returned.
/// \param vn1 is the first boolean Varnode
/// \param vn2 is the second boolean Varnode
/// \param depth is the maximum depth to traverse in the evaluation
/// \return the correlation class
int4 BooleanMatch::evaluate(Varnode *vn1,Varnode *vn2,int4 depth)
{
if (vn1 == vn2) return same;
PcodeOp *op1,*op2;
OpCode opc1,opc2;
if (vn1->isWritten()) {
op1 = vn1->getDef();
opc1 = op1->code();
if (opc1 == CPUI_BOOL_NEGATE) {
int res = evaluate(op1->getIn(0),vn2,depth);
if (res == same) // Flip same <-> complementary result
res = complementary;
else if (res == complementary)
res = same;
return res;
}
}
else {
op1 = (PcodeOp *)0; // Don't give up before checking if op2 is BOOL_NEGATE
opc1 = CPUI_MAX;
}
if (vn2->isWritten()) {
op2 = vn2->getDef();
opc2 = op2->code();
if (opc2 == CPUI_BOOL_NEGATE) {
int4 res = evaluate(vn1,op2->getIn(0),depth);
if (res == same) // Flip same <-> complementary result
res = complementary;
else if (res == complementary)
res = same;
return res;
}
}
else
return uncorrelated;
if (op1 == (PcodeOp *)0)
return uncorrelated;
if (!op1->isBoolOutput() || !op2->isBoolOutput())
return uncorrelated;
if (depth != 0 && (opc1 == CPUI_BOOL_AND || opc1 == CPUI_BOOL_OR || opc1 == CPUI_BOOL_XOR)) {
if (opc2 == CPUI_BOOL_AND || opc2 == CPUI_BOOL_OR || opc2 == CPUI_BOOL_XOR) {
if (opc1 == opc2 || (opc1 == CPUI_BOOL_AND && opc2 == CPUI_BOOL_OR) || (opc1 == CPUI_BOOL_OR && opc2 == CPUI_BOOL_AND)) {
int4 pair1 = evaluate(op1->getIn(0),op2->getIn(0),depth-1);
int4 pair2;
if (pair1 == uncorrelated) {
pair1 = evaluate(op1->getIn(0),op2->getIn(1),depth-1); // Try other possible pairing (commutative op)
if (pair1 == uncorrelated)
return uncorrelated;
pair2 = evaluate(op1->getIn(1),op2->getIn(0),depth-1);
}
else {
pair2 = evaluate(op1->getIn(1),op2->getIn(1),depth-1);
}
if (pair2 == uncorrelated)
return uncorrelated;
if (opc1 == opc2) {
if (pair1 == same && pair2 == same)
return same;
else if (opc1 == CPUI_BOOL_XOR) {
if (pair1 == complementary && pair2 == complementary)
return same;
return complementary;
}
}
else { // Must be CPUI_BOOL_AND and CPUI_BOOL_OR
if (pair1 == complementary && pair2 == complementary)
return complementary; // De Morgan's Law
}
}
}
}
else {
// Two boolean output ops, compare them directly
if (opc1 == opc2) {
bool sameOp = true;
int numInputs = op1->numInput();
for (int i = 0; i < numInputs; ++i){
if (!varnodeSame(op1->getIn(i),op2->getIn(i))){
sameOp = false;
break;
}
}
if (sameOp){
return same;
}
if (sameOpComplement(op1,op2)) {
return complementary;
}
return uncorrelated;
}
// Check if the binary ops are complements of one another
int4 slot1 = 0;
int4 slot2 = 0;
bool reorder;
if (opc1 != get_booleanflip(opc2,reorder))
return uncorrelated;
if (reorder) slot2 = 1;
if (!varnodeSame(op1->getIn(slot1),op2->getIn(slot2)))
return uncorrelated;
if (!varnodeSame(op1->getIn(1-slot1),op2->getIn(1-slot2)))
return uncorrelated;
return complementary;
}
return uncorrelated;
}
const int4 BooleanExpressionMatch::maxDepth = 1;
bool BooleanExpressionMatch::verifyCondition(PcodeOp *op, PcodeOp *iop)
{
int4 res = BooleanMatch::evaluate(op->getIn(1), iop->getIn(1), maxDepth);
if (res == BooleanMatch::uncorrelated)
return false;
matchflip = (res == BooleanMatch::complementary);
if (op->isBooleanFlip())
matchflip = !matchflip;
if (iop->isBooleanFlip())
matchflip = !matchflip;
return true;
}
/// Assuming root->getOut() is the root of an expression formed with the
/// CPUI_INT_ADD op, collect all the Varnode \e terms of the expression.
void TermOrder::collect(void)
{
Varnode *curvn;
PcodeOp *curop;
PcodeOp *subop,*multop;
vector<PcodeOp *> opstack; // Depth first traversal path
vector<PcodeOp *> multstack;
opstack.push_back(root);
multstack.push_back((PcodeOp *)0);
while(!opstack.empty()) {
curop = opstack.back();
multop = multstack.back();
opstack.pop_back();
multstack.pop_back();
for(int4 i=0;i<curop->numInput();++i) {
curvn = curop->getIn(i); // curvn is a node of the subtree IF
if (!curvn->isWritten()) { // curvn is not defined by another operation
terms.emplace_back(curop,i,multop);
continue;
}
if (curvn->loneDescend() == (PcodeOp *)0) { // curvn has more then one use
terms.emplace_back(curop,i,multop);
continue;
}
subop = curvn->getDef();
if (subop->code() != CPUI_INT_ADD) { // or if curvn is defined with some other type of op
if ((subop->code()==CPUI_INT_MULT)&&(subop->getIn(1)->isConstant())) {
PcodeOp *addop = subop->getIn(0)->getDef();
if ((addop!=(PcodeOp *)0)&&(addop->code()==CPUI_INT_ADD)) {
if (addop->getOut()->loneDescend()!=(PcodeOp *)0) {
opstack.push_back(addop);
multstack.push_back(subop);
continue;
}
}
}
terms.emplace_back(curop,i,multop);
continue;
}
opstack.push_back(subop);
multstack.push_back(multop);
}
}
}
void TermOrder::sortTerms(void)
{
sorter.reserve(terms.size());
for(vector<AdditiveEdge>::iterator iter=terms.begin();iter!=terms.end();++iter)
sorter.push_back( &(*iter) );
sort(sorter.begin(),sorter.end(),additiveCompare);
}
/// The value \b true is returned if it can be proven that two terms add the same value to their
/// respective expressions.
/// \param op2 is the other term to compare with \b this
/// \return \b true if the terms are equivalent
bool AddExpression::Term::isEquivalent(const Term &op2) const
{
if (coeff != op2.coeff) return false;
return functionalEquality(vn,op2.vn);
}
/// The value \b true is returned if it can be proven that the expressions always produce the same value.
/// \param op2 is the other expression to compare with \b this
/// \return \b true if the expressions are equivalent
bool AddExpression::isEquivalent(const AddExpression &op2) const
{
if (constval != op2.constval)
return false;
if (numTerms != op2.numTerms) return false;
if (numTerms == 1) {
if (terms[0].isEquivalent(op2.terms[0]))
return true;
}
else if (numTerms == 2) {
if (terms[0].isEquivalent(op2.terms[0]) && terms[1].isEquivalent(op2.terms[1]))
return true;
if (terms[0].isEquivalent(op2.terms[1]) && terms[1].isEquivalent(op2.terms[0]))
return true;
}
return false;
}
/// Recursively collect terms, up to the given depth. INT_ADD either contributes to the constant sum, or
/// it is recursively walked. Term coefficients are collected from INT_MULT with a constant.
/// \param vn is the root of the (sub)expression
/// \param coeff is the current multiplicative coefficient of the subexpression
/// \param depth is the current depth
void AddExpression::gather(Varnode *vn,uintb coeff,int4 depth)
{
if (vn->isConstant()) {
constval = constval + coeff * vn->getOffset();
constval &= calc_mask(vn->getSize());
return;
}
if (vn->isWritten()) {
PcodeOp *op = vn->getDef();
if (op->code() == CPUI_INT_ADD) {
if (!op->getIn(1)->isConstant())
depth -= 1;
if (depth >= 0) {
gather(op->getIn(0),coeff,depth);
gather(op->getIn(1),coeff,depth);
return;
}
}
else if (op->code() == CPUI_INT_MULT) {
if (op->getIn(1)->isConstant()) {
coeff = coeff * op->getIn(1)->getOffset();
coeff &= calc_mask(vn->getSize());
gather(op->getIn(0),coeff,depth);
return;
}
}
}
add(vn,coeff);
return;
}
/// Gather up to two non-constant additive terms, given two root Varnodes that are being subtracted.
/// \param a is the first root
/// \param b is the second root being subtracted from the first
void AddExpression::gatherTwoTermsSubtract(Varnode *a,Varnode *b)
{
int4 depth = (a->isConstant() || b->isConstant()) ? 1 : 0;
gather(a,(uintb)1,depth);
gather(b,calc_mask(b->getSize()),depth);
}
/// Gather up to two non-constant additive terms, given two root Varnodes being added
/// \param a is the first root
/// \param b is the second root being added to the first
void AddExpression::gatherTwoTermsAdd(Varnode *a,Varnode *b)
{
int4 depth = (a->isConstant() || b->isConstant()) ? 1 : 0;
gather(a,(uintb)1,depth);
gather(b,(uintb)1,depth);
}
/// Gather up to two non-constant additive terms in the expression at the given root.
/// \param root is the root Varnode
void AddExpression::gatherTwoTermsRoot(Varnode *root)
{
gather(root,(uintb)1,1);
}
/// Find the structure immediately containing the byte range described by the given data-type.
/// Then, given the least significant bit of the bitfield, find the structure immediately containing the bitfield,
/// which may be a different structure.
/// \param dt is the data-type describing the byte range
/// \param initByteOff is the initial offset of the byte range within the data-type (may be -1)
/// \param leastBitOff is the least significant bit of the bitfield within the byte range
/// \param isBigEndian is \b true if the data-type is stored in big endian memory
void BitFieldExpression::getStructures(Datatype *dt,int4 initByteOff,int4 leastBitOff,bool isBigEndian)
{
TypeStruct *encompassStruct;
theStruct = (TypeStruct *)0;
byteRangeOffset = (initByteOff < 0) ? 0 : initByteOff;
if (dt->getMetatype() == TYPE_PARTIALSTRUCT) {
TypePartialStruct *partial = (TypePartialStruct *)dt;
Datatype *structTmp = partial->getParent();
if (structTmp->getMetatype() != TYPE_STRUCT) return;
byteRangeOffset += partial->getOffset();
encompassStruct = (TypeStruct *)structTmp;
}
else if (dt->getMetatype() == TYPE_STRUCT) {
encompassStruct = (TypeStruct *)dt;
}
else
return;
int8 offset = byteRangeOffset;
leastBitOff /= 8;
if (isBigEndian)
offset += (dt->getSize() - leastBitOff - 1);
else
offset += leastBitOff;
theStruct = encompassStruct;
offsetToBitStruct = 0;
for(;;) {
int8 newoff;
Datatype *tmpDt = theStruct->getSubType(offset, &newoff);
if (tmpDt == (Datatype *)0) break;
if (tmpDt->getMetatype() != TYPE_STRUCT) break;
theStruct = (TypeStruct *)tmpDt;
offsetToBitStruct += (offset-newoff);
offset = newoff;
}
}
const Varnode *BitFieldExpression::recoverStructurePointer(const Varnode *vn,int4 offset)
{
if (offset == 0 && theStruct->getSize() == vn->getSize())
return vn;
else if (vn->isWritten()) {
const PcodeOp *ptrSub = vn->getDef();
if (ptrSub->code() == CPUI_PTRSUB) {
if ((int4)ptrSub->getIn(1)->getOffset() == offset) {
return ptrSub->getIn(0);
}
}
}
if (offset != 0)
return (const Varnode *)0;
return vn;
}
/// \param pull is the given ZPULL or SPULL
/// \return the corresponding bitfield description or null
const TypeBitField *BitFieldExpression::getPullField(const PcodeOp *pull)
{
BitFieldExpression expr;
const Varnode *inVn = pull->getIn(0);
int4 leastBitOff = (int4)pull->getIn(1)->getOffset();
int4 bitSize = (int4)pull->getIn(2)->getOffset();
bool isBig = inVn->getSpace()->isBigEndian();
Datatype *dt = inVn->getTypeReadFacing(pull);
expr.getStructures(dt, 0, leastBitOff, isBig);
if (expr.theStruct == (TypeStruct *)0)
return (const TypeBitField *)0;
BitRange range(expr.byteRangeOffset-expr.offsetToBitStruct,inVn->getSize(),leastBitOff,bitSize,isBig);
return expr.theStruct->findMatchingBitField(range);
}
InsertExpression::InsertExpression(const PcodeOp *insert)
{
insertOp = insert;
bitfield = (const TypeBitField *)0;
const Varnode *value = insertOp->getOut();
symbol = value->getHigh()->getSymbol();
if (symbol == (const Symbol *)0) return;
AddrSpace *spc = value->getSpace();
int4 leastBitOff = (int4)insertOp->getIn(2)->getOffset();
int4 bitSize = (int4)insertOp->getIn(3)->getOffset();
getStructures(symbol->getType(),value->getHigh()->getSymbolOffset(),leastBitOff,spc->isBigEndian());
if (theStruct == (TypeStruct *)0) return;
BitRange range(byteRangeOffset - offsetToBitStruct,value->getSize(),leastBitOff,bitSize,spc->isBigEndian());
bitfield = theStruct->findMatchingBitField(range);
}
/// \param insert is the CPUI_INSERT op
/// \return a mask with a 1 wherever bits are inserted by the op
uintb InsertExpression::getRangeMask(const PcodeOp *insert)
{
int4 leastBitOff = (int4)insert->getIn(2)->getOffset();
int4 bitSize = (int4)insert->getIn(3)->getOffset();
uintb res = 0;
res = ~res;
if (bitSize < 8 * sizeof(uintb))
res = ~(res << bitSize);
res <<= leastBitOff;
return res;
}
/// \param insert is the CPUI_INSERT op
/// \return mask with of the least significant bits
uintb InsertExpression::getLSBMask(const PcodeOp *insert)
{
int4 bitSize = (int4)insert->getIn(3)->getOffset();
uintb res = 0;
res = ~res;
if (bitSize < 8 * sizeof(uintb))
res = ~(res << bitSize);
return res;
}
InsertStoreExpression::InsertStoreExpression(const PcodeOp *store)
{
bitfield = (const TypeBitField *)0;
structPtr = (Varnode *)0;
theStruct = (TypeStruct *)0;
loadOp = (PcodeOp *)0;
const Varnode *value = store->getIn(2);
if (!value->isWritten()) return;
insertOp = value->getDef();
if (insertOp->code() != CPUI_INSERT) return;
const Varnode *dest = insertOp->getIn(0); // dest can either be a constant or LOAD
if (dest->isWritten()) {
loadOp = dest->getDef();
if (loadOp->code() != CPUI_LOAD) return;
}
else if (!dest->isConstant())
return;
AddrSpace *spc = store->getIn(0)->getSpaceFromConst();
int4 leastBitOff = (int4)insertOp->getIn(2)->getOffset();
int4 bitSize = (int4)insertOp->getIn(3)->getOffset();
getStructures(value->getTypeDefFacing(),0,leastBitOff,spc->isBigEndian());
if (theStruct == (TypeStruct *)0) return;
structPtr = recoverStructurePointer(store->getIn(1), byteRangeOffset);
if (structPtr == (const Varnode *)0) return;
BitRange range(byteRangeOffset - offsetToBitStruct,value->getSize(),leastBitOff,bitSize,spc->isBigEndian());
bitfield = theStruct->findMatchingBitField(range);
}
PullExpression::PullExpression(const PcodeOp *pull)
{
pullOp = pull;
bitfield = (const TypeBitField *)0;
theStruct = (TypeStruct *)0;
loadOp = (const PcodeOp *)0;
structPtr = (const Varnode *)0;
const Varnode *inVn = pullOp->getIn(0);
AddrSpace *spc;
Datatype *dt;
int4 offset;
if (inVn->isWritten() && inVn->getDef()->code() == CPUI_LOAD) {
loadOp = inVn->getDef();
spc = loadOp->getIn(0)->getSpaceFromConst();
dt = inVn->getTypeReadFacing(pullOp);
offset = 0;
}
else {
symbol = inVn->getHigh()->getSymbol();
if (symbol == (const Symbol *)0) return;
spc = inVn->getSpace();
dt = symbol->getType();
offset = inVn->getHigh()->getSymbolOffset();
}
int4 leastBitOff = (int4)pullOp->getIn(1)->getOffset();
int4 bitSize = (int4)pullOp->getIn(2)->getOffset();
getStructures(dt,offset,leastBitOff,spc->isBigEndian());
if (theStruct == (TypeStruct *)0) return;
if (loadOp != (const PcodeOp *)0) {
structPtr = recoverStructurePointer(loadOp->getIn(1), byteRangeOffset);
if (structPtr == (const Varnode *)0) return;
}
BitRange range(byteRangeOffset-offsetToBitStruct,inVn->getSize(),leastBitOff,bitSize,spc->isBigEndian());
bitfield = theStruct->findMatchingBitField(range);
}
/// \brief Perform basic comparison of two given Varnodes
///
/// Return
/// - 0 if \b vn1 and \b vn2 must hold same value
/// - -1 if they definitely don't hold same value
/// - 1 if the same value depends on ops writing to \b vn1 and \b vn2
/// \param vn1 is the first Varnode to compare
/// \param vn2 is the second
/// \return a code -1, 0, or 1
static int4 functionalEqualityLevel0(Varnode *vn1,Varnode *vn2)
{
if (vn1==vn2) return 0;
if (vn1->getSize() != vn2->getSize()) return -1;
if (vn1->isConstant()) {
if (vn2->isConstant()) {
return (vn1->getOffset() == vn2->getOffset()) ? 0 : -1;
}
return -1;
}
if (vn1->isFree() || vn2->isFree()) return -1;
return 1;
}
/// \brief Try to determine if \b vn1 and \b vn2 contain the same value
///
/// Return:
/// - -1, if they do \b not, or if it can't be immediately verified
/// - 0, if they \b do hold the same value
/// - >0, if the result is contingent on additional varnode pairs having the same value
/// In the last case, the varnode pairs are returned as (res1[i],res2[i]),
/// where the return value is the number of pairs.
/// \param vn1 is the first Varnode to compare
/// \param vn2 is the second Varnode
/// \param res1 is a reference to the first returned Varnode
/// \param res2 is a reference to the second returned Varnode
/// \return the result of the comparison
int4 functionalEqualityLevel(Varnode *vn1,Varnode *vn2,Varnode **res1,Varnode **res2)
{
int4 testval = functionalEqualityLevel0(vn1,vn2);
if (testval != 1)
return testval;
if (!vn1->isWritten() || !vn2->isWritten()) {
return -1; // Did not find at least one level of match
}
PcodeOp *op1 = vn1->getDef();
PcodeOp *op2 = vn2->getDef();
OpCode opc = op1->code();
if (opc != op2->code()) return -1;
int4 num = op1->numInput();
if (num != op2->numInput()) return -1;
if (op1->isMarker()) return -1;
if (op2->isCall()) return -1;
if (opc == CPUI_LOAD) {
// FIXME: We assume two loads produce the same
// result if the address is the same and the loads
// occur in the same instruction
if (op1->getAddr() != op2->getAddr()) return -1;
}
if (num >= 3) {
if (opc != CPUI_PTRADD) return -1; // If this is a PTRADD
if (op1->getIn(2)->getOffset() != op2->getIn(2)->getOffset()) return -1; // Make sure the elsize constant is equal
num = 2; // Otherwise treat as having 2 inputs
}
for(int4 i=0;i<num;++i) {
res1[i] = op1->getIn(i);
res2[i] = op2->getIn(i);
}
testval = functionalEqualityLevel0(res1[0],res2[0]);
if (testval == 0) { // A match locks in this comparison ordering
if (num==1) return 0;
testval = functionalEqualityLevel0(res1[1],res2[1]);
if (testval==0) return 0;
if (testval < 0) return -1;
res1[0] = res1[1]; // Match is contingent on second pair
res2[0] = res2[1];
return 1;
}
if (num == 1) return testval;
int4 testval2 = functionalEqualityLevel0(res1[1],res2[1]);
if (testval2 == 0) { // A match locks in this comparison ordering
return testval;
}
int4 unmatchsize;
if ((testval==1)&&(testval2==1))
unmatchsize = 2;
else
unmatchsize = -1;
if (!op1->isCommutative()) return unmatchsize;
// unmatchsize must be 2 or -1 here on a commutative operator,
// try flipping
int4 comm1 = functionalEqualityLevel0(res1[0],res2[1]);
int4 comm2 = functionalEqualityLevel0(res1[1],res2[0]);
if ((comm1==0) && (comm2==0))
return 0;
if ((comm1<0)||(comm2<0))
return unmatchsize;
if (comm1==0) { // AND (comm2==1)
res1[0] = res1[1]; // Left over unmatch is res1[1] and res2[0]
return 1;
}
if (comm2==0) { // AND (comm1==1)
res2[0] = res2[1]; // Left over unmatch is res1[0] and res2[1]
return 1;
}
// If we reach here (comm1==1) AND (comm2==1)
if (unmatchsize == 2) // If the original ordering wasn't impossible
return 2; // Prefer the original ordering
Varnode *tmpvn = res2[0]; // Otherwise swap the ordering
res2[0] = res2[1];
res2[1] = tmpvn;
return 2;
}
/// \brief Determine if two Varnodes hold the same value
///
/// Only return \b true if it can be immediately determined they are equivalent
/// \param vn1 is the first Varnode
/// \param vn2 is the second Varnode
/// \return true if they are provably equal
bool functionalEquality(Varnode *vn1,Varnode *vn2)
{
Varnode *buf1[2];
Varnode *buf2[2];
return (functionalEqualityLevel(vn1,vn2,buf1,buf2)==0);
}
/// \brief Return true if vn1 and vn2 are verifiably different values
///
/// This is actually a rather speculative test
/// \param vn1 is the first Varnode to compare
/// \param vn2 is the second Varnode
/// \param depth is the maximum level to recurse while testing
/// \return \b true if they are different
bool functionalDifference(Varnode *vn1,Varnode *vn2,int4 depth)
{
PcodeOp *op1,*op2;
int4 i,num;
if (vn1 == vn2) return false;
if ((!vn1->isWritten())||(!vn2->isWritten())) {
if (vn1->isConstant() && vn2->isConstant())
return !(vn1->getAddr()==vn2->getAddr());
if (vn1->isInput()&&vn2->isInput()) return false; // Might be the same
if (vn1->isFree()||vn2->isFree()) return false; // Might be the same
return true;
}
op1 = vn1->getDef();
op2 = vn2->getDef();
if (op1->code() != op2->code()) return true;
num = op1->numInput();
if (num != op2->numInput()) return true;
if (depth==0) return true; // Different as far as we can tell
depth -= 1;
for(i=0;i<num;++i)
if (functionalDifference(op1->getIn(i),op2->getIn(i),depth))
return true;
return false;
}
/// \brief Back-track as far as possible from a pointer Varnode thru PTRSUB, INT_ADD, and COPY collecting offsets
///
/// The pointer that is reached by back-tracking is returned, and any accumulated offset is passed back.
/// \param vn is the pointer Varnode
/// \param offset passes back the accumulated offset
/// \return the reached Varnode pointer
Varnode *rootPointer(Varnode *vn,uintb &offset)
{
offset = 0;
for(;;) {
if (!vn->isWritten()) break;
PcodeOp *op = vn->getDef();
OpCode opc = op->code();
if (opc == CPUI_PTRSUB) {
offset += op->getIn(1)->getOffset();
vn = op->getIn(0);
}
else if (opc == CPUI_INT_ADD) {
Varnode *cvn = op->getIn(1);
if (!cvn->isConstant()) break;
offset += cvn->getOffset();
vn = op->getIn(0);
}
else if (opc == CPUI_COPY) {
vn = op->getIn(0);
}
else
break;
}
return vn;
}
/// \brief Determine if two pointer Varnodes always hold the same value
///
/// \param vn1 is the first pointer to compare
/// \param vn2 is the second pointer to compare
bool pointerEquality(Varnode *vn1,Varnode *vn2)
{
uintb off1,off2;
if (vn1 == vn2) return true;
vn1 = rootPointer(vn1,off1);
vn2 = rootPointer(vn2,off2);
if (off1 != off2) return false;
return (vn1 == vn2);
}
} // End namespace ghidra
@@ -0,0 +1,238 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// \file expression.hh
/// \brief Classes to collect, analyze, and match expressions within p-code data-flow
#ifndef __EXPRESSION_HH__
#define __EXPRESSION_HH__
#include "op.hh"
namespace ghidra {
/// \brief An edge in a data-flow path or graph
///
/// A minimal node for traversing expressions in the data-flow
struct PcodeOpNode {
PcodeOp *op; ///< The p-code end-point of the edge
int4 slot; ///< Slot indicating the input Varnode end-point of the edge
PcodeOpNode(void) { op = (PcodeOp *)0; slot = 0; } ///< Unused constructor
PcodeOpNode(PcodeOp *o,int4 s) { op = o; slot = s; } ///< Constructor
bool operator<(const PcodeOpNode &op2) const; ///< Simple comparator for putting edges in a sorted container
static bool compareByHigh(const PcodeOpNode &a,const PcodeOpNode &b); ///< Compare Varnodes by their HighVariable
};
/// Compare PcodeOps (as pointers) first, then slot
/// \param op2 is the other edge to compare with \b this
/// \return true if \b this should come before the other PcodeOp
inline bool PcodeOpNode::operator<(const PcodeOpNode &op2) const
{
if (op != op2.op)
return (op->getSeqNum().getTime() < op2.op->getSeqNum().getTime());
if (slot != op2.slot)
return (slot < op2.slot);
return false;
}
/// Allow a sorting that groups together input Varnodes with the same HighVariable
/// \param a is the first Varnode to compare
/// \param b is the second Varnode to compare
/// \return true is \b a should come before \b b
inline bool PcodeOpNode::compareByHigh(const PcodeOpNode &a, const PcodeOpNode &b)
{
return a.op->getIn(a.slot)->getHigh() < b.op->getIn(b.slot)->getHigh();
}
/// \brief Node for a forward traversal of a Varnode expression
struct TraverseNode {
enum {
actionalt = 1, ///< Alternate path traverses a solid action or \e non-incidental COPY
indirect = 2, ///< Main path traverses an INDIRECT
indirectalt = 4, ///< Alternate path traverses an INDIRECT
lsb_truncated = 8, ///< Least significant byte(s) of original value have been truncated
concat_high = 0x10 ///< Original value has been concatented as \e most significant portion
};
const Varnode *vn; ///< Varnode at the point of traversal
uint4 flags; ///< Flags associated with the node
TraverseNode(const Varnode *v,uint4 f) { vn = v; flags = f; } ///< Constructor
static bool isAlternatePathValid(const Varnode *vn,uint4 flags);
};
/// \brief Static methods for determining if two boolean expressions are the \b same or \b complementary
///
/// Traverse (upto a specific depth) the two boolean expressions consisting of BOOL_AND, BOOL_OR, and
/// BOOL_XOR operations. Leaf operators in the expression can be other operators with boolean output (INT_LESS,
/// INT_SLESS, etc.).
class BooleanMatch {
static bool sameOpComplement(PcodeOp *bin1op, PcodeOp *bin2op);
static bool varnodeSame(Varnode *a,Varnode *b);
public:
enum {
same = 1, ///< Pair always hold the same value
complementary = 2, ///< Pair always hold complementary values
uncorrelated = 3 ///< Pair values are uncorrelated
};
static int4 evaluate(Varnode *vn1,Varnode *vn2,int4 depth);
};
/// \brief A helper class for describing the similarity of the boolean condition between 2 CBRANCH operations
///
/// This class determines if two CBRANCHs share the same condition. It also determines if the conditions
/// are complements of each other, and/or they are shared along only one path.
class BooleanExpressionMatch {
static const int4 maxDepth; ///< Maximum depth to trace a boolean expression
bool matchflip; ///< True if the compared CBRANCH keys on the opposite boolean value of the root
public:
bool verifyCondition(PcodeOp *op, PcodeOp *iop); ///< Perform the correlation test on two CBRANCH operations
int4 getMultiSlot(void) const { return -1; } ///< Get the MULTIEQUAL slot in the critical path
bool getFlip(void) const { return matchflip; } ///< Return \b true if the expressions are anti-correlated
};
/// Class representing a \e term in an additive expression
class AdditiveEdge {
PcodeOp *op; ///< Lone descendant reading the term
int4 slot; ///< The input slot of the term
Varnode *vn; ///< The term Varnode
PcodeOp *mult; ///< The (optional) multiplier being applied to the term
public:
AdditiveEdge(PcodeOp *o,int4 s,PcodeOp *m) { op = o; slot = s; vn = op->getIn(slot); mult=m; } ///< Constructor
PcodeOp *getMultiplier(void) const { return mult; } ///< Get the multiplier PcodeOp
PcodeOp *getOp(void) const { return op; } ///< Get the component PcodeOp adding in the term
int4 getSlot(void) const { return slot; } ///< Get the slot reading the term
Varnode *getVarnode(void) const { return vn; } ///< Get the Varnode term
};
/// \brief A class for ordering Varnode terms in an additive expression.
///
/// Given the final PcodeOp in a data-flow expression that sums 2 or more
/// Varnode \e terms, this class collects all the terms then allows
/// sorting of the terms to facilitate constant collapse and factoring simplifications.
class TermOrder {
PcodeOp *root; ///< The final PcodeOp in the expression
vector<AdditiveEdge> terms; ///< Collected terms
vector<AdditiveEdge *> sorter; ///< An array of references to terms for quick sorting
static bool additiveCompare(const AdditiveEdge *op1,const AdditiveEdge *op2);
public:
TermOrder(PcodeOp *rt) { root = rt; } ///< Construct given root PcodeOp
int4 getSize(void) const { return terms.size(); } ///< Get the number of terms in the expression
void collect(void); ///< Collect all the terms in the expression
void sortTerms(void); ///< Sort the terms using additiveCompare()
const vector<AdditiveEdge *> &getSort(void) { return sorter; } ///< Get the sorted list of references
};
/// \brief A comparison operator for ordering terms in a sum
///
/// This is based on Varnode::termOrder which groups constants terms and
/// ignores multiplicative coefficients.
/// \param op1 is the first term to compare
/// \param op2 is the second term
/// \return \b true if the first term is less than the second
inline bool TermOrder::additiveCompare(const AdditiveEdge *op1,const AdditiveEdge *op2) {
return (-1 == op1->getVarnode()->termOrder(op2->getVarnode()));
}
/// \brief Class for lightweight matching of two additive expressions
///
/// Collect (up to 2) terms along with any constants and coefficients.
//// Determine if two expressions are equivalent.
class AddExpression {
/// \brief A term in the expression
class Term {
Varnode *vn; ///< The Varnode representing the term
uintb coeff; ///< Multiplicative coefficient
public:
Term(void) {} ///< Uninitialized constructor
Term(Varnode *v,uintb c) { vn = v; coeff = c; } ///< Constructor
bool isEquivalent(const Term &op2) const; ///< Compare two terms for functional equivalence
};
uintb constval; ///< Collected constants in the expression
int4 numTerms; ///< Number of terms
Term terms[2]; ///< Terms making up the expression
void add(Varnode *vn,uintb coeff) { if (numTerms < 2) terms[numTerms++] = Term(vn,coeff); } ///< Add a term to the expression
void gather(Varnode *vn,uintb coeff,int4 depth); ///< Gather terms in the expression from a root point
public:
AddExpression(void) { constval = 0; numTerms = 0; } ///< Construct an empty expression
void gatherTwoTermsSubtract(Varnode *a,Varnode *b); ///< Walk expression given two roots being subtracted from one another
void gatherTwoTermsAdd(Varnode *a,Varnode *b); ///< Walk expression given two roots being added to each other
void gatherTwoTermsRoot(Varnode *root); ///< Gather up to 2 terms given root Varnode
bool isEquivalent(const AddExpression &op2) const; ///< Determine if 2 expressions are equivalent
};
/// \brief A container for an expression manipulating a bitfield
///
/// The expression centers around either a CPUI_INSERT or a CPUI_EXTRACT op but encompasses multiple p-code ops
/// that represent either a single read of or single write to a bitfield within a structure. This class recovers
/// the expected elements of the expression. The method isValid() returns \b true if the expression has the
/// expected form and can be interpreted as a single read or write.
class BitFieldExpression {
protected:
void getStructures(Datatype *dt,int4 initByteOff,int4 leastBitOff,bool isBigEndian); ///< Recover the structure(s) holding the bitfield
public:
TypeStruct *theStruct; ///< Parent structure containing the bitfield
const TypeBitField *bitfield; ///< Formal bitfield description
int4 byteRangeOffset; ///< Offset of byte range into encompassStruct
int4 offsetToBitStruct; ///< Offset of structure containing bitfield in encompassStruct
const Varnode *recoverStructurePointer(const Varnode *vn,int4 offset); ///< Recover the Varnode holding the pointer to the parent structure
bool isValid(void) const { return (bitfield != (const TypeBitField *)0); } ///< Is \b this a valid bitfield expression
static const TypeBitField *getPullField(const PcodeOp *pull); ///< Get field description corresponding to given ZPULL or SPULL
};
/// \brief A write to a bitfield stored in an explicit Varnode
///
/// The INSERT output is expected to be a associated with a (partial) symbol and
/// hold data-type information.
class InsertExpression : public BitFieldExpression {
public:
const PcodeOp *insertOp; ///< INSERT op
const Symbol *symbol; ///< Structure symbol represented by the INSERT output
InsertExpression(const PcodeOp *insert); ///< Construct from an INSERT
static uintb getRangeMask(const PcodeOp *insert); ///< Get a mask representing the INSERTed range of bits
static uintb getLSBMask(const PcodeOp *insert); ///< Get mask of least significant bits matching INSERT size
};
/// \brief A write to a bitfield through a STORE op
///
/// The INSERT output is expected to hold data-type info. A final STORE must be
/// present and a LOAD, recovering parts of the structure that are unaffected, may be present.
class InsertStoreExpression : public BitFieldExpression {
public:
const PcodeOp *insertOp; ///< INSERT op
const PcodeOp *loadOp; ///< LOAD op (may be null)
const Varnode *structPtr; ///< Varnode holding pointer to the parent structure
InsertStoreExpression(const PcodeOp *store); ///< Construct from a STORE
};
/// \brief A read of a bitfield via a ZPULL or SPULL operator
///
/// The first input to the operator must either be a (partial) symbol or be written by a LOAD.
class PullExpression : public BitFieldExpression {
public:
const PcodeOp *pullOp; ///< ZPULL or SPULL op
const Symbol *symbol; ///< Symbol holding the structure and bitfield (may be null)
const PcodeOp *loadOp; ///< LOAD reading bytes containing the bitfield (may be null)
const Varnode *structPtr; ///< Varnode holding pointer to the parent structure
PullExpression(const PcodeOp *pull); ///< Construct from a ZPULL or SPULL
};
extern int4 functionalEqualityLevel(Varnode *vn1,Varnode *vn2,Varnode **res1,Varnode **res2);
extern bool functionalEquality(Varnode *vn1,Varnode *vn2);
extern bool functionalDifference(Varnode *vn1,Varnode *vn2,int4 depth);
extern Varnode *rootPointer(Varnode *vn,uintb &offset);
extern bool pointerEquality(Varnode *vn1,Varnode *vn2);
} // End namespace ghidra
#endif
@@ -222,6 +222,25 @@ void FloatFormat::calcPrecision(void)
decimalMaxPrecision = (int4)ceil((frac_size + 1) * 0.30103) + 1;
}
/// \param encoding is the encoded floating-point value
/// \return either \e zero, \e infinity, \e denormalized, \e nan, or \e normalized
FloatFormat::floatclass FloatFormat::getClass(uintb encoding) const
{
int4 exp = extractExponentCode(encoding);
if (exp == 0) {
if ( extractFractionalCode(encoding) == 0 )
return zero;
return denormalized;
}
if (exp == maxexponent) {
if ( extractFractionalCode(encoding) == 0 )
return infinity;
return nan;
}
return normalized;
}
/// \param encoding is the encoding value
/// \param type points to the floating-point class, which is passed back
/// \return the equivalent double value
@@ -64,6 +64,7 @@ private:
public:
FloatFormat(int4 sz); ///< Construct default IEEE 754 standard settings
int4 getSize(void) const { return size; } ///< Get the size of the encoding in bytes
floatclass getClass(uintb encoding) const; ///< Get the class of an encoding
double getHostFloat(uintb encoding,floatclass *type) const; ///< Convert an encoding into host's double
uintb getEncoding(double host) const; ///< Convert host's double into \b this encoding
uintb convertEncoding(uintb encoding,const FloatFormat *formin) const; ///< Convert between two different formats
@@ -71,6 +72,7 @@ public:
uintb extractFractionalCode(uintb x) const; ///< Extract the fractional part of the encoding
bool extractSign(uintb x) const; ///< Extract the sign bit from the encoding
int4 extractExponentCode(uintb x) const; ///< Extract the exponent from the encoding
int4 getExponent(uintb x) const { return extractExponentCode(x) - bias; } ///< Get the exponent of an encoding
string printDecimal(double host,bool forcesci) const; ///< Print given value as a decimal string
@@ -38,7 +38,8 @@ FlowInfo::FlowInfo(Funcdata &d,PcodeOpBank &o,BlockGraph &b,vector<FuncCallSpecs
inline_recursion = (set<Address> *)0;
insn_count = 0;
insn_max = ~((uint4)0);
flowoverride_present = data.getOverride().hasFlowOverride();
baddata_count = 0;
pcode_override_present = data.getOverride().hasPCodeOverride();
}
/// Prepare a new flow cloned from an existing flow.
@@ -72,7 +73,8 @@ FlowInfo::FlowInfo(Funcdata &d,PcodeOpBank &o,BlockGraph &b,vector<FuncCallSpecs
inline_recursion = (set<Address> *)0;
insn_count = op2->insn_count;
insn_max = op2->insn_max;
flowoverride_present = data.getOverride().hasFlowOverride();
baddata_count = op2->baddata_count;
pcode_override_present = data.getOverride().hasPCodeOverride();
}
void FlowInfo::clearProperties(void)
@@ -80,6 +82,7 @@ void FlowInfo::clearProperties(void)
{
flags &= ~((uint4)(unimplemented_present|baddata_present|outofbounds_present));
insn_count = 0;
baddata_count = 0;
}
/// For efficiency, this method assumes the given op can actually fall-thru.
@@ -156,11 +159,10 @@ PcodeOp *FlowInfo::findRelTarget(PcodeOp *op,Address &res) const
if (retop != (PcodeOp *)0) // Is this a "properly" internal branch
return retop;
// Now we check if the relative branch is really to the next instruction
SeqNum seqnum1(op->getAddr(),id-1);
retop = obank.findOp(seqnum1); // We go back one sequence number
if (retop != (PcodeOp *)0) {
// If the PcodeOp exists here then branch was indeed to next instruction
// Check if the relative branch is to the next instruction
retop = obank.findLastOp(op->getAddr()); // Find the last op at this address
if (retop != (PcodeOp *)0 && retop->getTime() < id) {
// Branch is beyond the last op. Treat as branch to next instruction.
map<Address,VisitStat>::const_iterator miter;
miter = visited.upper_bound(retop->getAddr());
if (miter != visited.begin()) {
@@ -198,6 +200,19 @@ PcodeOp *FlowInfo::branchTarget(PcodeOp *op) const
return target(addr); // Otherwise a normal address target
}
/// Replace any reference to the op being inlined with the first op of the inlined sequence.
/// \param oldOp is the p-code op being inlined
/// \param newOp is the first p-code op in the inlined sequence
void FlowInfo::updateTarget(PcodeOp *oldOp,PcodeOp *newOp)
{
map<Address,VisitStat>::iterator viter = visited.find(oldOp->getAddr());
if (viter != visited.end()) { // Check if -oldOp- is a possible branch target
if ((*viter).second.seqnum == oldOp->getSeqNum()) // (if injection op is the first op for its address)
(*viter).second.seqnum = newOp->getSeqNum(); // change the seqnum to the newOp
}
}
/// Check to see if the new target has been seen before. Otherwise
/// add it to the list of addresses that need to be processed.
/// Also check range bounds and update basic block information.
@@ -375,7 +390,7 @@ bool FlowInfo::processInstruction(const Address &curaddr,bool &startbasic)
// JumpTable *jt;
list<PcodeOp *>::const_iterator oiter;
int4 step;
uint4 flowoverride;
const Override::Record *pCodeOverride;
if (insn_count >= insn_max) {
if ((flags & error_toomanyinstructions)!=0)
@@ -399,10 +414,10 @@ bool FlowInfo::processInstruction(const Address &curaddr,bool &startbasic)
oiter = obank.endDead();
--oiter;
}
if (flowoverride_present)
flowoverride = data.getOverride().getFlowOverride(curaddr);
if (pcode_override_present)
pCodeOverride = data.getOverride().getPCodeOverride(curaddr);
else
flowoverride = Override::NONE;
pCodeOverride = (const Override::Record *)0;
try {
step = glb->translate->oneInstruction(emitter,curaddr); // Generate ops for instruction
@@ -429,9 +444,10 @@ bool FlowInfo::processInstruction(const Address &curaddr,bool &startbasic)
}
}
catch(BadDataError &err) {
if ((flags & error_unimplemented)!=0)
if ((flags & error_baddata)!=0)
throw err; // rethrow
else {
countBadData(err.explain);
// Add infinite loop instruction
step = 1; // Pretend size 1
artificialHalt(curaddr,PcodeOp::badinstruction);
@@ -458,8 +474,8 @@ bool FlowInfo::processInstruction(const Address &curaddr,bool &startbasic)
if (oiter != obank.endDead()) {
stat.seqnum = (*oiter)->getSeqNum();
data.opMarkStartInstruction(*oiter); // Mark the first op in the instruction
if (flowoverride != Override::NONE)
data.overrideFlow(curaddr,flowoverride);
if (pCodeOverride != (const Override::Record *)0)
pCodeOverride->performOverride(curaddr,data);
xrefControlFlow(oiter,startbasic,isfallthru,(FuncCallSpecs *)0);
}
@@ -526,6 +542,17 @@ void FlowInfo::handleOutOfBounds(const Address &fromaddr,const Address &toaddr)
}
}
/// If the count exceeds the maximum allowable, an exception is thrown.
/// \param errMsg is the error message associated with the current bad data
void FlowInfo::countBadData(const string &errMsg)
{
if (baddata_count >= glb->max_baddata) {
throw BadDataError("Bad instruction count exceeded:\n ...\n "+ errMsg);
}
baddata_count += 1;
}
/// The address at the top stack that still needs processing is popped.
/// P-code is generated for instructions starting at this address until
/// one no longer has fall-thru flow (or some other error occurs).
@@ -609,6 +636,7 @@ void FlowInfo::reinterpreted(const Address &addr)
if ((flags & error_reinterpreted)!=0)
throw LowlevelError(s.str());
countBadData(s.str());
if ((flags & reinterpreted_present)==0) {
flags |= reinterpreted_present;
data.warningHeader(s.str());
@@ -669,8 +697,8 @@ bool FlowInfo::setupCallSpecs(PcodeOp *op,FuncCallSpecs *fc)
{
FuncCallSpecs *res;
res = new FuncCallSpecs(op);
data.opSetInput(op,data.newVarnodeCallSpecs(res),0);
qlst.push_back(res);
data.opSetInput(op,data.newVarnodeCallSpecs(res),0);
data.getOverride().applyPrototype(data,*res);
queryCall(*res);
@@ -755,25 +783,10 @@ void FlowInfo::truncateIndirectJump(PcodeOp *op,JumpTable::RecoveryMode mode)
}
}
/// \brief Test if the given p-code op is a member of an array
///
/// \param array is the array of p-code ops to search
/// \param op is the given p-code op to search for
/// \return \b true if the op is a member of the array
bool FlowInfo::isInArray(vector<PcodeOp *> &array,PcodeOp *op)
{
for(int4 i=0;i<array.size();++i) {
if (array[i] == op) return true;
}
return false;
}
void FlowInfo::generateOps(void)
{
vector<PcodeOp *> notreached; // indirect ops that are not reachable
int4 notreachcnt = 0;
clearProperties();
addrlist.push_back(data.getAddress());
while(!addrlist.empty()) // Recovering as much as possible except jumptables
@@ -799,10 +812,9 @@ void FlowInfo::generateOps(void)
checkContainedCall(); // Check for PIC constructions
checkMultistageJumptables();
while(notreachcnt < notreached.size()) {
tablelist.push_back(notreached[notreachcnt]);
notreachcnt += 1;
}
for(int4 i=0;i<notreached.size();++i)
tablelist.push_back(notreached[i]);
notreached.clear();
if (hasInject())
injectPcode();
} while(!tablelist.empty()); // Inlining or multistage may have added new indirect branches
@@ -1046,7 +1058,7 @@ void FlowInfo::xrefInlinedBranch(PcodeOp *op)
setupCallindSpecs(op,(FuncCallSpecs *)0);
else if (op->code() == CPUI_BRANCHIND) {
JumpTable *jt = data.linkJumpTable(op);
if (jt == (JumpTable *)0)
if (jt == (JumpTable *)0 || jt->numEntries() == 0)
tablelist.push_back(op); // Didn't recover a jumptable
}
}
@@ -1189,11 +1201,7 @@ void FlowInfo::doInjection(InjectPayload *payload,InjectContext &icontext,PcodeO
obank.markIncidentalCopy(firstop, lastop);
obank.moveSequenceDead(firstop,lastop,op); // Move the injection to right after the call
map<Address,VisitStat>::iterator viter = visited.find(op->getAddr());
if (viter != visited.end()) { // Check if -op- is a possible branch target
if ((*viter).second.seqnum == op->getSeqNum()) // (if injection op is the first op for its address)
(*viter).second.seqnum = firstop->getSeqNum(); // change the seqnum to the first injected op
}
updateTarget(op,firstop); // Replace -op- with -firstop- in the target map
// Get rid of the original call
data.opDestroyRaw(op);
}
@@ -1436,7 +1444,7 @@ void FlowInfo::recoverJumpTables(vector<JumpTable *> &newTables,vector<PcodeOp *
truncateIndirectJump(op,mode); // Treat the indirect jump as a call
}
else if (jt->isPartial()) {
if (tablelist.size() > 1 && !isInArray(notreached,op)) {
if (tablelist.size() > 1 && jt->getRecoverCount() <= 1) {
// If the recovery is incomplete with current flow AND there is more flow to generate,
// AND we haven't tried to recover this table before
notreached.push_back(op); // Save this op so we can try to recover the table again later
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -63,11 +63,12 @@ public:
error_unimplemented = 8, ///< Throw an exception for flow into unimplemented instructions
error_reinterpreted = 0x10, ///< Throw an exception for flow into previously encountered data at a difference \e cut
error_toomanyinstructions = 0x20, ///< Throw an exception if too many instructions are encountered
unimplemented_present = 0x40, ///< Indicate we have encountered unimplemented instructions
baddata_present = 0x80, ///< Indicate we have encountered flow into unaccessible data
outofbounds_present = 0x100, ///< Indicate we have encountered flow out of the specified range
reinterpreted_present = 0x200, ///< Indicate we have encountered reinterpreted data
toomanyinstructions_present = 0x400, ///< Indicate the maximum instruction threshold was reached
error_baddata = 0x40, ///< Throw an exception if an instruction cannot be decoded
unimplemented_present = 0x80, ///< Indicate we have encountered unimplemented instructions
baddata_present = 0x100, ///< Indicate we have encountered flow into unaccessible data
outofbounds_present = 0x200, ///< Indicate we have encountered flow out of the specified range
reinterpreted_present = 0x400, ///< Indicate we have encountered reinterpreted data
toomanyinstructions_present = 0x800, ///< Indicate the maximum instruction threshold was reached
possible_unreachable = 0x1000, ///< Indicate a CALL was converted to a BRANCH and some code may be unreachable
flow_forinline = 0x2000, ///< Indicate flow is being generated to in-line (a function)
record_jumploads = 0x4000 ///< Indicate that any jump table recovery should record the table structure
@@ -97,8 +98,9 @@ private:
Address eaddr; ///< End of range in which we are allowed to flow
Address minaddr; ///< Start of actual function range
Address maxaddr; ///< End of actual function range
bool flowoverride_present; ///< Does the function have registered flow override instructions
bool pcode_override_present; ///< Does the function have registered p-code override instructions
uint4 flags; ///< Boolean options for flow following
uint4 baddata_count; ///< Number of instructions that could not be disassembled
Funcdata *inline_head; ///< First function in the in-lining chain
set<Address> *inline_recursion; ///< Active list of addresses for function that are in-lined
set<Address> inline_base; ///< Storage for addresses of functions that are in-lined
@@ -122,6 +124,7 @@ private:
void connectBasic(void); ///< Generate edges between basic blocks
bool setFallthruBound(Address &bound); ///< Find end of the next unprocessed region
void handleOutOfBounds(const Address &fromaddr,const Address &toaddr);
void countBadData(const string &errMsg); ///< Increment bad data counter
PcodeOp *artificialHalt(const Address &addr,uint4 flag); ///< Create an artificial halt p-code op
void reinterpreted(const Address &addr); ///< Generate warning message or exception for a \e reinterpreted address
bool checkForFlowModification(FuncCallSpecs &fspecs);
@@ -138,7 +141,6 @@ private:
void recoverJumpTables(vector<JumpTable *> &newTables,vector<PcodeOp *> &notreached);
void deleteCallSpec(FuncCallSpecs *fc); ///< Remove the given call site from the list for \b this function
void truncateIndirectJump(PcodeOp *op,JumpTable::RecoveryMode mode); ///< Treat indirect jump as CALLIND/RETURN
static bool isInArray(vector<PcodeOp *> &array,PcodeOp *op);
public:
FlowInfo(Funcdata &d,PcodeOpBank &o,BlockGraph &b,vector<FuncCallSpecs *> &q); ///< Constructor
FlowInfo(Funcdata &d,PcodeOpBank &o,BlockGraph &b,vector<FuncCallSpecs *> &q,const FlowInfo *op2); ///< Cloning constructor
@@ -148,6 +150,7 @@ public:
void clearFlags(uint4 val) { flags &= ~val; } ///< Disable a specific option
PcodeOp *target(const Address &addr) const; ///< Return first p-code op for instruction at given address
PcodeOp *branchTarget(PcodeOp *op) const; ///< Find the target referred to by a given BRANCH or CBRANCH
void updateTarget(PcodeOp *oldOp,PcodeOp *newOp); ///< Update the branch target for an inlined p-code op
void generateOps(void); ///< Generate raw control-flow from the function's base address
void generateBlocks(void); ///< Generate basic blocks from the raw control-flow
bool testHardInlineRestrictions(Funcdata *inlinefd,PcodeOp *op,Address &retaddr);
@@ -50,6 +50,7 @@ ElementId ELEM_RETPARAM = ElementId("retparam",171);
ElementId ELEM_RETURNSYM = ElementId("returnsym",172);
ElementId ELEM_UNAFFECTED = ElementId("unaffected",173);
ElementId ELEM_INTERNAL_STORAGE = ElementId("internal_storage",286);
ElementId ELEM_SHARESTACK = ElementId("sharestack",291);
/// \brief Find a ParamEntry matching the given storage Varnode
///
@@ -94,14 +95,14 @@ void ParamEntry::resolveFirst(list<ParamEntry> &curList)
void ParamEntry::resolveJoin(list<ParamEntry> &curList)
{
if (spaceid->getType() != IPTR_JOIN) {
joinrec = (JoinRecord *)0;
joinrec = spaceid->findJoin(addressbase);
if (joinrec == (JoinRecord *)0)
return;
}
joinrec = spaceid->getManager()->findJoin(addressbase);
groupSet.clear();
for(int4 i=0;i<joinrec->numPieces();++i) {
const ParamEntry *entry = findEntryByStorage(curList, joinrec->getPiece(i));
const VarnodeData &vdat(joinrec->getPiece(i));
if (vdat.space->getType() == IPTR_CONSTANT) continue;
const ParamEntry *entry = findEntryByStorage(curList, vdat);
if (entry != (const ParamEntry *)0) {
groupSet.insert(groupSet.end(),entry->groupSet.begin(),entry->groupSet.end());
// For output <pentry>, if the most signifigant part overlaps with an earlier <pentry>
@@ -430,8 +431,26 @@ int4 ParamEntry::getSlot(const Address &addr,int4 skip) const
/// \param slotnum is a reference to used slots (which will be updated)
/// \param sz is the size of the parameter to allocated
/// \param typeAlign is the required byte alignment for the parameter
/// \param m is the space manager
/// \return the address of the new parameter (or an invalid address)
Address ParamEntry::getAddrBySlot(int4 &slotnum,int4 sz,int4 typeAlign) const
Address ParamEntry::getAddrBySlot(int4 &slotnum, int4 sz, int4 typeAlign,const AddrSpaceManager *m) const
{
return getAddrBySlot(slotnum, sz, typeAlign, !isLeftJustified(),m);
}
/// \brief Calculate the storage address assigned when allocating a parameter of a given size
///
/// Assume \b slotnum slots have already been assigned and increment \b slotnum
/// by the number of slots used.
/// Return an invalid address if the size is too small or if there are not enough slots left.
/// \param slotnum is a reference to used slots (which will be updated)
/// \param sz is the size of the parameter to allocated
/// \param typeAlign is the required byte alignment for the parameter
/// \param justifyRight is true if initial bytes are padding for odd data-type sizes
/// \param m is the space manager
/// \return the address of the new parameter (or an invalid address)
Address ParamEntry::getAddrBySlot(int4 &slotnum,int4 sz,int4 typeAlign, bool justifyRight,const AddrSpaceManager *m) const
{
Address res; // Start with an invalid result
@@ -443,8 +462,7 @@ Address ParamEntry::getAddrBySlot(int4 &slotnum,int4 sz,int4 typeAlign) const
res = Address(spaceid,addressbase); // Get base address of the slot
spaceused = size;
if (((flags & smallsize_floatext)!=0)&&(sz != size)) { // Do we have an implied floating-point extension
AddrSpaceManager *manager = spaceid->getManager();
res = manager->constructFloatExtensionAddress(res,size,sz);
res = m->constructFloatExtensionAddress(res,size,sz);
return res;
}
}
@@ -471,7 +489,7 @@ Address ParamEntry::getAddrBySlot(int4 &slotnum,int4 sz,int4 typeAlign) const
res = Address(spaceid, addressbase + index * alignment);
slotnum += slotsused; // Inform caller of number of slots used
}
if (!isLeftJustified()) // Adjust for right justified (big endian)
if (justifyRight) // Adjust for right justified (big endian)
res = res + (spaceused - sz);
return res;
}
@@ -521,7 +539,7 @@ void ParamEntry::decode(Decoder &decoder,bool normalstack,bool grouped,list<Para
else if (ext == "float")
flags |= smallsize_floatext;
else if (ext != "none")
throw LowlevelError("Bad extension attribute");
throw LowlevelError("Bad extension attribute: "+ext);
}
else
throw LowlevelError("Unknown <pentry> attribute");
@@ -536,9 +554,9 @@ void ParamEntry::decode(Decoder &decoder,bool normalstack,bool grouped,list<Para
spaceid = addr.getSpace();
addressbase = addr.getOffset();
if (alignment != 0) {
// if ((addressbase % alignment) != 0)
// throw LowlevelError("Stack <pentry> address must match alignment");
numslots = size / alignment;
if (spaceid->getType() == IPTR_SPACEBASE)
flags |= is_stackspill;
}
if (spaceid->isReverseJustified()) {
if (spaceid->isBigEndian())
@@ -583,11 +601,11 @@ ParamListStandard::ParamListStandard(const ParamListStandard &op2)
{
numgroup = op2.numgroup;
entry = op2.entry;
spacebase = op2.spacebase;
maxdelay = op2.maxdelay;
thisbeforeret = op2.thisbeforeret;
autoKilledByCall = op2.autoKilledByCall;
resourceStart = op2.resourceStart;
glb = op2.glb;
for(list<ModelRule>::const_iterator iter=op2.modelRules.begin();iter!=op2.modelRules.end();++iter) {
modelRules.emplace_back(*iter,&op2);
}
@@ -606,7 +624,6 @@ ParamListStandard::~ParamListStandard(void)
/// \param tiles will contain the set of matching entries
/// \param type is the storage class
/// \return the first matching iterator
void ParamListStandard::extractTiles(vector<const ParamEntry *> &tiles,type_class type) const
{
@@ -626,15 +643,10 @@ void ParamListStandard::extractTiles(vector<const ParamEntry *> &tiles,type_clas
const ParamEntry *ParamListStandard::getStackEntry(void) const
{
list<ParamEntry>::const_iterator iter = entry.end();
if (iter != entry.begin()) {
--iter; // Stack entry necessarily must be the last entry
const ParamEntry &curEntry( *iter );
if (!curEntry.isExclusion() && curEntry.getSpace()->getType() == IPTR_SPACEBASE) {
return &(*iter);
}
}
return (const ParamEntry *)0;
if (entry.empty())
return (const ParamEntry *)0;
const ParamEntry *res = &entry.back();
return (res->isStackSpill()) ? res : (const ParamEntry *)0;
}
/// Find the (first) entry containing the given memory range
@@ -729,7 +741,7 @@ uint4 ParamListStandard::assignAddressFallback(type_class resource,Datatype *tp,
continue; // Wrong type
}
param.addr = curEntry.getAddrBySlot(status[grp],tp->getAlignSize(),tp->getAlignment());
param.addr = curEntry.getAddrBySlot(status[grp],tp->getAlignSize(),tp->getAlignment(),glb);
if (param.addr.isInvalid()) continue; // If -tp- doesn't fit an invalid address is returned
if (curEntry.isExclusion()) {
const vector<int4> &groupSet(curEntry.getAllGroups());
@@ -757,6 +769,12 @@ uint4 ParamListStandard::assignAddress(Datatype *dt,const PrototypePieces &proto
vector<int4> &status,ParameterPieces &res) const
{
// if (dt->isFormalZeroLength()) {
// res.addr = Address();
// res.type = dt;
// res.flags = 0;
// return AssignAction::success;
// }
for(list<ModelRule>::const_iterator iter=modelRules.begin();iter!=modelRules.end();++iter) {
uint4 responseCode = (*iter).assignAddress(dt, proto, pos, tlist, status, res);
if (responseCode != AssignAction::fail)
@@ -766,23 +784,15 @@ uint4 ParamListStandard::assignAddress(Datatype *dt,const PrototypePieces &proto
return assignAddressFallback(store,dt,false,status,res);
}
void ParamListStandard::assignMap(const PrototypePieces &proto,TypeFactory &typefactory,vector<ParameterPieces> &res) const
void ParamListStandard::allocateStatus(vector<int4> &status) const
{
vector<int4> status(numgroup,0);
status.resize(numgroup,0);
}
if (res.size() == 2) { // Check for hidden parameters defined by the output list
Datatype *dt = res.back().type;
type_class store;
if ((res.back().flags & ParameterPieces::hiddenretparm) != 0)
store = TYPECLASS_HIDDENRET;
else
store = metatype2typeclass(dt->getMetatype());
// Reserve first param for hidden return pointer
if (assignAddressFallback(store,dt,false,status,res.back()) == AssignAction::fail)
throw ParamUnassignedError("Cannot assign parameter address for " + res.back().type->getName());
res.back().flags |= ParameterPieces::hiddenretparm;
}
void ParamListStandard::assignMap(const PrototypePieces &proto,TypeFactory &typefactory,vector<int4> &status,
vector<ParameterPieces> &res) const
{
for(int4 i=0;i<proto.intypes.size();++i) {
res.emplace_back();
Datatype *dt = proto.intypes[i];
@@ -871,7 +881,7 @@ void ParamListStandard::buildTrialMap(ParamActive *active) const
continue;
int4 sz = curentry->isExclusion() ? curentry->getSize() : curentry->getAlign();
int4 nextslot = 0;
Address addr = curentry->getAddrBySlot(nextslot,sz,1);
Address addr = curentry->getAddrBySlot(nextslot,sz,1,glb);
int4 trialpos = active->getNumTrials();
active->registerTrial(addr,sz);
ParamTrial &paramtrial(active->getTrial(trialpos));
@@ -902,7 +912,7 @@ void ParamListStandard::buildTrialMap(ParamActive *active) const
for(int4 j=0;j<slotlist.size();++j) {
if (slotlist[j] == 0) {
int4 nextslot = j; // Make copy of j, so that getAddrBySlot can change it
Address addr = curentry->getAddrBySlot(nextslot,curentry->getAlign(),1);
Address addr = curentry->getAddrBySlot(nextslot,curentry->getAlign(),1,glb);
int4 trialpos = active->getNumTrials();
active->registerTrial(addr,curentry->getAlign());
ParamTrial &paramtrial(active->getTrial(trialpos));
@@ -1180,6 +1190,7 @@ void ParamListStandard::populateResolver(void)
for(int4 i=0;i<joinRec->numPieces();++i) {
// Individual pieces making up the join are mapped to the ParamEntry
const VarnodeData &vData(joinRec->getPiece(i));
if (vData.space->getType() == IPTR_CONSTANT) continue;
uintb last = vData.offset + (vData.size - 1);
addResolverRange(vData.space,vData.offset,last,paramEntry,position);
position += 1;
@@ -1219,10 +1230,7 @@ void ParamListStandard::parsePentry(Decoder &decoder,vector<EffectRecord> &effec
resourceStart.push_back(groupid);
}
}
AddrSpace *spc = entry.back().getSpace();
if (spc->getType() == IPTR_SPACEBASE)
spacebase = spc;
else if (autoKilledByCall) // If a register parameter AND we automatically generate killedbycall
if (!entry.back().isStackSpill() && autoKilledByCall) // If a register parameter AND we automatically generate killedbycall
effectlist.push_back(EffectRecord(entry.back(),EffectRecord::killedbycall));
int4 maxgroup = entry.back().getAllGroups().back() + 1;
@@ -1415,6 +1423,15 @@ OpCode ParamListStandard::assumedExtension(const Address &addr,int4 size,Varnode
return CPUI_COPY;
}
AddrSpace *ParamListStandard::getSpacebase(void) const
{
const ParamEntry *entry = getStackEntry();
if (entry != (const ParamEntry *)0)
return entry->getSpace();
return (AddrSpace *)0;
}
void ParamListStandard::getRangeList(AddrSpace *spc,RangeList &res) const
{
@@ -1430,8 +1447,8 @@ void ParamListStandard::getRangeList(AddrSpace *spc,RangeList &res) const
void ParamListStandard::decode(Decoder &decoder,vector<EffectRecord> &effectlist,bool normalstack)
{
glb = decoder.getAddrSpaceManager();
numgroup = 0;
spacebase = (AddrSpace *)0;
int4 pointermax = 0;
thisbeforeret = false;
autoKilledByCall = false;
@@ -1495,10 +1512,10 @@ ParamList *ParamListStandard::clone(void) const
return res;
}
void ParamListRegisterOut::assignMap(const PrototypePieces &proto,TypeFactory &typefactory,vector<ParameterPieces> &res) const
void ParamListRegisterOut::assignMap(const PrototypePieces &proto,TypeFactory &typefactory,vector<int4> &status,
vector<ParameterPieces> &res) const
{
vector<int4> status(numgroup,0);
res.emplace_back();
if (proto.outtype->getMetatype() != TYPE_VOID) {
assignAddress(proto.outtype,proto,-1,typefactory,status,res.back());
@@ -1545,11 +1562,10 @@ ParamList *ParamListRegister::clone(void) const
return res;
}
void ParamListStandardOut::assignMap(const PrototypePieces &proto,TypeFactory &typefactory,vector<ParameterPieces> &res) const
void ParamListStandardOut::assignMap(const PrototypePieces &proto,TypeFactory &typefactory,vector<int4> &status,
vector<ParameterPieces> &res) const
{
vector<int4> status(numgroup,0);
res.emplace_back();
if (proto.outtype->getMetatype() == TYPE_VOID) {
res.back().type = proto.outtype;
@@ -1563,7 +1579,7 @@ void ParamListStandardOut::assignMap(const PrototypePieces &proto,TypeFactory &t
if (responseCode == AssignAction::hiddenret_ptrparam || responseCode == AssignAction::hiddenret_specialreg ||
responseCode == AssignAction::hiddenret_specialreg_void) { // Could not assign an address (too big)
AddrSpace *spc = spacebase;
AddrSpace *spc = getSpacebase();
if (spc == (AddrSpace *)0)
spc = typefactory.getArch()->getDefaultDataSpace();
int4 pointersize = spc->getAddrSize();
@@ -1573,8 +1589,10 @@ void ParamListStandardOut::assignMap(const PrototypePieces &proto,TypeFactory &t
res.back().type = typefactory.getTypeVoid();
}
else {
if (assignAddressFallback(TYPECLASS_PTR,pointertp,false,status,res.back()) == AssignAction::fail)
throw ParamUnassignedError("Cannot assign return value as a pointer");
res.back().type = pointertp;
if (assignAddress(pointertp,proto,-1,typefactory,status,res.back()) == AssignAction::fail) {
throw ParamUnassignedError("Cannot assign return value as a pointer");
}
}
res.back().flags = ParameterPieces::indirectstorage;
@@ -1772,12 +1790,9 @@ void ParamListMerged::foldIn(const ParamListStandard &op2)
{
if (entry.empty()) {
spacebase = op2.getSpacebase();
entry = op2.getEntry();
return;
}
if ((spacebase != op2.getSpacebase())&&(op2.getSpacebase() != (AddrSpace *)0))
throw LowlevelError("Cannot merge prototype models with different stacks");
list<ParamEntry>::const_iterator iter2;
for(iter2=op2.getEntry().begin();iter2!=op2.getEntry().end();++iter2) {
@@ -1894,19 +1909,19 @@ bool ParamTrial::operator<(const ParamTrial &b) const
/// \param a trial
/// \param b trial
/// \return \b true if \b a should be ordered before \b b
bool ParamTrial::fixedPositionCompare(const ParamTrial &a, const ParamTrial &b)
bool ParamTrial::fixedPositionCompare(const ParamTrial &a,const ParamTrial &b)
{
if (a.fixedPosition == -1 && b.fixedPosition == -1){
return a < b;
}
if (a.fixedPosition == -1){
return false;
}
if (b.fixedPosition == -1){
return true;
}
return a.fixedPosition < b.fixedPosition;
if (a.fixedPosition == -1 && b.fixedPosition == -1) {
return a < b;
}
if (a.fixedPosition == -1) {
return false;
}
if (b.fixedPosition == -1) {
return true;
}
return a.fixedPosition < b.fixedPosition;
}
/// \param recoversub selects whether a sub-function or the active function is being tested
@@ -1920,6 +1935,7 @@ ParamActive::ParamActive(bool recoversub)
isfullychecked = false;
needsfinalcheck = false;
recoversubcall = recoversub;
joinMostSigFirst = false;
}
void ParamActive::clear(void)
@@ -1930,6 +1946,7 @@ void ParamActive::clear(void)
stackplaceholder = -1;
numpasses = 0;
isfullychecked = false;
joinMostSigFirst = false;
}
/// A ParamTrial object is created and a slot is assigned.
@@ -1950,6 +1967,15 @@ void ParamActive::registerTrial(const Address &addr,int4 sz)
slotbase += 1;
}
/// Copy the memory range of the trial and its boolean properties but assign a new slot.
/// \param oldTrial is the trial to register
void ParamActive::reregisterTrial(const ParamTrial &oldTrial)
{
trial.emplace_back(oldTrial,slotbase);
slotbase += 1;
}
/// The (index of) the first overlapping trial is returned.
/// \param addr is the starting address of the given range
/// \param sz is the number of bytes in the range
@@ -2172,13 +2198,7 @@ void ParameterPieces::assignAddressFromPieces(vector<VarnodeData> &pieces,bool m
reverse.push_back(pieces[i]);
pieces.swap(reverse);
}
JoinRecord::mergeSequence(pieces,glb->translate);
if (pieces.size() == 1) {
addr = pieces[0].getAddr();
return;
}
JoinRecord *joinRecord = glb->findAddJoin(pieces, 0);
addr = joinRecord->getUnified().getAddr();
addr = glb->joinPieces(pieces, glb->translate);
}
/// The type is set to \e unknown_effect
@@ -2244,22 +2264,17 @@ void ProtoModel::defaultLocalRange(void)
if (stackgrowsnegative) { // This the normal stack convention
// Default locals are negative offsets off the stack
last = spc->getHighest();
if (spc->getAddrSize()>=4)
first = last - 999999;
else if (spc->getAddrSize()>=2)
first = last - 9999;
else
first = last - 99;
uintb size = last >> 1;
if (size > 0x7fffffff)
size = 0x7fffffff;
first = last - size;
localrange.insertRange(spc,first,last);
}
else { // This is the flipped stack convention
first = 0;
if (spc->getAddrSize()>=4)
last = 999999;
else if (spc->getAddrSize()>=2)
last = 9999;
else
last = 99;
last = spc->getHighest() >> 1;
if (last > 0x7fffffff)
last = 0x7fffffff;
localrange.insertRange(spc,first,last);
}
}
@@ -2273,22 +2288,17 @@ void ProtoModel::defaultParamRange(void)
if (stackgrowsnegative) { // This the normal stack convention
// Default parameters are positive offsets off the stack
first = 0;
if (spc->getAddrSize()>=4)
last = 511;
else if (spc->getAddrSize()>=2)
last = 255;
else
last = 15;
last = spc->getHighest() >> 2;
if (last > 0x7fffffff)
last = 0x7fffffff;
paramrange.insertRange(spc,first,last);
}
else { // This is the flipped stack convention
last = spc->getHighest();
if (spc->getAddrSize()>=4)
first = last - 511;
else if (spc->getAddrSize()>=2)
first = last - 255;
else
first = last - 15;
uintb size = last >> 2;
if (size > 0x7fffffff)
size = 0x7fffffff;
first = last - size;
paramrange.insertRange(spc,first,last); // Parameters are negative offsets
}
}
@@ -2347,6 +2357,8 @@ ProtoModel::ProtoModel(const string &nm,const ProtoModel &op2)
output = op2.output->clone();
else
output = (ParamList *)0;
for (int4 i=0;i <sharedActions.size(); ++i)
sharedActions[i] = op2.sharedActions[i]->clone(this);
effectlist = op2.effectlist;
likelytrash = op2.likelytrash;
@@ -2371,6 +2383,8 @@ ProtoModel::~ProtoModel(void)
delete input;
if (output != (ParamList *)0)
delete output;
for(int4 i=0;i<sharedActions.size();++i)
delete sharedActions[i];
}
/// Test whether one ProtoModel can substituted for another during FuncCallSpecs::deindirect
@@ -2404,9 +2418,13 @@ bool ProtoModel::isCompatible(const ProtoModel *op2) const
void ProtoModel::assignParameterStorage(const PrototypePieces &proto,vector<ParameterPieces> &res,bool ignoreOutputError)
{
vector<int4> inputStatus;
vector<int4> outputStatus;
input->allocateStatus(inputStatus);
output->allocateStatus(outputStatus);
if (ignoreOutputError) {
try {
output->assignMap(proto,*glb->types,res);
output->assignMap(proto,*glb->types,outputStatus,res);
}
catch(ParamUnassignedError &err) {
res.clear();
@@ -2417,23 +2435,13 @@ void ProtoModel::assignParameterStorage(const PrototypePieces &proto,vector<Para
}
}
else {
output->assignMap(proto,*glb->types,res);
}
input->assignMap(proto,*glb->types,res);
if (hasThis && res.size() > 1) {
int4 thisIndex = 1;
if ((res[1].flags & ParameterPieces::hiddenretparm) != 0 && res.size() > 2) {
if (input->isThisBeforeRetPointer()) {
// pointer has been bumped by auto-return-storage
res[1].swapMarkup(res[2]); // must swap markup for slots 1 and 2
}
else {
thisIndex = 2;
}
}
res[thisIndex].flags |= ParameterPieces::isthis;
output->assignMap(proto,*glb->types,outputStatus,res);
}
for(int4 i=0;i<sharedActions.size();++i)
sharedActions[i]->applyBefore(proto, *glb->types, res, inputStatus, outputStatus);
input->assignMap(proto,*glb->types,inputStatus,res);
for (int4 i=0;i<sharedActions.size();++i)
sharedActions[i]->applyAfter(proto, *glb->types, res, inputStatus, outputStatus);
}
/// \brief Look up an effect from the given EffectRecord list
@@ -2573,6 +2581,7 @@ void ProtoModel::decode(Decoder &decoder)
throw LowlevelError("Missing prototype attributes");
buildParamList(strategystring); // Allocate input and output ParamLists
sharedActions.push_back(new HiddenReturnAction(this));
for(;;) {
uint4 subId = decoder.peekElement();
if (subId == 0) break;
@@ -2618,7 +2627,7 @@ void ProtoModel::decode(Decoder &decoder)
while(decoder.peekElement() != 0) {
Range range;
range.decode(decoder);
localrange.insertRange(range.getSpace(),range.getFirst(),range.getLast());
localrange.insertRange(range);
}
decoder.closeElement(subId);
}
@@ -2628,10 +2637,15 @@ void ProtoModel::decode(Decoder &decoder)
while(decoder.peekElement() != 0) {
Range range;
range.decode(decoder);
paramrange.insertRange(range.getSpace(),range.getFirst(),range.getLast());
paramrange.insertRange(range);
}
decoder.closeElement(subId);
}
else if (subId == ELEM_SHARESTACK) {
unique_ptr<ShareStackAction> action(new ShareStackAction(this));
action->decode(decoder);
sharedActions.push_back(action.release());
}
else if (subId == ELEM_LIKELYTRASH) {
decoder.openElement();
while(decoder.peekElement() != 0) {
@@ -2838,9 +2852,9 @@ void ProtoModelMerged::foldIn(ProtoModel *model)
// Take the union of the localrange and paramrange
set<Range>::const_iterator iter;
for(iter=model->localrange.begin();iter!=model->localrange.end();++iter)
localrange.insertRange((*iter).getSpace(),(*iter).getFirst(),(*iter).getLast());
localrange.insertRange(*iter);
for(iter=model->paramrange.begin();iter!=model->paramrange.end();++iter)
paramrange.insertRange((*iter).getSpace(),(*iter).getFirst(),(*iter).getLast());
paramrange.insertRange(*iter);
}
}
@@ -2894,7 +2908,6 @@ void ProtoModelMerged::decode(Decoder &decoder)
}
decoder.closeElement(elemId);
((ParamListMerged *)input)->finalize();
((ParamListMerged *)output)->finalize();
}
void ParameterBasic::setTypeLock(bool val)
@@ -2969,7 +2982,10 @@ Datatype *ParameterSymbol::getType(void) const
Address ParameterSymbol::getAddress(void) const
{
return sym->getFirstWholeMap()->getAddr();
SymbolEntry *entry = sym->getFirstWholeMap();
if (!entry->isMapEntry())
return Address();
return ((MapEntry *)entry)->getAddr();
}
int4 ParameterSymbol::getSize(void) const
@@ -2978,6 +2994,12 @@ int4 ParameterSymbol::getSize(void) const
return sym->getFirstWholeMap()->getSize();
}
bool ParameterSymbol::hasStorage(void) const
{
return sym->getFirstWholeMap()->isMapEntry();
}
bool ParameterSymbol::isTypeLocked(void) const
{
@@ -3125,7 +3147,6 @@ ProtoParameter *ProtoStoreSymbol::setInput(int4 i, const string &nm,const Parame
{
ParameterSymbol *res = getSymbolBacked(i);
res->sym = scope->getCategorySymbol(Symbol::function_parameter,i);
SymbolEntry *entry;
Address usepoint;
bool isindirect = (pieces.flags & ParameterPieces::indirectstorage) != 0;
@@ -3133,8 +3154,8 @@ ProtoParameter *ProtoStoreSymbol::setInput(int4 i, const string &nm,const Parame
bool istypelock = (pieces.flags & ParameterPieces::typelock) != 0;
bool isnamelock = (pieces.flags & ParameterPieces::namelock) != 0;
if (res->sym != (Symbol *)0) {
entry = res->sym->getFirstWholeMap();
if ((entry->getAddr() != pieces.addr)||(entry->getSize() != pieces.type->getSize())) {
SymbolEntry *entry = res->sym->getFirstWholeMap();
if (((MapEntry *)entry)->getAddr() != pieces.addr || entry->getSize() != pieces.type->getSize()) {
scope->removeSymbol(res->sym);
res->sym = (Symbol *)0;
}
@@ -3957,6 +3978,7 @@ void FuncProto::resolveExtraPop(void)
int4 expop = 4; // Extrapop is at least 4 for the return address
for(int4 i=0;i<numparams;++i) {
ProtoParameter *param = getParam(i);
if (!param->hasStorage()) continue;
const Address &addr( param->getAddress() );
if (addr.getSpace()->getType() != IPTR_SPACEBASE) continue;
int4 cur = (int4)addr.getOffset() + param->getSize();
@@ -4016,93 +4038,33 @@ void FuncProto::cancelInjectId(void)
flags &= ~((uint4)is_inline);
}
/// \brief Update input parameters based on Varnode trials
/// \brief Update input parameters based on active trials
///
/// If the input parameters are locked, don't do anything. Otherwise,
/// given a list of Varnodes and their associated trial information,
/// create an input parameter for each trial in order, grabbing data-type
/// information from the Varnode. Any old input parameters are cleared.
/// Create an input parameter for each trial in order, grabbing data-type information from the
/// list provided, linked by trial \e slot. Any old input parameters are cleared.
/// \param data is the function containing the trial Varnodes
/// \param triallist is the list of Varnodes
/// \param typeList is the list of data-types
/// \param activeinput is the trial container
void FuncProto::updateInputTypes(Funcdata &data,const vector<Varnode *> &triallist,ParamActive *activeinput)
void FuncProto::updateInputTypes(Funcdata &data,const vector<Datatype *> &typeList,ParamActive *activeinput)
{
if (isInputLocked()) return; // Input is locked, do no updating
store->clearAllInputs();
int4 count = 0;
int4 numtrials = activeinput->getNumTrials();
for(int4 i=0;i<numtrials;++i) {
ParamTrial &trial(activeinput->getTrial(i));
if (trial.isUsed()) {
Varnode *vn = triallist[trial.getSlot()-1];
if (vn->isMark()) continue;
ParameterPieces pieces;
if (vn->isPersist()) {
int4 sz;
pieces.addr = data.findDisjointCover(vn, sz);
if (sz == vn->getSize())
pieces.type = vn->getHigh()->getType();
else
pieces.type = data.getArch()->types->getBase(sz, TYPE_UNKNOWN);
pieces.flags = 0;
}
else {
pieces.addr = trial.getAddress();
pieces.type = vn->getHigh()->getType();
pieces.flags = 0;
}
pieces.addr = trial.getAddress();
pieces.type = typeList[trial.getSlot()-1];
pieces.flags = 0;
store->setInput(count,"",pieces);
count += 1;
vn->setMark();
}
}
for(int4 i=0;i<triallist.size();++i)
triallist[i]->clearMark();
updateThisPointer();
}
/// \brief Update input parameters based on Varnode trials, but do not store the data-type
///
/// This is accomplished in the same way as if there were data-types but instead of
/// pulling a data-type from the Varnode, only the size is used.
/// Undefined data-types are pulled from the given TypeFactory
/// \param data is the function containing the trial Varnodes
/// \param triallist is the list of Varnodes
/// \param activeinput is the trial container
void FuncProto::updateInputNoTypes(Funcdata &data,const vector<Varnode *> &triallist,ParamActive *activeinput)
{
if (isInputLocked()) return; // Input is locked, do no updating
store->clearAllInputs();
int4 count = 0;
int4 numtrials = activeinput->getNumTrials();
TypeFactory *factory = data.getArch()->types;
for(int4 i=0;i<numtrials;++i) {
ParamTrial &trial(activeinput->getTrial(i));
if (trial.isUsed()) {
Varnode *vn = triallist[trial.getSlot()-1];
if (vn->isMark()) continue;
ParameterPieces pieces;
if (vn->isPersist()) {
int4 sz;
pieces.addr = data.findDisjointCover(vn, sz);
pieces.type = factory->getBase(sz, TYPE_UNKNOWN);
pieces.flags = 0;
}
else {
pieces.addr = trial.getAddress();
pieces.type = factory->getBase(vn->getSize(),TYPE_UNKNOWN);
pieces.flags = 0;
}
store->setInput(count,"",pieces);
count += 1;
vn->setMark(); // Make sure vn is used only once
}
}
for(int4 i=0;i<triallist.size();++i)
triallist[i]->clearMark();
}
/// \brief Update the return value based on Varnode trials
///
/// If the output parameter is locked, don't do anything. Otherwise,
@@ -4275,6 +4237,7 @@ int4 FuncProto::characterizeAsInputParam(const Address &addr,int4 size) const
for(int4 i=0;i<num;++i) {
ProtoParameter *param = getParam(i);
if (!param->isTypeLocked()) continue;
if (!param->hasStorage()) continue;
locktest = true;
Address iaddr = param->getAddress();
// If the parameter already exists, the varnode must be justified in the parameter relative
@@ -4314,7 +4277,7 @@ int4 FuncProto::characterizeAsOutput(const Address &addr,int4 size) const
{
if (isOutputLocked()) {
ProtoParameter *outparam = getOutput();
if (outparam->getType()->getMetatype() == TYPE_VOID)
if (!outparam->hasStorage())
return ParamEntry::no_containment;
Address iaddr = outparam->getAddress();
// If the output is locked, the varnode must be justified in the location relative
@@ -4350,6 +4313,7 @@ bool FuncProto::possibleInputParam(const Address &addr,int4 size) const
for(int4 i=0;i<num;++i) {
ProtoParameter *param = getParam(i);
if (!param->isTypeLocked()) continue;
if (!param->hasStorage()) continue;
locktest = true;
Address iaddr = param->getAddress();
// If the parameter already exists, the varnode must be justified in the parameter relative
@@ -4376,7 +4340,7 @@ bool FuncProto::possibleOutputParam(const Address &addr,int4 size) const
{
if (isOutputLocked()) {
ProtoParameter *outparam = getOutput();
if (outparam->getType()->getMetatype() == TYPE_VOID)
if (!outparam->hasStorage())
return false;
Address iaddr = outparam->getAddress();
// If the output is locked, the varnode must be justified in the location relative
@@ -4410,6 +4374,7 @@ bool FuncProto::unjustifiedInputParam(const Address &addr,int4 size,VarnodeData
for(int4 i=0;i<num;++i) {
ProtoParameter *param = getParam(i);
if (!param->isTypeLocked()) continue;
if (!param->hasStorage()) continue;
locktest = true;
Address iaddr = param->getAddress();
// If the parameter already exists, test if -addr- -size- is improperly contained in param
@@ -4444,6 +4409,7 @@ bool FuncProto::getBiggestContainedInputParam(const Address &loc,int4 size,Varno
for(int4 i=0;i<num;++i) {
ProtoParameter *param = getParam(i);
if (!param->isTypeLocked()) continue;
if (!param->hasStorage()) continue;
locktest = true;
Address iaddr = param->getAddress();
if (iaddr.containedBy(param->getSize(), loc, size)) {
@@ -4470,7 +4436,7 @@ bool FuncProto::getBiggestContainedOutput(const Address &loc,int4 size,VarnodeDa
{
if (isOutputLocked()) {
ProtoParameter *outparam = getOutput();
if (outparam->getType()->getMetatype() == TYPE_VOID)
if (!outparam->hasStorage())
return false;
Address iaddr = outparam->getAddress();
if (iaddr.containedBy(outparam->getSize(), loc, size)) {
@@ -5024,6 +4990,7 @@ int4 FuncCallSpecs::transferLockedInputParam(ProtoParameter *param)
Address trialend = curtrial.getAddress() + (curtrial.getSize() - 1);
if (trialend < lastaddr) continue;
if (curtrial.isDefinitelyNotUsed()) return 0; // Trial has already been stripped
curtrial.markUsed(); // Trial is definitely used, picked up by collectUnlockedTrials
return curtrial.getSlot();
}
if (startaddr.getSpace()->getType() == IPTR_SPACEBASE)
@@ -5040,7 +5007,6 @@ int4 FuncCallSpecs::transferLockedInputParam(ProtoParameter *param)
/// - The Varnode properly contains the parameter
/// \param param is the given paramter (return value)
/// \param newoutput will hold any overlapping output Varnodes
/// \return the matching PcodeOp or NULL
void FuncCallSpecs::transferLockedOutputParam(ProtoParameter *param,vector<Varnode *> &newoutput)
{
@@ -5080,7 +5046,9 @@ bool FuncCallSpecs::transferLockedInput(vector<Varnode *> &newinput,const FuncPr
int4 numparams = source.numParams();
Varnode *stackref = (Varnode *)0;
for(int4 i=0;i<numparams;++i) {
int4 reuse = transferLockedInputParam(source.getParam(i));
ProtoParameter *param = source.getParam(i);
if (!param->hasStorage()) continue;
int4 reuse = transferLockedInputParam(param);
if (reuse == 0) return false;
if (reuse > 0)
newinput.push_back(op->getIn(reuse));
@@ -5107,13 +5075,30 @@ bool FuncCallSpecs::transferLockedOutput(vector<Varnode *> &newoutput,const Func
{
ProtoParameter *param = source.getOutput();
if (param->getType()->getMetatype() == TYPE_VOID) {
if (!param->hasStorage()) {
return true;
}
transferLockedOutputParam(param,newoutput);
return true;
}
/// \brief Put any trials that might represent a \e varargs parameter in the given container
///
/// For a \e locked and \e varargs prototype, collect trials that are not in the locked portion of the prototype.
/// \param unlockedTrials will hold the collected trials
void FuncCallSpecs::collectUnlockedTrials(vector<ParamTrial> &unlockedTrials)
{
if (!isDotdotdot()) return;
for(int4 i=0;i<activeinput.getNumTrials();++i) {
const ParamTrial &trial(activeinput.getTrial(i));
if (trial.isUsed()) continue; // Trials for locked slots are marked as used
int4 slot = trial.getSlot();
if (slot < 1 || slot >= op->numInput()) continue;
unlockedTrials.push_back(trial);
}
}
/// \brief Update input Varnodes to \b this CALL to reflect the formal input parameters
///
/// The current input parameters must be locked and are presumably out of date
@@ -5129,6 +5114,8 @@ void FuncCallSpecs::commitNewInputs(Funcdata &data,vector<Varnode *> &newinput)
if (!isInputLocked()) return;
Varnode *stackref = getSpacebaseRelative();
Varnode *placeholder = (Varnode *)0;
vector<ParamTrial> unlockedTrials;
collectUnlockedTrials(unlockedTrials);
if (stackPlaceholderSlot>=0)
placeholder = op->getIn(stackPlaceholderSlot);
bool noplacehold = true;
@@ -5141,6 +5128,7 @@ void FuncCallSpecs::commitNewInputs(Funcdata &data,vector<Varnode *> &newinput)
int4 numparams = numParams();
for(int4 i=0;i<numparams;++i) {
ProtoParameter *param = getParam(i);
if (!param->hasStorage()) continue;
Varnode *vn = buildParam(data,newinput[1+i],param,stackref);
newinput[1+i] = vn;
activeinput.registerTrial(param->getAddress(),param->getSize());
@@ -5152,6 +5140,11 @@ void FuncCallSpecs::commitNewInputs(Funcdata &data,vector<Varnode *> &newinput)
placeholder = (Varnode *)0; // With a locked stack param, we don't need a placeholder
}
}
for(int4 i=0;i<unlockedTrials.size();++i) {
Varnode *vn = op->getIn(unlockedTrials[i].getSlot());
newinput.push_back(vn);
activeinput.reregisterTrial(unlockedTrials[i]);
}
if (placeholder != (Varnode *)0) { // If we still need a placeholder
newinput.push_back(placeholder); // Add it at end of parameters
setStackPlaceholderSlot(newinput.size()-1);
@@ -5427,7 +5420,7 @@ void FuncCallSpecs::deindirect(Funcdata &data,Funcdata *newfd)
data.opSetInput(op,vn,0);
data.opSetOpcode(op,CPUI_CALL);
data.getOverride().insertIndirectOverride(op->getAddr(),entryaddress);
data.getOverride().insertDeindirect(op->getAddr(),entryaddress);
// Try our best to merge existing prototype
// with the one we have just been handed
@@ -5671,9 +5664,9 @@ void FuncCallSpecs::buildInputFromTrials(Funcdata &data)
newparam.push_back(op->getIn(0)); // Preserve the fspec parameter
if (isDotdotdot() && isInputLocked()){
//if varargs, move the fixed args to the beginning of the list in order
//preserve relative order of variable args
activeinput.sortFixedPosition();
// if varargs, move the fixed args to the beginning of the list in order to
// preserve relative order of variable args
activeinput.sortFixedPosition();
}
for(int4 i=0;i<activeinput.getNumTrials();++i) {
@@ -5746,75 +5739,59 @@ Varnode *FuncCallSpecs::findPreexistingWhole(Varnode *vn1,Varnode *vn2)
void FuncCallSpecs::buildOutputFromTrials(Funcdata &data,vector<Varnode *> &trialvn)
{
Varnode *finaloutvn;
vector<Varnode *> finalvn;
for(int4 i=0;i<activeoutput.getNumTrials();++i) { // Reorder the varnodes
for(int4 i=0;i<activeoutput.getNumTrials();++i) { // Extract the used Varnodes
ParamTrial &curtrial(activeoutput.getTrial(i));
if (!curtrial.isUsed()) break;
Varnode *vn = trialvn[ curtrial.getSlot() - 1];
finalvn.push_back(vn);
}
activeoutput.deleteUnusedTrials(); // This deletes unused, and renumbers used (matches finalvn)
activeoutput.deleteUnusedTrials(); // This deletes unused, and renumbers used
if (activeoutput.getNumTrials()==0) return; // Nothing is a formal output
if (!activeoutput.isJoinMostSigFirst() && finalvn.size() > 1) { // Make sure Varnodes listed from most to least significant
vector<Varnode *> reverse;
for(int4 i=finalvn.size()-1;i>=0;--i)
reverse.push_back(finalvn[i]);
finalvn.swap(reverse);
}
vector<PcodeOp *> deletedops;
if (activeoutput.getNumTrials()==1) { // We have a single, properly justified output
finaloutvn = finalvn[0];
Varnode *finaloutvn = finalvn[0];
PcodeOp *indop = finaloutvn->getDef();
// ParamTrial &curtrial(activeoutput.getTrial(0));
// if (finaloutvn->getSize() != curtrial.getSize()) { // If the varnode does not exactly match the original trial
// int4 res = curtrial.getEntry()->justifiedContain(finaloutvn->getAddress(),finaloutvn->getSize());
// if (res > 0) {
// data.opUninsert(indop);
// data.opSetOpcode(indop,CPUI_SUBPIECE); // Insert a subpiece
// Varnode *wholevn = data.newVarnodeOut(curtrial.getSize(),curtrial.getAddress(),op);
// data.opSetInput(indop,wholevn,0);
// data.opSetInput(indop,data.newConstant(4,res),1);
// data.opInsertAfter(indop,op);
// return;
// }
// }
deletedops.push_back(indop);
data.opSetOutput(op,finaloutvn); // Move varnode to its new position as output of call
}
else if (activeoutput.getNumTrials()==2) {
Varnode *hivn = finalvn[1]; // orderOutputPieces puts hi last
Varnode *lovn = finalvn[0];
if (data.isDoublePrecisOn()) {
lovn->setPrecisLo(); // Mark that these varnodes are part of a larger precision whole
hivn->setPrecisHi();
else {
vector<VarnodeData> pieces;
int4 finalSize = 0;
for(int4 i=0;i<finalvn.size();++i) {
Varnode *vn = finalvn[i];
pieces.emplace_back(vn->getAddr(),vn->getSize());
finalSize += vn->getSize();
deletedops.push_back(vn->getDef());
}
deletedops.push_back(hivn->getDef());
deletedops.push_back(lovn->getDef());
finaloutvn = findPreexistingWhole(hivn,lovn);
if (finaloutvn == (Varnode *)0) {
Address joinaddr = data.getArch()->constructJoinAddress(data.getArch()->translate,
hivn->getAddr(),hivn->getSize(),
lovn->getAddr(),lovn->getSize());
finaloutvn = data.newVarnode(hivn->getSize()+lovn->getSize(),joinaddr);
data.opSetOutput(op,finaloutvn);
PcodeOp *sublo = data.newOp(2,op->getAddr());
data.opSetOpcode(sublo,CPUI_SUBPIECE);
data.opSetInput(sublo,finaloutvn,0);
data.opSetInput(sublo,data.newConstant(4,0),1);
data.opSetOutput(sublo,lovn);
data.opInsertAfter(sublo,op);
PcodeOp *subhi = data.newOp(2,op->getAddr());
data.opSetOpcode(subhi,CPUI_SUBPIECE);
data.opSetInput(subhi,finaloutvn,0);
data.opSetInput(subhi,data.newConstant(4,lovn->getSize()),1);
data.opSetOutput(subhi,hivn);
data.opInsertAfter(subhi,op);
Address addr = data.getArch()->joinPieces(pieces,data.getArch()->translate);
Varnode *finaloutvn = data.newVarnode(finalSize,addr);
data.opSetOutput(op,finaloutvn);
int4 truncAmount = 0;
for(int4 i=finalvn.size()-1;i>=0;--i) {
PcodeOp *subop = data.newOp(2,op->getAddr());
data.opSetOpcode(subop,CPUI_SUBPIECE);
data.opSetInput(subop,finaloutvn,0);
data.opSetInput(subop,data.newConstant(4,truncAmount),1);
data.opSetOutput(subop,finalvn[i]); // Move output from INDIRECT to SUBPIECE
data.opInsertAfter(subop,op);
truncAmount += finalvn[i]->getSize();
}
else { // Preexisting whole
deletedops.push_back(finaloutvn->getDef()); // Its inputs are used only in this op
data.opSetOutput(op,finaloutvn);
if (finalvn.size() == 2 && data.isDoublePrecisOn()) {
finalvn[1]->setPrecisLo(); // Mark that these varnodes are part of a larger precision whole
finalvn[0]->setPrecisHi();
}
}
else
return;
for(int4 i=0;i<deletedops.size();++i) { // Destroy the original INDIRECT ops
PcodeOp *dop = deletedops[i];
@@ -59,6 +59,7 @@ extern ElementId ELEM_RETPARAM; ///< Marshaling element \<retparam>
extern ElementId ELEM_RETURNSYM; ///< Marshaling element \<returnsym>
extern ElementId ELEM_UNAFFECTED; ///< Marshaling element \<unaffected>
extern ElementId ELEM_INTERNAL_STORAGE; ///< Marshaling element \<internal_storage>
extern ElementId ELEM_SHARESTACK; ///< Marshaling element \<sharestack>
/// \brief Exception thrown when a prototype can't be modeled properly
struct ParamUnassignedError : public LowlevelError {
@@ -95,7 +96,8 @@ public:
extracheck_low = 0x100, ///< Perform extra checks during parameter recovery on least sig portion of the double
is_grouped = 0x200, ///< This entry is grouped with other entries
overlapping = 0x400, ///< Overlaps an earlier entry (and doesn't consume additional resource slots)
first_storage = 0x800 ///< Entry is first in its storage class
first_storage = 0x800, ///< Entry is first in its storage class
is_stackspill = 0x1000 ///< Is the \e stack entry that parameter assignments spill over into
};
enum {
no_containment, ///< Range neither contains nor is contained by a ParamEntry
@@ -131,6 +133,7 @@ public:
int4 getAlign(void) const { return alignment; } ///< Get the alignment of \b this entry
JoinRecord *getJoinRecord(void) const { return joinrec; } ///< Get record describing joined pieces (or null if only 1 piece)
type_class getType(void) const { return type; } ///< Get the data-type class associated with \b this
bool isStackSpill(void) const { return ((flags & is_stackspill)!=0); } ///< Return \b true if \b this is the \e stack entry holding spill
bool isExclusion(void) const { return (alignment==0); } ///< Return \b true if this holds a single parameter exclusively
bool isReverseStack(void) const { return ((flags & reverse_stack)!=0); } ///< Return \b true if parameters are allocated in reverse order
bool isGrouped(void) const { return ((flags & is_grouped)!=0); } ///< Return \b true if \b this is grouped with other entries
@@ -146,7 +149,8 @@ public:
int4 getSlot(const Address &addr,int4 skip) const;
AddrSpace *getSpace(void) const { return spaceid; } ///< Get the address space containing \b this entry
uintb getBase(void) const { return addressbase; } ///< Get the starting offset of \b this entry
Address getAddrBySlot(int4 &slot,int4 sz,int4 typeAlign) const;
Address getAddrBySlot(int4 &slot, int4 sz, int4 typeAlign, bool justifyRight,const AddrSpaceManager *m) const;
Address getAddrBySlot(int4 &slot,int4 sz,int4 typeAlign,const AddrSpaceManager *m) const;
void decode(Decoder &decoder,bool normalstack,bool grouped,list<ParamEntry> &curList);
bool isParamCheckHigh(void) const { return ((flags & extracheck_high)!=0); } ///< Return \b true if there is a high overlap
bool isParamCheckLow(void) const { return ((flags & extracheck_low)!=0); } ///< Return \b true if there is a low overlap
@@ -232,6 +236,8 @@ private:
public:
/// \brief Construct from components
ParamTrial(const Address &ad,int4 sz,int4 sl) { addr = ad; size = sz; slot = sl; flags=0; entry=(ParamEntry *)0; offset=-1; fixedPosition = -1; }
/// \brief Construct version with new slot
ParamTrial(const ParamTrial &op2,int4 sl) { addr = op2.addr; size = op2.size; flags = op2.flags; slot = sl; entry=(ParamEntry *)0; offset=-1; fixedPosition = -1; }
const Address &getAddress(void) const { return addr; } ///< Get the starting address of \b this trial
int4 getSize(void) const { return size; } ///< Get the number of bytes in \b this trial
int4 getSlot(void) const { return slot; } ///< Get the \e slot associated with \b this trial
@@ -290,16 +296,20 @@ class ParamActive {
bool isfullychecked; ///< True if all trials are fully examined (and no new trials are expected)
bool needsfinalcheck; ///< Should a final pass be made on trials (to take into account control-flow changes)
bool recoversubcall; ///< True if \b this is being used to recover prototypes of a sub-function call
bool joinMostSigFirst; ///< True if trials are joined starting with the most significant piece first
public:
ParamActive(bool recoversub); ///< Construct an empty container
void clear(void); ///< Reset to an empty container
void registerTrial(const Address &addr,int4 sz); ///< Add a new trial to the container
void reregisterTrial(const ParamTrial &oldTrial); ///< Register a previously existing trial
int4 getNumTrials(void) const { return trial.size(); } ///< Get the number of trials in \b this container
ParamTrial &getTrial(int4 i) { return trial[i]; } ///< Get the i-th trial
const ParamTrial &getTrialForInputVarnode(int4 slot) const; ///< Get trial corresponding to the given input Varnode
int4 whichTrial(const Address &addr,int4 sz) const; ///< Get the trial overlapping with the given memory range
bool needsFinalCheck(void) const { return needsfinalcheck; } ///< Is a final check required
void markNeedsFinalCheck(void) { needsfinalcheck = true; } ///< Mark that a final check is required
bool isJoinMostSigFirst(void) const { return joinMostSigFirst; } ///< Return \b true if pieces are joined starting with most significant
void setJoinMostSigFirst(void) { joinMostSigFirst = true; } ///< Mark that pieces are joined starting with the most significant
bool isRecoverSubcall(void) const { return recoversubcall; } ///< Are these trials for a call to a sub-function
bool isFullyChecked(void) const { return isfullychecked; } ///< Are all trials checked with no new trials expected
void markFullyChecked(void) { isfullychecked = true; } ///< Mark that all trials are checked
@@ -310,6 +320,7 @@ public:
void setMaxPass(int4 val) { maxpass = val; } ///< Set the maximum number of passes
void finishPass(void) { numpasses += 1; } ///< Mark that an analysis pass has completed
void sortTrials(void) { sort(trial.begin(),trial.end()); } ///< Sort the trials in formal parameter order
void sortFixedPosition(void) {sort(trial.begin(),trial.end(),ParamTrial::fixedPositionCompare);} ///< sort the trials by fixed position then <
void deleteUnusedTrials(void); ///< Remove trials that were found not to be parameters
void splitTrial(int4 i,int4 sz); ///< Split the given trial in two
void joinTrial(int4 slot,const Address &addr,int4 sz); ///< Join adjacent parameter trials
@@ -329,8 +340,6 @@ public:
/// \param addr is the new range's starting address
/// \param sz is the new range's size in bytes
void shrink(int4 i,const Address &addr,int4 sz) { trial[i].setAddress(addr,sz); }
void sortFixedPosition(void) {sort(trial.begin(),trial.end(),ParamTrial::fixedPositionCompare);} ///< sort the trials by fixed position then <
};
/// \brief A special space for encoding FuncCallSpecs
@@ -431,13 +440,20 @@ public:
virtual ~ParamList(void) {} ///< Destructor
virtual uint4 getType(void) const=0; ///< Get the type of parameter list
/// \brief Initialized the resource state for \b this to indicate all resources are available
///
/// \param status is the state object
virtual void allocateStatus(vector<int4> &status) const=0;
/// \brief Given list of data-types, map the list positions to storage locations
///
/// If we know the function prototype, recover how parameters are actually stored using the model.
/// \param proto is the ordered list of data-types
/// \param typefactory is the TypeFactory (for constructing pointers)
/// \param status is the state of consumption for \b this resource
/// \param res will contain the storage locations corresponding to the datatypes
virtual void assignMap(const PrototypePieces &proto,TypeFactory &typefactory,vector<ParameterPieces> &res) const=0;
virtual void assignMap(const PrototypePieces &proto,TypeFactory &typefactory,vector<int4> &status,
vector<ParameterPieces> &res) const=0;
/// \brief Given an unordered list of storage locations, calculate a function prototype
///
@@ -593,7 +609,7 @@ protected:
list<ParamEntry> entry; ///< The ordered list of parameter entries
vector<ParamEntryResolver *> resolverMap; ///< Map from space id to resolver
list<ModelRule> modelRules; ///< Rules to apply when assigning addresses
AddrSpace *spacebase; ///< Address space containing relative offset parameters
const AddrSpaceManager *glb; ///< Owning manager
const ParamEntry *findEntry(const Address &loc,int4 size,bool just) const; ///< Given storage location find matching ParamEntry
const ParamEntry *selectUnreferenceEntry(int4 grp,type_class prefType) const; ///< Select entry to fill an unreferenced param
void buildTrialMap(ParamActive *active) const; ///< Build map from parameter trials to model ParamEntrys
@@ -615,6 +631,8 @@ public:
ParamListStandard(const ParamListStandard &op2); ///< Copy constructor
virtual ~ParamListStandard(void);
const list<ParamEntry> &getEntry(void) const { return entry; } ///< Get the list of parameter entries
const AddrSpaceManager *getManager(void) const { return glb; } ///< Get the owner
bool isBigEndian(void) const { return entry.front().getSpace()->isBigEndian(); } ///< Return \b true if resources are big endian
void extractTiles(vector<const ParamEntry *> &tiles,type_class type) const; ///< Get registers of given storage class
const ParamEntry *getStackEntry(void) const; ///< Get the stack entry
uint4 assignAddressFallback(type_class resource,Datatype *tp,bool matchExact,vector<int4> &status,
@@ -622,7 +640,9 @@ public:
uint4 assignAddress(Datatype *dt,const PrototypePieces &proto,int4 pos,TypeFactory &tlst,
vector<int4> &status,ParameterPieces &res) const;
virtual uint4 getType(void) const { return p_standard; }
virtual void assignMap(const PrototypePieces &proto,TypeFactory &typefactory,vector<ParameterPieces> &res) const;
virtual void allocateStatus(vector<int4> &status) const;
virtual void assignMap(const PrototypePieces &proto,TypeFactory &typefactory,vector<int4> &status,
vector<ParameterPieces> &res) const;
virtual void fillinMap(ParamActive *active) const;
virtual bool checkJoin(const Address &hiaddr,int4 hisize,const Address &loaddr,int4 losize) const;
virtual bool checkSplit(const Address &loc,int4 size,int4 splitpoint) const;
@@ -632,7 +652,7 @@ public:
virtual bool getBiggestContainedParam(const Address &loc,int4 size,VarnodeData &res) const;
virtual bool unjustifiedContainer(const Address &loc,int4 size,VarnodeData &res) const;
virtual OpCode assumedExtension(const Address &addr,int4 size,VarnodeData &res) const;
virtual AddrSpace *getSpacebase(void) const { return spacebase; }
virtual AddrSpace *getSpacebase(void) const;
virtual bool isThisBeforeRetPointer(void) const { return thisbeforeret; }
virtual void getRangeList(AddrSpace *spc,RangeList &res) const;
virtual int4 getMaxDelay(void) const { return maxdelay; }
@@ -658,7 +678,8 @@ public:
useFillinFallback = op2.useFillinFallback; } ///< Copy constructor
void fillinMapFallback(ParamActive *active,bool firstOnly) const;
virtual uint4 getType(void) const { return p_standard_out; }
virtual void assignMap(const PrototypePieces &proto,TypeFactory &typefactory,vector<ParameterPieces> &res) const;
virtual void assignMap(const PrototypePieces &proto,TypeFactory &typefactory,vector<int4> &status,
vector<ParameterPieces> &res) const;
virtual void fillinMap(ParamActive *active) const;
virtual bool possibleParam(const Address &loc,int4 size) const;
virtual void decode(Decoder &decoder,vector<EffectRecord> &effectlist,bool normalstack);
@@ -677,7 +698,8 @@ public:
ParamListRegisterOut(void) : ParamListStandardOut() {} ///< Constructor
ParamListRegisterOut(const ParamListRegisterOut &op2) : ParamListStandardOut(op2) {} ///< Copy constructor
virtual uint4 getType(void) const { return p_register_out; }
virtual void assignMap(const PrototypePieces &proto,TypeFactory &typefactory,vector<ParameterPieces> &res) const;
virtual void assignMap(const PrototypePieces &proto,TypeFactory &typefactory,vector<int4> &status,
vector<ParameterPieces> &res) const;
virtual ParamList *clone(void) const;
};
@@ -712,7 +734,8 @@ public:
void foldIn(const ParamListStandard &op2); ///< Add another model to the union
void finalize(void) { populateResolver(); } ///< Fold-ins are finished, finalize \b this
virtual uint4 getType(void) const { return p_merged; }
virtual void assignMap(const PrototypePieces &proto,TypeFactory &typefactory,vector<ParameterPieces> &res) const {
virtual void assignMap(const PrototypePieces &proto,TypeFactory &typefactory,vector<int4> &status,
vector<ParameterPieces> &res) const {
throw LowlevelError("Cannot assign prototype before model has been resolved"); }
virtual void fillinMap(ParamActive *active) const {
throw LowlevelError("Cannot determine prototype before model has been resolved"); }
@@ -748,6 +771,7 @@ class ProtoModel {
int4 extrapop; ///< Extra bytes popped from stack
ParamList *input; ///< Resource model for input parameters
ParamList *output; ///< Resource model for output parameters
vector<const SharedAction *> sharedActions; ///< Actions invoked during parameter assignment
const ProtoModel *compatModel; ///< The model \b this is a copy of
vector<EffectRecord> effectlist; ///< List of side-effects
vector<VarnodeData> likelytrash; ///< Storage locations potentially carrying \e trash values
@@ -772,6 +796,8 @@ public:
virtual ~ProtoModel(void); ///< Destructor
const string &getName(void) const { return name; } ///< Get the name of the prototype model
Architecture *getArch(void) const { return glb; } ///< Get the owning Architecture
const ParamList *getInputResource(void) const { return input; } ///< Get input parameter resources
const ParamList *getOutputResource(void) const { return output; } ///< Get output parameter resources
const ProtoModel *getAliasParent(void) const { return compatModel; } ///< Return \e model \b this is an alias of (or null)
uint4 hasEffect(const Address &addr,int4 size) const; ///< Determine side-effect of \b this on the given memory range
int4 getExtraPop(void) const { return extrapop; } ///< Get the stack-pointer \e extrapop for \b this model
@@ -1101,6 +1127,7 @@ public:
virtual Datatype *getType(void) const=0; ///< Get the data-type associate with \b this
virtual Address getAddress(void) const=0; ///< Get the storage address for \b this parameter
virtual int4 getSize(void) const=0; ///< Get the number of bytes occupied by \b this parameter
virtual bool hasStorage(void) const=0; ///< Does \b this have assigned storage
virtual bool isTypeLocked(void) const=0; ///< Is the parameter data-type locked
virtual bool isNameLocked(void) const=0; ///< Is the parameter name locked
virtual bool isSizeTypeLocked(void) const=0; ///< Is the size of the parameter locked
@@ -1170,6 +1197,7 @@ public:
virtual Datatype *getType(void) const { return type; }
virtual Address getAddress(void) const { return addr; }
virtual int4 getSize(void) const { return type->getSize(); }
virtual bool hasStorage(void) const { return !addr.isInvalid(); }
virtual bool isTypeLocked(void) const { return ((flags&ParameterPieces::typelock)!=0); }
virtual bool isNameLocked(void) const { return ((flags&ParameterPieces::namelock)!=0); }
virtual bool isSizeTypeLocked(void) const { return ((flags&ParameterPieces::sizelock)!=0); }
@@ -1258,6 +1286,7 @@ public:
virtual Datatype *getType(void) const;
virtual Address getAddress(void) const;
virtual int4 getSize(void) const;
virtual bool hasStorage(void) const;
virtual bool isTypeLocked(void) const;
virtual bool isNameLocked(void) const;
virtual bool isSizeTypeLocked(void) const;
@@ -1520,8 +1549,7 @@ public:
bool checkInputSplit(const Address &loc,int4 size,int4 splitpoint) const {
return model->checkInputSplit(loc,size,splitpoint); }
void updateInputTypes(Funcdata &data,const vector<Varnode *> &triallist,ParamActive *activeinput);
void updateInputNoTypes(Funcdata &data,const vector<Varnode *> &triallist,ParamActive *activeinput);
void updateInputTypes(Funcdata &data,const vector<Datatype *> &typeList,ParamActive *activeinput);
void updateOutputTypes(const vector<Varnode *> &triallist);
void updateOutputNoTypes(const vector<Varnode *> &triallist,TypeFactory *factory);
void updateAllTypes(const PrototypePieces &proto);
@@ -1661,6 +1689,7 @@ class FuncCallSpecs : public FuncProto {
void transferLockedOutputParam(ProtoParameter *param,vector<Varnode *> &newoutput);
bool transferLockedInput(vector<Varnode *> &newinput,const FuncProto &source);
bool transferLockedOutput(vector<Varnode *> &newoutput,const FuncProto &source);
void collectUnlockedTrials(vector<ParamTrial> &unlockedTrials);
void commitNewInputs(Funcdata &data,vector<Varnode *> &newinput);
void commitNewOutputs(Funcdata &data,vector<Varnode *> &newoutput);
void collectOutputTrialVarnodes(vector<Varnode *> &trialvn);
@@ -86,7 +86,7 @@ void Funcdata::clear(void)
{ // Clear everything associated with decompilation (analysis)
flags &= ~(highlevel_on|blocks_generated|processing_started|typerecovery_start|typerecovery_on|
double_precis_on|restart_pending);
double_precis_on|restart_pending|normalization_on);
clean_up_index = 0;
high_level_index = 0;
cast_phase_index = 0;
@@ -172,8 +172,6 @@ void Funcdata::stopProcessing(void)
{
flags |= processing_complete;
obank.destroyDead(); // Free up anything in the dead list
if (!isJumptableRecoveryOn())
issueDatatypeWarnings();
#ifdef CPUI_STATISTICS
glb->stats->process(*this);
#endif
@@ -214,7 +212,7 @@ void Funcdata::printRaw(ostream &s) const
throw RecovError("No operations to print");
PcodeOpTree::const_iterator iter;
s << "Raw operations: \n";
for(iter=obank.beginAll();iter!=obank.endAll();++iter) {
for(iter=obank.beginMain();iter!=obank.endMain();++iter) {
s << (*iter).second->getSeqNum() << ":\t";
(*iter).second->printRaw(s);
s << endl;
@@ -242,7 +240,7 @@ void Funcdata::spacebase(void)
for(i=0;i<numspace;++i) {
const VarnodeData &point(spc->getSpacebase(i));
// Find input varnode at this size and location
Datatype *ct = glb->types->getTypeSpacebase(spc,getAddress());
Datatype *ct = glb->types->getTypeSpacebase(spc,localmap->getId());
Datatype *ptr = glb->types->getTypePointer(point.size,ct,spc->getWordSize());
iter = vbank.beginLoc(point.size,Address(point.space,point.offset));
@@ -315,7 +313,7 @@ Varnode *Funcdata::constructSpacebaseInput(AddrSpace *id)
if (id->numSpacebase() == 0)
throw LowlevelError("Unable to construct pointer into space: "+id->getName());
const VarnodeData &point(id->getSpacebase(0));
Datatype *ct = glb->types->getTypeSpacebase(id,getAddress());
Datatype *ct = glb->types->getTypeSpacebase(id,localmap->getId());
Datatype *ptr = glb->types->getTypePointer(point.size,ct,id->getWordSize());
spacePtr = newVarnode(point.size, point.getAddr(), ptr);
spacePtr = setInputVarnode(spacePtr);
@@ -332,7 +330,7 @@ Varnode *Funcdata::constructSpacebaseInput(AddrSpace *id)
Varnode *Funcdata::constructConstSpacebase(AddrSpace *id)
{
Datatype *ct = glb->types->getTypeSpacebase(id,Address());
Datatype *ct = glb->types->getTypeSpacebase(id,0);
Datatype *ptr = glb->types->getTypePointer(id->getAddrSize(),ct,id->getWordSize());
Varnode *spacePtr = newConstant(id->getAddrSize(),0);
spacePtr->updateType(ptr,true,true);
@@ -357,12 +355,12 @@ Varnode *Funcdata::constructConstSpacebase(AddrSpace *id)
/// \param rampoint is the constant pointer interpreted as an Address
/// \param origval is the constant
/// \param origsize is the size of the constant
void Funcdata::spacebaseConstant(PcodeOp *op,int4 slot,SymbolEntry *entry,const Address &rampoint,uintb origval,int4 origsize)
void Funcdata::spacebaseConstant(PcodeOp *op,int4 slot,MapEntry *entry,const Address &rampoint,uintb origval,int4 origsize)
{
int4 sz = rampoint.getAddrSize();
AddrSpace *spaceid = rampoint.getSpace();
Datatype *sb_type = glb->types->getTypeSpacebase(spaceid,Address());
Datatype *sb_type = glb->types->getTypeSpacebase(spaceid,entry->getSymbol()->getScope()->getId());
sb_type = glb->types->getTypePointer(sz,sb_type,spaceid->getWordSize());
Varnode *spacebase_vn,*outvn,*newconst;
@@ -404,7 +402,7 @@ void Funcdata::spacebaseConstant(PcodeOp *op,int4 slot,SymbolEntry *entry,const
// Make sure newconstant and extra preserve origval in address units
uintb newconstoff = origval - extra; // everything is already in address units
newconst = newConstant(sz,newconstoff);
newconst->setPtrCheck(); // No longer need to check this constant as a pointer
newconst->setSymbolCheck(Varnode::symcheck_complete); // No longer need to check this constant as symbolref
if (spaceid->isTruncated())
addOp->setPtrFlow();
opSetInput(addOp,spacebase_vn,0);
@@ -427,7 +425,7 @@ void Funcdata::spacebaseConstant(PcodeOp *op,int4 slot,SymbolEntry *entry,const
else
opSetOpcode(extraOp,CPUI_INT_ADD);
Varnode *extconst = newConstant(sz,extra);
extconst->setPtrCheck();
extconst->setSymbolCheck(Varnode::symcheck_complete);
opSetInput(extraOp,outvn,0);
opSetInput(extraOp,extconst,1);
outvn = extraOp->getOut();
@@ -472,13 +470,12 @@ void Funcdata::clearCallSpecs(void)
qlst.clear(); // Delete list of pointers
}
void Funcdata::issueDatatypeWarnings(void)
void Funcdata::issueDatatypeWarning(Datatype *dt)
{
list<DatatypeWarning>::const_iterator iter;
for(iter=glb->types->beginWarnings();iter!=glb->types->endWarnings();++iter) {
warningHeader((*iter).getWarning());
}
string warn = glb->types->findWarning(dt);
if (warn.size() > 0)
warningHeader(warn);
}
FuncCallSpecs *Funcdata::getCallSpecs(const PcodeOp *op) const
@@ -615,9 +612,9 @@ void Funcdata::decodeJumpTable(Decoder &decoder)
{
uint4 elemId = decoder.openElement(ELEM_JUMPTABLELIST);
while(decoder.peekElement() != 0) {
JumpTable *jt = new JumpTable(glb);
unique_ptr<JumpTable> jt(new JumpTable());
jt->decode(decoder);
jumpvec.push_back(jt);
jumpvec.push_back(jt.release());
}
decoder.closeElement(elemId);
}
@@ -733,8 +730,9 @@ void Funcdata::encodeTree(Encoder &encoder) const
/// tree is also emitted.
/// \param encoder is the stream encoder
/// \param id is the unique id associated with the function symbol
/// \param savetree is \b true if the p-code tree should be emitted
void Funcdata::encode(Encoder &encoder,uint8 id,bool savetree) const
/// \param saveTree is \b true if the p-code tree should be emitted
/// \param saveOverrides is \b true if information about overrides should be emitted
void Funcdata::encode(Encoder &encoder,uint8 id,bool saveTree,bool saveOverrides) const
{
encoder.openElement(ELEM_FUNCTION);
@@ -750,13 +748,14 @@ void Funcdata::encode(Encoder &encoder,uint8 id,bool savetree) const
localmap->encodeRecursive(encoder,false); // Save scope and all subscopes
}
if (savetree) {
if (saveTree) {
encodeTree(encoder);
encodeHigh(encoder);
}
encodeJumpTable(encoder);
funcp.encode(encoder); // Must be saved after database
localoverride.encode(encoder,glb);
if (saveOverrides)
localoverride.encode(encoder,glb);
encoder.closeElement(ELEM_FUNCTION);
}
@@ -907,44 +906,87 @@ void PcodeEmitFd::dump(const Address &addr,OpCode opc,VarnodeData *outvar,Varnod
}
}
/// \brief Get the resolved union field associated with the given edge
/// \brief Get the resolution (union field) associated with an unresolved data-type and the given edge
///
/// If there is no field associated with the edge, null is returned
/// \param parent is the data-type being resolved
/// If there is no field associated with the edge, or the resolved data-type is not
/// the same size as the given data-type, null is returned.
/// \param unresType is the given data-type being resolved
/// \param op is the PcodeOp component of the given edge
/// \param slot is the slot component of the given edge
/// \return the associated field as a ResolvedUnion or null
const ResolvedUnion *Funcdata::getUnionField(const Datatype *parent,const PcodeOp *op,int4 slot) const
const ResolvedUnion *Funcdata::getUnionField(const Datatype *unresType,const PcodeOp *op,int4 slot) const
{
map<ResolveEdge,ResolvedUnion>::const_iterator iter;
ResolveEdge edge(parent,op,slot);
ResolveEdge edge(unresType,op,slot);
iter = unionMap.find(edge);
if (iter != unionMap.end()) {
const ResolvedUnion *res = &(*iter).second;
Datatype *dt = res->getDatatype();
// Check that the Varnode size matches the data-type
if (unresType->getSize() == dt->getSize())
return res;
}
return (const ResolvedUnion *)0;
}
/// \brief Get the resolution (union field) associated with an unresolved data-type and the given edge
///
/// The size of the resolved data-type does not have to match the given data-type.
/// If there is no field associated with the edge, null is returned.
/// \param unresType is the unresolved data-type
/// \param op is the PcodeOp component of the given edge
/// \param slot is the slot component of the given edge
/// \return the associated field as a ResolvedUnion or null
const ResolvedUnion *Funcdata::getUnionResolution(const Datatype *unresType,const PcodeOp *op,int4 slot) const
{
map<ResolveEdge,ResolvedUnion>::const_iterator iter;
ResolveEdge edge(unresType,op,slot);
iter = unionMap.find(edge);
if (iter != unionMap.end()) {
const ResolvedUnion *res = &(*iter).second;
return res;
}
return (const ResolvedUnion *)0;
}
/// \brief Get any resolution (union field) associated with an unresolved data-type and the given address
///
/// If there is no associated field, null is returned
/// \param unresType is the unresolved data-type
/// \param addr is the given address
/// \param slot is the slot component the resolution matches
/// \return the associated field as a ResolvedUnion or null
const ResolvedUnion *Funcdata::getAddressBasedUnionField(const Datatype *unresType,const Address &addr,int4 slot) const
{
map<ResolveEdge,ResolvedUnion>::const_iterator iter;
ResolveEdge edge(unresType,addr,slot);
iter = unionMap.find(edge);
if (iter != unionMap.end())
return &(*iter).second;
return (const ResolvedUnion *)0;
}
/// \brief Associate a union field with the given edge
/// \brief Associate a resolution (union field) with an unresolved data-type and the given edge
///
/// If there was a previous association, it is overwritten unless it was \e locked.
/// The method returns \b true except in this case where a previous locked association exists.
/// \param parent is the parent union data-type
/// \param unresType is the unresolved data-type
/// \param op is the PcodeOp component of the given edge
/// \param slot is the slot component of the given edge
/// \param resolve is the resolved union
/// \return \b true unless there was a locked association
bool Funcdata::setUnionField(const Datatype *parent,const PcodeOp *op,int4 slot,const ResolvedUnion &resolve)
/// \return \b true unless the resolution was locked
bool Funcdata::setUnionField(const Datatype *unresType,const PcodeOp *op,int4 slot,const ResolvedUnion &resolve)
{
ResolveEdge edge(parent,op,slot);
ResolveEdge edge(unresType,op,slot);
pair<map<ResolveEdge,ResolvedUnion>::iterator,bool> res;
res = unionMap.emplace(edge,resolve);
if (!res.second) {
if ((*res.first).second.isLocked()) {
return false;
}
(*res.first).second = resolve;
if (!(*res.first).second.update(resolve))
return !(*res.first).second.isLocked();
}
if (op->code() == CPUI_MULTIEQUAL && slot >= 0) {
// Data-type propagation doesn't happen between MULTIEQUAL input slots holding the same Varnode
@@ -953,54 +995,124 @@ bool Funcdata::setUnionField(const Datatype *parent,const PcodeOp *op,int4 slot,
for(int4 i=0;i<op->numInput();++i) {
if (i == slot) continue;
if (op->getIn(i) != vn) continue; // Check that different input slot holds same Varnode
ResolveEdge dupedge(parent,op,i);
ResolveEdge dupedge(unresType,op,i);
res = unionMap.emplace(dupedge,resolve);
if (!res.second) {
if (!(*res.first).second.isLocked())
(*res.first).second = resolve;
(*res.first).second.update(resolve);
}
}
}
return true;
}
/// \brief Force a specific union field resolution for the given edge
/// \brief Associate a resolution (union field) with an unresolved data-type and the given address
///
/// The \b parent data-type is taken directly from the given Varnode.
/// \param parent is the parent data-type
/// If there was a previous association, it is overwritten unless it was \e locked.
/// The method returns \b true except in this case where a previous locked association exists.
/// \param unresType is the unresolved data-type
/// \param addr is the given address
/// \param slot is the slot component the resolution matches
/// \param resolve is the resolved union
/// \return \b true unless there was a locked association
bool Funcdata::setAddressBasedUnionField(const Datatype *unresType,const Address &addr,int4 slot,const ResolvedUnion &resolve)
{
ResolveEdge edge(unresType,addr,slot);
pair<map<ResolveEdge,ResolvedUnion>::iterator,bool> res;
res = unionMap.emplace(edge,resolve);
if (!res.second) {
if ((*res.first).second.isLocked()) {
return false;
}
(*res.first).second = resolve;
}
return true;
}
/// \brief Update the resolution data-type associated with an unresolved data-type for a given edge
///
/// If further resolution of the cached data-type has happened, update the cache with the new data-type.
/// \param unresType is the unresolved data-type
/// \param op is the PcodeOp component of the given edge
/// \param slot is the slot component of the given edge
/// \param resType is the new resolution data-type
/// \return \b true unless there was a locked association
bool Funcdata::updateUnionField(const Datatype *unresType,const PcodeOp *op,int4 slot,Datatype *resType)
{
map<ResolveEdge,ResolvedUnion>::iterator iter;
ResolveEdge edge(unresType,op,slot);
iter = unionMap.find(edge);
if (iter != unionMap.end()) {
(*iter).second.setResolve(resType);
return true;
}
return false;
}
/// \brief Force a specific resolution (union field) resolution for an unresolved data-type and the given edge
///
/// \param unresType is the unresolved data-type
/// \param fieldNum is the index of the field to force
/// \param op is PcodeOp of the edge
/// \param slot is -1 for the write edge or >=0 indicating the particular read edge
void Funcdata::forceFacingType(Datatype *parent,int4 fieldNum,PcodeOp *op,int4 slot)
void Funcdata::forceFacingType(Datatype *unresType,int4 fieldNum,PcodeOp *op,int4 slot)
{
Datatype *baseType = parent;
Datatype *baseType = unresType;
if (baseType->getMetatype() == TYPE_PTR)
baseType = ((TypePointer *)baseType)->getPtrTo();
if (parent->isPointerRel()) {
if (unresType->isPointerRel()) {
// Don't associate a relative pointer with the resolution, but convert to a standard pointer
parent = glb->types->getTypePointer(parent->getSize(), baseType, ((TypePointer *)parent)->getWordSize());
unresType = glb->types->getTypePointer(unresType->getSize(), baseType, ((TypePointer *)unresType)->getWordSize());
}
ResolvedUnion resolve(parent,fieldNum,*glb->types);
setUnionField(parent, op, slot, resolve);
ResolvedUnion resolve(unresType,fieldNum,*glb->types);
setUnionField(unresType, op, slot, resolve);
}
/// \brief Copy a read/write facing resolution for a specific data-type from one PcodeOp to another
/// \brief Copy a read/write facing resolution for an unresolved data-type from one PcodeOp to another
///
/// \param parent is the data-type that needs resolution
/// \param unresType is the unresolved data-type
/// \param op is the new reading PcodeOp
/// \param slot is the new slot (-1 for write, >=0 for read)
/// \param oldOp is the PcodeOp to inherit the resolution from
/// \param oldSlot is the old slot (-1 for write, >=0 for read)
int4 Funcdata::inheritResolution(Datatype *parent,const PcodeOp *op,int4 slot,PcodeOp *oldOp,int4 oldSlot)
/// \return the field number that was inherited
int4 Funcdata::inheritUnionField(Datatype *unresType,const PcodeOp *op,int4 slot,PcodeOp *oldOp,int4 oldSlot)
{
map<ResolveEdge,ResolvedUnion>::const_iterator iter;
if (slot < 0 && oldOp->isMarker())
slot = 0;
ResolveEdge edge(unresType,oldOp,oldSlot);
iter = unionMap.find(edge);
if (iter == unionMap.end())
return -1;
setUnionField(unresType,op,slot,(*iter).second);
return (*iter).second.getFieldNum();
}
/// \brief Create a resolution for an unresolved pointer data-type based on earlier non-pointer resolution
///
/// \param unresPtr is the unresolved pointer data-type
/// \param op is the new reading PcodeOp
/// \param slot is the new slot (-1 for write, >=0 for read)
/// \param oldOp is the PcodeOp to inherit the resolution from
/// \param oldSlot is the old slot (-1 for write, >=0 for read)
/// \return the field number that was inherited
int4 Funcdata::inheritUnionFieldPtr(Datatype *unresPtr,const PcodeOp *op,int4 slot,PcodeOp *oldOp,int4 oldSlot)
{
Datatype *parent = unresPtr->getDepend(0);
if (slot < 0 && oldOp->isMarker())
slot = 0;
map<ResolveEdge,ResolvedUnion>::const_iterator iter;
ResolveEdge edge(parent,oldOp,oldSlot);
iter = unionMap.find(edge);
if (iter == unionMap.end())
return -1;
setUnionField(parent,op,slot,(*iter).second);
ResolvedUnion ptrres(unresPtr,(*iter).second.getFieldNum(),*glb->types);
setUnionField(unresPtr,op,slot,ptrres);
return (*iter).second.getFieldNum();
}
@@ -69,7 +69,8 @@ class Funcdata {
unimplemented_present = 0x800, ///< Set if function contains unimplemented instructions
baddata_present = 0x1000, ///< Set if function flowed into bad data
double_precis_on = 0x2000, ///< Set if we are performing double precision recovery
typerecovery_exceeded= 0x4000 ///< Set if data-type propagation passes reached maximum
typerecovery_exceeded= 0x4000, ///< Set if data-type propagation passes reached maximum
normalization_on = 0x8000 ///< Set if normalization will be performed
};
uint4 flags; ///< Boolean properties associated with \b this function
uint4 clean_up_index; ///< Creation index of first Varnode created after start of cleanup
@@ -102,20 +103,21 @@ class Funcdata {
// Low level Varnode functions
void setVarnodeProperties(Varnode *vn) const; ///< Look-up boolean properties and data-type information
HighVariable *assignHigh(Varnode *vn); ///< Assign a new HighVariable to a Varnode
Symbol *handleSymbolConflict(SymbolEntry *entry,Varnode *vn); ///< Handle two variables with matching storage
static void markIndirectAliasUpdate(Varnode *vn); ///< Inform defining INDIRECT of update in alias status for given Varnode
bool syncVarnodesWithSymbol(VarnodeLocSet::const_iterator &iter,uint4 fl,Datatype *ct);
bool descend2Undef(Varnode *vn); ///< Transform all reads of the given Varnode to a special \b undefined constant
void splitUses(Varnode *vn); ///< Make all reads of the given Varnode unique
Varnode *cloneVarnode(const Varnode *vn); ///< Clone a Varnode (between copies of the function)
void destroyVarnode(Varnode *vn); ///< Delete the given Varnode from \b this function
void coverVarnodes(SymbolEntry *entry,vector<Varnode *> &list);
bool applyUnionFacet(SymbolEntry *entry,DynamicHash &dhash);
void coverVarnodes(MapEntry *entry,vector<Varnode *> &list);
bool applyUnionFacet(DynamicEntry *entry,DynamicHash &dhash);
// Low level op functions
void opZeroMulti(PcodeOp *op); ///< Transform trivial CPUI_MULTIEQUAL to CPUI_COPY
// Low level block functions
void blockRemoveInternal(BlockBasic *bb,bool unreachable);
void branchRemoveInternal(BlockBasic *bb,int4 num);
Varnode *createReplaceVarnode(Varnode *origvn,bool makeUnique); ///< Create a replacement for a Varnode that may be merged
void pushMultiequals(BlockBasic *bb); ///< Push MULTIEQUAL Varnodes of the given block into the output block
void clearBlocks(void); ///< Clear all basic blocks
void structureReset(void); ///< Calculate initial basic block structures (after a control-flow change)
@@ -127,13 +129,11 @@ class Funcdata {
void sortCallSpecs(void); ///< Sort calls using a dominance based order
void deleteCallSpecs(PcodeOp *op); ///< Remove the specification for a particular call
void clearCallSpecs(void); ///< Remove all call specifications
void issueDatatypeWarnings(void); ///< Add warning headers for any data-types that have been modified
void issueDatatypeWarning(Datatype *dt); ///< Add any warning header for the given data-type
static bool descendantsOutside(Varnode *vn);
static void encodeVarnode(Encoder &encoder,VarnodeLocSet::const_iterator iter,VarnodeLocSet::const_iterator enditer);
static bool checkIndirectUse(Varnode *vn);
static PcodeOp *findPrimaryBranch(PcodeOpTree::const_iterator iter,PcodeOpTree::const_iterator enditer,
bool findbranch,bool findcall,bool findreturn);
public:
Funcdata(const string &nm,const string &disp,Scope *conf,const Address &addr,FunctionSymbol *sym,int4 sz=0); ///< Constructor
~Funcdata(void); ///< Destructor
@@ -150,6 +150,7 @@ public:
bool isTypeRecoveryOn(void) const { return ((flags&typerecovery_on)!=0); } ///< Will data-type analysis be performed
bool hasTypeRecoveryStarted(void) const { return ((flags&typerecovery_start)!=0); } ///< Has data-type recovery processes started
bool isTypeRecoveryExceeded(void) const { return ((flags&typerecovery_exceeded)!=0); } ///< Has maximum propagation passes been reached
bool isNormalizationOn(void) const { return ((flags&normalization_on)!=0); } ///< Will normalization be performed
bool hasNoCode(void) const { return ((flags & no_code)!=0); } ///< Return \b true if \b this function has no code body
void setNoCode(bool val) { if (val) flags |= no_code; else flags &= ~no_code; } ///< Toggle whether \b this has a body
void setLanedRegGenerated(void) { minLanedSize = 1000000; } ///< Mark that laned registers have been collected
@@ -180,6 +181,11 @@ public:
/// \param val is \b true if data-type analysis is enabled
void setTypeRecovery(bool val) { flags = val ? (flags | typerecovery_on) : (flags & ~typerecovery_on); }
void setTypeRecoveryExceeded(void) { flags |= typerecovery_exceeded; } ///< Mark propagation passes have reached maximum
/// \brief Toggle whether normalization transforms will be performed on \b this function
///
/// \param val is \b true if normalization is enabled
void setNormalization(bool val) { flags = val ? (flags | normalization_on) : (flags & ~normalization_on); }
void startCastPhase(void) { cast_phase_index = vbank.getCreateIndex(); } ///< Start the \b cast insertion phase
uint4 getCastPhaseIndex(void) const { return cast_phase_index; } ///< Get creation index at the start of \b cast insertion
uint4 getHighLevelIndex(void) const { return high_level_index; } ///< Get creation index at the start of HighVariable creation
@@ -189,14 +195,13 @@ public:
void followFlow(const Address &baddr,const Address &eadddr);
void truncatedFlow(const Funcdata *fd,const FlowInfo *flow);
int4 inlineFlow(Funcdata *inlinefd,FlowInfo &flow,PcodeOp *callop);
void overrideFlow(const Address &addr,uint4 type);
void doLiveInject(InjectPayload *payload,const Address &addr,BlockBasic *bl,list<PcodeOp *>::iterator pos);
void printRaw(ostream &s) const; ///< Print raw p-code op descriptions to a stream
void printVarnodeTree(ostream &s) const; ///< Print a description of all Varnodes to a stream
void printBlockTree(ostream &s) const; ///< Print a description of control-flow structuring to a stream
void printLocalRange(ostream &s) const; ///< Print description of memory ranges associated with local scopes
void encode(Encoder &encoder,uint8 id,bool savetree) const; ///< Encode a description of \b this function to stream
void encode(Encoder &encoder,uint8 id,bool saveTree,bool saveOverrides) const; ///< Encode a description of \b this function to stream
uint8 decode(Decoder &decoder); ///< Restore the state of \b this function from a stream
void encodeJumpTable(Encoder &encoder) const; ///< Encode a description of jump-tables to stream
void decodeJumpTable(Decoder &decoder); ///< Decode jump-tables from a stream
@@ -226,7 +231,7 @@ public:
Varnode *findSpacebaseInput(AddrSpace *id) const;
Varnode *constructSpacebaseInput(AddrSpace *id);
Varnode *constructConstSpacebase(AddrSpace *id);
void spacebaseConstant(PcodeOp *op,int4 slot,SymbolEntry *entry,const Address &rampoint,uintb origval,int4 origsize);
void spacebaseConstant(PcodeOp *op,int4 slot,MapEntry *entry,const Address &rampoint,uintb origval,int4 origsize);
int4 getHeritagePass(void) const { return heritage.getPass(); } ///< Get overall count of heritage passes
@@ -292,6 +297,7 @@ public:
Varnode *newExtendedConstant(int4 s,uint8 *val,PcodeOp *op); ///< Create extended precision constant
void adjustInputVarnodes(const Address &addr,int4 sz);
void deleteVarnode(Varnode *vn) { vbank.destroy(vn); } ///< Delete the given varnode
void destroyVarnodeRecursive(Varnode *vn); ///< Destroy Varnode (if unused) and any PcodeOp that produced it
Address findDisjointCover(Varnode *vn,int4 &sz); ///< Find range covering given Varnode and any intersecting Varnodes
@@ -309,6 +315,13 @@ public:
/// \return the matching Varnode or NULL
Varnode *findCoveringInput(int4 s,const Address &loc) const { return vbank.findCoveringInput(s,loc); }
/// \brief Check if an input Varnode exists that overlaps the given range
///
/// \param s is the size of the range in bytes
/// \param loc is the starting address of the given range
/// \return \b true if there is an input Varnode that overlaps the range
bool hasInputIntersection(int4 s,const Address &loc) const { return vbank.hasInputIntersection(s, loc); }
/// \brief Find the input Varnode with the given size and storage address
///
/// \param s is the size in bytes
@@ -421,6 +434,8 @@ public:
void clearDeadOps(void) { obank.destroyDead(); } ///< Delete any dead PcodeOps
void remapVarnode(Varnode *vn,Symbol *sym,const Address &usepoint);
void remapDynamicVarnode(Varnode *vn,Symbol *sym,const Address &usepoint,uint8 hash);
void remapConflictSymbol(Symbol *sym); ///< Convert any MapEntryConflict on the Symbol into a DynamicEntry
bool detectSymbolConflicts(Varnode *vn); ///< Detect potential symbol conflicts
void linkProtoPartial(Varnode *vn); ///< Find or create Symbol and a partial mapping
Symbol *linkSymbol(Varnode *vn); ///< Find or create Symbol associated with given Varnode
Symbol *linkSymbolReference(Varnode *vn); ///< Discover and attach Symbol to a constant reference
@@ -428,8 +443,8 @@ public:
void findLinkedVarnodes(SymbolEntry *entry,vector<Varnode *> &res) const; ///< Find Varnodes that map to the given SymbolEntry
void buildDynamicSymbol(Varnode *vn); ///< Build a \e dynamic Symbol associated with the given Varnode
bool testForReturnAddress(Varnode *vn); ///< Test if the given Varnode is (derived from) the return address
bool attemptDynamicMapping(SymbolEntry *entry,DynamicHash &dhash);
bool attemptDynamicMappingLate(SymbolEntry *entry,DynamicHash &dhash);
bool attemptDynamicMapping(DynamicEntry *entry,DynamicHash &dhash);
bool attemptDynamicMappingLate(DynamicEntry *entry,DynamicHash &dhash);
Merge &getMerge(void) { return covermerge; } ///< Get the Merge object for \b this function
Varnode *getInternalString(const uint1 *buf,int4 size,Datatype *ptrType,PcodeOp *readOp);
@@ -438,6 +453,7 @@ public:
PcodeOp *newOp(int4 inputs,const SeqNum &sq); /// Allocate a new PcodeOp with sequence number
PcodeOp *newOpBefore(PcodeOp *follow,OpCode opc,Varnode *in1,Varnode *in2,Varnode *in3=(Varnode *)0);
PcodeOp *cloneOp(const PcodeOp *op,const SeqNum &seq); /// Clone a PcodeOp into \b this function
PcodeOp *newIndirect(PcodeOp *target); ///< Allocate a new CPUI_INDIRECT
PcodeOp *getFirstReturnOp(void) const; /// Find a representative CPUI_RETURN op for \b this function
PcodeOp *newIndirectOp(PcodeOp *indeffect,const Address &addr,int4 sz,uint4 extraFlags);
PcodeOp *newIndirectCreation(PcodeOp *indeffect,const Address &addr,int4 sz,bool possibleout);
@@ -486,8 +502,11 @@ public:
PcodeOp *opStackStore(AddrSpace *spc,uintb off,PcodeOp *op,bool insertafter);
Varnode *opBoolNegate(Varnode *vn,PcodeOp *op,bool insertafter);
void opUndoPtradd(PcodeOp *op,bool finalize); ///< Convert a CPUI_PTRADD back into a CPUI_INT_ADD
static int4 opFlipInPlaceTest(PcodeOp *op,vector<PcodeOp *> &fliplist);
static int4 opFlipInPlaceTest(PcodeOp *op,vector<PcodeOp *> &fliplist,bool allowOpRemoval);
void opFlipInPlaceExecute(vector<PcodeOp *> &fliplist);
bool opNormalizeFlip(PcodeOp *cbranch);
void opCollapseIndirectsForCopy(PcodeOp *copyOp); ///< Convert INDIRECTs associated with the given COPY op
void opCollapseIndirectsForAlias(PcodeOp *effectOp); ///< Eliminate INDIRECTs for addresses with no alias
/// \brief Start of PcodeOp objects with the given op-code
list<PcodeOp *>::const_iterator beginOp(OpCode opc) const { return obank.begin(opc); }
@@ -507,25 +526,32 @@ public:
/// \brief End of PcodeOp objects in the \e dead list
list<PcodeOp *>::const_iterator endOpDead(void) const { return obank.endDead(); }
/// \brief Start of all (alive) PcodeOp objects sorted by sequence number
PcodeOpTree::const_iterator beginOpAll(void) const { return obank.beginAll(); }
/// \brief Start of PcodeOp objects sorted by sequence number, excluding CPUI_INDIRECT
PcodeOpTree::const_iterator beginOpMain(void) const { return obank.beginMain(); }
/// \brief End of all (alive) PcodeOp objects sorted by sequence number
PcodeOpTree::const_iterator endOpAll(void) const { return obank.endAll(); }
/// \brief End of PcodeOp objects sorted by sequence number, excluding CPUI_INDIRECT
PcodeOpTree::const_iterator endOpMain(void) const { return obank.endMain(); }
/// \brief Start of all (alive) PcodeOp objects attached to a specific Address
PcodeOpTree::const_iterator beginOp(const Address &addr) const { return obank.begin(addr); }
PcodeOpTree::const_iterator beginOpMain(const Address &addr) const { return obank.beginMain(addr); }
/// \brief End of all (alive) PcodeOp objects attached to a specific Address
PcodeOpTree::const_iterator endOp(const Address &addr) const { return obank.end(addr); }
PcodeOpTree::const_iterator endOpMain(const Address &addr) const { return obank.endMain(addr); }
PcodeOp *findPrimaryBranch(const Address &addr,bool findBranch,bool findCall,bool findCallother,bool findReturn);
void listOps(vector<PcodeOp *> &res,const Address &addr) const;
bool moveRespectingCover(PcodeOp *op,PcodeOp *lastOp); ///< Move given op past \e lastOp respecting covers if possible
const ResolvedUnion *getUnionField(const Datatype *parent,const PcodeOp *op,int4 slot) const;
bool setUnionField(const Datatype *parent,const PcodeOp *op,int4 slot,const ResolvedUnion &resolve);
void forceFacingType(Datatype *parent,int4 fieldNum,PcodeOp *op,int4 slot);
int4 inheritResolution(Datatype *parent,const PcodeOp *op,int4 slot,PcodeOp *oldOp,int4 oldSlot);
const ResolvedUnion *getUnionField(const Datatype *unresType,const PcodeOp *op,int4 slot) const;
const ResolvedUnion *getAddressBasedUnionField(const Datatype *unresType,const Address &addr,int4 slot) const;
const ResolvedUnion *getUnionResolution(const Datatype *unresType,const PcodeOp *op,int4 slot) const;
bool setUnionField(const Datatype *unresType,const PcodeOp *op,int4 slot,const ResolvedUnion &resolve);
bool setAddressBasedUnionField(const Datatype *unresType,const Address &addr,int4 slot,const ResolvedUnion &resolve);
bool updateUnionField(const Datatype *unresType,const PcodeOp *op,int4 slot,Datatype *resType);
void forceFacingType(Datatype *unresType,int4 fieldNum,PcodeOp *op,int4 slot);
int4 inheritUnionField(Datatype *unresType,const PcodeOp *op,int4 slot,PcodeOp *oldOp,int4 oldSlot);
int4 inheritUnionFieldPtr(Datatype *unresPtr,const PcodeOp *op,int4 slot,PcodeOp *oldOp,int4 oldSlot);
// Jumptable routines
JumpTable *linkJumpTable(PcodeOp *op); ///< Link jump-table with a given BRANCHIND
JumpTable *findJumpTable(const PcodeOp *op) const; ///< Find a jump-table associated with a given BRANCHIND
@@ -77,6 +77,27 @@ void Funcdata::removeJumpTable(JumpTable *jt)
jumpvec = remain;
}
/// The replacement has the same address and size as the given Varnode but can optionally turned into a new \e unique.
/// We assume the given Varnode will be destroyed but that it may already be merged into a HighVariable.
/// If a HighVariable exists, the given Varnode is removed and the replacement is added.
/// \param origvn is the given Varnode to be replaced
/// \param makeUnique is \b true if the replacement should be a new \e unique
/// \return the new replacement Varnode
Varnode *Funcdata::createReplaceVarnode(Varnode *origvn,bool makeUnique)
{
Varnode *replacevn;
if (makeUnique)
replacevn = newUnique(origvn->getSize(),origvn->getType());
else
replacevn = newVarnode(origvn->getSize(),origvn->getAddr(),origvn->getType());
if (isHighOn()) {
origvn->replaceInHigh(replacevn);
replacevn->setExplicit();
}
return replacevn;
}
/// Assuming the given basic block is being removed, force any Varnode defined by
/// a MULTIEQUAL in the block to be defined in the output block instead. This is used
/// as part of the basic block removal process to patch up data-flow.
@@ -128,11 +149,8 @@ void Funcdata::pushMultiequals(BlockBasic *bb)
}
if (!needreplace) continue;
// Construct artificial MULTIEQUAL
replacevn = createReplaceVarnode(origvn, neednewunique);
vector<Varnode *> branches;
if (neednewunique)
replacevn = newUnique(origvn->getSize());
else
replacevn = newVarnode(origvn->getSize(),origvn->getAddr());
for(int4 i=0;i<outblock->sizeIn();++i) {
if (outblock->getIn(i) == bb)
branches.push_back(origvn);
@@ -157,12 +175,15 @@ void Funcdata::pushMultiequals(BlockBasic *bb)
list<PcodeOp *>::iterator titer = origvn->descend.begin();
while(titer != origvn->descend.end()) {
PcodeOp *op = *titer++;
i = op->getSlot(origvn);
// Do not replace MULTIEQUAL references in the same block
// as replaceop. These are patched by block_remove
if ((op->code()==CPUI_MULTIEQUAL)&&(op->getParent()==outblock)&&(i==outblock_ind))
continue;
opSetInput(op,replacevn,i);
for(i=0;i<op->numInput();++i) {
if (op->getIn(i) != origvn)
continue;
if (i == outblock_ind && op->getParent() == outblock && op->code() == CPUI_MULTIEQUAL) {
continue;
}
opSetInput(op,replacevn,i);
break;
}
}
}
}
@@ -205,7 +226,7 @@ void Funcdata::branchRemoveInternal(BlockBasic *bb,int4 num)
bblocks.removeEdge(bb,bbout); // Sever (one) connection between bb and bbout
for(iter=bbout->beginOp();iter!=bbout->endOp();++iter) {
op = *iter;
if (op->code() != CPUI_MULTIEQUAL) continue;
if (op->code() != CPUI_MULTIEQUAL) break;
opRemoveInput(op,blocknum);
opZeroMulti(op);
}
@@ -467,7 +488,7 @@ JumpTable *Funcdata::installJumpTable(const Address &addr)
if (jt->getOpAddress() == addr)
throw LowlevelError("Trying to install over existing jumptable");
}
JumpTable *newjt = new JumpTable(glb,addr);
JumpTable *newjt = new JumpTable(addr);
jumpvec.push_back(newjt);
return newjt;
}
@@ -488,6 +509,7 @@ JumpTable *Funcdata::installJumpTable(const Address &addr)
JumpTable::RecoveryMode Funcdata::stageJumpTable(Funcdata &partial,JumpTable *jt,PcodeOp *op,FlowInfo *flow)
{
jt->incrementRecoveryCount();
if (!partial.isJumptableRecoveryOn()) {
// Do full analysis on the table if we haven't before
partial.flags |= jumptablerecovery_on; // Mark that this Funcdata object is dedicated to jumptable recovery
@@ -642,10 +664,10 @@ JumpTable *Funcdata::recoverJumpTable(Funcdata &partial,PcodeOp *op,FlowInfo *fl
jt = linkJumpTable(op); // Search for pre-existing jumptable
if (jt != (JumpTable *)0) {
if (!jt->isOverride()) {
if (!jt->isPartial())
if (!jt->isPartial() && jt->numEntries() != 0)
return jt; // Previously calculated jumptable (NOT an override and NOT incomplete)
}
mode = stageJumpTable(partial,jt,op,flow); // Recover based on override information
mode = stageJumpTable(partial,jt,op,flow); // Recover empty jumptable or based on override information
if (mode != JumpTable::success)
return (JumpTable *)0;
jt->setIndirectOp(op); // Relink table back to original op
@@ -657,7 +679,7 @@ JumpTable *Funcdata::recoverJumpTable(Funcdata &partial,PcodeOp *op,FlowInfo *fl
mode = earlyJumpTableFail(op);
if (mode != JumpTable::success)
return (JumpTable *)0;
JumpTable trialjt(glb);
JumpTable trialjt;
mode = stageJumpTable(partial,&trialjt,op,flow);
if (mode != JumpTable::success)
return (JumpTable *)0;
@@ -335,6 +335,20 @@ PcodeOp *Funcdata::newOp(int4 inputs,const SeqNum &sq)
return obank.create(inputs,sq);
}
/// The new INDIRECT is registered in alternate storage, quarantined from the
/// main sequence number sort. The first input and output to the INDIRECT, need to be filled in.
/// The second input is populated with a Varnode that points to the \b target op.
/// \param target is the PcodeOp causing the indirect effect
/// \return the new INDIRECT op
PcodeOp *Funcdata::newIndirect(PcodeOp *target)
{
PcodeOp *op = obank.createIndirect(2,target->getAddr());
obank.changeOpcode(op, glb->inst[CPUI_INDIRECT]);
opSetInput(op,newVarnodeIop(target),1);
return op;
}
/// The given PcodeOp is inserted \e immediately before the \e follow op except:
/// - MULTIEQUALS in a basic block all occur first
/// - INDIRECTs occur immediately before their op
@@ -687,12 +701,10 @@ PcodeOp *Funcdata::newIndirectOp(PcodeOp *indeffect,const Address &addr,int4 sz,
PcodeOp *newop;
newin = newVarnode(sz,addr);
newop = newOp(2,indeffect->getAddr());
newop = newIndirect(indeffect);
newop->flags |= extraFlags;
newVarnodeOut(sz,addr,newop);
opSetOpcode(newop,CPUI_INDIRECT);
opSetInput(newop,newin,0);
opSetInput(newop,newVarnodeIop(indeffect),1);
opInsertBefore(newop,indeffect);
return newop;
}
@@ -714,15 +726,13 @@ PcodeOp *Funcdata::newIndirectCreation(PcodeOp *indeffect,const Address &addr,in
PcodeOp *newop;
newin = newConstant(sz,0);
newop = newOp(2,indeffect->getAddr());
newop = newIndirect(indeffect);
newop->flags |= PcodeOp::indirect_creation;
newout = newVarnodeOut(sz,addr,newop);
if (!possibleout)
newin->flags |= Varnode::indirect_creation;
newout->flags |= Varnode::indirect_creation;
opSetOpcode(newop,CPUI_INDIRECT);
opSetInput(newop,newin,0);
opSetInput(newop,newVarnodeIop(indeffect),1);
opInsertBefore(newop,indeffect);
return newop;
}
@@ -862,7 +872,7 @@ int4 Funcdata::inlineFlow(Funcdata *inlinefd,FlowInfo &flow,PcodeOp *callop)
Address eaddr(baseaddr.getSpace(),~((uintb)0));
inlineflow.setRange(baddr,eaddr);
inlineflow.setFlags(FlowInfo::error_outofbounds|FlowInfo::error_unimplemented|
FlowInfo::error_reinterpreted|FlowInfo::flow_forinline);
FlowInfo::error_baddata|FlowInfo::error_reinterpreted|FlowInfo::flow_forinline);
inlineflow.forwardRecursion(flow);
inlineflow.generateOps();
@@ -880,8 +890,10 @@ int4 Funcdata::inlineFlow(Funcdata *inlinefd,FlowInfo &flow,PcodeOp *callop)
--oiter;
PcodeOp *lastop = *oiter;
obank.moveSequenceDead(firstop,lastop,callop); // Move cloned sequence to right after callop
if (callop->isBlockStart())
if (callop->isBlockStart()) {
firstop->setFlag(PcodeOp::startbasic); // First op of inline inherits callop's startbasic flag
flow.updateTarget(callop, firstop);
}
else
firstop->clearFlag(PcodeOp::startbasic);
}
@@ -915,106 +927,64 @@ int4 Funcdata::inlineFlow(Funcdata *inlinefd,FlowInfo &flow,PcodeOp *callop)
/// \brief Find the primary branch operation for an instruction
///
/// For machine instructions that branch, this finds the \e primary PcodeOp that performs
/// the branch. The instruction is provided as a list of p-code ops, and the caller can
/// specify whether they expect to see a \e branch, \e call, or \e return operation.
/// \param iter is the start of the operations for the instruction
/// \param enditer is the end of the operations for the instruction
/// \param findbranch is \b true if the caller expects to see a BRANCH, CBRANCH, or BRANCHIND
/// \param findcall is \b true if the caller expects to see CALL or CALLIND
/// \param findreturn is \b true if the caller expects to see RETURN
/// For instructions that branch, this finds the \e primary PcodeOp that performs the branch.
/// The caller can specify whether they expect to see a \e branch, \e call, \e callother, or \e return operation.
/// \param addr is the address of the instruction
/// \param findBranch is \b true if the caller expects to see a BRANCH, CBRANCH, or BRANCHIND
/// \param findCall is \b true if the caller expects to see CALL or CALLIND
/// \param findCallother is \b true if the caller expects to see CALLOTHER
/// \param findReturn is \b true if the caller expects to see RETURN
/// \return the first branching PcodeOp that matches the criteria or NULL
PcodeOp *Funcdata::findPrimaryBranch(PcodeOpTree::const_iterator iter,PcodeOpTree::const_iterator enditer,
bool findbranch,bool findcall,bool findreturn)
PcodeOp *Funcdata::findPrimaryBranch(const Address &addr,bool findBranch,bool findCall,bool findCallother,bool findReturn)
{
PcodeOpTree::const_iterator iter = beginOpMain(addr);
PcodeOpTree::const_iterator enditer = endOpMain(addr);
while(iter != enditer) {
PcodeOp *op = (*iter).second;
switch(op->code()) {
case CPUI_BRANCH:
case CPUI_CBRANCH:
if (findbranch) {
if (op->isCallOrBranch() || op->isFlowBreak()) {
OpCode opc = op->code();
if (findBranch && (opc == CPUI_BRANCH || opc == CPUI_CBRANCH)) {
if (!op->getIn(0)->isConstant()) // Make sure this is not an internal branch
return op;
}
break;
case CPUI_BRANCHIND:
if (findbranch)
if (findBranch && opc == CPUI_BRANCHIND)
return op;
break;
case CPUI_CALL:
case CPUI_CALLIND:
if (findcall)
if (findCall && (opc == CPUI_CALL || opc == CPUI_CALLIND))
return op;
break;
case CPUI_RETURN:
if (findreturn)
if (findReturn && opc == CPUI_RETURN)
return op;
if (findCallother && opc == CPUI_CALLOTHER)
return op;
break;
default:
break;
}
++iter;
}
return (PcodeOp *)0;
}
/// \brief Override the control-flow p-code for a particular instruction
/// \brief Collect all ops at the given Address in one container
///
/// P-code in \b this function is modified to change the control-flow of
/// the instruction at the given address, based on the Override type.
/// \param addr is the given address of the instruction to modify
/// \param type is the Override type
void Funcdata::overrideFlow(const Address &addr,uint4 type)
/// All ops at the address, including INDIRECTs, that are currently alive are placed in the container.
/// \param res is the container to hold the ops
/// \param addr is the given Address
void Funcdata::listOps(vector<PcodeOp *> &res,const Address &addr) const
{
PcodeOpTree::const_iterator iter = beginOp(addr);
PcodeOpTree::const_iterator enditer = endOp(addr);
PcodeOp *op = (PcodeOp *)0;
if (type == Override::BRANCH)
op = findPrimaryBranch(iter,enditer,false,true,true);
else if (type == Override::CALL)
op = findPrimaryBranch(iter,enditer,true,false,true);
else if (type == Override::CALL_RETURN)
op = findPrimaryBranch(iter,enditer,true,true,true);
else if (type == Override::RETURN)
op = findPrimaryBranch(iter,enditer,true,true,false);
if ((op == (PcodeOp *)0)||(!op->isDead()))
throw LowlevelError("Could not apply flowoverride");
OpCode opc = op->code();
if (type == Override::BRANCH) {
if (opc == CPUI_CALL)
opSetOpcode(op,CPUI_BRANCH);
else if (opc == CPUI_CALLIND)
opSetOpcode(op,CPUI_BRANCHIND);
else if (opc == CPUI_RETURN)
opSetOpcode(op,CPUI_BRANCHIND);
PcodeOpTree::const_iterator iter,enditer;
iter = obank.beginMain(addr);
enditer = obank.endMain(addr);
while(iter != enditer) {
PcodeOp *op = (*iter).second;
++iter;
if (!op->isDead())
res.push_back(op);
}
else if ((type == Override::CALL)||(type == Override::CALL_RETURN)) {
if (opc == CPUI_BRANCH)
opSetOpcode(op,CPUI_CALL);
else if (opc == CPUI_BRANCHIND)
opSetOpcode(op,CPUI_CALLIND);
else if (opc == CPUI_CBRANCH)
throw LowlevelError("Do not currently support CBRANCH overrides");
else if (opc == CPUI_RETURN)
opSetOpcode(op,CPUI_CALLIND);
if (type == Override::CALL_RETURN) { // Insert a new return op after call
PcodeOp *newReturn = newOp(1,addr);
opSetOpcode(newReturn,CPUI_RETURN);
opSetInput(newReturn,newConstant(1,0),0);
opDeadInsertAfter(newReturn,op);
}
}
else if (type == Override::RETURN) {
if ((opc == CPUI_BRANCH)||(opc == CPUI_CBRANCH)||(opc == CPUI_CALL))
throw LowlevelError("Do not currently support complex overrides");
else if (opc == CPUI_BRANCHIND)
opSetOpcode(op,CPUI_RETURN);
else if (opc == CPUI_CALLIND)
opSetOpcode(op,CPUI_RETURN);
iter = obank.beginIndirect(addr);
enditer = obank.endIndirect(addr);
while(iter != enditer) {
PcodeOp *op = (*iter).second;
++iter;
if (!op->isDead())
res.push_back(op);
}
}
@@ -1029,7 +999,8 @@ bool Funcdata::replaceLessequal(PcodeOp *op)
{
Varnode *vn;
int4 i;
intb val,diff;
uintb val;
intb diff;
if ((vn=op->getIn(0))->isConstant()) {
diff = -1;
@@ -1042,15 +1013,16 @@ bool Funcdata::replaceLessequal(PcodeOp *op)
else
return false;
val = sign_extend(vn->getOffset(),8*vn->getSize()-1);
val = vn->getOffset();
if (op->code() == CPUI_INT_SLESSEQUAL) {
if ((val<0)&&(val+diff>0)) return false; // Check for sign overflow
if ((val>0)&&(val+diff<0)) return false;
// Check for signed overflow
if ((diff == -1) && (val == calc_int_min(vn->getSize()))) return false;
if ((diff == 1) && (val == calc_int_max(vn->getSize()))) return false;
opSetOpcode(op,CPUI_INT_SLESS);
}
else { // Check for unsigned overflow
if ((diff==-1)&&(val==0)) return false;
if ((diff==1)&&(val==-1)) return false;
if ((diff == -1) && (val == 0)) return false;
if ((diff == 1) && (val == calc_uint_max(vn->getSize()))) return false;
opSetOpcode(op,CPUI_INT_LESS);
}
uintb res = (val+diff) & calc_mask(vn->getSize());
@@ -1212,11 +1184,12 @@ Varnode *Funcdata::buildCopyTemp(Varnode *vn,PcodeOp *point)
///
/// The boolean Varnode is either the output of the given PcodeOp or the
/// first input if the PcodeOp is a CBRANCH. The list of ops that need flipping is
/// returned in an array
/// returned in an array.
/// \param op is the given PcodeOp
/// \param fliplist is the array that will hold the ops to flip
/// \return 0 if the change normalizes, 1 if the change is ambivalent, 2 if the change does not normalize
int4 Funcdata::opFlipInPlaceTest(PcodeOp *op,vector<PcodeOp *> &fliplist)
/// \param allowOpRemoval if \b true allow for removal of BOOL_NEGATE ops to achieve flip
/// \return 0 if the change normalizes, 1 if the change denormalizes or is ambivalent, 2 if flip in place is not possible
int4 Funcdata::opFlipInPlaceTest(PcodeOp *op,vector<PcodeOp *> &fliplist,bool allowOpRemoval)
{
Varnode *vn;
@@ -1226,12 +1199,19 @@ int4 Funcdata::opFlipInPlaceTest(PcodeOp *op,vector<PcodeOp *> &fliplist)
vn = op->getIn(1);
if (vn->loneDescend() != op) return 2;
if (!vn->isWritten()) return 2;
return opFlipInPlaceTest(vn->getDef(),fliplist);
subtest1 = opFlipInPlaceTest(vn->getDef(),fliplist,allowOpRemoval);
if (subtest1 != 2 && op->isBooleanFlip())
subtest1 = 1-subtest1;
return subtest1;
case CPUI_INT_EQUAL:
case CPUI_FLOAT_EQUAL:
fliplist.push_back(op);
return 1;
case CPUI_BOOL_NEGATE:
if (!allowOpRemoval)
return 2;
fliplist.push_back(op);
return 0;
case CPUI_INT_NOTEQUAL:
case CPUI_FLOAT_NOTEQUAL:
fliplist.push_back(op);
@@ -1253,13 +1233,13 @@ int4 Funcdata::opFlipInPlaceTest(PcodeOp *op,vector<PcodeOp *> &fliplist)
vn = op->getIn(0);
if (vn->loneDescend() != op) return 2;
if (!vn->isWritten()) return 2;
subtest1 = opFlipInPlaceTest(vn->getDef(),fliplist);
subtest1 = opFlipInPlaceTest(vn->getDef(),fliplist,allowOpRemoval);
if (subtest1 == 2)
return 2;
vn = op->getIn(1);
if (vn->loneDescend() != op) return 2;
if (!vn->isWritten()) return 2;
subtest2 = opFlipInPlaceTest(vn->getDef(),fliplist);
subtest2 = opFlipInPlaceTest(vn->getDef(),fliplist,allowOpRemoval);
if (subtest2 == 2)
return 2;
fliplist.push_back(op);
@@ -1310,6 +1290,196 @@ void Funcdata::opFlipInPlaceExecute(vector<PcodeOp *> &fliplist)
}
}
/// \brief Remove the \b boolean_flip flag on a CBRANCH op, without changing behavior
///
/// Try to flip the true/false meaning of the CBRANCH and negate the meaning of the comparison op feeding the CBRANCH.
/// Only the \b boolean_flip flag and the comparison op's opcode are affected.
/// \param cbranch is CBRANCH to modify
/// \return \b true if the ops were successfully modified
bool Funcdata::opNormalizeFlip(PcodeOp *cbranch)
{
Varnode *boolVn = cbranch->getIn(1);
if (!boolVn->isWritten()) return false;
if (boolVn->loneDescend() != cbranch) return false;
PcodeOp *condOp = boolVn->getDef();
bool flipyes;
OpCode opc = get_booleanflip(condOp->code(), flipyes);
if (opc == CPUI_MAX) return false;
opSetOpcode(condOp,opc); // Set the negated opcode
if (flipyes) // Do we need to reverse the two operands
opSwapInput(condOp,0,1);
cbranch->flipFlag(PcodeOp::boolean_flip);
if (opc == CPUI_INT_LESSEQUAL || opc == CPUI_INT_SLESSEQUAL)
replaceLessequal(condOp);
return true;
}
/// The op is assumed to be a recent STORE converted to a COPY. The INDIRECTs associated with
/// the old STORE are converted to a COPY or SUBPIECE, depending on the overlap of the
/// INDIRECT output with the COPY output.
/// \param copyOp is the new COPY converted from a STORE
void Funcdata::opCollapseIndirectsForCopy(PcodeOp *copyOp)
{
BlockBasic *bb = copyOp->getParent();
list<PcodeOp *>::iterator iter = copyOp->getBasicIter();
while(iter != bb->beginOp()) {
list<PcodeOp *>::iterator previter = iter;
--previter;
PcodeOp *op = *previter;
if (op->code() != CPUI_INDIRECT) break;
Varnode *vn1 = copyOp->getOut();
Varnode *vn2 = op->getOut();
int4 res = vn1->characterizeOverlap(*vn2);
if (res > 0) { // Copy has an effect of some sort
if (res != 2 && vn1->contains(*vn2) == 0) { // INDIRECT output is properly contained in COPY output
// Convert INDIRECT to a SUBPIECE
uintb trunc;
if (vn1->getSpace()->isBigEndian())
trunc = vn1->getOffset() + vn1->getSize() - (vn2->getOffset() + vn2->getSize());
else
trunc = vn2->getOffset() - vn1->getOffset();
opUninsert(op);
opSetInput(op,vn1,0);
opSetInput(op,newConstant(4,trunc),1);
opSetOpcode(op, CPUI_SUBPIECE);
opInsertAfter(op, copyOp);
continue;
}
if (res != 2) {
Varnode *invn = op->getIn(0);
PcodeOp *insertPoint = copyOp;
int4 bytesBefore = 0;
if (vn2->getOffset() < vn1->getOffset())
bytesBefore = vn1->getOffset() - vn2->getOffset();
uintb vn2end = vn2->getOffset() + vn2->getSize()-1;
uintb vn1end = vn1->getOffset() + vn1->getSize()-1;
int4 bytesAfter = 0;
if (vn2end > vn1end)
bytesAfter = vn2end - vn1end;
int4 overlap = vn2->getSize() - bytesBefore - bytesAfter;
Varnode *frontVn = (Varnode *)0;
Varnode *backVn = (Varnode *)0;
Varnode *otherPiece;
int4 frontSlot = (vn2->getSpace()->isBigEndian()) ? 0 : 1;
if (bytesBefore != 0) {
int4 byteOff = (vn2->getSpace()->isBigEndian()) ? vn2->getSize() - bytesBefore : 0;
PcodeOp *subBefore = newOp(2,op->getAddr());
opSetOpcode(subBefore,CPUI_SUBPIECE);
frontVn = newVarnodeOut(bytesAfter,vn2->getAddr(),subBefore);
opSetInput(subBefore,invn,0);
opSetInput(subBefore,newConstant(4,byteOff),1);
opInsertAfter(subBefore, insertPoint);
insertPoint = subBefore;
}
if (bytesAfter != 0) {
int4 byteOff = (vn2->getSpace()->isBigEndian()) ? 0 : vn2->getSize() - bytesAfter;
PcodeOp *subAfter = newOp(2,op->getAddr());
opSetOpcode(subAfter,CPUI_SUBPIECE);
Address addr = vn2->getAddr() + (vn2->getSize() - bytesAfter);
backVn = newVarnodeOut(bytesAfter,addr,subAfter);
opSetInput(subAfter,invn,0);
opSetInput(subAfter,newConstant(4,byteOff),1);
opInsertAfter(subAfter,insertPoint);
insertPoint = subAfter;
}
if (overlap != vn1->getSize()) {
int4 byteOff;
if (bytesAfter == 0)
byteOff = (vn1->getSpace()->isBigEndian()) ? vn1->getSize() - overlap : 0;
else
byteOff = (vn1->getSpace()->isBigEndian()) ? 0 : vn1->getSize() - overlap;
PcodeOp *subMiddle = newOp(2,op->getAddr());
opSetOpcode(subMiddle,CPUI_SUBPIECE);
Address addr = vn2->getAddr() + bytesBefore;
otherPiece = newVarnodeOut(overlap,addr,subMiddle);
opSetInput(subMiddle,vn1,0);
opSetInput(subMiddle,newConstant(4,byteOff),1);
opInsertAfter(subMiddle,insertPoint);
insertPoint = subMiddle;
}
else {
otherPiece = vn1;
}
if (bytesBefore == 0) {
frontVn = otherPiece;
}
else if (bytesAfter == 0) {
backVn = otherPiece;
}
else {
PcodeOp *concat = newOp(2,op->getAddr());
opSetOpcode(concat,CPUI_PIECE);
Varnode *newVn = newVarnodeOut(frontVn->getSize() + otherPiece->getSize(),vn2->getAddr(),concat);
opSetInput(concat,frontVn,frontSlot);
opSetInput(concat,otherPiece,1-frontSlot);
opInsertAfter(concat,insertPoint);
insertPoint = concat;
frontVn = newVn;
}
opUninsert(op);
opSetOpcode(op, CPUI_PIECE);
opSetInput(op,frontVn,frontSlot);
opSetInput(op,backVn,1-frontSlot);
opInsertAfter(op, insertPoint);
continue;
}
// Convert INDIRECT to COPY
opUninsert(op);
opSetInput(op,vn1,0);
opRemoveInput(op,1);
opSetOpcode(op,CPUI_COPY);
opInsertAfter(op, copyOp);
}
else {
totalReplace(op->getOut(),op->getIn(0));
opDestroy(op); // Get rid of the INDIRECT
}
}
}
/// For the given op with indirect effects, run through its INDIRECTs, and
/// if there is no longer a possible alias for an INDIRECT address, remove the INDIRECT.
/// \param effectOp is the given op with indirect effects
void Funcdata::opCollapseIndirectsForAlias(PcodeOp *effectOp)
{
effectOp->clearAdditionalFlag(PcodeOp::store_aliasupdate);
BlockBasic *bb = effectOp->getParent();
list<PcodeOp *>::iterator iter = effectOp->getBasicIter();
if (iter == bb->beginOp()) return;
--iter;
const LoadGuard *guard = (const LoadGuard *)0;
if (effectOp->usesSpacebasePtr() && effectOp->code() == CPUI_STORE)
guard = getStoreGuard(effectOp);
for(;;) {
PcodeOp *op = *iter;
if (op->code() != CPUI_INDIRECT) break;
bool shouldDestroy = false;
if (op->getOut()->hasNoLocalAlias() && !op->isIndirectCreation() && !op->noIndirectCollapse())
shouldDestroy = true;
else if (guard != (const LoadGuard *)0 && !guard->isGuarded(op->getOut()->getAddr()))
shouldDestroy = true;
if (shouldDestroy) {
totalReplace(op->getOut(),op->getIn(0));
if (iter == bb->beginOp()) {
opDestroy(op); // Get rid of the INDIRECT
break;
}
else {
--iter;
opDestroy(op);
}
}
else if (iter == bb->beginOp())
break;
else
--iter;
}
}
/// \brief Find a duplicate calculation of a given PcodeOp reading a specific Varnode
///
/// We only match 1 level of calculation. Additionally the duplicate must occur in the
@@ -51,6 +51,8 @@ HighVariable *Funcdata::assignHigh(Varnode *vn)
if ((flags & highlevel_on)!=0) {
if (vn->hasCover())
vn->calcCover();
if (vn->getType()->hasWarning())
issueDatatypeWarning(vn->getType());
if (!vn->isAnnotation()) {
return new HighVariable(vn);
}
@@ -104,8 +106,15 @@ Varnode *Funcdata::newUnique(int4 s,Datatype *ct)
Varnode *Funcdata::newVarnodeOut(int4 s,const Address &m,PcodeOp *op)
{
Varnode *vn;
Datatype *ct = glb->types->getBase(s,TYPE_UNKNOWN);
Varnode *vn = vbank.createDef(s,m,ct,op);
if (m.isValidRange(s)) {
vn = vbank.createDef(s,m,ct,op);
}
else {
Address addr = glb->constructWrappingAddress(m, s);
vn = vbank.createDef(s,addr,ct,op);
}
op->setOutput(vn);
assignHigh(vn);
@@ -152,8 +161,13 @@ Varnode *Funcdata::newVarnode(int4 s,const Address &m,Datatype *ct)
if (ct == (const Datatype *)0)
ct = glb->types->getBase(s,TYPE_UNKNOWN);
vn = vbank.create(s,m,ct);
if (m.isValidRange(s)) {
vn = vbank.create(s,m,ct);
}
else {
Address addr = glb->constructWrappingAddress(m, s);
vn = vbank.create(s,addr,ct);
}
assignHigh(vn);
if (s >= minLanedSize)
@@ -525,10 +539,8 @@ void Funcdata::adjustInputVarnodes(const Address &addr,int4 sz)
// Now that all the intersecting inputs have been pulled out, we can create the new input
Varnode *invn = newVarnode(sz,addr);
invn = setInputVarnode(invn);
// The new input may cause new heritage and "Heritage AFTER dead removal" errors
// So tell heritage to ignore it
// FIXME: It would probably be better to insert this directly into heritage's globaldisjoint
invn->setWriteMask();
// Treat full range as if it has already been heritaged
heritage.markRangeHeritaged(invn->getAddr(), invn->getSize());
// Now change all old inputs to be created as SUBPIECE from the new input
for(uint4 i=0;i<inlist.size();++i) {
PcodeOp *op = inlist[i]->getDef();
@@ -536,6 +548,22 @@ void Funcdata::adjustInputVarnodes(const Address &addr,int4 sz)
}
}
/// If the Varnode has descendants or is address forced, this method does nothing.
/// Otherwise, the Varnode is destroyed as is its defining PcodeOp. Any dead inputs to the PcodeOp are
/// then destroyed recursively.
/// \param vn is the Varnode to destroy
void Funcdata::destroyVarnodeRecursive(Varnode *vn)
{
if (vn->isAutoLive() || !vn->hasNoDescend()) return;
if (!vn->isWritten()) {
vbank.destroy(vn);
return;
}
vector<PcodeOp *> scratch;
opDestroyRecursive(vn->getDef(), scratch);
}
/// All p-code ops that read the Varnode are transformed so that they read
/// a special constant instead (associate with unreachable block removal).
/// \param vn is the given Varnode
@@ -610,11 +638,17 @@ void Funcdata::setHighLevel(void)
/// Properties like boolean flags and \e consume bits are copied as appropriate.
/// \param vn is the existing Varnode
/// \param newVn is the new Varnode that has its properties set
/// \param lsbOffset is the significance offset of the new Varnode within the exising
/// \param lsbOffset is the significance offset of the new Varnode within the existing Varnode
void Funcdata::transferVarnodeProperties(Varnode *vn,Varnode *newVn,int4 lsbOffset)
{
uintb newConsume = (vn->getConsume() >> 8*lsbOffset) & calc_mask(newVn->getSize());
uintb newConsume = ~((uintb)0); // Make sure any bits shifted in above the precision of Varnode::consume are set
if (lsbOffset < sizeof(uintb)) {
uintb fillBits = 0;
if (lsbOffset != 0)
fillBits = newConsume << 8*(sizeof(uintb) - lsbOffset);
newConsume = ((vn->getConsume() >> 8*lsbOffset) | fillBits) & calc_mask(newVn->getSize());
}
uint4 vnFlags = vn->getFlags() & (Varnode::directwrite|Varnode::addrforce);
@@ -882,6 +916,9 @@ void Funcdata::calcNZMask(void)
if (!vn->isWritten()) {
if (vn->isConstant())
vn->nzm = vn->getOffset();
else if (vn->isTypeLock() && vn->getType()->getMetatype() == TYPE_BOOL) {
vn->nzm = 1;
}
else {
vn->nzm = calc_mask(vn->getSize());
if (vn->isSpacebase())
@@ -982,44 +1019,17 @@ bool Funcdata::syncVarnodesWithSymbols(const ScopeLocal *lm,bool updateDatatypes
return updateoccurred;
}
/// A Varnode overlaps the given SymbolEntry. Make sure the Varnode is part of the variable
/// underlying the Symbol. If not, remap things so that the Varnode maps to a distinct Symbol.
/// In either case, attach the appropriate Symbol to the Varnode
/// \param entry is the given SymbolEntry
/// \param vn is the overlapping Varnode
/// \return the Symbol attached to the Varnode
Symbol *Funcdata::handleSymbolConflict(SymbolEntry *entry,Varnode *vn)
/// If the Varnode is defined by an INDIRECT, mark PcodeOp causing the effect as having updated alias information
/// \param vn is the given Varnode
void Funcdata::markIndirectAliasUpdate(Varnode *vn)
{
if (vn->isInput() || vn->isAddrTied() ||
vn->isPersist() || vn->isConstant() || entry->isDynamic()) {
vn->setSymbolEntry(entry);
return entry->getSymbol();
}
HighVariable *high = vn->getHigh();
Varnode *otherVn;
HighVariable *otherHigh = (HighVariable *)0;
// Look for a conflicting HighVariable
VarnodeLocSet::const_iterator iter = beginLoc(entry->getSize(),entry->getAddr());
while(iter != endLoc()) {
otherVn = *iter;
if (otherVn->getSize() != entry->getSize()) break;
if (otherVn->getAddr() != entry->getAddr()) break;
HighVariable *tmpHigh = otherVn->getHigh();
if (tmpHigh != high) {
otherHigh = tmpHigh;
break;
}
++iter;
}
if (otherHigh == (HighVariable *)0) {
vn->setSymbolEntry(entry);
return entry->getSymbol();
}
// If we reach here, we have a conflicting variable
buildDynamicSymbol(vn);
return vn->getSymbolEntry()->getSymbol();
PcodeOp *indop = vn->def;
if (indop == (PcodeOp *)0) return;
if (indop->code() != CPUI_INDIRECT) return;
if (indop->getIn(1)->getSpace()->getType()!=IPTR_IOP) return ;
PcodeOp *effectOp = PcodeOp::getOpFromConst(indop->getIn(1)->getAddr());
effectOp->setAliasUpdate();
}
/// \brief Update properties (and the data-type) for a set of Varnodes associated with one Symbol
@@ -1073,12 +1083,14 @@ bool Funcdata::syncVarnodesWithSymbol(VarnodeLocSet::const_iterator &iter,uint4
updateoccurred = true;
vn->setFlags(localFlags);
vn->clearFlags((~localFlags)&localMask);
markIndirectAliasUpdate(vn);
}
}
else if ((vnflags & mask) != fl) { // We have a change
updateoccurred = true;
vn->setFlags(fl);
vn->clearFlags((~fl)&mask);
markIndirectAliasUpdate(vn);
}
if (ct != (Datatype *)0) {
if (vn->updateType(ct))
@@ -1119,6 +1131,65 @@ void Funcdata::remapDynamicVarnode(Varnode *vn,Symbol *sym,const Address &usepoi
vn->setSymbolEntry(entry);
}
/// If there is no conflict, nothing happens. If there is a conflict but it can't be resolved,
/// throw an exception. Otherwise a DynamicEntry is generated and becomes the primary SymbolEntry
/// \param sym is the Symbol to resolve
void Funcdata::remapConflictSymbol(Symbol *sym)
{
SymbolEntry *entry = sym->getFirstWholeMap();
if (!entry->isConflict()) return;
MapEntryConflict *map = (MapEntryConflict *)entry;
Varnode *vn = findVarnodeWritten(map->getSize(), map->getAddr(), map->getFirstUseAddress(), map->getUnique());
if (vn == (Varnode *)0)
throw LowlevelError("Cannot resolve SymbolEntry conflict on "+sym->getName()+": no varnode");
DynamicHash dhash;
dhash.uniqueHash(vn,this); // Calculate the dynamic hash
if (dhash.getHash() == 0)
throw LowlevelError("Cannot resolve SymbolEntry conflict on "+sym->getName()+": cannot generate hash");
remapDynamicVarnode(vn,sym,vn->getUsePoint(*this),dhash.getHash());
}
/// If the given Varnode shares the same storage and instruction as another Varnode, but with
/// a different HighVariable, return \b true.
/// \param vn is the given Varnode
/// \return \b true if the Varnode storage is shared across different HighVariables
bool Funcdata::detectSymbolConflicts(Varnode *vn)
{
if (vn->isAddrTied()) return false;
if (!vn->isWritten()) return false;
if (vn->getSpace()->getType() == IPTR_INTERNAL)
return true; // Temporary registers are automatically assumed to be in conflict
VarnodeDefSet::const_iterator iter = vn->defiter;
VarnodeDefSet::const_iterator enditer = vbank.endDef();
++iter;
while(iter != enditer) {
Varnode *otherVn = *iter;
if (!otherVn->isWritten()) break;
if (vn->def->getSeqNum().getAddr() != otherVn->def->getSeqNum().getAddr()) break;
if (vn->intersects(*otherVn)) {
if (vn->high != otherVn->high && !vn->high->isSameGroup(otherVn->high))
return true;
}
++iter;
}
iter = vn->defiter;
enditer = vbank.beginDef();
while(iter != enditer) {
--iter;
Varnode *otherVn = *iter;
if (!otherVn->isWritten()) break;
if (vn->def->getSeqNum().getAddr() != otherVn->def->getSeqNum().getAddr()) break;
if (vn->intersects(*otherVn)) {
if (vn->high != otherVn->high && !vn->high->isSameGroup(otherVn->high))
return true;
}
}
return false;
}
/// PIECE operations put the given Varnode into a larger structure. Find the resulting
/// whole Varnode, make sure it has a symbol assigned, and then assign the same symbol
/// to the given Varnode piece. If the given Varnode has been merged with something
@@ -1153,25 +1224,29 @@ Symbol *Funcdata::linkSymbol(Varnode *vn)
if (vn->isProtoPartial())
linkProtoPartial(vn);
HighVariable *high = vn->getHigh();
SymbolEntry *entry;
uint4 fl = 0;
Symbol *sym = high->getSymbol();
if (sym != (Symbol *)0) return sym; // Symbol already assigned
uint4 fl = 0;
Address usepoint = vn->getUsePoint(*this);
// Find any entry overlapping base address
entry = localmap->queryProperties(vn->getAddr(), 1, usepoint, fl);
if (entry != (SymbolEntry *) 0) {
sym = handleSymbolConflict(entry, vn);
SymbolEntry *entry = localmap->queryProperties(vn->getAddr(), 1, usepoint, fl);
if (entry != (SymbolEntry *)0 && !entry->isConflict()) {
vn->setSymbolEntry(entry);
return entry->getSymbol();
}
else { // Must create a symbol entry
if (!vn->isPersist()) { // Only create local symbol
if (!vn->isPersist()) { // Only create local symbol
if (detectSymbolConflicts(vn)) {
entry = localmap->addSymbolWithConflict("", high->getType(), vn);
}
else {
Address usepoint = vn->getUsePoint(*this);
if (vn->isAddrTied())
usepoint = Address();
entry = localmap->addSymbol("", high->getType(), vn->getAddr(), usepoint);
sym = entry->getSymbol();
vn->setSymbolEntry(entry);
}
sym = entry->getSymbol();
vn->setSymbolEntry(entry);
}
return sym;
@@ -1198,8 +1273,8 @@ Symbol *Funcdata::linkSymbolReference(Varnode *vn)
Address addr = sb->getAddress(vn->getOffset(),in0->getSize(),op->getAddr());
if (addr.isInvalid())
throw LowlevelError("Unable to generate proper address from spacebase");
SymbolEntry *entry = scope->queryContainer(addr,1,Address());
if (entry == (SymbolEntry *)0)
MapEntry *entry = scope->queryContainer(addr,1,Address());
if (entry == (MapEntry *)0)
return (Symbol *)0;
int4 off = (int4)(addr.getOffset() - entry->getAddr().getOffset()) + entry->getOffset();
vn->setSymbolReference(entry, off);
@@ -1214,18 +1289,21 @@ Varnode *Funcdata::findLinkedVarnode(SymbolEntry *entry) const
{
if (entry->isDynamic()) {
DynamicHash dhash;
Varnode *vn = dhash.findVarnode(this, entry->getFirstUseAddress(), entry->getHash());
Varnode *vn = dhash.findVarnode(this, entry->getFirstUseAddress(), ((DynamicEntry *)entry)->getHash());
if (vn == (Varnode *)0 || vn->isAnnotation())
return (Varnode *)0;
return vn;
}
if (!entry->isMapEntry())
return (Varnode *)0;
MapEntry *mapentry = (MapEntry *)entry;
VarnodeLocSet::const_iterator iter,enditer;
Address usestart = entry->getFirstUseAddress();
enditer = vbank.endLoc(entry->getSize(),entry->getAddr());
Address usestart = mapentry->getFirstUseAddress();
enditer = vbank.endLoc(mapentry->getSize(),mapentry->getAddr());
if (usestart.isInvalid()) {
iter = vbank.beginLoc(entry->getSize(),entry->getAddr());
iter = vbank.beginLoc(mapentry->getSize(),mapentry->getAddr());
if (iter == enditer)
return (Varnode *)0;
Varnode *vn = *iter;
@@ -1233,12 +1311,12 @@ Varnode *Funcdata::findLinkedVarnode(SymbolEntry *entry) const
return (Varnode *)0; // Varnode(s) must be address tied in order to match this symbol
return vn;
}
iter = vbank.beginLoc(entry->getSize(),entry->getAddr(),usestart,~((uintm)0));
iter = vbank.beginLoc(mapentry->getSize(),mapentry->getAddr(),usestart,~((uintm)0));
// TODO: Use a better end iterator
for(;iter!=enditer;++iter) {
Varnode *vn = *iter;
Address usepoint = vn->getUsePoint(*this);
if (entry->inUse(usepoint))
if (mapentry->inUse(usepoint))
return vn;
}
return (Varnode *)0;
@@ -1253,13 +1331,13 @@ void Funcdata::findLinkedVarnodes(SymbolEntry *entry,vector<Varnode *> &res) con
{
if (entry->isDynamic()) {
DynamicHash dhash;
Varnode *vn = dhash.findVarnode(this,entry->getFirstUseAddress(),entry->getHash());
Varnode *vn = dhash.findVarnode(this,entry->getFirstUseAddress(),((DynamicEntry *)entry)->getHash());
if (vn != (Varnode *)0)
res.push_back(vn);
}
else {
VarnodeLocSet::const_iterator iter = beginLoc(entry->getSize(),entry->getAddr());
VarnodeLocSet::const_iterator enditer = endLoc(entry->getSize(),entry->getAddr());
else if (entry->isMapEntry()) {
VarnodeLocSet::const_iterator iter = beginLoc(entry->getSize(),((MapEntry *)entry)->getAddr());
VarnodeLocSet::const_iterator enditer = endLoc(entry->getSize(),((MapEntry *)entry)->getAddr());
for(;iter!=enditer;++iter) {
Varnode *vn = *iter;
Address addr = vn->getUsePoint(*this);
@@ -1277,8 +1355,6 @@ void Funcdata::findLinkedVarnodes(SymbolEntry *entry,vector<Varnode *> &res) con
void Funcdata::buildDynamicSymbol(Varnode *vn)
{
if (vn->isTypeLock()||vn->isNameLock())
throw RecovError("Trying to build dynamic symbol on locked varnode");
if (!isHighOn())
throw RecovError("Cannot create dynamic symbols until decompile has completed");
HighVariable *high = vn->getHigh();
@@ -1305,7 +1381,7 @@ void Funcdata::buildDynamicSymbol(Varnode *vn)
/// \param entry is the (dynamic) Symbol entry
/// \param dhash is the dynamic mapping information
/// \return \b true if a Varnode was adjusted
bool Funcdata::attemptDynamicMapping(SymbolEntry *entry,DynamicHash &dhash)
bool Funcdata::attemptDynamicMapping(DynamicEntry *entry,DynamicHash &dhash)
{
Symbol *sym = entry->getSymbol();
@@ -1338,7 +1414,7 @@ bool Funcdata::attemptDynamicMapping(SymbolEntry *entry,DynamicHash &dhash)
/// \param entry is the (dynamic) Symbol entry
/// \param dhash is the dynamic mapping information
/// \return \b true if a Varnode was adjusted
bool Funcdata::attemptDynamicMappingLate(SymbolEntry *entry,DynamicHash &dhash)
bool Funcdata::attemptDynamicMappingLate(DynamicEntry *entry,DynamicHash &dhash)
{
dhash.clear();
@@ -1597,7 +1673,7 @@ Address Funcdata::findDisjointCover(Varnode *vn,int4 &sz)
/// overlaps its first byte (to guarantee a link). If one doesn't exist it is created.
/// \param entry is the existing Symbol entry
/// \param list is the list of Varnodes
void Funcdata::coverVarnodes(SymbolEntry *entry,vector<Varnode *> &list)
void Funcdata::coverVarnodes(MapEntry *entry,vector<Varnode *> &list)
{
Scope *scope = entry->getSymbol()->getScope();
@@ -1608,8 +1684,8 @@ void Funcdata::coverVarnodes(SymbolEntry *entry,vector<Varnode *> &list)
if (i+1<list.size() && list[i+1]->getAddr() == vn->getAddr())
continue;
Address usepoint = vn->getUsePoint(*this);
SymbolEntry *overlapEntry = scope->findContainer(vn->getAddr(), vn->getSize(), usepoint);
if (overlapEntry == (SymbolEntry *)0) {
MapEntry *overlapEntry = scope->findContainer(vn->getAddr(), vn->getSize(), usepoint);
if (overlapEntry == (MapEntry *)0) {
int4 diff = (int4)(vn->getOffset() - entry->getAddr().getOffset());
ostringstream s;
s << entry->getSymbol()->getName() << '_' << diff;
@@ -1628,18 +1704,43 @@ void Funcdata::coverVarnodes(SymbolEntry *entry,vector<Varnode *> &list)
/// \param entry is the given SymbolEntry
/// \param dhash is preallocated storage for calculating the dynamic hash
/// \return \b true if the UnionFacetSymbol is successfully cached
bool Funcdata::applyUnionFacet(SymbolEntry *entry,DynamicHash &dhash)
bool Funcdata::applyUnionFacet(DynamicEntry *entry,DynamicHash &dhash)
{
Symbol *sym = entry->getSymbol();
UnionFacetSymbol *sym = (UnionFacetSymbol *)entry->getSymbol();
if (sym->isAddrBased()) {
ResolvedUnion resolve(sym->getType(), sym->getFieldNumber(), *glb->types);
resolve.setLock(true);
int4 slot = DynamicHash::getSlotFromHash(entry->getHash());
return setAddressBasedUnionField(sym->getType(), entry->getFirstUseAddress(), slot, resolve);
}
PcodeOp *op = dhash.findOp(this, entry->getFirstUseAddress(), entry->getHash());
if (op == (PcodeOp *)0)
return false;
int4 slot = DynamicHash::getSlotFromHash(entry->getHash());
int4 fldNum = ((UnionFacetSymbol *)sym)->getFieldNumber();
ResolvedUnion resolve(sym->getType(), fldNum, *glb->types);
const ResolvedUnion *res = getUnionResolution(sym->getType(), op, slot);
if (res != (const ResolvedUnion *)0 && res->getFieldNum() == sym->getFieldNumber())
return false;
Varnode *vn = (slot < 0) ? op->getOut() : op->getIn(slot);
Datatype *unresType = sym->getType();
Datatype *dt = vn->getType();
if (dt->getMetatype() == TYPE_PTR) {
if (((TypePointer *)dt)->getPtrTo() == unresType) {
unresType = dt;
}
}
else if (dt->getMetatype() == TYPE_PARTIALSTRUCT) {
if (((TypePartialStruct *)dt)->getParent() == unresType)
unresType = dt;
}
else if (dt->getMetatype() == TYPE_PARTIALUNION) {
if (((TypePartialUnion *)dt)->getParentUnion() == unresType)
unresType = dt;
}
ResolvedUnion resolve(unresType,sym->getFieldNumber(), *glb->types);
resolve.setLock(true);
return setUnionField(sym->getType(),op,slot,resolve);
setUnionField(unresType,op,slot,resolve);
return true;
}
/// Search for \e addrtied Varnodes whose storage falls in the global Scope, then
@@ -1647,7 +1748,7 @@ bool Funcdata::applyUnionFacet(SymbolEntry *entry,DynamicHash &dhash)
void Funcdata::mapGlobals(void)
{
SymbolEntry *entry;
MapEntry *entry;
VarnodeLocSet::const_iterator iter,enditer;
Varnode *vn,*maxvn;
Datatype *ct;
@@ -1693,7 +1794,7 @@ void Funcdata::mapGlobals(void)
Address usepoint;
// Find any entry overlapping base address
entry = localmap->queryProperties(addr,1,usepoint,fl);
if (entry==(SymbolEntry *)0) {
if (entry==(MapEntry *)0) {
Scope *discover = localmap->discoverScope(addr,ct->getSize(),usepoint);
if (discover == (Scope *)0)
throw LowlevelError("Could not discover scope");
@@ -47,14 +47,6 @@ ElementId ELEM_COMMAND_GETSTRINGDATA = ElementId("command_getstringdata",255);
ElementId ELEM_COMMAND_GETTRACKEDREGISTERS = ElementId("command_gettrackedregisters",256);
ElementId ELEM_COMMAND_GETUSEROPNAME = ElementId("command_getuseropname",257);
/// Catch the signal so the OS doesn't pop up a dialog
/// \param sig is the OS signal (should always be SIGSEGV)
void ArchitectureGhidra::segvHandler(int4 sig)
{
exit(1); // Just die - prevents OS from popping-up a dialog
}
/// All communications between the Ghidra client and the decompiler are surrounded
/// by alignment bursts. A burst is 1 or more zero bytes followed by
/// an 0x01 byte, then followed by a code byte.
@@ -746,6 +738,8 @@ void ArchitectureGhidra::getBytes(uint1 *buf,int4 size,const Address &inaddr)
if (type == 12) {
uint1 *dblbuf = new uint1[size * 2];
sin.read((char *)dblbuf,size*2);
if (sin.gcount() != size*2)
throw JavaError("alignment","Could not read expected number of bytes");
for (int4 i=0; i < size; i++) {
buf[i] = ((dblbuf[i*2]-'A') << 4) | (dblbuf[i*2 + 1]-'A');
}
@@ -901,10 +895,13 @@ bool ArchitectureGhidra::getCPoolRef(const vector<uintb> &refs,Decoder &decoder)
return readAll(sin,decoder);
}
void ArchitectureGhidra::printMessage(const string &message) const
void ArchitectureGhidra::printWarning(const string &message) const
{
warnings += '\n'+message;
sout.write("\000\000\001\022",4);
sout << "Decompiler: " << message;
sout.write("\000\000\001\023",4);
sout.flush();
}
/// \brief Construct given specification files and i/o streams
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -82,7 +82,6 @@ struct JavaError : public LowlevelError {
class ArchitectureGhidra : public Architecture {
istream &sin; ///< Input stream for interfacing with Ghidra
ostream &sout; ///< Output stream for interfacing with Ghidra
mutable string warnings; ///< Warnings accumulated by the decompiler
string pspecxml; ///< XML pspec passed from Ghidra
string cspecxml; ///< XML cspec passed from Ghidra
string tspecxml; ///< Stripped down .sla file passed from Ghidra
@@ -108,8 +107,6 @@ class ArchitectureGhidra : public Architecture {
public:
ArchitectureGhidra(const string &pspec,const string &cspec,const string &tspec,const string &corespec,
istream &i,ostream &o);
const string &getWarnings(void) const { return warnings; } ///< Get warnings produced by the last decompilation
void clearWarnings(void) { warnings.clear(); } ///< Clear warnings
bool getRegister(const string &regname,Decoder &decoder); ///< Retrieve a register description given a name
string getRegisterName(const VarnodeData &vndata); ///< Retrieve a register name given its storage location
bool getTrackedRegisters(const Address &addr,Decoder &decoder); ///< Retrieve \e tracked register values at the given address
@@ -153,9 +150,8 @@ public:
bool getSendParamMeasures(void) const { return sendParamMeasures; } ///< Get the current setting for emitting parameter info
void getStringData(vector<uint1> &buffer,const Address &addr,Datatype *ct,int4 maxBytes,bool &isTrunc);
virtual void printMessage(const string &message) const;
virtual void printWarning(const string &message) const;
static void segvHandler(int4 sig); ///< Handler for a segment violation (SIGSEGV) signal
static int4 readToAnyBurst(istream &s); ///< Read the next message protocol marker
static bool readBoolStream(istream &s); ///< Read a boolean value from the client
static void readStringStream(istream &s,string &res); ///< Receive a string from the client
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -99,18 +99,17 @@ void GhidraCommand::loadParameters(void)
if (ghidra == (ArchitectureGhidra *)0)
throw JavaError("decompiler","No architecture registered with decompiler");
ghidra->clearWarnings();
}
/// This method sends any warnings accumulated during execution back, but it can be overloaded
/// to send back any kind of information. Individual records are sent using
/// the message protocol.
void GhidraCommand::sendResult(void)
/// This method can be overloaded to send back any kind of information as a string. Individual records
/// are sent using the message protocol. If the command failed, a string describing the error is passed in.
/// \param errorMsg is, if not empty, the error causing the commmand to fail
void GhidraCommand::sendResult(const string &errorMsg)
{
if (ghidra != (ArchitectureGhidra *)0) {
sout.write("\000\000\001\020",4);
sout << ghidra->getWarnings();
sout << errorMsg;
sout.write("\000\000\001\021",4);
}
}
@@ -127,6 +126,7 @@ int4 GhidraCommand::doit(void)
{
status = 0;
sout.write("\000\000\001\006",4); // Command response header
string errorMsg;
try {
loadParameters();
int4 type = ArchitectureGhidra::readToAnyBurst(sin);
@@ -135,25 +135,19 @@ int4 GhidraCommand::doit(void)
rawAction();
}
catch(DecoderError &err) {
string errmsg;
errmsg = "Marshaling error: " + err.explain;
ghidra->printMessage( errmsg );
errorMsg = "Marshaling error: " + err.explain;
}
catch(JavaError &err) {
ArchitectureGhidra::passJavaException(sout,err.type,err.explain);
return status; // Abort sending any results
}
catch(RecovError &err) {
string errmsg;
errmsg = "Recoverable Error: " + err.explain;
ghidra->printMessage( errmsg );
errorMsg = "Recoverable Error: " + err.explain;
}
catch(LowlevelError &err) {
string errmsg;
errmsg = "Low-level Error: " + err.explain;
ghidra->printMessage( errmsg );
errorMsg = "Low-level Error: " + err.explain;
}
sendResult();
sendResult(errorMsg);
sout.write("\000\000\001\007",4); // Command response closer
sout.flush();
return status;
@@ -200,13 +194,13 @@ void RegisterProgram::rawAction(void)
archid = open;
}
void RegisterProgram::sendResult(void)
void RegisterProgram::sendResult(const string &errorMsg)
{
sout.write("\000\000\001\016",4);
sout << dec << archid;
sout.write("\000\000\001\017",4);
GhidraCommand::sendResult();
GhidraCommand::sendResult(errorMsg);
}
void DeregisterProgram::loadParameters(void)
@@ -225,7 +219,6 @@ void DeregisterProgram::loadParameters(void)
if (ghidra == (ArchitectureGhidra *)0)
throw JavaError("decompiler","No architecture registered with decompiler");
ghidra->clearWarnings();
}
void DeregisterProgram::rawAction(void)
@@ -250,13 +243,13 @@ void DeregisterProgram::rawAction(void)
res = 0;
}
void DeregisterProgram::sendResult(void)
void DeregisterProgram::sendResult(const string &errorMsg)
{
sout.write("\000\000\001\016",4);
sout << dec << res;
sout.write("\000\000\001\017",4);
GhidraCommand::sendResult();
GhidraCommand::sendResult(errorMsg);
}
void FlushNative::rawAction(void)
@@ -272,13 +265,13 @@ void FlushNative::rawAction(void)
res = 0;
}
void FlushNative::sendResult(void)
void FlushNative::sendResult(const string &errorMsg)
{
sout.write("\000\000\001\016",4);
sout << dec << res;
sout.write("\000\000\001\017",4);
GhidraCommand::sendResult();
GhidraCommand::sendResult(errorMsg);
}
void DecompileAt::loadParameters(void)
@@ -324,7 +317,7 @@ void DecompileAt::rawAction(void)
ParamIDAnalysis pidanalysis( fd, false );
pidanalysis.encode( encoder, true );
}
fd->encode(encoder,0,ghidra->getSendSyntaxTree());
fd->encode(encoder,0,ghidra->getSendSyntaxTree(),false);
if (ghidra->getSendCCode()&&
(ghidra->allacts.getCurrentName() == "decompile"))
ghidra->print->docFunction(fd);
@@ -405,14 +398,14 @@ void SetAction::rawAction(void)
res = true;
}
void SetAction::sendResult(void)
void SetAction::sendResult(const string &errorMsg)
{
if (res)
ArchitectureGhidra::writeStringStream(sout,"t");
else
ArchitectureGhidra::writeStringStream(sout,"f");
GhidraCommand::sendResult();
GhidraCommand::sendResult(errorMsg);
}
void SetOptions::loadParameters(void)
@@ -444,14 +437,14 @@ void SetOptions::rawAction(void)
res = true;
}
void SetOptions::sendResult(void)
void SetOptions::sendResult(const string &errorMsg)
{
if (res)
ArchitectureGhidra::writeStringStream(sout,"t");
else
ArchitectureGhidra::writeStringStream(sout,"f");
GhidraCommand::sendResult();
GhidraCommand::sendResult(errorMsg);
}
/// A command is read from the Ghidra client. The matching GhidraCommand object is
@@ -505,6 +498,14 @@ void GhidraDecompCapability::initialize(void)
commandmap["setOptions"] = new SetOptions();
}
/// Catch the signal so the OS doesn't pop up a dialog
/// \param sig is the OS signal (should always be SIGSEGV)
static void segvHandler(int4 sig)
{
_Exit(1); // Don't do any cleanup, just die - prevents OS from popping-up a dialog
}
} // End namespace ghidra
int main(int argc,char **argv)
@@ -512,7 +513,7 @@ int main(int argc,char **argv)
{
using namespace ghidra;
signal(SIGSEGV, &ArchitectureGhidra::segvHandler); // Exit on SEGV errors
signal(SIGSEGV, &segvHandler); // Exit on SEGV errors
#ifdef _WINDOWS
// Force i/o streams to be in binary mode
_setmode(_fileno(stdin), _O_BINARY);
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -82,7 +82,7 @@ protected:
ArchitectureGhidra *ghidra; ///< The Architecture on which to perform the command
int4 status; ///< Meta-command to system (0=wait for next command, 1=terminate process)
virtual void loadParameters(void); ///< Read parameters directing command execution
virtual void sendResult(void); ///< Send results of the command (if any) back to the Ghidra client
virtual void sendResult(const string &errorMsg); ///< Send back response to the command
public:
GhidraCommand(void) : sin(cin),sout(cout) {
ghidra = (ArchitectureGhidra *)0;
@@ -112,7 +112,7 @@ class RegisterProgram : public GhidraCommand {
string tspec; ///< Configuration (address-spaces) for the Translate object
string corespec; ///< A description of core data-types for the TypeFactory object
virtual void loadParameters(void);
virtual void sendResult(void);
virtual void sendResult(const string &errorMsg);
public:
int4 archid; ///< Resulting id of the program to send back
virtual void rawAction(void);
@@ -126,7 +126,7 @@ public:
class DeregisterProgram : public GhidraCommand {
int4 inid; ///< The id of the Architecture being terminated
virtual void loadParameters(void);
virtual void sendResult(void);
virtual void sendResult(const string &errorMsg);
public:
int4 res; ///< The meta-command being issued to send back
virtual void rawAction(void);
@@ -140,7 +140,7 @@ public:
/// (re)fetch any symbols as needed.
/// The command expects a single string parameter encoding the id of the program to flush.
class FlushNative : public GhidraCommand {
virtual void sendResult(void);
virtual void sendResult(const string &errorMsg);
public:
int4 res; ///< Success status returned to the client (0=success)
virtual void rawAction(void);
@@ -211,7 +211,7 @@ class SetAction : public GhidraCommand {
string actionstring; ///< The \e root Action to switch to
string printstring; ///< The \e printing output configuration to toggle
virtual void loadParameters(void);
virtual void sendResult(void);
virtual void sendResult(const string &errorMsg);
public:
bool res; ///< Set to \b true if the configuration action was successful
virtual void rawAction(void);
@@ -229,7 +229,7 @@ public:
class SetOptions : public GhidraCommand {
Decoder *decoder; ///< The \<optionslist> decoder
virtual void loadParameters(void);
virtual void sendResult(void);
virtual void sendResult(const string &errorMsg);
public:
bool res; ///< Set to \b true if the option change succeeded
SetOptions(void) { decoder = (Decoder *)0; res = false; } ///< Constructor
File diff suppressed because it is too large. Load diff
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -37,11 +37,12 @@ public:
badtoken = 0x100,
endoffile = 0x101,
dotdotdot = 0x102,
scoperes = 0x103,
integer = 0x103,
charconstant = 0x104,
identifier = 0x105,
stringval = 0x106,
integer = 0x104,
charconstant = 0x105,
identifier = 0x106,
stringval = 0x107,
};
private:
uint4 type;
@@ -85,6 +86,8 @@ class GrammarLexer {
dot1,
dot2,
dot3,
scoperes1,
scoperes2,
punctuation,
endofline_comment,
c_comment,
@@ -169,12 +172,15 @@ class TypeDeclarator {
string ident; // variable identifier associated with type
string model; // name of model associated with function pointer
uint4 flags; // Specifiers qualifiers
int4 numBits; // Number of bits associated with declaration (0=unspecified)
public:
TypeDeclarator(void) { basetype=(Datatype *)0; flags=0; }
TypeDeclarator(const string &nm) { ident=nm; basetype=(Datatype *)0; flags=0; }
TypeDeclarator(void) { basetype=(Datatype *)0; flags=0; numBits=0; }
TypeDeclarator(const string &nm) { ident=nm; basetype=(Datatype *)0; flags=0; numBits=0; }
~TypeDeclarator(void);
Datatype *getBaseType(void) const { return basetype; }
int4 numModifiers(void) const { return mods.size(); }
int4 getNumBits(void) const { return numBits; }
void setNumBits(int4 val) { numBits = val; }
const string &getIdentifier(void) const { return ident; }
ProtoModel *getModel(Architecture *glb) const;
bool getPrototype(PrototypePieces &pieces,Architecture *glb) const;
@@ -39,7 +39,7 @@ static CParse *parse;
// Grammar taken from ISO/IEC 9899
%token DOTDOTDOT BADTOKEN STRUCT UNION ENUM DECLARATION_RESULT PARAM_RESULT
%token DOTDOTDOT BADTOKEN STRUCT UNION ENUM DECLARATION_RESULT PARAM_RESULT SCOPERES
%token <i> NUMBER
%token <str> IDENTIFIER
%token <str> STORAGE_CLASS_SPECIFIER TYPE_QUALIFIER FUNCTION_SPECIFIER
@@ -56,6 +56,7 @@ static CParse *parse;
%type <type> type_specifier struct_or_union_specifier enum_specifier
%type <enumer> enumerator
%type <vecenum> enumerator_list
%type <str> var_identifier
%%
document:
@@ -127,7 +128,7 @@ struct_declarator_list:
struct_declarator:
declarator { $$ = $1; }
// declarator ':' NUMBER
| declarator ':' NUMBER { $$ = $1; $1->setNumBits((int4)*$3); }
;
enum_specifier:
@@ -153,8 +154,13 @@ declarator:
| pointer direct_declarator { $$ = parse->mergePointer($1,$2); }
;
var_identifier:
IDENTIFIER { $$ = $1; }
| var_identifier SCOPERES IDENTIFIER { $$ = $1; $$->append("::"); $$->append(*$3); }
;
direct_declarator:
IDENTIFIER { $$ = parse->newDeclarator($1); }
var_identifier { $$ = parse->newDeclarator($1); }
| '(' declarator ')' { $$ = $2; }
| direct_declarator '[' type_qualifier_list assignment_expression ']' { $$ = parse->newArray($1,$3,$4); }
| direct_declarator '[' assignment_expression ']' { $$ = parse->newArray($1,0,$3); }
@@ -361,6 +367,9 @@ uint4 GrammarLexer::moveState(char lookahead)
state = punctuation;
bufstart = bufend-1;
break;
case ':':
state = scoperes1;
break;
case '-':
case '0':
case '1':
@@ -469,6 +478,19 @@ uint4 GrammarLexer::moveState(char lookahead)
state = start;
res = GrammarToken::dotdotdot;
break;
case scoperes1:
if (lookahead == ':') {
state = scoperes2;
}
else {
state = start;
res = ':';
}
break;
case scoperes2:
state = start;
res = GrammarToken::scoperes;
break;
case punctuation:
state = start;
res = (uint4)buffer[bufstart];
@@ -529,7 +551,7 @@ uint4 GrammarLexer::moveState(char lookahead)
}
else if ((lookahead>='a')&&(lookahead<='z')) {
}
else if (lookahead == '_' || lookahead == ':') {
else if (lookahead == '_') {
}
else {
state = start;
@@ -1035,6 +1057,8 @@ Datatype *CParse::newStruct(const string &ident,vector<TypeDeclarator *> *declis
{ // Build a new structure
TypeStruct *res = glb->types->getTypeStruct(ident); // Create stub (for recursion)
vector<TypeField> sublist;
vector<TypeBitField> bitlist;
bool isBigEndian = glb->getDefaultDataSpace()->isBigEndian();
for(uint4 i=0;i<declist->size();++i) {
TypeDeclarator *decl = (*declist)[i];
@@ -1043,14 +1067,14 @@ Datatype *CParse::newStruct(const string &ident,vector<TypeDeclarator *> *declis
glb->types->destroyType(res);
return (Datatype *)0;
}
sublist.emplace_back(0,-1,decl->getIdentifier(),decl->buildType(glb));
if (decl->getNumBits() != 0)
bitlist.emplace_back(sublist.size(),decl->getNumBits(),isBigEndian,decl->getIdentifier(),decl->buildType(glb));
else
sublist.emplace_back(0,-1,decl->getIdentifier(),decl->buildType(glb));
}
try {
int4 newSize;
int4 newAlign;
TypeStruct::assignFieldOffsets(sublist,newSize,newAlign);
glb->types->setFields(sublist,res,newSize,newAlign,0);
glb->types->assignRawFields(res,sublist,bitlist);
}
catch (LowlevelError &err) {
setError(err.explain);
@@ -1086,10 +1110,7 @@ Datatype *CParse::newUnion(const string &ident,vector<TypeDeclarator *> *declist
}
try {
int4 newSize;
int4 newAlign;
TypeUnion::assignFieldOffsets(sublist,newSize,newAlign,res);
glb->types->setFields(sublist,res,newSize,newAlign,0);
glb->types->assignRawFields(res,sublist);
}
catch (LowlevelError &err) {
setError(err.explain);
@@ -1282,6 +1303,8 @@ int4 CParse::lex(void)
return BADTOKEN;
case GrammarToken::dotdotdot:
return DOTDOTDOT;
case GrammarToken::scoperes:
return SCOPERES;
case GrammarToken::badtoken:
setError(lexer.getError()); // Error from lexer
return BADTOKEN;
@@ -882,6 +882,7 @@ void Heritage::analyzeNewLoadGuards(void)
for(iter=storeIter;iter!=storeGuard.end(); ++iter) {
LoadGuard &guard( *iter );
guard.establishRange(vsSolver.getValueSetRead(guard.op->getSeqNum()));
guard.op->setAliasUpdate(); // Mark that alias information for the STORE has been changed
if (guard.analysisState == 0)
runFullAnalysis = true;
}
@@ -1191,7 +1192,7 @@ void Heritage::guard(const Address &addr,int4 size,bool addIndirects,
fd->getScopeLocal()->queryProperties(addr,size,Address(),fl);
guardCalls(fl,addr,size,write);
guardReturns(fl,addr,size,write);
if (fd->getArch()->highPtrPossible(addr,size)) {
if (addr.highPtrPossible(size)) {
guardStores(addr,size,write);
guardLoads(fl,addr,size,write);
}
@@ -1739,15 +1740,16 @@ void Heritage::splitByRefinement(Varnode *vn,const Address &addr,const vector<in
uint4 diff = (uint4)spc->wrapOffset(curaddr.getOffset() - addr.getOffset());
int4 cutsz = refine[diff];
if (sz <= cutsz) return; // Already refined
split.push_back(fd->newVarnode(cutsz,curaddr));
sz -= cutsz;
while(sz > 0) {
Varnode *vn2 = fd->newVarnode(cutsz,curaddr);
split.push_back(vn2);
curaddr = curaddr + cutsz;
sz -= cutsz;
diff = (uint4)spc->wrapOffset(curaddr.getOffset() - addr.getOffset());
cutsz = refine[diff];
if (cutsz > sz)
cutsz = sz; // Final piece
split.push_back(fd->newVarnode(cutsz,curaddr));
sz -= cutsz;
}
}
@@ -1960,7 +1962,6 @@ void Heritage::guardInput(const Address &addr,int4 size,vector<Varnode *> &input
int4 i = 0;
uintb cur = addr.getOffset(); // Range that needs to be covered
uintb end = cur + size;
// bool seenunspliced = false;
Varnode *vn;
vector<Varnode *> newinput;
@@ -1972,11 +1973,8 @@ void Heritage::guardInput(const Address &addr,int4 size,vector<Varnode *> &input
int4 sz = vn->getOffset() - cur;
vn = fd->newVarnode(sz,Address(addr.getSpace(),cur));
vn = fd->setInputVarnode(vn);
// seenunspliced = true;
}
else {
// if (vn->hasNoDescend())
// seenunspliced = true;
i += 1;
}
}
@@ -1984,7 +1982,6 @@ void Heritage::guardInput(const Address &addr,int4 size,vector<Varnode *> &input
int4 sz = end-cur;
vn = fd->newVarnode(sz,Address(addr.getSpace(),cur));
vn = fd->setInputVarnode(vn);
// seenunspliced = true;
}
newinput.push_back(vn);
cur += vn->getSize();
@@ -1993,17 +1990,6 @@ void Heritage::guardInput(const Address &addr,int4 size,vector<Varnode *> &input
// Now we need to make sure that all the inputs get linked
// together into a single input
if (newinput.size()==1) return; // Will get linked in automatically
for(uint4 j=0;j<newinput.size();++j)
newinput[j]->setWriteMask();
// if (!seenunspliced) {
// // Check to see if a concatenation of inputs already exists
// // If it existed already it would be defined at fd->getAddress()
// // and it would have full size
// VarnodeLocSet::const_iterator iter,enditer;
// iter = fd->beginLoc(size,addr,fd->getAddress());
// enditer = fd->endLoc(size,addr,fd->getAddress());
// if (iter != enditer) return; // It already exists
// }
Varnode *newout = fd->newVarnode(size,addr);
concatPieces(newinput,(PcodeOp *)0,newout)->setActiveHeritage();
}
@@ -2187,32 +2173,38 @@ void Heritage::splitJoinWrite(Varnode *vn,JoinRecord *joinrec)
Varnode *mosthalf = nextlev[2*i];
Varnode *leasthalf = nextlev[2*i+1];
if (leasthalf == (Varnode *)0) continue; // Varnode didn't get split this level
PcodeOp *split;
if (vn->isInput())
split = fd->newOp(2,bb->getStart());
else
split = fd->newOp(2,op->getAddr());
fd->opSetOpcode(split,CPUI_SUBPIECE);
fd->opSetOutput(split,mosthalf);
fd->opSetInput(split,curvn,0);
fd->opSetInput(split,fd->newConstant(4,leasthalf->getSize()),1);
if (op == (PcodeOp *)0)
fd->opInsertBegin(split,bb);
else
fd->opInsertAfter(split,op);
op = split; // Keep -op- as the latest op in the split construction
split = fd->newOp(2,op->getAddr());
fd->opSetOpcode(split,CPUI_SUBPIECE);
fd->opSetOutput(split,leasthalf);
fd->opSetInput(split,curvn,0);
fd->opSetInput(split,fd->newConstant(4,0),1);
fd->opInsertAfter(split,op);
if (isPrimitive) {
mosthalf->setPrecisHi(); // Make sure we set the precision flags to trigger "double precision" rules
leasthalf->setPrecisLo();
if (!mosthalf->isConstant()) {
PcodeOp *split;
if (vn->isInput())
split = fd->newOp(2,bb->getStart());
else
split = fd->newOp(2,op->getAddr());
fd->opSetOpcode(split,CPUI_SUBPIECE);
fd->opSetOutput(split,mosthalf);
fd->opSetInput(split,curvn,0);
fd->opSetInput(split,fd->newConstant(4,leasthalf->getSize()),1);
if (op == (PcodeOp *)0)
fd->opInsertBegin(split,bb);
else
fd->opInsertAfter(split,op);
op = split; // Keep -op- as the latest op in the split construction
}
if (!leasthalf->isConstant()) {
PcodeOp *split = fd->newOp(2,op->getAddr());
fd->opSetOpcode(split,CPUI_SUBPIECE);
fd->opSetOutput(split,leasthalf);
fd->opSetInput(split,curvn,0);
fd->opSetInput(split,fd->newConstant(4,0),1);
if (op == (PcodeOp *)0)
fd->opInsertBegin(split,bb);
else
fd->opInsertAfter(split,op);
if (isPrimitive) {
mosthalf->setPrecisHi(); // Make sure we set the precision flags to trigger "double precision" rules
leasthalf->setPrecisLo();
}
op = split; // Keep -op- as the latest op in the split construction
}
op = split; // Keep -op- as the latest op in the split construction
}
lastcombo.clear();
@@ -2295,6 +2287,7 @@ void Heritage::processJoins(void)
if (joinrec->getUnified().size != vn->getSize())
throw LowlevelError("Joined varnode does not match size of record");
if (vn->isFree()) {
if (vn->hasNoDescend()) continue; // Its possible vn is dead
if (joinrec->isFloatExtension())
floatExtensionRead(vn,joinrec);
else
@@ -2745,8 +2738,10 @@ void Heritage::heritage(void)
}
}
}
placeMultiequals();
rename();
if (!disjoint.empty()) {
placeMultiequals();
rename();
}
if (reprocessStackCount > 0)
reprocessFreeStores(stackSpace, freeStores);
analyzeNewLoadGuards();
@@ -2849,6 +2844,17 @@ bool Heritage::deadRemovalAllowedSeen(AddrSpace *spc)
return res;
}
/// If no heritage has happened yet, do nothing.
/// \param addr is the start of the range
/// \param sz is the number of bytes in the range
void Heritage::markRangeHeritaged(const Address &addr,int4 sz)
{
int4 intersect;
if (pass > 0)
globaldisjoint.add(addr,sz,pass-1,intersect);
}
/// Reset all analysis as if no heritage passes have yet taken place for the function.
/// This does not directly affect Varnodes and PcodeOps in the underlying Funcdata.
void Heritage::clear(void)
@@ -90,6 +90,7 @@ public:
iterator begin(void) { return tasklist.begin(); } ///< Get iterator to beginning of \b this list
iterator end(void) { return tasklist.end(); } ///< Get iterator to end of \b this list
void clear(void) { tasklist.clear(); } ///< Clear all ranges in the list
bool empty(void) { return tasklist.empty(); } ///< Return \b true if the list is empty
};
/// \brief Priority queue for the phi-node (MULTIEQUAL) placement algorithm
@@ -329,6 +330,7 @@ public:
void setDeadCodeDelay(AddrSpace *spc,int4 delay); ///< Set delay for a specific space
bool deadRemovalAllowed(AddrSpace *spc) const; ///< Return \b true if it is \e safe to remove dead code
bool deadRemovalAllowedSeen(AddrSpace *spc);
void markRangeHeritaged(const Address &addr,int4 sz); ///< Mark range as heritaged (on previous pass)
void buildInfoList(void); ///< Initialize information for each space
void forceRestructure(void) { maxdepth = -1; } ///< Force regeneration of basic block structures
void clear(void); ///< Reset all analysis of heritage
@@ -72,6 +72,7 @@ void IfaceDecompCapability::registerCommands(IfaceStatus *status)
status->registerCom(new IfcProtooverride(),"override","prototype");
status->registerCom(new IfcJumpOverride(),"override","jumptable");
status->registerCom(new IfcFlowOverride(),"override","flow");
status->registerCom(new IfcDestinationOverride(),"override","destination");
status->registerCom(new IfcDeadcodedelay(),"deadcode","delay");
status->registerCom(new IfcGlobalAdd(),"global","add");
status->registerCom(new IfcGlobalRemove(),"global","remove");
@@ -122,6 +123,8 @@ void IfaceDecompCapability::registerCommands(IfaceStatus *status)
status->registerCom(new IfcLockPrototype(),"prototype","lock");
status->registerCom(new IfcUnlockPrototype(),"prototype","unlock");
status->registerCom(new IfcCommentInstr(),"comment","instruction");
status->registerCom(new IfcFindVarnodeHash(),"find","varnode","hash");
status->registerCom(new IfcFindOpHash(),"find","op","hash");
status->registerCom(new IfcDuplicateHash(),"duplicate","hash");
status->registerCom(new IfcCallGraphBuild(),"callgraph","build");
status->registerCom(new IfcCallGraphBuildQuick(),"callgraph","build","quick");
@@ -459,7 +462,7 @@ void IfaceDecompData::followFlow(ostream &s,int4 size)
/// \class IfcFuncload
/// \brief Make a specific function current: `load function <functionname>`
///
/// The name must be a fully qualified symbol with "::" separating namespaces.
/// The name must be a fully qualified symbol with namespaces.
/// If the symbol represents a function, that function becomes \e current for
/// the console. If there are bytes for the function, raw p-code and control-flow
/// are calculated.
@@ -475,7 +478,7 @@ void IfcFuncload::execute(istream &s)
throw IfaceExecutionError("No image loaded");
string basename;
Scope *funcscope = dcp->conf->symboltab->resolveScopeFromSymbolName(funcname,"::",basename,(Scope *)0);
Scope *funcscope = dcp->conf->symboltab->resolveScopeFromSymbolName(funcname,basename,(Scope *)0);
if (funcscope == (Scope *)0)
throw IfaceExecutionError("Bad namespace: "+funcname);
dcp->fd = funcscope->queryFunction( basename ); // Is function already in database
@@ -534,7 +537,7 @@ void IfcReadSymbols::execute(istream &s)
if (dcp->conf->loader == (LoadImage *)0)
throw IfaceExecutionError("No binary loaded");
dcp->conf->readLoaderSymbols("::");
dcp->conf->readLoaderSymbols();
}
/// \class IfcMapaddress
@@ -544,8 +547,8 @@ void IfcReadSymbols::execute(istream &s)
/// \code
/// map address r0x1000 int4 globalvar
/// \endcode
/// The symbol specified in the type declaration can qualify the namespace using the "::"
/// specifier. If there is a current function, the variable is local to the function.
/// The symbol specified in the type declaration can qualify the namespace.
/// If there is a current function, the variable is local to the function.
/// Otherwise the symbol is created relative to the global scope.
void IfcMapaddress::execute(istream &s)
@@ -563,16 +566,15 @@ void IfcMapaddress::execute(istream &s)
sym->getScope()->setAttribute(sym,Varnode::namelock|Varnode::typelock);
}
else {
Symbol *sym;
uint4 flags = Varnode::namelock|Varnode::typelock;
flags |= dcp->conf->symboltab->getProperty(addr); // Inherit existing properties
string basename;
Scope *scope = dcp->conf->symboltab->findCreateScopeFromSymbolName(name, "::", basename, (Scope *)0);
sym = scope->addSymbol(basename,ct,addr,Address())->getSymbol();
Scope *scope = dcp->conf->symboltab->findCreateScopeFromSymbolName(name, basename, (Scope *)0);
MapEntry *entry = scope->addSymbol(basename,ct,addr,Address());
Symbol *sym = entry->getSymbol();
sym->getScope()->setAttribute(sym,flags);
if (scope->getParent() != (Scope *)0) { // If this is a global namespace scope
SymbolEntry *e = sym->getFirstWholeMap(); // Adjust range
dcp->conf->symboltab->addRange(scope,e->getAddr().getSpace(),e->getFirst(),e->getLast());
dcp->conf->symboltab->addRange(scope,entry->getAddr().getSpace(),entry->getFirst(),entry->getLast());
}
}
@@ -670,7 +672,7 @@ void IfcMapfunction::execute(istream &s)
if (name.empty())
dcp->conf->nameFunction(addr,name); // Pick default name if necessary
string basename;
Scope *scope = dcp->conf->symboltab->findCreateScopeFromSymbolName(name, "::", basename, (Scope *)0);
Scope *scope = dcp->conf->symboltab->findCreateScopeFromSymbolName(name, basename, (Scope *)0);
dcp->fd = scope->addFunction(addr,name)->getFunction();
string nocode;
@@ -1353,6 +1355,7 @@ void IfcRename::execute(istream &s)
if (sym->getCategory() == Symbol::function_parameter)
dcp->fd->getFuncProto().setInputLock(true);
dcp->fd->remapConflictSymbol(sym);
sym->getScope()->renameSymbol(sym,newname);
sym->getScope()->setAttribute(sym,Varnode::namelock|Varnode::typelock);
}
@@ -1411,6 +1414,7 @@ void IfcRetype::execute(istream &s)
if (sym->getCategory()==Symbol::function_parameter)
dcp->fd->getFuncProto().setInputLock(true);
dcp->fd->remapConflictSymbol(sym);
sym->getScope()->retypeSymbol(sym,ct);
sym->getScope()->setAttribute(sym,Varnode::typelock);
if ((newname.size()!=0)&&(newname != name)) {
@@ -1525,7 +1529,7 @@ void IfaceDecompData::readSymbol(const string &name,vector<Symbol *> &res)
{
Scope *scope = (fd == (Funcdata *)0) ? conf->symboltab->getGlobalScope() : fd->getScopeLocal();
string basename;
scope = conf->symboltab->resolveScopeFromSymbolName(name, "::", basename, scope);
scope = conf->symboltab->resolveScopeFromSymbolName(name, basename, scope);
if (scope == (Scope *)0)
throw IfaceParseError("Bad namespace for symbol: " + name);
scope->queryByName(basename,res);
@@ -1856,12 +1860,12 @@ void IfcProtooverride::execute(istream &s)
PrototypePieces pieces;
parse_protopieces(pieces,s,dcp->conf); // Parse the prototype from stream
FuncProto *newproto = new FuncProto();
unique_ptr<FuncProto> newproto(new FuncProto());
// Make proto whose storage is internal, not backed by a real scope
newproto->setInternal(pieces.model,dcp->conf->types->getTypeVoid());
newproto->setPieces(pieces);
dcp->fd->getOverride().insertProtoOverride(callpoint,newproto);
dcp->fd->getOverride().insertProtoOverride(callpoint,newproto.release());
dcp->fd->clear(); // Clear any analysis (this leaves overrides intact)
}
@@ -1933,7 +1937,6 @@ void IfcFlowOverride::execute(istream &s)
{
int4 discard;
uint4 type;
string token;
if (dcp->fd == (Funcdata *)0)
@@ -1944,12 +1947,37 @@ void IfcFlowOverride::execute(istream &s)
s >> token;
if (token.size() == 0)
throw IfaceParseError("Missing override type");
type = Override::stringToType(token);
if (type == Override::NONE)
throw IfaceParseError("Bad override type");
dcp->fd->getOverride().insertFlowOverride(addr,type);
*status->optr << "Successfully added override" << endl;
dcp->fd->getOverride().insertFlowOverride(addr,token);
*status->optr << "Successfully added flow override" << endl;
}
/// \class IfcDestinationOverride
/// \brief Create an override changing a call destination: `override destination <address> <type> <destaddress>`
///
/// The override modifies a branching op-code at \<address\> to have particular destination address,
/// depending on the \<type\>.
/// - callind_call converts a CALLIND to CALL (with the destination address)
/// - callother_call converts a CALLOTHER to a CALL
/// - callother_branch converts a CALLOTHER to a BRANCH
/// - call_call converts a CALL to have the specified destination address
void IfcDestinationOverride::execute(istream &s)
{
int4 discard;
string token;
if (dcp->fd == (Funcdata *)0)
throw IfaceExecutionError("No function selected");
s >> ws;
Address addr( parse_machaddr(s,discard,*dcp->conf->types));
s >> token >> ws;
if (token.size() == 0)
throw IfaceParseError("Missing override type");
Address dest( parse_machaddr(s,discard,*dcp->conf->types));
dcp->fd->getOverride().insertDestinationOverride(addr, dest, token);
*status->optr << "Successfully added destination override" << endl;
}
/// \class IfcDeadcodedelay
@@ -2339,7 +2367,7 @@ void IfcPrintMap::execute(istream &s)
throw IfaceExecutionError("No load image");
if (name.size() != 0 || dcp->fd==(Funcdata *)0) {
string fullname = name + "::a"; // Add fake variable name
scope = dcp->conf->symboltab->resolveScopeFromSymbolName(fullname, "::", fullname, (Scope *)0);
scope = dcp->conf->symboltab->resolveScopeFromSymbolName(fullname, fullname, (Scope *)0);
}
else
scope = dcp->fd->getScopeLocal();
@@ -2671,6 +2699,55 @@ void IfcDuplicateHash::check(Funcdata *fd,ostream &s)
}
}
/// \class IfcFindVarnodeHash
/// \brief Find a Varnode in the current function given a hash and address
///
/// If a matching Varnode is found, info is displayed. Otherwise "Varnode not found" is displayed.
void IfcFindVarnodeHash::execute(istream &s)
{
if (dcp->conf == (Architecture *)0)
throw IfaceExecutionError("Image not loaded");
if (dcp->fd == (Funcdata *)0)
throw IfaceExecutionError("No function selected");
int4 size;
Address addr = parse_machaddr(s,size,*dcp->conf->types); // Read required address
uint8 hash = 0;
s >> ws >> hex >> hash;
DynamicHash dynamic;
Varnode *vn = dynamic.findVarnode(dcp->fd,addr,hash);
if (vn == (Varnode *)0)
*status->optr << "Varnode not found" << endl;
else {
vn->printInfo(*status->optr);
}
}
/// \class IfcFindOpHash
/// \brief Find a PcodeOp in the current function given a hash and address
///
/// If a matching PcodeOp is found, info is displayed. Otherwise "Op not found" is displayed.
void IfcFindOpHash::execute(istream &s)
{
if (dcp->conf == (Architecture *)0)
throw IfaceExecutionError("Image not loaded");
if (dcp->fd == (Funcdata *)0)
throw IfaceExecutionError("No function selected");
int4 size;
Address addr = parse_machaddr(s,size,*dcp->conf->types); // Read required address
uint8 hash = 0;
s >> ws >> hex >> hash;
DynamicHash dynamic;
PcodeOp *op = dynamic.findOp(dcp->fd,addr,hash);
if (op == (PcodeOp *)0)
*status->optr << "Op not found" << endl;
else {
op->printRaw(*status->optr);
*status->optr << endl;
}
}
/// \class IfcDuplicateHash
/// \brief Check for duplicate hashes in functions: `duplicate hash`
///
@@ -2987,7 +3064,7 @@ void IfcFixupApply::execute(istream &s)
throw IfaceExecutionError("Unknown fixup: " + fixupName);
string basename;
Scope *funcscope = dcp->conf->symboltab->resolveScopeFromSymbolName(funcName,"::",basename,(Scope *)0);
Scope *funcscope = dcp->conf->symboltab->resolveScopeFromSymbolName(funcName,basename,(Scope *)0);
if (funcscope == (Scope *)0)
throw IfaceExecutionError("Bad namespace: "+funcName);
Funcdata *fd = funcscope->queryFunction( basename ); // Is function already in database
@@ -405,6 +405,11 @@ public:
virtual void execute(istream &s);
};
class IfcDestinationOverride : public IfaceDecompCommand {
public:
virtual void execute(istream &s);
};
class IfcDeadcodedelay : public IfaceDecompCommand {
public:
virtual void execute(istream &s);
@@ -495,12 +500,21 @@ public:
virtual void execute(istream &s);
};
class IfcFindVarnodeHash : public IfaceDecompCommand {
public:
virtual void execute(istream &s);
};
class IfcFindOpHash : public IfaceDecompCommand {
public:
virtual void execute(istream &s);
};
class IfcDuplicateHash : public IfaceDecompCommand {
public:
virtual void execute(istream &s);
virtual void iterationCallback(Funcdata *fd);
static void check(Funcdata *fd,ostream &s); ///< Check for duplicate hashes in given function
};
class IfcCallGraphDump : public IfaceDecompCommand {
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -128,6 +128,7 @@ void IfaceTerm::readLine(string &line)
int4 escval;
int4 cursor,lastlen,i;
bool onecharecho;
bool history_up, history_down;
int4 hist;
string saveline;
@@ -136,6 +137,7 @@ void IfaceTerm::readLine(string &line)
hist = 0;
do {
onecharecho = false;
history_up = history_down = false;
lastlen = line.size();
val = sptr->get();
if (sptr->eof())
@@ -180,23 +182,10 @@ void IfaceTerm::readLine(string &line)
case 0x0c: // C-l
break;
case 0x0e: // C-n
if (hist >0) {
hist -= 1; // Get more recent history
if (hist>0)
getHistory(line,hist-1);
else
line = saveline;
cursor = line.size();
}
history_down = true;
break;
case 0x10: // C-p
if (hist < getHistorySize()) {
hist += 1; // Get more ancient history
if (hist==1)
saveline = line;
getHistory(line,hist-1);
cursor = line.size();
}
history_up = true;
break;
case 0x12: // C-r
break;
@@ -209,14 +198,20 @@ void IfaceTerm::readLine(string &line)
escval <<= 8;
escval += sptr->get();
switch(escval) {
case 0x4f44: // left arrow
if (cursor>0)
cursor -= 1;
break;
case 0x4f43: // right arrow
case 0x5b41: // up arrow
history_up = true;
break;
case 0x5b42: // down arrow
history_down = true;
break;
case 0x5b43: // right arrow
if (cursor<line.size())
cursor += 1;
break;
case 0x5b44: // left arrow
if (cursor>0)
cursor -= 1;
break;
}
break;
case 0x08:
@@ -230,6 +225,24 @@ void IfaceTerm::readLine(string &line)
onecharecho = true;
break;
}
if (history_down) {
if (hist >0) {
hist -= 1; // Get more recent history
if (hist>0)
getHistory(line,hist-1);
else
line = saveline;
cursor = line.size();
}
} else if (history_up) {
if (hist < getHistorySize()) {
hist += 1; // Get more ancient history
if (hist==1)
saveline = line;
getHistory(line,hist-1);
cursor = line.size();
}
}
if (onecharecho)
optr->put(val); // Echo most characters
else {
@@ -249,7 +262,7 @@ void IfaceTerm::pushScript(istream *iptr,const string &newprompt)
{
inputstack.push_back(sptr);
sptr = iptr;
IfaceStatus::pushScript(iptr,newprompt);
IfaceStatus::pushScript((istream *)0,newprompt);
}
void IfaceTerm::popScript(void)
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -33,6 +33,10 @@ InjectPayloadSleigh::~InjectPayloadSleigh(void)
delete tpl;
}
/// Create an empty payload in preparation for parsing the injection from a stream
/// \param src is a name or other description of the document to be parsed
/// \param nm is the name of the injection
/// \param tp is the type of injection
InjectPayloadSleigh::InjectPayloadSleigh(const string &src,const string &nm,int4 tp)
: InjectPayload(nm,tp)
{
@@ -63,8 +67,8 @@ void InjectPayloadSleigh::inject(InjectContext &context,PcodeEmit &emit) const
con.cacher.emit(con.baseaddr,&emit);
}
/// The content is read as raw p-code source
/// \param decoder is the XML stream decoder
/// The content is read as raw p-code source.
/// \param decoder is the stream decoder
void InjectPayloadSleigh::decodeBody(Decoder &decoder)
{
@@ -95,11 +99,18 @@ void InjectPayloadSleigh::printTemplate(ostream &s) const
tpl->encode(encoder,-1);
}
/// \brief Verify that storage locations passed in -con- match the restrictions set for a given payload
///
/// If the parsed injection does not match the restrictions, an exception is thrown.
/// \param con is the SLEIGH context established after parsing the injection
/// \param inputlist is the list of input parameters specified for the given payload
/// \param output is the list of output parameters specified for the given payload
/// \param source is a description or name for the payload document
void InjectPayloadSleigh::checkParameterRestrictions(InjectContextSleigh &con,
const vector<InjectParameter> &inputlist,
const vector<InjectParameter> &output,
const string &source)
{ // Verify that the storage locations passed in -con- match the restrictions set for this payload
{
if (inputlist.size() != con.inputlist.size())
throw LowlevelError("Injection parameter list has different number of parameters than p-code operation: "+source);
for(int4 i=0;i<inputlist.size();++i) {
@@ -116,11 +127,18 @@ void InjectPayloadSleigh::checkParameterRestrictions(InjectContextSleigh &con,
}
}
/// \brief Set-up operands in the parser state so that they pick up storage locations in InjectContext
///
/// \param con is context for the parser
/// \param walker is the parser state
/// \param inputlist is the input varnodes as described by the payload
/// \param output is the output varnodes as described by the payload
/// \param source is a description or name of the payload document
void InjectPayloadSleigh::setupParameters(InjectContextSleigh &con,ParserWalkerChange &walker,
const vector<InjectParameter> &inputlist,
const vector<InjectParameter> &output,
const string &source)
{ // Set-up operands in the parser state so that they pick up storage locations in InjectContext
{
checkParameterRestrictions(con,inputlist,output,source);
ParserContext *pos = walker.getParserContext();
for(int4 i=0;i<inputlist.size();++i) {
@@ -195,6 +213,11 @@ void InjectPayloadCallother::decode(Decoder &decoder)
decoder.closeElement(elemId);
}
/// \brief Constructor for use with decode
///
/// \param g is the Architecture owning the script
/// \param src is a description or name of the payload document
/// \param nm is the name of the script
ExecutablePcodeSleigh::ExecutablePcodeSleigh(Architecture *g,const string &src,const string &nm)
: ExecutablePcode(g,src,nm)
{
@@ -252,6 +275,25 @@ void ExecutablePcodeSleigh::printTemplate(ostream &s) const
tpl->encode(encoder,-1);
}
/// \brief Constructor for use with decode
///
/// \param g is the Architecture
/// \param base is original InjectPayload object whose dynamic payloads are being cached
InjectPayloadDynamic::InjectPayloadDynamic(Architecture *g,InjectPayload *base)
: InjectPayload(base->getName(),base->getType())
{
glb = g;
dynamic = true;
// Clone basic properties of the original payload
incidentalCopy = base->isIncidentalCopy();
paramshift = base->getParamShift();
for(int4 i=0;i<base->sizeInput();++i)
inputlist.push_back(base->getInput(i));
for(int4 i=0;i<base->sizeOutput();++i)
output.push_back(base->getOutput(i));
}
InjectPayloadDynamic::~InjectPayloadDynamic(void)
{
@@ -260,7 +302,11 @@ InjectPayloadDynamic::~InjectPayloadDynamic(void)
delete (*iter).second;
}
void InjectPayloadDynamic::decodeEntry(Decoder &decoder)
/// \brief Decode a specific p-code sequence and the context in which it applied
///
/// Decode the Address for a specific context and then elements for the specific p-code ops.
/// \param decoder is the stream to pull from
void InjectPayloadDynamic::decode(Decoder &decoder)
{
Address addr = Address::decode(decoder);
@@ -294,6 +340,39 @@ void InjectPayloadDynamic::inject(InjectContext &context,PcodeEmit &emit) const
decoder.closeElement(rootId);
}
ExecutablePcodeDynamic::ExecutablePcodeDynamic(Architecture *g,InjectPayload *base)
: ExecutablePcode(g,base->getSource(),base->getName())
{
dynamic = true;
dynamicPayload = new InjectPayloadDynamic(g,base);
// Clone basic properties of the original payload
incidentalCopy = base->isIncidentalCopy();
paramshift = base->getParamShift();
for(int4 i=0;i<base->sizeInput();++i)
inputlist.push_back(base->getInput(i));
for(int4 i=0;i<base->sizeOutput();++i)
output.push_back(base->getOutput(i));
}
ExecutablePcodeDynamic::~ExecutablePcodeDynamic(void)
{
delete dynamicPayload;
}
void ExecutablePcodeDynamic::inject(InjectContext &context,PcodeEmit &emit) const
{
dynamicPayload->inject(context,emit);
}
void ExecutablePcodeDynamic::decode(Decoder &decoder)
{
dynamicPayload->decode(decoder);
}
PcodeInjectLibrarySleigh::PcodeInjectLibrarySleigh(Architecture *g)
: PcodeInjectLibrary(g,g->translate->getUniqueStart(Translate::INJECT))
{
@@ -301,31 +380,42 @@ PcodeInjectLibrarySleigh::PcodeInjectLibrarySleigh(Architecture *g)
contextCache.glb = g;
}
int4 PcodeInjectLibrarySleigh::registerDynamicInject(InjectPayload *payload)
{
int4 id = injection.size();
injection.push_back(payload);
return id;
}
/// \brief Force a payload to be dynamic for debug purposes
/// \brief Decode a dynamic inject payload
///
/// Debug information may include inject information for payloads that aren't dynamic.
/// We substitute a dynamic payload so that analysis uses the debug info to inject, rather
/// than the hard-coded payload information.
/// \param injectid is the id of the payload to treat dynamic
/// \param decoder is the stream to read the dynamic injection from
/// \return the new dynamic payload object
InjectPayloadDynamic *PcodeInjectLibrarySleigh::forceDebugDynamic(int4 injectid)
InjectPayload *PcodeInjectLibrarySleigh::decodeDynamic(Decoder &decoder)
{
InjectPayload *oldPayload = injection[injectid];
InjectPayloadDynamic *newPayload = new InjectPayloadDynamic(glb,oldPayload->getName(),oldPayload->getType());
uint4 subId = decoder.openElement(ELEM_INJECT);
string name = decoder.readString(ATTRIB_NAME);
int4 type = decoder.readSignedInteger(ATTRIB_TYPE);
int4 id = getPayloadId(type,name);
if (id < 0 || id >= injection.size())
throw DecoderError("Invalid dynamic injection");
InjectPayload *oldPayload = injection[id];
InjectPayload *newPayload;
if (oldPayload->getType() == InjectPayload::EXECUTABLEPCODE_TYPE) {
newPayload = new ExecutablePcodeDynamic(glb,oldPayload);
}
else
newPayload = new InjectPayloadDynamic(glb,oldPayload);
injection[id] = newPayload;
delete oldPayload;
injection[injectid] = newPayload;
newPayload->decode(decoder);
decoder.closeElement(subId);
return newPayload;
}
/// \brief Convert SLEIGH syntax to p-code templates for the given InjectPayload
///
/// The payload \b parsestring must be populated with SLEIGH synatax.
/// The SLEIGH translator is used to parse the syntax and produce the
/// p-code templates that are then ready to be injected via InjectPayload::inject.
/// \param payload is the given InjectPayload
void PcodeInjectLibrarySleigh::parseInject(InjectPayload *payload)
{
@@ -338,7 +428,7 @@ void PcodeInjectLibrarySleigh::parseInject(InjectPayload *payload)
}
if (contextCache.pos == (ParserContext *)0) { // Make sure we have a context
contextCache.pos = new ParserContext((ContextCache *)0,(Translate *)0);
contextCache.pos->initialize(8,8,slgh->getConstantSpace());
contextCache.pos->initialize(slgh->getConstantSpace(),8);
}
PcodeSnippet compiler(slgh);
// compiler.clear(); // Not necessary unless we reuse
@@ -391,7 +481,7 @@ void PcodeInjectLibrarySleigh::registerInject(int4 injectid)
{
InjectPayload *payload = injection[injectid];
if (payload->isDynamic()) {
InjectPayload *sub = new InjectPayloadDynamic(glb,payload->getName(),payload->getType());
InjectPayload *sub = new InjectPayloadDynamic(glb,payload);
delete payload;
payload = sub;
injection[injectid] = payload;
@@ -423,17 +513,9 @@ void PcodeInjectLibrarySleigh::decodeDebug(Decoder &decoder)
{
uint4 elemId = decoder.openElement(ELEM_INJECTDEBUG);
for(;;) {
uint4 subId = decoder.openElement();
uint4 subId = decoder.peekElement();
if (subId != ELEM_INJECT) break;
string name = decoder.readString(ATTRIB_NAME);
int4 type = decoder.readSignedInteger(ATTRIB_TYPE);
int4 id = getPayloadId(type,name);
InjectPayloadDynamic *payload = dynamic_cast<InjectPayloadDynamic *>(getPayload(id));
if (payload == (InjectPayloadDynamic *)0) {
payload = forceDebugDynamic(id);
}
payload->decodeEntry(decoder);
decoder.closeElement(subId);
decodeDynamic(decoder);
}
decoder.closeElement(elemId);
}
@@ -4,15 +4,18 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// \file inject_sleigh.hh
/// \brief Implementation of p-code injection using the internal SLEIGH engine to build the p-code ops
#ifndef __INJECT_SLEIGH_HH__
#define __INJECT_SLEIGH_HH__
@@ -21,24 +24,30 @@
namespace ghidra {
/// \brief Context for performing injection using the SLEIGH engine
class InjectContextSleigh : public InjectContext {
public:
PcodeCacher cacher;
ParserContext *pos;
InjectContextSleigh(void) { pos = (ParserContext *)0; }
PcodeCacher cacher; ///< Cache of p-code data accumulated just prior to injection
ParserContext *pos; ///< Context for final parsing and emitting of p-code during injection
InjectContextSleigh(void) { pos = (ParserContext *)0; } ///< Constructor
virtual ~InjectContextSleigh(void);
virtual void encode(Encoder &encoder) const {} // We don't need this functionality for sleigh
virtual void encode(Encoder &encoder) const {} ///< We don't need this functionality for sleigh
};
/// \brief An injection payload built by the SLEIGH engine
///
/// The p-code ops for the injection are described using SLEIGH syntax.
/// This object can hold both the SLEIGH syntax as a string or the p-code templates
/// (VarnodeTpl and OpTpl) that are prepared for emitting the p-code for the injection.
class InjectPayloadSleigh : public InjectPayload {
friend class PcodeInjectLibrarySleigh;
ConstructTpl *tpl;
string parsestring;
string source;
ConstructTpl *tpl; ///< The VarnodeTpl and OpTpl objects prepared for injection
string parsestring; ///< SLEIGH syntax describing the injection p-code
string source; ///< A description of the document containing the SLEIGH syntax
protected:
void decodeBody(Decoder &decoder); ///< Parse the <body> tag
void decodeBody(Decoder &decoder); ///< Parse the \<body> tag
public:
InjectPayloadSleigh(const string &src,const string &nm,int4 tp);
InjectPayloadSleigh(const string &src,const string &nm,int4 tp); ///< Constructor for use with decode
virtual ~InjectPayloadSleigh(void);
virtual void inject(InjectContext &context,PcodeEmit &emit) const;
virtual void decode(Decoder &decoder);
@@ -52,24 +61,27 @@ public:
const string &source);
};
/// \brief An injection payload, described by SLEIGH, for replacing CALL ops to specific functions
class InjectPayloadCallfixup : public InjectPayloadSleigh {
vector<string> targetSymbolNames;
vector<string> targetSymbolNames; ///< Names (symbols) of specific functions to replace with \b this payload
public:
InjectPayloadCallfixup(const string &sourceName);
InjectPayloadCallfixup(const string &sourceName); ///< Constructor
virtual void decode(Decoder &decoder);
};
/// \brief An injection payload, described by SLEIGH, for replacing specific user (CALLOTHER) ops
class InjectPayloadCallother : public InjectPayloadSleigh {
public:
InjectPayloadCallother(const string &sourceName);
InjectPayloadCallother(const string &sourceName); ///< Constructor
virtual void decode(Decoder &decoder);
};
/// \brief A p-code snippet, described by SLEIGH, that can be executed as a script
class ExecutablePcodeSleigh : public ExecutablePcode {
friend class PcodeInjectLibrarySleigh;
protected:
string parsestring;
ConstructTpl *tpl;
string parsestring; ///< SLEIGH syntax describing the p-code snippet
ConstructTpl *tpl; ///< Parsed template objects (VarnodeTpl and OpTpl) ready for injection
public:
ExecutablePcodeSleigh(Architecture *g,const string &src,const string &nm);
virtual ~ExecutablePcodeSleigh(void);
@@ -78,31 +90,52 @@ protected:
virtual void printTemplate(ostream &s) const;
};
/// \brief A debugging placeholder for a payload that changes depending on context
///
/// Implemented as a simple map from an Address to an XML description of the p-code sequence to inject.
/// This is used internally by PcodeInjectLibrarySleigh in a debug environment to hold multiple payloads
/// for objects where InjectPayload::isDynamic() returns \b true.
class InjectPayloadDynamic : public InjectPayload {
Architecture *glb;
map<Address,Document *> addrMap; // Map from address to specific inject
Architecture *glb; ///< The architecture owning \b this payload
map<Address,Document *> addrMap; ///< Map from address to specific inject
public:
InjectPayloadDynamic(Architecture *g,const string &nm,int4 tp) : InjectPayload(nm,tp) { glb = g; dynamic = true; }
InjectPayloadDynamic(Architecture *g,InjectPayload *base);
virtual ~InjectPayloadDynamic(void);
void decodeEntry(Decoder &decoder);
virtual void inject(InjectContext &context,PcodeEmit &emit) const;
virtual void decode(Decoder &decoder) { throw LowlevelError("decode not supported for InjectPayloadDynamic"); }
virtual void decode(Decoder &decoder);
virtual void printTemplate(ostream &s) const { s << "dynamic"; }
virtual string getSource(void) const { return "dynamic"; }
};
/// \brief Dynamic form of executable p-code
///
/// The p-code script for the underlying ExecutablePcode is dynamically replaced.
/// This wraps a standard InjectPayloadDynamic and feeds its p-code inject to an emulator.
class ExecutablePcodeDynamic : public ExecutablePcode {
InjectPayloadDynamic *dynamicPayload; ///< Dynamic payload wrapped as executable
public:
ExecutablePcodeDynamic(Architecture *g,InjectPayload *base); ///< Constructor
virtual ~ExecutablePcodeDynamic(void);
virtual void inject(InjectContext &context,PcodeEmit &emit) const;
virtual void decode(Decoder &decoder);
virtual void printTemplate(ostream &s) const { s << "dynamic_executable"; }
};
/// \brief An implementation of an injection library using the internal SLEIGH engine to build payloads
///
/// Payloads from compiler specs and other sources are parsed as SLEIGH syntax and stored
/// internally as InjectPayloadSleigh objects.
class PcodeInjectLibrarySleigh : public PcodeInjectLibrary {
const SleighBase *slgh;
vector<OpBehavior *> inst;
InjectContextSleigh contextCache;
int4 registerDynamicInject(InjectPayload *payload);
InjectPayloadDynamic *forceDebugDynamic(int4 injectid);
const SleighBase *slgh; ///< The SLEIGH engine for parsing payloads
vector<OpBehavior *> inst; ///< P-code behaviors used for p-code scripts
InjectContextSleigh contextCache; ///< Reusable context for emitting p-code payloads
InjectPayload *decodeDynamic(Decoder &decoder);
void parseInject(InjectPayload *payload);
protected:
virtual int4 allocateInject(const string &sourceName,const string &name,int4 type);
virtual void registerInject(int4 injectid);
public:
PcodeInjectLibrarySleigh(Architecture *g);
PcodeInjectLibrarySleigh(Architecture *g); ///< Constructor
virtual void decodeDebug(Decoder &decoder);
virtual int4 manualCallFixup(const string &name,const string &snippetstring);
virtual int4 manualCallOtherFixup(const string &name,const string &outname,const vector<string> &inname,
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -145,8 +145,10 @@ void IfaceStatus::pushScript(const string &filename,const string &newprompt)
{
ifstream *s = new ifstream(filename.c_str());
if (!*s)
if (!*s) {
delete s;
throw IfaceParseError("Unable to open script file: "+filename);
}
pushScript(s,newprompt);
}
@@ -159,6 +161,10 @@ void IfaceStatus::pushScript(const string &filename,const string &newprompt)
void IfaceStatus::pushScript(istream *iptr,const string &newprompt)
{
if (iptr != (istream *)0) {
delete iptr;
throw IfaceExecutionError("Unable to read script from stream on this interface");
}
promptstack.push_back(prompt);
uint4 flags = 0;
if (errorisdone)
@@ -386,11 +386,11 @@ JumpValues *JumpValuesRangeDefault::clone(void) const
return res;
}
bool JumpModelTrivial::recoverModel(Funcdata *fd,PcodeOp *indop,uint4 matchsize,uint4 maxtablesize)
bool JumpModelTrivial::recoverModel(Funcdata *fd,PcodeOp *indop,const JumpModel *previous,uint4 maxtablesize)
{
size = indop->getParent()->sizeOut();
return ((size != 0)&&(size<=matchsize));
return ((size != 0)&&(size<=jumptable->numEntries()));
}
void JumpModelTrivial::buildAddresses(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable,
@@ -505,44 +505,58 @@ uintb JumpBasic::backup2Switch(Funcdata *fd,uintb output,Varnode *outvn,Varnode
return output;
}
/// If the Varnode has a restricted range due to masking via INT_AND, the maximum value of this range is returned.
/// Otherwise, 0 is returned, indicating that the Varnode can take all possible values.
/// \param vn is the given Varnode
/// \return the maximum value or 0
uintb JumpBasic::getMaxValue(Varnode *vn)
/// \param rng passes back the initial range
void JumpBasic::getInitialRange(Varnode *vn,CircleRange &rng) const
{
uintb maxValue = 0; // 0 indicates maximum possible value
if (!vn->isWritten())
return maxValue;
if (vn->isConstant()) {
rng = CircleRange(vn->getOffset(),vn->getSize());
return;
}
if (vn->isWritten() && vn->getDef()->isBoolOutput()) {
rng = CircleRange(0,2,1,1); // Only 0 or 1 possible
return;
}
int4 step = getStride(vn);
if (!vn->isWritten()) {
rng = CircleRange(0,0,vn->getSize(),step);
return;
}
if (jumptable->isPartial())
rng.setRange(0,0,vn->getSize(),step); // Don't restrict with non-zero mask if we restricted too far previously
else
rng.setRange(0,vn->getNZMask() + step, vn->getSize(),step);
PcodeOp *op = vn->getDef();
if (op->code() == CPUI_INT_AND) {
Varnode *constvn = op->getIn(1);
if (constvn->isConstant()) {
maxValue = coveringmask( constvn->getOffset() );
maxValue = (maxValue + 1) & calc_mask(vn->getSize());
Varnode *cvn = op->getIn(1);
if (cvn->isConstant()) {
CircleRange tmprange(0,cvn->getOffset()+step,vn->getSize(),step);
if (tmprange.getSize() < rng.getSize())
rng = tmprange;
}
}
else if (op->code() == CPUI_MULTIEQUAL) { // Its possible the AND is duplicated across multiple blocks
int4 i;
for(i=0;i<op->numInput();++i) {
Varnode *subvn = op->getIn(i);
if (!subvn->isWritten()) break;
PcodeOp *andOp = subvn->getDef();
if (andOp->code() != CPUI_INT_AND) break;
Varnode *constvn = andOp->getIn(1);
if (!constvn->isConstant()) break;
if (maxValue < constvn->getOffset())
maxValue = constvn->getOffset();
else if (op->code() == CPUI_INT_REM) {
Varnode *cvn = op->getIn(1);
if (cvn->isConstant()) {
CircleRange tmprange(0,cvn->getOffset(),vn->getSize(),step);
if (tmprange.getSize() < rng.getSize())
rng = tmprange;
}
}
else if (op->code() == CPUI_INT_SREM) {
Varnode *cvn = op->getIn(1);
if (cvn->isConstant()) {
uintb val = cvn->getOffset();
if (signbit_negative(val, cvn->getSize())) {
val = uintb_negate(val,cvn->getSize());
val += 1;
}
CircleRange tmprange(-val+step,val,vn->getSize(),step);
if (tmprange.getSize() < rng.getSize())
rng = tmprange;
}
if (i == op->numInput()) {
maxValue = coveringmask( maxValue );
maxValue = (maxValue + 1) & calc_mask(vn->getSize());
}
else
maxValue = 0;
}
return maxValue;
}
/// \brief Calculate the initial set of Varnodes that might be switch variables
@@ -721,8 +735,8 @@ Varnode *GuardRecord::quasiCopy(Varnode *vn,int4 &bitsPreserved)
{
bitsPreserved = mostsigbit_set(vn->getNZMask()) + 1;
if (bitsPreserved == 0) return vn;
uintb mask = 1;
mask <<= bitsPreserved;
uintb mask = 1 << 1;
mask <<= (bitsPreserved - 1);
mask -= 1;
PcodeOp *op = vn->getDef();
Varnode *constVn;
@@ -1030,6 +1044,21 @@ PcodeOp *PathMeld::getEarliestOp(int4 pos) const
return (PcodeOp *)0;
}
/// Search for a Varnode in the common path, prior to the given point, defined by a LOAD operation.
/// \param i is the given point in the path
/// \return \b true if a LOAD is present
bool PathMeld::isLoadInPath(int4 i) const
{
while(i > 0) {
i -= 1;
Varnode *vn = commonVn[i];
if (!vn->isWritten()) continue;
if (vn->getDef()->code() == CPUI_LOAD) return true;
}
return false;
}
/// \brief Analyze CBRANCHs leading up to the given basic-block as a potential switch \e guard.
///
/// In general there is only one path to the switch, and the given basic-block will
@@ -1120,17 +1149,7 @@ void JumpBasic::analyzeGuards(BlockBasic *bl,int4 pathout)
void JumpBasic::calcRange(Varnode *vn,CircleRange &rng) const
{
// Get an initial range, based on the size/type of -vn-
int4 stride = 1;
if (vn->isConstant())
rng = CircleRange(vn->getOffset(),vn->getSize());
else if (vn->isWritten() && vn->getDef()->isBoolOutput())
rng = CircleRange(0,2,1,1); // Only 0 or 1 possible
else { // Should we go ahead and use nzmask in all cases?
uintb maxValue = getMaxValue(vn);
stride = getStride(vn);
rng = CircleRange(0,maxValue,vn->getSize(),stride);
}
getInitialRange(vn,rng);
// Intersect any guard ranges which apply to -vn-
int4 bitsPreserved;
@@ -1148,47 +1167,73 @@ void JumpBasic::calcRange(Varnode *vn,CircleRange &rng) const
// in which case the guard might not check for it. If the
// size is too big, we try only positive values
if (rng.getSize() > 0x10000) {
CircleRange positive(0,(rng.getMask()>>1)+1,vn->getSize(),stride);
CircleRange positive(0,(rng.getMask()>>1)+1,vn->getSize(),rng.getStep());
positive.intersect(rng);
if (!positive.isEmpty())
rng = positive;
}
}
/// \brief Return \b true if the \b newRange is preferred over the current range
///
/// If the ranges are equal keep the old. Prefer a range with a smaller step,min,or size.
/// \param pos is the position of Varnode associated with the \b newRange
/// \param newRange is the new range
/// \return \b true if the new range is preferred
bool JumpBasic::isPreferredRange(int4 pos,const CircleRange &newRange)
{
const CircleRange &oldRange(jrange->getRange());
if (oldRange.getStep() != newRange.getStep())
return (newRange.getStep() < oldRange.getStep());
if (oldRange.getMin() != newRange.getMin())
return (newRange.getMin() < oldRange.getMin());
int4 oldSize = pathMeld.getVarnode(varnodeIndex)->getSize();
int4 newSize = pathMeld.getVarnode(pos)->getSize();
return (newSize < oldSize);
}
/// \brief Find the putative switch variable with the smallest range of values reaching the switch
///
/// The Varnode with the smallest range and closest to the BRANCHIND is assumed to be the normalized
/// switch variable. If an expected range size is provided, it is used to \e prefer a particular
/// Varnode as the switch variable. Whatever Varnode is selected,
/// the JumpValue object is set up to iterator over its range.
/// \param matchsize optionally gives an expected size of the range, or it can be 0
void JumpBasic::findSmallestNormal(uint4 matchsize)
/// \param previous (if not NULL) is a previously recovered model for the same switch
void JumpBasic::findSmallestNormal(const JumpBasic *previous)
{
CircleRange rng;
CircleRange expectedRange;
uintb sz,maxsize;
if (previous != (const JumpBasic *)0 && previous->jrange != (JumpValuesRange *)0) {
expectedRange = previous->jrange->getRange();
}
varnodeIndex = 0;
calcRange(pathMeld.getVarnode(0),rng);
jrange->setRange(rng);
jrange->setStartVn(pathMeld.getVarnode(0));
jrange->setStartOp(pathMeld.getOp(0));
jrange->setRange(rng,pathMeld.getVarnode(0),pathMeld.getOp(0));
maxsize = rng.getSize();
for(uint4 i=1;i<pathMeld.numCommonVarnode();++i) {
if (maxsize == matchsize) // Found variable that gives (already recovered) size
if (rng == expectedRange) // Found variable that gives (already recovered) range
return;
calcRange(pathMeld.getVarnode(i),rng);
sz = rng.getSize();
if (sz < maxsize) {
// Don't let a 1-byte switch variable get thru without a guard
if ((sz != 256)||(pathMeld.getVarnode(i)->getSize()!=1)) {
varnodeIndex = i;
maxsize = sz;
jrange->setRange(rng);
jrange->setStartVn(pathMeld.getVarnode(i));
jrange->setStartOp(pathMeld.getEarliestOp(i));
}
if (sz > maxsize) continue;
if (sz == maxsize) { // If range sizes are the same
if (!isPreferredRange(i, rng)) // Prefer a smaller step, min, or size
continue;
}
varnodeIndex = i;
maxsize = sz;
jrange->setRange(rng,pathMeld.getVarnode(i),pathMeld.getEarliestOp(i));
}
if (maxsize == 256 && pathMeld.getVarnode(varnodeIndex)->getSize()==1 && !pathMeld.isLoadInPath(varnodeIndex)) {
// Don't accept a 1-byte switch variable unless there is an explicit guard
// or a table lookup between the byte and the indirect jump.
// "goto *(#const + byteVar)" should not be interpreted as 256 case switch
rng.setFull(pathMeld.getVarnode(0)->getSize());
jrange->setRange(rng,pathMeld.getVarnode(0),pathMeld.getOp(0));
}
}
@@ -1199,15 +1244,15 @@ void JumpBasic::findSmallestNormal(uint4 matchsize)
/// \param fd is the function containing the switch
/// \param rootbl is the basic-block
/// \param pathout is the (optional) path to the BRANCHIND or -1
/// \param matchsize is an (optional) size to expect for the normalized switch variable range
/// \param previous is an (optional) previous model to compare with (or NULL)
/// \param maxtablesize is the maximum size expected for the normalized switch variable range
void JumpBasic::findNormalized(Funcdata *fd,BlockBasic *rootbl,int4 pathout,uint4 matchsize,uint4 maxtablesize)
void JumpBasic::findNormalized(Funcdata *fd,BlockBasic *rootbl,int4 pathout,const JumpModel *previous,uint4 maxtablesize)
{
uintb sz;
analyzeGuards(rootbl,pathout);
findSmallestNormal(matchsize);
findSmallestNormal(dynamic_cast<const JumpBasic *>(previous));
sz = jrange->getSize();
if ((sz > maxtablesize)&&(pathMeld.numCommonVarnode()==1)) {
// Check for jump through readonly variable
@@ -1225,9 +1270,7 @@ void JumpBasic::findNormalized(Funcdata *fd,BlockBasic *rootbl,int4 pathout,uint
MemoryImage mem(vn->getSpace(),4,16,glb->loader);
uintb val = mem.getValue(vn->getOffset(),vn->getSize());
varnodeIndex = 0;
jrange->setRange(CircleRange(val,vn->getSize()));
jrange->setStartVn(vn);
jrange->setStartOp(pathMeld.getOp(0));
jrange->setRange(CircleRange(val,vn->getSize()),vn,pathMeld.getOp(0));
}
}
}
@@ -1284,6 +1327,18 @@ bool JumpBasic::flowsOnlyToModel(Varnode *vn,PcodeOp *trailOp)
return true;
}
/// \param arr is the array of Varnodes
/// \return \b true if all elements are the same
bool JumpBasic::duplicateVarnodes(const vector<Varnode *> &arr)
{
Varnode *vn = arr[0];
for(int4 i=1;i<arr.size();++i) {
if (arr[i] != vn) return false;
}
return true;
}
/// All CBRANCHs in addition to flowing to the given block, must also flow to another common block,
/// and each boolean value must select between the given block and the common block in the same way.
/// If this flow exists, \b true is returned and the boolean Varnode inputs to each CBRANCH are passed back.
@@ -1338,9 +1393,14 @@ void JumpBasic::checkUnrolledGuard(BlockBasic *bl,int4 maxpullback,bool usenzmas
int4 indpathstore = bl->getIn(0)->getFlipPath() ? 1-indpath : indpath;
PcodeOp *readOp = cbranch;
for(int4 j=0;j<maxpullback;++j) {
PcodeOp *multiOp = bl->findMultiequal(varArray);
if (multiOp != (PcodeOp *)0) {
selectguards.push_back(GuardRecord(cbranch,readOp,indpathstore,rng,multiOp->getOut(),true));
if (duplicateVarnodes(varArray)) {
selectguards.push_back(GuardRecord(cbranch,readOp,indpathstore,rng,varArray[0],true));
}
else {
PcodeOp *multiOp = bl->findMultiequal(varArray);
if (multiOp != (PcodeOp *)0) {
selectguards.push_back(GuardRecord(cbranch,readOp,indpathstore,rng,multiOp->getOut(),true));
}
}
Varnode *markup; // Throw away markup information
Varnode *vn = varArray[0];
@@ -1398,7 +1458,7 @@ JumpBasic::~JumpBasic(void)
delete jrange;
}
bool JumpBasic::recoverModel(Funcdata *fd,PcodeOp *indop,uint4 matchsize,uint4 maxtablesize)
bool JumpBasic::recoverModel(Funcdata *fd,PcodeOp *indop,const JumpModel *previous,uint4 maxtablesize)
{
// Basically there needs to be a straight line calculation from a switch variable to the final
@@ -1407,7 +1467,7 @@ bool JumpBasic::recoverModel(Funcdata *fd,PcodeOp *indop,uint4 matchsize,uint4 m
// location.
jrange = new JumpValuesRange();
findDeterminingVarnodes(indop,0);
findNormalized(fd,indop->getParent(),-1,matchsize,maxtablesize);
findNormalized(fd,indop->getParent(),-1,previous,maxtablesize);
if (jrange->getSize() > maxtablesize)
return false;
markFoldableGuards();
@@ -1643,7 +1703,7 @@ void JumpBasic2::initializeStart(const PathMeld &pMeld)
origPathMeld.set(pMeld);
}
bool JumpBasic2::recoverModel(Funcdata *fd,PcodeOp *indop,uint4 matchsize,uint4 maxtablesize)
bool JumpBasic2::recoverModel(Funcdata *fd,PcodeOp *indop,const JumpModel *previous,uint4 maxtablesize)
{ // Try to recover a jumptable using the second model
// Basically there is a guard on the main switch variable,
@@ -1685,7 +1745,7 @@ bool JumpBasic2::recoverModel(Funcdata *fd,PcodeOp *indop,uint4 matchsize,uint4
jdef->setDefaultOp(origPathMeld.getOp(origPathMeld.numOps()-1));
findDeterminingVarnodes(multiop,1-path);
findNormalized(fd,rootbl,pathout,matchsize,maxtablesize);
findNormalized(fd,rootbl,pathout,previous,maxtablesize);
if (jrange->getSize() > maxtablesize)
return false; // We didn't find a good range
@@ -1932,7 +1992,7 @@ void JumpBasicOverride::clearCopySpecific(void)
switchvn = (Varnode *)0;
}
bool JumpBasicOverride::recoverModel(Funcdata *fd,PcodeOp *indop,uint4 matchsize,uint4 maxtablesize)
bool JumpBasicOverride::recoverModel(Funcdata *fd,PcodeOp *indop,const JumpModel *previous,uint4 maxtablesize)
{
clearCopySpecific();
@@ -2071,7 +2131,7 @@ void JumpBasicOverride::decode(Decoder &decoder)
throw LowlevelError("Empty jumptable override");
}
bool JumpAssisted::recoverModel(Funcdata *fd,PcodeOp *indop,uint4 matchsize,uint4 maxtablesize)
bool JumpAssisted::recoverModel(Funcdata *fd,PcodeOp *indop,const JumpModel *previous,uint4 maxtablesize)
{
// Look for the special "jumpassist" pseudo-op
@@ -2103,7 +2163,7 @@ bool JumpAssisted::recoverModel(Funcdata *fd,PcodeOp *indop,uint4 matchsize,uint
inputs.push_back(assistOp->getIn(i+1)->getOffset());
sizeIndices = pcodeScript->evaluate(inputs);
}
if (matchsize !=0 && matchsize-1 != sizeIndices) // matchsize has 1 added to it for the default case
if (previous != (const JumpModel *)0 && previous->getTableSize()-1 != sizeIndices) // table size has 1 added to it for the default case
return false; // Not matching the size we saw previously
if (sizeIndices > maxtablesize)
return false;
@@ -2232,14 +2292,16 @@ void JumpTable::clearSavedModel(void)
}
}
/// Try to recover each model in turn, until we find one that matches the specific BRANCHIND.
/// Try to recover each model in turn, until we find one that matches data-flow around the specific BRANCHIND.
/// \param fd is the function containing the switch
void JumpTable::recoverModel(Funcdata *fd)
/// \param matchModel (if not NULL) is a previously calculated model that we are trying to match
void JumpTable::recoverModel(Funcdata *fd,const JumpModel *matchModel)
{
uint4 maxTableSize = fd->getArch()->max_jumptable_size;
if (jmodel != (JumpModel *)0) {
if (jmodel->isOverride()) { // If preexisting model is override
jmodel->recoverModel(fd,indirect,0,glb->max_jumptable_size);
jmodel->recoverModel(fd,indirect,(const JumpModel *)0,maxTableSize);
return;
}
delete jmodel; // Otherwise this is an old attempt we should remove
@@ -2250,23 +2312,43 @@ void JumpTable::recoverModel(Funcdata *fd)
if (op->code() == CPUI_CALLOTHER) {
JumpAssisted *jassisted = new JumpAssisted(this);
jmodel = jassisted;
if (jmodel->recoverModel(fd,indirect,addresstable.size(),glb->max_jumptable_size))
if (jmodel->recoverModel(fd,indirect,matchModel,maxTableSize))
return;
}
}
JumpBasic *jbasic = new JumpBasic(this);
jmodel = jbasic;
if (jmodel->recoverModel(fd,indirect,addresstable.size(),glb->max_jumptable_size))
if (jmodel->recoverModel(fd,indirect,matchModel,maxTableSize))
return;
jmodel = new JumpBasic2(this);
((JumpBasic2 *)jmodel)->initializeStart(jbasic->getPathMeld());
delete jbasic;
if (jmodel->recoverModel(fd,indirect,addresstable.size(),glb->max_jumptable_size))
if (jmodel->recoverModel(fd,indirect,matchModel,maxTableSize))
return;
delete jmodel;
jmodel = (JumpModel *)0;
}
/// If the function is just a sequence of absolute jumps ending in an indirect jump that recovers
/// to a single address, return \b true.
/// \param fd is the function to test
/// \return \b true if the function looks like a thunk
bool JumpTable::isThunk(Funcdata *fd) const
{
if (addresstable.size() != 1) return false;
Address addr = addresstable[0];
if (addr.getOffset()==0)
return true;
list<PcodeOp *>::const_iterator iter;
for(iter = fd->beginOpAlive(); iter != fd->endOpAlive(); ++iter) {
OpCode opc = (*iter)->code();
if (opc != CPUI_BRANCHIND && opc != CPUI_BRANCH)
return false;
}
return true;
}
/// Check that the BRANCHIND is still reachable, if not throw JumptableNotReachableError.
/// Check pathological cases when there is only one address in the table, if we find
/// this, throw the JumptableThunkError. Let the model run its sanity check.
@@ -2284,24 +2366,8 @@ void JumpTable::sanityCheck(Funcdata *fd,vector<int4> *loadcounts)
if (!isReachable(indirect))
partialTable = true; // If the jumptable is not reachable, mark as incomplete
if (addresstable.size() == 1) { // One entry is likely some kind of thunk
bool isthunk = false;
uintb diff;
Address addr = addresstable[0];
if (addr.getOffset()==0)
isthunk = true;
else {
Address addr2 = indirect->getAddr();
diff = (addr.getOffset() < addr2.getOffset()) ?
(addr2.getOffset() - addr.getOffset()) :
(addr.getOffset() - addr2.getOffset());
if (diff > 0xffff)
isthunk = true;
}
if (isthunk) {
throw JumptableThunkError("Likely thunk");
}
}
if (isThunk(fd))
throw JumptableThunkError("Likely thunk");
if (!jmodel->sanityCheck(fd,indirect,addresstable,loadpoints,loadcounts)) {
ostringstream err;
err << "Jumptable at " << opaddress << " did not pass sanity check.";
@@ -2358,21 +2424,18 @@ bool JumpTable::isReachable(PcodeOp *op)
return true;
}
/// \param g is the Architecture the table exists within
/// \param ad is the Address of the BRANCHIND \b this models
JumpTable::JumpTable(Architecture *g,Address ad)
JumpTable::JumpTable(Address ad)
: opaddress(ad)
{
glb = g;
jmodel = (JumpModel *)0;
origmodel = (JumpModel *)0;
indirect = (PcodeOp *)0;
switchVarConsume = ~((uintb)0);
defaultBlock = -1;
lastBlock = -1;
maxaddsub = 1;
maxleftright = 1;
maxext = 1;
recoverCount = 0;
displayFormat = 0;
partialTable = false;
collectloads = false;
defaultIsFolded = false;
@@ -2384,16 +2447,14 @@ JumpTable::JumpTable(Architecture *g,Address ad)
JumpTable::JumpTable(const JumpTable *op2)
{
glb = op2->glb;
jmodel = (JumpModel *)0;
origmodel = (JumpModel *)0;
indirect = (PcodeOp *)0;
switchVarConsume = ~((uintb)0);
defaultBlock = -1;
lastBlock = op2->lastBlock;
maxaddsub = op2->maxaddsub;
maxleftright = op2->maxleftright;
maxext = op2->maxext;
recoverCount = op2->recoverCount;
displayFormat = op2->displayFormat;
partialTable = op2->partialTable;
collectloads = op2->collectloads;
defaultIsFolded = false;
@@ -2452,11 +2513,11 @@ void JumpTable::setOverride(const vector<Address> &addrtable,const Address &nadd
if (jmodel != (JumpModel *)0)
delete jmodel;
JumpBasicOverride *override;
jmodel = override = new JumpBasicOverride(this);
override->setAddresses(addrtable);
override->setNorm(naddr,h);
override->setStartingValue(sv);
JumpBasicOverride *jumpOverride;
jmodel = jumpOverride = new JumpBasicOverride(this);
jumpOverride->setAddresses(addrtable);
jumpOverride->setNorm(naddr,h);
jumpOverride->setStartingValue(sv);
}
/// \brief Get the index of the i-th address table entry that corresponds to the given basic-block
@@ -2606,7 +2667,7 @@ void JumpTable::trivialSwitchOver(void)
void JumpTable::recoverAddresses(Funcdata *fd)
{
recoverModel(fd);
recoverModel(fd,(const JumpModel *)0);
if (jmodel == (JumpModel *)0) {
ostringstream err;
err << "Could not recover jumptable at " << opaddress << ". Too many branches";
@@ -2678,7 +2739,7 @@ void JumpTable::matchModel(Funcdata *fd)
fd->warning("Switch is manually overridden",opaddress);
}
}
recoverModel(fd); // Create a current instance of the model
recoverModel(fd,origmodel); // Create a current instance of the model (matching the previous model)
if (jmodel != (JumpModel *)0 && jmodel->getTableSize() != addresstable.size()) {
if ((addresstable.size()==1)&&(jmodel->getTableSize() > 1)) {
// The jumptable was not fully recovered during flow analysis, try to issue a restart
@@ -2709,7 +2770,7 @@ void JumpTable::recoverLabels(Funcdata *fd)
}
else {
jmodel = new JumpModelTrivial(this);
jmodel->recoverModel(fd,indirect,addresstable.size(),glb->max_jumptable_size);
jmodel->recoverModel(fd,indirect,origmodel,fd->getArch()->max_jumptable_size);
jmodel->buildAddresses(fd,indirect,addresstable,(vector<LoadTable> *)0,(vector<int4> *)0);
trivialSwitchOver();
jmodel->buildLabels(fd,addresstable,label,origmodel);
@@ -2737,8 +2798,9 @@ void JumpTable::clear(void)
indirect = (PcodeOp *)0;
switchVarConsume = ~((uintb)0);
defaultBlock = -1;
recoverCount = 0;
partialTable = false;
// -opaddress- -maxtablesize- -maxaddsub- -maxleftright- -maxext- -collectloads- are permanent
// -opaddress- -maxtablesize- -collectloads- are permanent
}
/// The recovered addresses and case labels are encode to the stream.
@@ -2751,6 +2813,8 @@ void JumpTable::encode(Encoder &encoder) const
throw LowlevelError("Trying to save unrecovered jumptable");
encoder.openElement(ELEM_JUMPTABLE);
if (displayFormat != 0)
encoder.writeUnsignedInteger(ATTRIB_FORMAT, displayFormat);
opaddress.encode(encoder);
for(int4 i=0;i<addresstable.size();++i) {
encoder.openElement(ELEM_DEST);
@@ -2780,6 +2844,8 @@ void JumpTable::decode(Decoder &decoder)
{
uint4 elemId = decoder.openElement(ELEM_JUMPTABLE);
if (decoder.getNextAttributeId() == ATTRIB_FORMAT)
displayFormat = decoder.readUnsignedInteger();
opaddress = Address::decode( decoder );
bool missedlabel = false;
for(;;) {
@@ -2833,6 +2899,7 @@ bool JumpTable::checkForMultistage(Funcdata *fd)
if (addresstable.size()!=1) return false;
if (partialTable) return false;
if (indirect == (PcodeOp *)0) return false;
if (recoverCount > 1) return false;
if (fd->getOverride().queryMultistageJumptable(indirect->getAddr())) {
partialTable = true; // Mark that we need additional recovery
@@ -21,6 +21,7 @@
#include "emulateutil.hh"
#include "rangeutil.hh"
#include "expression.hh"
namespace ghidra {
@@ -97,6 +98,7 @@ public:
Varnode *getOpParent(int4 i) const { return commonVn[ opMeld[i].rootVn ]; } ///< Get the split-point for the i-th PcodeOp
PcodeOp *getOp(int4 i) const { return opMeld[i].op; } ///< Get the i-th PcodeOp
PcodeOp *getEarliestOp(int4 pos) const; ///< Find \e earliest PcodeOp that has a specific common Varnode as input
bool isLoadInPath(int4 i) const; ///< Return \b true if a LOAD exists in the common path
bool empty(void) const { return commonVn.empty(); } ///< Return \b true if \b this container holds no paths
};
@@ -190,9 +192,9 @@ protected:
PcodeOp *startop; ///< First PcodeOp in the jump-table calculation
mutable uintb curval; ///< The current value pointed to be the iterator
public:
void setRange(const CircleRange &rng) { range = rng; } ///< Set the range of values explicitly
void setStartVn(Varnode *vn) { normqvn = vn; } ///< Set the normalized switch Varnode explicitly
void setStartOp(PcodeOp *op) { startop = op; } ///< Set the starting PcodeOp explicitly
/// \brief Set the range of values explicitly
void setRange(const CircleRange &rng,Varnode *vn,PcodeOp *op) { range = rng; normqvn = vn; startop = op; }
const CircleRange &getRange(void) const { return range; } ///< Get the full range of values
virtual void truncate(int4 nm);
virtual uintb getSize(void) const;
virtual bool contains(uintb val) const;
@@ -252,10 +254,10 @@ public:
/// This generally recovers the normalized switch variable and any guards.
/// \param fd is the function containing the switch
/// \param indop is the given BRANCHIND
/// \param matchsize is the expected number of address table entries to recover, or 0 for no expectation
/// \param previous (if not NULL) is a previous version of the model we are trying to match
/// \param maxtablesize is maximum number of address table entries to allow in the model
/// \return \b true if details of the model were successfully recovered
virtual bool recoverModel(Funcdata *fd,PcodeOp *indop,uint4 matchsize,uint4 maxtablesize)=0;
virtual bool recoverModel(Funcdata *fd,PcodeOp *indop,const JumpModel *previous,uint4 maxtablesize)=0;
/// \brief Construct the explicit list of target addresses (the Address Table) from \b this model
///
@@ -351,7 +353,7 @@ public:
JumpModelTrivial(JumpTable *jt) : JumpModel(jt) { size = 0; } ///< Construct given a parent JumpTable
virtual bool isOverride(void) const { return false; }
virtual int4 getTableSize(void) const { return size; }
virtual bool recoverModel(Funcdata *fd,PcodeOp *indop,uint4 matchsize,uint4 maxtablesize);
virtual bool recoverModel(Funcdata *fd,PcodeOp *indop,const JumpModel *previous,uint4 maxtablesize);
virtual void buildAddresses(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable,
vector<LoadTable> *loadpoints,vector<int4> *loadcounts) const;
virtual void findUnnormalized(uint4 maxaddsub,uint4 maxleftright,uint4 maxext) {}
@@ -381,12 +383,14 @@ protected:
static bool ispoint(Varnode *vn); ///< Is it possible for the given Varnode to be a switch variable?
static int4 getStride(Varnode *vn); ///< Get the step/stride associated with the Varnode
static uintb backup2Switch(Funcdata *fd,uintb output,Varnode *outvn,Varnode *invn);
static uintb getMaxValue(Varnode *vn); ///< Get maximum value associated with the given Varnode
static bool duplicateVarnodes(const vector<Varnode *> &arr); ///< Return \b true if all array elements are the same Varnode
void getInitialRange(Varnode *vn,CircleRange &rng) const; ///< Get initial range of values the given Varnode can take
void findDeterminingVarnodes(PcodeOp *op,int4 slot);
void analyzeGuards(BlockBasic *bl,int4 pathout);
void calcRange(Varnode *vn,CircleRange &rng) const;
void findSmallestNormal(uint4 matchsize);
void findNormalized(Funcdata *fd,BlockBasic *rootbl,int4 pathout,uint4 matchsize,uint4 maxtablesize);
bool isPreferredRange(int4 pos,const CircleRange &newRange);
void findSmallestNormal(const JumpBasic *previous);
void findNormalized(Funcdata *fd,BlockBasic *rootbl,int4 pathout,const JumpModel *previous,uint4 maxtablesize);
void markFoldableGuards();
void markModel(bool val); ///< Mark (or unmark) all PcodeOps involved in the model
bool flowsOnlyToModel(Varnode *vn,PcodeOp *trailOp); ///< Check if the given Varnode flows to anything other than \b this model
@@ -410,7 +414,7 @@ public:
virtual ~JumpBasic(void);
virtual bool isOverride(void) const { return false; }
virtual int4 getTableSize(void) const { return jrange->getSize(); }
virtual bool recoverModel(Funcdata *fd,PcodeOp *indop,uint4 matchsize,uint4 maxtablesize);
virtual bool recoverModel(Funcdata *fd,PcodeOp *indop,const JumpModel *previous,uint4 maxtablesize);
virtual void buildAddresses(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable,
vector<LoadTable> *loadpoints,vector<int4> *loadcounts) const;
virtual void findUnnormalized(uint4 maxaddsub,uint4 maxleftright,uint4 maxext);
@@ -443,7 +447,7 @@ class JumpBasic2 : public JumpBasic {
public:
JumpBasic2(JumpTable *jt) : JumpBasic(jt) {} ///< Constructor
void initializeStart(const PathMeld &pMeld); ///< Pass in the prior PathMeld calculation
virtual bool recoverModel(Funcdata *fd,PcodeOp *indop,uint4 matchsize,uint4 maxtablesize);
virtual bool recoverModel(Funcdata *fd,PcodeOp *indop,const JumpModel *previous,uint4 maxtablesize);
virtual void findUnnormalized(uint4 maxaddsub,uint4 maxleftright,uint4 maxext);
virtual JumpModel *clone(JumpTable *jt) const;
virtual void clear(void);
@@ -475,7 +479,7 @@ public:
void setStartingValue(uintb val) { startingvalue = val; } ///< Set the starting value for the normalized range
virtual bool isOverride(void) const { return true; }
virtual int4 getTableSize(void) const { return addrtable.size(); }
virtual bool recoverModel(Funcdata *fd,PcodeOp *indop,uint4 matchsize,uint4 maxtablesize);
virtual bool recoverModel(Funcdata *fd,PcodeOp *indop,const JumpModel *previous,uint4 maxtablesize);
virtual void buildAddresses(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable,
vector<LoadTable> *loadpoints,vector<int4> *loadcounts) const;
// findUnnormalized inherited from JumpBasic
@@ -514,7 +518,7 @@ public:
// virtual ~JumpAssisted(void);
virtual bool isOverride(void) const { return false; }
virtual int4 getTableSize(void) const { return sizeIndices+1; }
virtual bool recoverModel(Funcdata *fd,PcodeOp *indop,uint4 matchsize,uint4 maxtablesize);
virtual bool recoverModel(Funcdata *fd,PcodeOp *indop,const JumpModel *previous,uint4 maxtablesize);
virtual void buildAddresses(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable,
vector<LoadTable> *loadpoints,vector<int4> *loadcounts) const;
virtual void findUnnormalized(uint4 maxaddsub,uint4 maxleftright,uint4 maxext) {}
@@ -546,6 +550,9 @@ public:
fail_callother = 4 ///< Address formed by CALLOTHER
};
private:
static constexpr uint4 maxaddsub = 1; ///< Maximum ADDs or SUBs to normalize
static constexpr uint4 maxleftright = 1; ///< Maximum shifts to normalize
static constexpr uint4 maxext = 1; ///< Maximum extensions to normalize
/// \brief An address table index and its corresponding out-edge
struct IndexPair {
int4 blockPosition; ///< Out-edge index for the basic-block
@@ -554,7 +561,6 @@ private:
bool operator<(const IndexPair &op2) const; ///< Compare by position then by index
static bool compareByPosition(const IndexPair &op1,const IndexPair &op2); ///< Compare just by position
};
Architecture *glb; ///< Architecture under which this jump-table operates
JumpModel *jmodel; ///< Current model of how the jump table is implemented in code
JumpModel *origmodel; ///< Initial jump table model, which may be incomplete
vector<Address> addresstable; ///< Raw addresses in the jump-table
@@ -566,22 +572,22 @@ private:
uintb switchVarConsume; ///< Bits of the switch variable being consumed
int4 defaultBlock; ///< The out-edge corresponding to the \e default switch destination (-1 = undefined)
int4 lastBlock; ///< Block out-edge corresponding to last entry in the address table
uint4 maxaddsub; ///< Maximum ADDs or SUBs to normalize
uint4 maxleftright; ///< Maximum shifts to normalize
uint4 maxext; ///< Maximum extensions to normalize
int4 recoverCount; ///< Number of times recovery attempted on \b this table
uint4 displayFormat; ///< Display format for integer \e case values
bool partialTable; ///< Set to \b true if \b this table is incomplete and needs additional recovery steps
bool collectloads; ///< Set to \b true if information about in-memory model data is/should be collected
bool defaultIsFolded; ///< The \e default block is the target of a folded CBRANCH (and cannot have a label)
void saveModel(void); ///< Save off current model (if any) and prepare for instantiating a new model
void restoreSavedModel(void); ///< Restore any saved model as the current model
void clearSavedModel(void); ///< Clear any saved model
void recoverModel(Funcdata *fd); ///< Attempt recovery of the jump-table model
void recoverModel(Funcdata *fd,const JumpModel *matchModel); ///< Attempt recovery of the jump-table model
void trivialSwitchOver(void); ///< Switch \b this table over to a trivial model
bool isThunk(Funcdata *fd) const; ///< Return \b true if the function looks like a thunk
void sanityCheck(Funcdata *fd,vector<int4> *loadpoints); ///< Perform sanity check on recovered address targets
int4 block2Position(const FlowBlock *bl) const; ///< Convert a basic-block to an out-edge index from the switch.
static bool isReachable(PcodeOp *op); ///< Check if the given PcodeOp still seems reachable in its function
public:
JumpTable(Architecture *g,Address ad=Address()); ///< Constructor
JumpTable(Address ad=Address()); ///< Constructor
JumpTable(const JumpTable *op2); ///< Copy constructor
~JumpTable(void); ///< Destructor
bool isRecovered(void) const { return !addresstable.empty(); } ///< Return \b true if a model has been recovered
@@ -595,12 +601,14 @@ public:
const Address &getOpAddress(void) const { return opaddress; } ///< Get the address of the BRANCHIND for the switch
PcodeOp *getIndirectOp(void) const { return indirect; } ///< Get the BRANCHIND PcodeOp
void setIndirectOp(PcodeOp *ind) { opaddress = ind->getAddr(); indirect = ind; } ///< Set the BRANCHIND PcodeOp
void setNormMax(uint4 maddsub,uint4 mleftright,uint4 mext) {
maxaddsub = maddsub; maxleftright = mleftright; maxext = mext; } ///< Set the switch variable normalization model restrictions
uint4 getDisplayFormat(void) const { return displayFormat; } ///< Get the display format for integer cases
void setDisplayFormat(uint4 format) { displayFormat = format; } ///< Set the display format to use for integer case values
void setOverride(const vector<Address> &addrtable,const Address &naddr,uintb h,uintb sv);
int4 numIndicesByBlock(const FlowBlock *bl) const;
int4 getIndexByBlock(const FlowBlock *bl,int4 i) const;
Address getAddressByIndex(int4 i) const { return addresstable[i]; } ///< Get the i-th address table entry
int4 getRecoverCount(void) const { return recoverCount; } ///< Get number of times a recovery has been attempted
void incrementRecoveryCount(void) { recoverCount += 1; } ///< Record that another round of recovery is being attempted
void setLastAsDefault(void); ///< Set the \e default jump-table target to be the last address in the table
void setDefaultBlock(int4 bl) { defaultBlock = bl; } ///< Set out-edge of the switch destination considered to be \e default
void setLoadCollect(bool val) { collectloads = val; } ///< Set whether LOAD records should be collected
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -30,8 +30,6 @@ uint1 *LoadImage::load(int4 size,const Address &addr)
{
uint1 *buf = new uint1[ size ];
if (buf == (uint1 *)0)
throw LowlevelError("Out of memory");
loadFill(buf,size,addr);
return buf;
}
@@ -62,6 +60,7 @@ void RawLoadImage::open(void)
thefile = new ifstream(filename.c_str());
if (!(*thefile)) {
string errmsg = "Unable to open raw image file: "+filename;
delete thefile;
throw LowlevelError(errmsg);
}
thefile->seekg(0,ios::end);
@@ -455,6 +455,31 @@ OpCode XmlDecode::readOpcode(AttributeId &attribId)
return opc;
}
type_metatype XmlDecode::readDatatypeMeta(void)
{
const Element *el = elStack.back();
string nm = el->getAttributeValue(attributeIndex);
type_metatype meta = string2metatype(nm);
return meta;
}
type_metatype XmlDecode::readDatatypeMeta(AttributeId &attribId)
{
const Element *el = elStack.back();
string nm;
if (attribId == ATTRIB_CONTENT) {
nm = el->getContent();
}
else {
int4 index = findMatchingAttribute(el, attribId.getName());
nm = el->getAttributeValue(index);
}
type_metatype meta = string2metatype(nm);
return meta;
}
void XmlEncode::newLine(void)
{
@@ -597,6 +622,24 @@ void XmlEncode::writeOpcode(const AttributeId &attribId,OpCode opc)
outStream << "\"";
}
void XmlEncode::writeDatatypeMeta(const AttributeId &attribId,type_metatype metatype)
{
string name;
metatype2string(metatype, name);
if (attribId == ATTRIB_CONTENT) {
if (tagStatus == tag_start) {
outStream << '>';
}
outStream << name;
tagStatus = tag_content;
return;
}
outStream << ' ' << attribId.getName() << "=\"";
outStream << name;
outStream << "\"";
}
/// The integer is encoded, 7-bits per byte, starting with the most significant 7-bits.
/// The integer is decode from the \e current position, and the position is advanced.
/// \param len is the number of bytes to extract
@@ -648,7 +691,7 @@ void PackedDecode::skipAttribute(void)
uint1 attribType = typeByte >> TYPECODE_SHIFT;
if (attribType == TYPECODE_BOOLEAN || attribType == TYPECODE_SPECIALSPACE)
return; // has no additional data
uint4 length = readLengthCode(typeByte); // Length of data in bytes
uint8 length = readLengthCode(typeByte); // Length of data in bytes
if (attribType == TYPECODE_STRING) {
length = readInteger(length); // Read length field to get final length of string
}
@@ -664,7 +707,7 @@ void PackedDecode::skipAttributeRemaining(uint1 typeByte)
uint1 attribType = typeByte >> TYPECODE_SHIFT;
if (attribType == TYPECODE_BOOLEAN || attribType == TYPECODE_SPECIALSPACE)
return; // has no additional data
uint4 length = readLengthCode(typeByte); // Length of data in bytes
uint8 length = readLengthCode(typeByte); // Length of data in bytes
if (attribType == TYPECODE_STRING) {
length = readInteger(length); // Read length field to get final length of string
}
@@ -676,10 +719,8 @@ void PackedDecode::skipAttributeRemaining(uint1 typeByte)
void PackedDecode::endIngest(int4 bufPos)
{
endPos.seqIter = inStream.begin(); // Set position to beginning of stream
endPos.seqIter = inStream.begin(); // Set position to first buffer
if (endPos.seqIter != inStream.end()) {
endPos.current = (*endPos.seqIter).start;
endPos.end = (*endPos.seqIter).end;
// Make sure there is at least one character after ingested buffer
if (bufPos == BUFFER_SIZE) {
// Last buffer was entirely filled
@@ -689,6 +730,11 @@ void PackedDecode::endIngest(int4 bufPos)
}
uint1 *buf = inStream.back().start;
buf[bufPos] = ELEMENT_END;
inStream.back().end = buf + bufPos + 1;
endPos.current = (*endPos.seqIter).start; // Set position to start of buffer
endPos.end = (*endPos.seqIter).end;
} else {
throw DecoderError("Ended ingestion without any input");
}
}
@@ -961,11 +1007,10 @@ string PackedDecode::readString(void)
attributeRead = true;
throw DecoderError("Expecting string attribute");
}
int4 length = readLengthCode(typeByte);
length = readInteger(length);
uint8 length = readInteger(readLengthCode(typeByte));
attributeRead = true;
int4 curLen = curPos.end - curPos.current;
uint8 curLen = curPos.end - curPos.current;
if (curLen >= length) {
string res((const char *)curPos.current,length);
advancePosition(curPos, length);
@@ -1002,10 +1047,12 @@ AddrSpace *PackedDecode::readSpace(void)
getNextByte(curPos);
uint1 typeByte = getNextByte(curPos);
uint4 typeCode = typeByte >> TYPECODE_SHIFT;
int4 res;
AddrSpace *spc;
if (typeCode == TYPECODE_ADDRESSSPACE) {
res = readInteger(readLengthCode(typeByte));
uint8 res = readInteger(readLengthCode(typeByte));
if (res >= spcManager->numSpaces())
throw DecoderError("Invalid address space index");
spc = spcManager->getSpace(res);
if (spc == (AddrSpace *)0)
throw DecoderError("Unknown address space index");
@@ -1057,6 +1104,24 @@ OpCode PackedDecode::readOpcode(AttributeId &attribId)
return opc;
}
type_metatype PackedDecode::readDatatypeMeta(void)
{
int4 val = (int4)readSignedInteger();
if (val < 0 || val > TYPE_VOID)
throw DecoderError("Bad encoded metatype");
return (type_metatype)val;
}
type_metatype PackedDecode::readDatatypeMeta(AttributeId &attribId)
{
findMatchingAttribute(attribId);
type_metatype metatype = readDatatypeMeta();
curPos = startPos;
return metatype;
}
/// The value is either an unsigned integer, an address space index, or (the absolute value of) a signed integer.
/// A type header is passed in with the particular type code for the value already filled in.
/// This method then fills in the length code, outputs the full type header and the encoded bytes of the integer.
@@ -1176,18 +1241,28 @@ void PackedEncode::writeString(const AttributeId &attribId,const string &val)
{
uint8 length = val.length();
const char *ptr = val.c_str();
for(uint8 i=0;i<length;++i) {
if (ptr[i] == '\0')
throw LowlevelError("PackedEncode: string with null character");
}
writeHeader(ATTRIBUTE, attribId.getId());
writeInteger((TYPECODE_STRING << TYPECODE_SHIFT), length);
outStream.write(val.c_str(), length);
outStream.write(ptr, length);
}
void PackedEncode::writeStringIndexed(const AttributeId &attribId,uint4 index,const string &val)
{
uint8 length = val.length();
const char *ptr = val.c_str();
for(uint8 i=0;i<length;++i) {
if (ptr[i] == '\0')
throw LowlevelError("PackedEncode: string with null character");
}
writeHeader(ATTRIBUTE, attribId.getId() + index);
writeInteger((TYPECODE_STRING << TYPECODE_SHIFT), length);
outStream.write(val.c_str(), length);
outStream.write(ptr, length);
}
void PackedEncode::writeSpace(const AttributeId &attribId,const AddrSpace *spc)
@@ -1224,6 +1299,13 @@ void PackedEncode::writeOpcode(const AttributeId &attribId,OpCode opc)
writeInteger((TYPECODE_SIGNEDINT_POSITIVE << TYPECODE_SHIFT), opc);
}
void PackedEncode::writeDatatypeMeta(const AttributeId &attribId,type_metatype metatype)
{
writeHeader(ATTRIBUTE, attribId.getId());
writeInteger((TYPECODE_SIGNEDINT_POSITIVE << TYPECODE_SHIFT), metatype);
}
// Common attributes. Attributes with multiple uses
AttributeId ATTRIB_CONTENT = AttributeId("XMLcontent",1);
AttributeId ATTRIB_ALIGN = AttributeId("align",2);
@@ -1254,7 +1336,8 @@ AttributeId ATTRIB_WORDSIZE = AttributeId("wordsize",26);
AttributeId ATTRIB_STORAGE = AttributeId("storage",149);
AttributeId ATTRIB_STACKSPILL = AttributeId("stackspill",150);
AttributeId ATTRIB_UNKNOWN = AttributeId("XMLunknown",152); // Number serves as next open index
AttributeId ATTRIB_UNKNOWN = AttributeId("XMLunknown",161); // Number serves as next open index
ElementId ELEM_DATA = ElementId("data",1);
ElementId ELEM_INPUT = ElementId("input",2);
@@ -1267,6 +1350,6 @@ ElementId ELEM_VAL = ElementId("val",8);
ElementId ELEM_VALUE = ElementId("value",9);
ElementId ELEM_VOID = ElementId("void",10);
ElementId ELEM_UNKNOWN = ElementId("XMLunknown",288); // Number serves as next open index
ElementId ELEM_UNKNOWN = ElementId("XMLunknown",292); // Number serves as next open index
} // End namespace ghidra
@@ -18,6 +18,7 @@
#include "xml.hh"
#include "opcodes.hh"
#include "metatype.hh"
#include <list>
#include <unordered_map>
@@ -110,7 +111,6 @@ public:
/// Called once before any decoding. Currently this is assumed to make an internal copy of the stream data,
/// i.e. the input stream is cleared before any decoding takes place.
/// \param s is the given input stream to be decode
/// \return \b true if the stream was fully ingested
virtual void ingestStream(istream &s)=0;
/// \brief Peek at the next child element of the current parent, without traversing in (opening) it.
@@ -285,6 +285,21 @@ public:
/// \return the OpCode associated with the attribute
virtual OpCode readOpcode(AttributeId &attribId)=0;
/// \brief Parse the current attribute as a metatype
///
/// The last attribute, as returned by getNextAttributeId, is returned as a data-type metatype.
/// \return the metatype associated with the current attribute
virtual type_metatype readDatatypeMeta(void)=0;
/// \brief Find the specific attribute in the current element and return it as a metatype
///
/// Search attributes from the current element for a match to the given attribute id.
/// Return this attribute as a metatype. If there is no matching attribute id, an exception is thrown.
/// Parse via getNextAttributeId is reset.
/// \param attribId is the specific attribute id to match
/// \return the metatype associated with the attribute
virtual type_metatype readDatatypeMeta(AttributeId &attribId)=0;
/// \brief Skip parsing of the next element
///
/// The element skipped is the one that would be opened by the next call to openElement.
@@ -373,6 +388,11 @@ public:
/// \param opc is the opcode
virtual void writeOpcode(const AttributeId &attribId,OpCode opc)=0;
/// \brief Write a metatype into the encoding, associating it with the given attribute
///
/// \param attribId is the given attribute
/// \param metatype is the data-type metatype
virtual void writeDatatypeMeta(const AttributeId &attribId,type_metatype metatype)=0;
};
/// \brief An XML based decoder
@@ -418,6 +438,8 @@ public:
virtual AddrSpace *readSpace(const AttributeId &attribId);
virtual OpCode readOpcode(void);
virtual OpCode readOpcode(AttributeId &attribId);
virtual type_metatype readDatatypeMeta(void);
virtual type_metatype readDatatypeMeta(AttributeId &attribId);
};
/// \brief An XML based encoder
@@ -449,6 +471,7 @@ public:
virtual void writeStringIndexed(const AttributeId &attribId,uint4 index,const string &val);
virtual void writeSpace(const AttributeId &attribId,const AddrSpace *spc);
virtual void writeOpcode(const AttributeId &attribId,OpCode opc);
virtual void writeDatatypeMeta(const AttributeId &attribId,type_metatype metatype);
};
/// \brief Protocol format for PackedEncode and PackedDecode classes
@@ -536,7 +559,7 @@ private:
uint1 getByte(Position &pos) { return *pos.current; } ///< Get the byte at the current position, do not advance
uint1 getBytePlus1(Position &pos); ///< Get the byte following the current byte, do not advance position
uint1 getNextByte(Position &pos); ///< Get the byte at the current position and advance to the next byte
void advancePosition(Position &pos,int4 skip); ///< Advance the position by the given number of bytes
void advancePosition(Position &pos,uint8 skip); ///< Advance the position by the given number of bytes
uint8 readInteger(int4 len); ///< Read an integer from the \e current position given its length in bytes
uint4 readLengthCode(uint1 typeByte) { return ((uint4)typeByte & PackedFormat::LENGTHCODE_MASK); } ///< Extract length code from type byte
void findMatchingAttribute(const AttributeId &attribId); ///< Find attribute matching the given id in open element
@@ -571,6 +594,8 @@ public:
virtual AddrSpace *readSpace(const AttributeId &attribId);
virtual OpCode readOpcode(void);
virtual OpCode readOpcode(AttributeId &attribId);
virtual type_metatype readDatatypeMeta(void);
virtual type_metatype readDatatypeMeta(AttributeId &attribId);
};
/// \brief A byte-based encoder designed to marshal from the decompiler efficiently
@@ -591,6 +616,7 @@ public:
virtual void writeStringIndexed(const AttributeId &attribId,uint4 index,const string &val);
virtual void writeSpace(const AttributeId &attribId,const AddrSpace *spc);
virtual void writeOpcode(const AttributeId &attribId,OpCode opc);
virtual void writeDatatypeMeta(const AttributeId &attribId,type_metatype metatype);
};
/// An exception is thrown if the position currently points to the last byte in the stream
@@ -631,7 +657,7 @@ inline uint1 PackedDecode::getNextByte(Position &pos)
/// An exception is thrown of position is advanced past the end of the stream
/// \param pos is the position being advanced
/// \param skip is the number of bytes to advance
inline void PackedDecode::advancePosition(Position &pos,int4 skip)
inline void PackedDecode::advancePosition(Position &pos,uint8 skip)
{
while(pos.end - pos.current <= skip) {
@@ -416,7 +416,7 @@ PcodeOp *Merge::allocateCopyTrim(Varnode *inVn,const Address &addr,PcodeOp *trim
Datatype *ct = inVn->getType();
if (ct->needsResolution()) { // If the data-type needs resolution
if (inVn->isWritten()) {
int4 fieldNum = data.inheritResolution(ct, copyOp, -1, inVn->getDef(), -1);
int4 fieldNum = data.inheritUnionField(ct, copyOp, -1, inVn->getDef(), -1);
data.forceFacingType(ct, fieldNum, copyOp, 0);
}
else {
@@ -669,7 +669,7 @@ void Merge::trimOpOutput(PcodeOp *op)
copyop = data.newOp(1,op->getAddr());
data.opSetOpcode(copyop,CPUI_COPY);
if (ct->needsResolution()) {
int4 fieldNum = data.inheritResolution(ct, copyop, -1, op, -1);
int4 fieldNum = data.inheritUnionField(ct, copyop, -1, op, -1);
data.forceFacingType(ct, fieldNum, copyop, 0);
if (ct->getMetatype() == TYPE_PARTIALUNION)
ct = vn->getTypeDefFacing();
@@ -871,7 +871,7 @@ void Merge::mergeIndirect(PcodeOp *indop)
PcodeOp *newop = allocateCopyTrim(invn0, indop->getAddr(), indop);
SymbolEntry *entry = outvn->getSymbolEntry();
if (entry != (SymbolEntry *)0 && entry->getSymbol()->getType()->needsResolution()) {
data.inheritResolution(entry->getSymbol()->getType(), newop, -1, indop, -1);
data.inheritUnionField(entry->getSymbol()->getType(), newop, -1, indop, -1);
}
data.opSetInput(indop,newop->getOut(),0);
data.opInsertBefore(newop,indop);
@@ -1541,6 +1541,39 @@ void Merge::markInternalCopies(void)
#endif
}
/// \brief Mark COPYs to \e join space padding
///
/// Search for any COPY of #0 to a Varnode with an address marked a pure padding
/// and mark the COPY as \e non-printing.
void Merge::markPurePaddingCopies(void)
{
AddrSpaceManager *glb = data.getArch();
set<JoinRecord *,JoinRecordCompare>::const_iterator iter = glb->beginJoinPadding();
while(iter != glb->endJoin()) {
JoinRecord *joinRec = *iter;
if (!joinRec->isPurePadding()) break;
++iter;
Address addr = joinRec->getUnified().getAddr();
int4 size = joinRec->getUnified().size;
VarnodeLocSet::const_iterator viter = data.beginLoc(size,addr);
VarnodeLocSet::const_iterator venditer = data.endLoc(size,addr);
while(viter != venditer) {
Varnode *vn = *viter;
++viter;
if (vn->isWritten()) {
PcodeOp *copy = vn->getDef();
if (copy->code() == CPUI_COPY) {
Varnode *cvn = copy->getIn(0);
if (cvn->isConstant() && cvn->getOffset() == 0) {
data.opMarkNonPrinting(copy);
}
}
}
}
}
}
/// \brief Register an unmapped CONCAT stack with the merge process
///
/// The given Varnode must be the root of a tree of CPUI_PIECE operations as produced by
@@ -20,6 +20,7 @@
/// \brief Utilities for merging low-level Varnodes into high-level variables
#include "op.hh"
#include "expression.hh"
namespace ghidra {
@@ -131,6 +132,7 @@ public:
bool hideShadows(HighVariable *high);
void processCopyTrims(void);
void markInternalCopies(void);
void markPurePaddingCopies(void);
void registerProtoPartialRoot(Varnode *vn);
#ifdef MERGEMULTI_DEBUG
void verifyHighCovers(void);
@@ -0,0 +1,154 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "metatype.hh"
namespace ghidra {
/// Convert a type \b meta-type into the string name of the meta-type
/// \param metatype is the encoded type meta-type
/// \param res will hold the resulting string
void metatype2string(type_metatype metatype,string &res)
{
switch(metatype) {
case TYPE_VOID:
res = "void";
break;
case TYPE_PTR:
res = "ptr";
break;
case TYPE_PTRREL:
res = "ptrrel";
break;
case TYPE_ARRAY:
res = "array";
break;
case TYPE_PARTIALENUM:
res = "partenum";
break;
case TYPE_PARTIALSTRUCT:
res = "partstruct";
break;
case TYPE_PARTIALUNION:
res = "partunion";
break;
case TYPE_ENUM_INT:
res = "enum_int";
break;
case TYPE_ENUM_UINT:
res = "enum_uint";
break;
case TYPE_STRUCT:
res = "struct";
break;
case TYPE_UNION:
res = "union";
break;
case TYPE_SPACEBASE:
res = "spacebase";
break;
case TYPE_UNKNOWN:
res = "unknown";
break;
case TYPE_UINT:
res = "uint";
break;
case TYPE_INT:
res = "int";
break;
case TYPE_BOOL:
res = "bool";
break;
case TYPE_CODE:
res = "code";
break;
case TYPE_FLOAT:
res = "float";
break;
default:
throw LowlevelError("Unknown metatype");
}
}
/// Given a string description of a type \b meta-type. Return the meta-type.
/// \param metastring is the description of the meta-type
/// \return the encoded type meta-type
type_metatype string2metatype(const string &metastring)
{
switch(metastring[0]) {
case 'p':
if (metastring=="ptr")
return TYPE_PTR;
else if (metastring=="ptrrel")
return TYPE_PTRREL;
else if (metastring=="partunion")
return TYPE_PARTIALUNION;
else if (metastring=="partstruct")
return TYPE_PARTIALSTRUCT;
break;
case 'a':
if (metastring=="array")
return TYPE_ARRAY;
break;
case 'e':
if (metastring=="enum_int")
return TYPE_ENUM_INT;
else if (metastring == "enum_uint")
return TYPE_ENUM_UINT;
break;
case 's':
if (metastring=="struct")
return TYPE_STRUCT;
if (metastring=="spacebase")
return TYPE_SPACEBASE;
break;
case 'u':
if (metastring=="unknown")
return TYPE_UNKNOWN;
else if (metastring=="uint")
return TYPE_UINT;
else if (metastring=="union")
return TYPE_UNION;
break;
case 'i':
if (metastring == "int")
return TYPE_INT;
break;
case 'f':
if (metastring == "float")
return TYPE_FLOAT;
break;
case 'b':
if (metastring == "bool")
return TYPE_BOOL;
break;
case 'c':
if (metastring == "code")
return TYPE_CODE;
break;
case 'v':
if (metastring == "void")
return TYPE_VOID;
break;
default:
break;
}
throw LowlevelError("Unknown metatype: "+metastring);
}
} // End namespace ghidra
@@ -0,0 +1,57 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// \file metatype.hh
/// \brief Enumeration describing classes of data-types
#ifndef __METATYPE_HH__
#define __METATYPE_HH__
#include "error.hh"
namespace ghidra {
/// The core meta-types supported by the decompiler. These are sizeless templates
/// for the elements making up the type algebra. Index is important for Datatype::base2sub array.
enum type_metatype {
TYPE_VOID = 17, ///< Standard "void" type, absence of type
TYPE_SPACEBASE = 16, ///< Placeholder for symbol/type look-up calculations
TYPE_UNKNOWN = 15, ///< An unknown low-level type. Treated as an unsigned integer.
TYPE_INT = 14, ///< Signed integer. Signed is considered less specific than unsigned in C
TYPE_UINT = 13, ///< Unsigned integer
TYPE_BOOL = 12, ///< Boolean
TYPE_CODE = 11, ///< Data is actual executable code
TYPE_FLOAT = 10, ///< Floating-point
TYPE_PTR = 9, ///< Pointer data-type
TYPE_PTRREL = 8, ///< Pointer relative to another data-type (specialization of TYPE_PTR)
TYPE_ARRAY = 7, ///< Array data-type, made up of a sequence of "element" datatype
TYPE_ENUM_UINT = 6, ///< Unsigned enumeration data-type (specialization of TYPE_UINT)
TYPE_ENUM_INT = 5, ///< Signed enumeration data-type (specialization of TYPE_INT)
TYPE_STRUCT = 4, ///< Structure data-type, made up of component datatypes
TYPE_UNION = 3, ///< An overlapping union of multiple datatypes
TYPE_PARTIALENUM = 2, ///< Part of an enumerated value (specialization of TYPE_UINT)
TYPE_PARTIALSTRUCT = 1, ///< Part of a structure, stored separately from the whole
TYPE_PARTIALUNION = 0 ///< Part of a union
};
/// Convert type \b meta-type to name
extern void metatype2string(type_metatype metatype,string &res);
/// Convert string to type \b meta-type
extern type_metatype string2metatype(const string &metastring);
} // End namespace ghidra
#endif
Loaded 100 of 185 files, more files were not shown because too many files have changed in this diff. Show more