mirror of
https://github.com/radareorg/r2sleigh.git
synced 2026-11-07 06:36:00 -10:00
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:
1 parent
9386165cfb
commit
d7d966651c
185 files changed
+19532
-9485
No files matched your search
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
+345
-345
File diff suppressed because it is too large.
Load diff
@@ -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
@@ -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;
|
||||
|
||||
Vendored
+2
-1
@@ -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
|
||||
|
||||
+2
-8
@@ -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.
|
||||
|
||||
+94
-152
@@ -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
|
||||
+10
-22
@@ -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
|
||||
}
|
||||
|
||||
+4
-1
@@ -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
|
||||
///
|
||||
|
||||
+355
-7
@@ -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
|
||||
|
||||
+62
-3
@@ -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
|
||||
|
||||
|
||||
+39
-37
@@ -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;
|
||||
|
||||
+6
-20
@@ -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
|
||||
+7
-7
@@ -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)
|
||||
|
||||
+2418
File diff suppressed because it is too large.
Load diff
+268
@@ -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 ©,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
|
||||
+265
-97
@@ -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);
|
||||
}
|
||||
|
||||
+118
-36
@@ -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
|
||||
|
||||
+24
-23
@@ -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;
|
||||
|
||||
+6
-4
@@ -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);
|
||||
};
|
||||
|
||||
+5
-2
@@ -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
|
||||
|
||||
+6
-6
@@ -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;
|
||||
}
|
||||
|
||||
+144
-205
@@ -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)
|
||||
|
||||
+7
-19
@@ -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
|
||||
|
||||
+25
-30
@@ -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();
|
||||
|
||||
+118
-34
@@ -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())
|
||||
|
||||
+19
-5
@@ -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
|
||||
|
||||
+103
-19
@@ -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
|
||||
|
||||
+208
-123
@@ -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
|
||||
+771
-302
File diff suppressed because it is too large.
Load diff
+53
-50
@@ -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
|
||||
+4
-1
@@ -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) {
|
||||
|
||||
+3
-2
@@ -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
|
||||
|
||||
+499
-310
File diff suppressed because it is too large.
Load diff
+200
-129
@@ -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
|
||||
|
||||
+59
-28
@@ -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
|
||||
|
||||
+17
-19
@@ -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
|
||||
|
||||
+2
-3
@@ -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
|
||||
|
||||
+2
-4
@@ -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
|
||||
|
||||
|
||||
+5
-21
@@ -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);
|
||||
|
||||
-1
@@ -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);
|
||||
|
||||
+10
-28
@@ -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
|
||||
|
||||
+2
-3
@@ -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
|
||||
|
||||
+6
-2
@@ -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
|
||||
|
||||
+804
@@ -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
|
||||
+238
@@ -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
|
||||
+19
@@ -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
|
||||
|
||||
+2
@@ -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
|
||||
|
||||
|
||||
+49
-41
@@ -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
|
||||
|
||||
+12
-9
@@ -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 *> ¬reached);
|
||||
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);
|
||||
|
||||
+228
-251
@@ -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 ¶mtrial(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 ¶mtrial(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];
|
||||
|
||||
+42
-13
@@ -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);
|
||||
|
||||
+164
-52
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
+50
-24
@@ -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
|
||||
|
||||
+37
-15
@@ -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;
|
||||
|
||||
+270
-100
@@ -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
|
||||
|
||||
+181
-80
@@ -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");
|
||||
|
||||
+7
-10
@@ -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
|
||||
|
||||
+3
-7
@@ -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 ®name,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
|
||||
|
||||
+32
-31
@@ -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);
|
||||
|
||||
+8
-8
@@ -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
|
||||
|
||||
+435
-593
File diff suppressed because it is too large.
Load diff
+14
-8
@@ -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;
|
||||
|
||||
+36
-13
@@ -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;
|
||||
|
||||
+53
-47
@@ -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)
|
||||
|
||||
+2
@@ -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
|
||||
|
||||
+99
-22
@@ -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
|
||||
|
||||
+15
-1
@@ -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 {
|
||||
|
||||
+36
-23
@@ -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)
|
||||
|
||||
+115
-33
@@ -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);
|
||||
}
|
||||
|
||||
+60
-27
@@ -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,
|
||||
|
||||
+9
-3
@@ -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)
|
||||
|
||||
+186
-119
@@ -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
|
||||
|
||||
+29
-21
@@ -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
|
||||
|
||||
+3
-4
@@ -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);
|
||||
|
||||
+97
-14
@@ -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
|
||||
+29
-3
@@ -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) {
|
||||
|
||||
+36
-3
@@ -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
|
||||
|
||||
+2
@@ -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);
|
||||
|
||||
+154
@@ -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
|
||||
+57
@@ -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
Reference in new issue
Block a user