angr 9.2.192__cp311-cp311-macosx_10_12_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- angr/__init__.py +366 -0
- angr/__main__.py +182 -0
- angr/ail_callable.py +79 -0
- angr/ailment/__init__.py +83 -0
- angr/ailment/block.py +88 -0
- angr/ailment/block_walker.py +856 -0
- angr/ailment/constant.py +3 -0
- angr/ailment/converter_common.py +11 -0
- angr/ailment/converter_pcode.py +648 -0
- angr/ailment/converter_vex.py +829 -0
- angr/ailment/expression.py +1655 -0
- angr/ailment/manager.py +34 -0
- angr/ailment/statement.py +973 -0
- angr/ailment/tagged_object.py +58 -0
- angr/ailment/utils.py +114 -0
- angr/analyses/__init__.py +117 -0
- angr/analyses/analysis.py +429 -0
- angr/analyses/backward_slice.py +686 -0
- angr/analyses/binary_optimizer.py +670 -0
- angr/analyses/bindiff.py +1512 -0
- angr/analyses/boyscout.py +76 -0
- angr/analyses/callee_cleanup_finder.py +74 -0
- angr/analyses/calling_convention/__init__.py +6 -0
- angr/analyses/calling_convention/calling_convention.py +1113 -0
- angr/analyses/calling_convention/fact_collector.py +647 -0
- angr/analyses/calling_convention/utils.py +60 -0
- angr/analyses/cdg.py +189 -0
- angr/analyses/cfg/__init__.py +23 -0
- angr/analyses/cfg/cfb.py +451 -0
- angr/analyses/cfg/cfg.py +74 -0
- angr/analyses/cfg/cfg_arch_options.py +95 -0
- angr/analyses/cfg/cfg_base.py +2954 -0
- angr/analyses/cfg/cfg_emulated.py +3451 -0
- angr/analyses/cfg/cfg_fast.py +5431 -0
- angr/analyses/cfg/cfg_fast_soot.py +662 -0
- angr/analyses/cfg/cfg_job_base.py +203 -0
- angr/analyses/cfg/indirect_jump_resolvers/__init__.py +30 -0
- angr/analyses/cfg/indirect_jump_resolvers/aarch64_macho_got.py +77 -0
- angr/analyses/cfg/indirect_jump_resolvers/amd64_elf_got.py +62 -0
- angr/analyses/cfg/indirect_jump_resolvers/amd64_pe_iat.py +51 -0
- angr/analyses/cfg/indirect_jump_resolvers/arm_elf_fast.py +159 -0
- angr/analyses/cfg/indirect_jump_resolvers/const_resolver.py +339 -0
- angr/analyses/cfg/indirect_jump_resolvers/constant_value_manager.py +107 -0
- angr/analyses/cfg/indirect_jump_resolvers/default_resolvers.py +82 -0
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +2490 -0
- angr/analyses/cfg/indirect_jump_resolvers/memload_resolver.py +81 -0
- angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py +286 -0
- angr/analyses/cfg/indirect_jump_resolvers/mips_elf_got.py +148 -0
- angr/analyses/cfg/indirect_jump_resolvers/propagator_utils.py +46 -0
- angr/analyses/cfg/indirect_jump_resolvers/resolver.py +74 -0
- angr/analyses/cfg/indirect_jump_resolvers/syscall_resolver.py +92 -0
- angr/analyses/cfg/indirect_jump_resolvers/x86_elf_pic_plt.py +88 -0
- angr/analyses/cfg/indirect_jump_resolvers/x86_pe_iat.py +47 -0
- angr/analyses/cfg_slice_to_sink/__init__.py +11 -0
- angr/analyses/cfg_slice_to_sink/cfg_slice_to_sink.py +117 -0
- angr/analyses/cfg_slice_to_sink/graph.py +87 -0
- angr/analyses/cfg_slice_to_sink/transitions.py +27 -0
- angr/analyses/class_identifier.py +63 -0
- angr/analyses/code_tagging.py +123 -0
- angr/analyses/codecave.py +77 -0
- angr/analyses/complete_calling_conventions.py +475 -0
- angr/analyses/congruency_check.py +377 -0
- angr/analyses/data_dep/__init__.py +16 -0
- angr/analyses/data_dep/data_dependency_analysis.py +595 -0
- angr/analyses/data_dep/dep_nodes.py +171 -0
- angr/analyses/data_dep/sim_act_location.py +49 -0
- angr/analyses/datagraph_meta.py +105 -0
- angr/analyses/ddg.py +1670 -0
- angr/analyses/decompiler/__init__.py +41 -0
- angr/analyses/decompiler/ail_simplifier.py +2246 -0
- angr/analyses/decompiler/ailgraph_walker.py +49 -0
- angr/analyses/decompiler/block_io_finder.py +302 -0
- angr/analyses/decompiler/block_similarity.py +199 -0
- angr/analyses/decompiler/block_simplifier.py +397 -0
- angr/analyses/decompiler/callsite_maker.py +579 -0
- angr/analyses/decompiler/ccall_rewriters/__init__.py +9 -0
- angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +618 -0
- angr/analyses/decompiler/ccall_rewriters/rewriter_base.py +24 -0
- angr/analyses/decompiler/ccall_rewriters/x86_ccalls.py +354 -0
- angr/analyses/decompiler/clinic.py +3662 -0
- angr/analyses/decompiler/condition_processor.py +1323 -0
- angr/analyses/decompiler/counters/__init__.py +16 -0
- angr/analyses/decompiler/counters/boolean_counter.py +27 -0
- angr/analyses/decompiler/counters/call_counter.py +77 -0
- angr/analyses/decompiler/counters/expression_counters.py +77 -0
- angr/analyses/decompiler/counters/seq_cf_structure_counter.py +63 -0
- angr/analyses/decompiler/decompilation_cache.py +54 -0
- angr/analyses/decompiler/decompilation_options.py +317 -0
- angr/analyses/decompiler/decompiler.py +796 -0
- angr/analyses/decompiler/dephication/__init__.py +6 -0
- angr/analyses/decompiler/dephication/dephication_base.py +100 -0
- angr/analyses/decompiler/dephication/graph_dephication.py +70 -0
- angr/analyses/decompiler/dephication/graph_rewriting.py +112 -0
- angr/analyses/decompiler/dephication/graph_vvar_mapping.py +357 -0
- angr/analyses/decompiler/dephication/rewriting_engine.py +528 -0
- angr/analyses/decompiler/dephication/seqnode_dephication.py +156 -0
- angr/analyses/decompiler/dirty_rewriters/__init__.py +7 -0
- angr/analyses/decompiler/dirty_rewriters/amd64_dirty.py +74 -0
- angr/analyses/decompiler/dirty_rewriters/rewriter_base.py +27 -0
- angr/analyses/decompiler/empty_node_remover.py +212 -0
- angr/analyses/decompiler/expression_narrower.py +290 -0
- angr/analyses/decompiler/goto_manager.py +112 -0
- angr/analyses/decompiler/graph_region.py +441 -0
- angr/analyses/decompiler/jump_target_collector.py +37 -0
- angr/analyses/decompiler/jumptable_entry_condition_rewriter.py +67 -0
- angr/analyses/decompiler/label_collector.py +32 -0
- angr/analyses/decompiler/node_replacer.py +42 -0
- angr/analyses/decompiler/notes/__init__.py +9 -0
- angr/analyses/decompiler/notes/decompilation_note.py +48 -0
- angr/analyses/decompiler/notes/deobfuscated_strings.py +56 -0
- angr/analyses/decompiler/optimization_passes/__init__.py +164 -0
- angr/analyses/decompiler/optimization_passes/base_ptr_save_simplifier.py +157 -0
- angr/analyses/decompiler/optimization_passes/call_stmt_rewriter.py +46 -0
- angr/analyses/decompiler/optimization_passes/code_motion.py +362 -0
- angr/analyses/decompiler/optimization_passes/condition_constprop.py +211 -0
- angr/analyses/decompiler/optimization_passes/const_derefs.py +127 -0
- angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +365 -0
- angr/analyses/decompiler/optimization_passes/cross_jump_reverter.py +106 -0
- angr/analyses/decompiler/optimization_passes/deadblock_remover.py +82 -0
- angr/analyses/decompiler/optimization_passes/determine_load_sizes.py +64 -0
- angr/analyses/decompiler/optimization_passes/div_simplifier.py +425 -0
- angr/analyses/decompiler/optimization_passes/duplication_reverter/__init__.py +5 -0
- angr/analyses/decompiler/optimization_passes/duplication_reverter/ail_merge_graph.py +503 -0
- angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +1221 -0
- angr/analyses/decompiler/optimization_passes/duplication_reverter/errors.py +16 -0
- angr/analyses/decompiler/optimization_passes/duplication_reverter/similarity.py +126 -0
- angr/analyses/decompiler/optimization_passes/duplication_reverter/utils.py +167 -0
- angr/analyses/decompiler/optimization_passes/eager_std_string_concatenation.py +236 -0
- angr/analyses/decompiler/optimization_passes/eager_std_string_eval.py +186 -0
- angr/analyses/decompiler/optimization_passes/engine_base.py +502 -0
- angr/analyses/decompiler/optimization_passes/expr_op_swapper.py +138 -0
- angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +113 -0
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +618 -0
- angr/analyses/decompiler/optimization_passes/inlined_strlen_simplifier.py +274 -0
- angr/analyses/decompiler/optimization_passes/ite_expr_converter.py +224 -0
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +337 -0
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +939 -0
- angr/analyses/decompiler/optimization_passes/mod_simplifier.py +99 -0
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +710 -0
- angr/analyses/decompiler/optimization_passes/peephole_simplifier.py +75 -0
- angr/analyses/decompiler/optimization_passes/register_save_area_simplifier.py +263 -0
- angr/analyses/decompiler/optimization_passes/register_save_area_simplifier_adv.py +198 -0
- angr/analyses/decompiler/optimization_passes/ret_addr_save_simplifier.py +171 -0
- angr/analyses/decompiler/optimization_passes/ret_deduplicator.py +222 -0
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +632 -0
- angr/analyses/decompiler/optimization_passes/return_duplicator_high.py +61 -0
- angr/analyses/decompiler/optimization_passes/return_duplicator_low.py +166 -0
- angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +333 -0
- angr/analyses/decompiler/optimization_passes/static_vvar_rewriter.py +336 -0
- angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +166 -0
- angr/analyses/decompiler/optimization_passes/switch_reused_entry_rewriter.py +102 -0
- angr/analyses/decompiler/optimization_passes/tag_slicer.py +41 -0
- angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +477 -0
- angr/analyses/decompiler/optimization_passes/x86_gcc_getpc_simplifier.py +88 -0
- angr/analyses/decompiler/peephole_optimizations/__init__.py +136 -0
- angr/analyses/decompiler/peephole_optimizations/a_div_const_add_a_mul_n_div_const.py +42 -0
- angr/analyses/decompiler/peephole_optimizations/a_mul_const_div_shr_const.py +38 -0
- angr/analyses/decompiler/peephole_optimizations/a_mul_const_sub_a.py +34 -0
- angr/analyses/decompiler/peephole_optimizations/a_shl_const_sub_a.py +34 -0
- angr/analyses/decompiler/peephole_optimizations/a_sub_a_div.py +25 -0
- angr/analyses/decompiler/peephole_optimizations/a_sub_a_shr_const_shr_const.py +37 -0
- angr/analyses/decompiler/peephole_optimizations/a_sub_a_sub_n.py +23 -0
- angr/analyses/decompiler/peephole_optimizations/arm_cmpf.py +236 -0
- angr/analyses/decompiler/peephole_optimizations/base.py +157 -0
- angr/analyses/decompiler/peephole_optimizations/basepointeroffset_add_n.py +34 -0
- angr/analyses/decompiler/peephole_optimizations/basepointeroffset_and_mask.py +36 -0
- angr/analyses/decompiler/peephole_optimizations/bitwise_or_to_logical_or.py +34 -0
- angr/analyses/decompiler/peephole_optimizations/bool_expr_xor_1.py +27 -0
- angr/analyses/decompiler/peephole_optimizations/bswap.py +142 -0
- angr/analyses/decompiler/peephole_optimizations/cas_intrinsics.py +182 -0
- angr/analyses/decompiler/peephole_optimizations/cmpord_rewriter.py +71 -0
- angr/analyses/decompiler/peephole_optimizations/coalesce_adjacent_shrs.py +39 -0
- angr/analyses/decompiler/peephole_optimizations/coalesce_same_cascading_ifs.py +28 -0
- angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +44 -0
- angr/analyses/decompiler/peephole_optimizations/conv_a_sub0_shr_and.py +69 -0
- angr/analyses/decompiler/peephole_optimizations/conv_shl_shr.py +52 -0
- angr/analyses/decompiler/peephole_optimizations/eager_eval.py +436 -0
- angr/analyses/decompiler/peephole_optimizations/extended_byte_and_mask.py +56 -0
- angr/analyses/decompiler/peephole_optimizations/inlined_memcpy.py +78 -0
- angr/analyses/decompiler/peephole_optimizations/inlined_memset.py +262 -0
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +217 -0
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +106 -0
- angr/analyses/decompiler/peephole_optimizations/inlined_wcscpy.py +256 -0
- angr/analyses/decompiler/peephole_optimizations/inlined_wcscpy_consolidation.py +296 -0
- angr/analyses/decompiler/peephole_optimizations/invert_negated_logical_conjuction_disjunction.py +50 -0
- angr/analyses/decompiler/peephole_optimizations/modulo_simplifier.py +89 -0
- angr/analyses/decompiler/peephole_optimizations/one_sub_bool.py +33 -0
- angr/analyses/decompiler/peephole_optimizations/optimized_div_simplifier.py +356 -0
- angr/analyses/decompiler/peephole_optimizations/remove_cascading_conversions.py +45 -0
- angr/analyses/decompiler/peephole_optimizations/remove_cxx_destructor_calls.py +32 -0
- angr/analyses/decompiler/peephole_optimizations/remove_empty_if_body.py +46 -0
- angr/analyses/decompiler/peephole_optimizations/remove_noop_conversions.py +47 -0
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_bitmasks.py +125 -0
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +273 -0
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_derefs.py +21 -0
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_ite_branch.py +30 -0
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_ite_comparisons.py +54 -0
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_nots.py +36 -0
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_reinterprets.py +44 -0
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts.py +95 -0
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts_around_comparators.py +115 -0
- angr/analyses/decompiler/peephole_optimizations/rewrite_bit_extractions.py +85 -0
- angr/analyses/decompiler/peephole_optimizations/rewrite_conv_mul.py +40 -0
- angr/analyses/decompiler/peephole_optimizations/rewrite_cxx_operator_calls.py +90 -0
- angr/analyses/decompiler/peephole_optimizations/rewrite_mips_gp_loads.py +49 -0
- angr/analyses/decompiler/peephole_optimizations/rol_ror.py +130 -0
- angr/analyses/decompiler/peephole_optimizations/sar_to_signed_div.py +143 -0
- angr/analyses/decompiler/peephole_optimizations/shl_to_mul.py +25 -0
- angr/analyses/decompiler/peephole_optimizations/simplify_pc_relative_loads.py +51 -0
- angr/analyses/decompiler/peephole_optimizations/single_bit_cond_to_boolexpr.py +28 -0
- angr/analyses/decompiler/peephole_optimizations/single_bit_xor.py +29 -0
- angr/analyses/decompiler/peephole_optimizations/tidy_stack_addr.py +131 -0
- angr/analyses/decompiler/peephole_optimizations/utils.py +18 -0
- angr/analyses/decompiler/presets/__init__.py +22 -0
- angr/analyses/decompiler/presets/basic.py +36 -0
- angr/analyses/decompiler/presets/fast.py +66 -0
- angr/analyses/decompiler/presets/full.py +76 -0
- angr/analyses/decompiler/presets/malware.py +70 -0
- angr/analyses/decompiler/presets/preset.py +37 -0
- angr/analyses/decompiler/redundant_label_remover.py +141 -0
- angr/analyses/decompiler/region_identifier.py +1319 -0
- angr/analyses/decompiler/region_simplifiers/__init__.py +5 -0
- angr/analyses/decompiler/region_simplifiers/cascading_cond_transformer.py +95 -0
- angr/analyses/decompiler/region_simplifiers/cascading_ifs.py +82 -0
- angr/analyses/decompiler/region_simplifiers/expr_folding.py +838 -0
- angr/analyses/decompiler/region_simplifiers/goto.py +178 -0
- angr/analyses/decompiler/region_simplifiers/if_.py +135 -0
- angr/analyses/decompiler/region_simplifiers/ifelse.py +91 -0
- angr/analyses/decompiler/region_simplifiers/loop.py +143 -0
- angr/analyses/decompiler/region_simplifiers/node_address_finder.py +24 -0
- angr/analyses/decompiler/region_simplifiers/region_simplifier.py +270 -0
- angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +654 -0
- angr/analyses/decompiler/region_simplifiers/switch_expr_simplifier.py +87 -0
- angr/analyses/decompiler/region_walker.py +24 -0
- angr/analyses/decompiler/return_maker.py +72 -0
- angr/analyses/decompiler/semantic_naming/__init__.py +37 -0
- angr/analyses/decompiler/semantic_naming/array_index_naming.py +196 -0
- angr/analyses/decompiler/semantic_naming/boolean_naming.py +264 -0
- angr/analyses/decompiler/semantic_naming/call_result_naming.py +220 -0
- angr/analyses/decompiler/semantic_naming/naming_base.py +166 -0
- angr/analyses/decompiler/semantic_naming/orchestrator.py +107 -0
- angr/analyses/decompiler/semantic_naming/pointer_naming.py +334 -0
- angr/analyses/decompiler/semantic_naming/region_loop_counter_naming.py +246 -0
- angr/analyses/decompiler/semantic_naming/size_naming.py +137 -0
- angr/analyses/decompiler/seq_to_blocks.py +20 -0
- angr/analyses/decompiler/sequence_walker.py +261 -0
- angr/analyses/decompiler/ssailification/__init__.py +4 -0
- angr/analyses/decompiler/ssailification/rewriting.py +451 -0
- angr/analyses/decompiler/ssailification/rewriting_engine.py +1091 -0
- angr/analyses/decompiler/ssailification/rewriting_state.py +61 -0
- angr/analyses/decompiler/ssailification/ssailification.py +283 -0
- angr/analyses/decompiler/ssailification/traversal.py +127 -0
- angr/analyses/decompiler/ssailification/traversal_engine.py +323 -0
- angr/analyses/decompiler/ssailification/traversal_state.py +48 -0
- angr/analyses/decompiler/stack_item.py +36 -0
- angr/analyses/decompiler/structured_codegen/__init__.py +25 -0
- angr/analyses/decompiler/structured_codegen/base.py +193 -0
- angr/analyses/decompiler/structured_codegen/c.py +4257 -0
- angr/analyses/decompiler/structured_codegen/dummy.py +15 -0
- angr/analyses/decompiler/structured_codegen/dwarf_import.py +190 -0
- angr/analyses/decompiler/structuring/__init__.py +30 -0
- angr/analyses/decompiler/structuring/dream.py +1217 -0
- angr/analyses/decompiler/structuring/phoenix.py +3636 -0
- angr/analyses/decompiler/structuring/recursive_structurer.py +187 -0
- angr/analyses/decompiler/structuring/sailr.py +120 -0
- angr/analyses/decompiler/structuring/structurer_base.py +1140 -0
- angr/analyses/decompiler/structuring/structurer_nodes.py +442 -0
- angr/analyses/decompiler/utils.py +1224 -0
- angr/analyses/deobfuscator/__init__.py +23 -0
- angr/analyses/deobfuscator/api_obf_finder.py +333 -0
- angr/analyses/deobfuscator/api_obf_peephole_optimizer.py +80 -0
- angr/analyses/deobfuscator/api_obf_type2_finder.py +166 -0
- angr/analyses/deobfuscator/data_transformation_embedder.py +633 -0
- angr/analyses/deobfuscator/hash_lookup_api_deobfuscator.py +156 -0
- angr/analyses/deobfuscator/irsb_reg_collector.py +54 -0
- angr/analyses/deobfuscator/scope_ops_analyzer.py +68 -0
- angr/analyses/deobfuscator/string_obf_finder.py +983 -0
- angr/analyses/deobfuscator/string_obf_opt_passes.py +136 -0
- angr/analyses/deobfuscator/string_obf_peephole_optimizer.py +47 -0
- angr/analyses/disassembly.py +1351 -0
- angr/analyses/disassembly_utils.py +101 -0
- angr/analyses/dominance_frontier.py +57 -0
- angr/analyses/fcp/__init__.py +4 -0
- angr/analyses/fcp/fcp.py +427 -0
- angr/analyses/find_objects_static.py +205 -0
- angr/analyses/flirt/__init__.py +47 -0
- angr/analyses/flirt/consts.py +160 -0
- angr/analyses/flirt/flirt.py +249 -0
- angr/analyses/flirt/flirt_function.py +20 -0
- angr/analyses/flirt/flirt_matcher.py +352 -0
- angr/analyses/flirt/flirt_module.py +32 -0
- angr/analyses/flirt/flirt_node.py +23 -0
- angr/analyses/flirt/flirt_sig.py +359 -0
- angr/analyses/flirt/flirt_utils.py +31 -0
- angr/analyses/forward_analysis/__init__.py +12 -0
- angr/analyses/forward_analysis/forward_analysis.py +619 -0
- angr/analyses/forward_analysis/job_info.py +64 -0
- angr/analyses/forward_analysis/visitors/__init__.py +14 -0
- angr/analyses/forward_analysis/visitors/call_graph.py +29 -0
- angr/analyses/forward_analysis/visitors/function_graph.py +86 -0
- angr/analyses/forward_analysis/visitors/graph.py +242 -0
- angr/analyses/forward_analysis/visitors/loop.py +29 -0
- angr/analyses/forward_analysis/visitors/single_node_graph.py +38 -0
- angr/analyses/identifier/__init__.py +5 -0
- angr/analyses/identifier/custom_callable.py +137 -0
- angr/analyses/identifier/errors.py +10 -0
- angr/analyses/identifier/func.py +60 -0
- angr/analyses/identifier/functions/__init__.py +37 -0
- angr/analyses/identifier/functions/atoi.py +73 -0
- angr/analyses/identifier/functions/based_atoi.py +125 -0
- angr/analyses/identifier/functions/fdprintf.py +123 -0
- angr/analyses/identifier/functions/free.py +64 -0
- angr/analyses/identifier/functions/int2str.py +287 -0
- angr/analyses/identifier/functions/malloc.py +111 -0
- angr/analyses/identifier/functions/memcmp.py +67 -0
- angr/analyses/identifier/functions/memcpy.py +89 -0
- angr/analyses/identifier/functions/memset.py +43 -0
- angr/analyses/identifier/functions/printf.py +123 -0
- angr/analyses/identifier/functions/recv_until.py +312 -0
- angr/analyses/identifier/functions/skip_calloc.py +73 -0
- angr/analyses/identifier/functions/skip_realloc.py +97 -0
- angr/analyses/identifier/functions/skip_recv_n.py +105 -0
- angr/analyses/identifier/functions/snprintf.py +112 -0
- angr/analyses/identifier/functions/sprintf.py +116 -0
- angr/analyses/identifier/functions/strcasecmp.py +33 -0
- angr/analyses/identifier/functions/strcmp.py +113 -0
- angr/analyses/identifier/functions/strcpy.py +43 -0
- angr/analyses/identifier/functions/strlen.py +27 -0
- angr/analyses/identifier/functions/strncmp.py +104 -0
- angr/analyses/identifier/functions/strncpy.py +65 -0
- angr/analyses/identifier/functions/strtol.py +89 -0
- angr/analyses/identifier/identify.py +825 -0
- angr/analyses/identifier/runner.py +360 -0
- angr/analyses/init_finder.py +289 -0
- angr/analyses/loop_analysis/__init__.py +4 -0
- angr/analyses/loop_analysis/loop_analysis.py +464 -0
- angr/analyses/loop_analysis.py +349 -0
- angr/analyses/loop_unroller/__init__.py +4 -0
- angr/analyses/loop_unroller/loop_unroller.py +222 -0
- angr/analyses/loopfinder.py +171 -0
- angr/analyses/outliner/__init__.py +7 -0
- angr/analyses/outliner/outliner.py +402 -0
- angr/analyses/patchfinder.py +137 -0
- angr/analyses/pathfinder.py +282 -0
- angr/analyses/propagator/__init__.py +5 -0
- angr/analyses/propagator/engine_base.py +62 -0
- angr/analyses/propagator/engine_vex.py +297 -0
- angr/analyses/propagator/propagator.py +361 -0
- angr/analyses/propagator/top_checker_mixin.py +218 -0
- angr/analyses/propagator/values.py +117 -0
- angr/analyses/propagator/vex_vars.py +68 -0
- angr/analyses/proximity_graph.py +444 -0
- angr/analyses/purity/__init__.py +15 -0
- angr/analyses/purity/analysis.py +78 -0
- angr/analyses/purity/engine.py +593 -0
- angr/analyses/reaching_definitions/__init__.py +67 -0
- angr/analyses/reaching_definitions/call_trace.py +73 -0
- angr/analyses/reaching_definitions/dep_graph.py +433 -0
- angr/analyses/reaching_definitions/engine_ail.py +1128 -0
- angr/analyses/reaching_definitions/engine_vex.py +1128 -0
- angr/analyses/reaching_definitions/external_codeloc.py +0 -0
- angr/analyses/reaching_definitions/function_handler.py +639 -0
- angr/analyses/reaching_definitions/function_handler_library/__init__.py +12 -0
- angr/analyses/reaching_definitions/function_handler_library/stdio.py +269 -0
- angr/analyses/reaching_definitions/function_handler_library/stdlib.py +195 -0
- angr/analyses/reaching_definitions/function_handler_library/string.py +158 -0
- angr/analyses/reaching_definitions/function_handler_library/unistd.py +51 -0
- angr/analyses/reaching_definitions/heap_allocator.py +70 -0
- angr/analyses/reaching_definitions/rd_initializer.py +237 -0
- angr/analyses/reaching_definitions/rd_state.py +579 -0
- angr/analyses/reaching_definitions/reaching_definitions.py +581 -0
- angr/analyses/reaching_definitions/subject.py +65 -0
- angr/analyses/reassembler.py +2900 -0
- angr/analyses/s_liveness.py +254 -0
- angr/analyses/s_propagator.py +575 -0
- angr/analyses/s_reaching_definitions/__init__.py +12 -0
- angr/analyses/s_reaching_definitions/s_rda_model.py +145 -0
- angr/analyses/s_reaching_definitions/s_rda_view.py +344 -0
- angr/analyses/s_reaching_definitions/s_reaching_definitions.py +230 -0
- angr/analyses/smc.py +160 -0
- angr/analyses/soot_class_hierarchy.py +273 -0
- angr/analyses/stack_pointer_tracker.py +954 -0
- angr/analyses/static_hooker.py +53 -0
- angr/analyses/typehoon/__init__.py +5 -0
- angr/analyses/typehoon/dfa.py +118 -0
- angr/analyses/typehoon/lifter.py +133 -0
- angr/analyses/typehoon/simple_solver.py +2009 -0
- angr/analyses/typehoon/translator.py +283 -0
- angr/analyses/typehoon/typeconsts.py +439 -0
- angr/analyses/typehoon/typehoon.py +338 -0
- angr/analyses/typehoon/typevars.py +633 -0
- angr/analyses/typehoon/variance.py +11 -0
- angr/analyses/unpacker/__init__.py +6 -0
- angr/analyses/unpacker/obfuscation_detector.py +103 -0
- angr/analyses/unpacker/packing_detector.py +138 -0
- angr/analyses/variable_recovery/__init__.py +9 -0
- angr/analyses/variable_recovery/annotations.py +58 -0
- angr/analyses/variable_recovery/engine_ail.py +978 -0
- angr/analyses/variable_recovery/engine_base.py +1256 -0
- angr/analyses/variable_recovery/engine_vex.py +594 -0
- angr/analyses/variable_recovery/irsb_scanner.py +143 -0
- angr/analyses/variable_recovery/variable_recovery.py +574 -0
- angr/analyses/variable_recovery/variable_recovery_base.py +489 -0
- angr/analyses/variable_recovery/variable_recovery_fast.py +669 -0
- angr/analyses/veritesting.py +626 -0
- angr/analyses/vfg.py +1898 -0
- angr/analyses/vsa_ddg.py +420 -0
- angr/analyses/vtable.py +92 -0
- angr/analyses/xrefs.py +286 -0
- angr/angrdb/__init__.py +14 -0
- angr/angrdb/db.py +215 -0
- angr/angrdb/models.py +184 -0
- angr/angrdb/serializers/__init__.py +10 -0
- angr/angrdb/serializers/cfg_model.py +41 -0
- angr/angrdb/serializers/comments.py +60 -0
- angr/angrdb/serializers/funcs.py +61 -0
- angr/angrdb/serializers/kb.py +111 -0
- angr/angrdb/serializers/labels.py +59 -0
- angr/angrdb/serializers/loader.py +165 -0
- angr/angrdb/serializers/structured_code.py +167 -0
- angr/angrdb/serializers/variables.py +58 -0
- angr/angrdb/serializers/xrefs.py +48 -0
- angr/annocfg.py +317 -0
- angr/blade.py +431 -0
- angr/block.py +509 -0
- angr/callable.py +176 -0
- angr/calling_conventions.py +2613 -0
- angr/code_location.py +249 -0
- angr/codenode.py +145 -0
- angr/concretization_strategies/__init__.py +32 -0
- angr/concretization_strategies/any.py +17 -0
- angr/concretization_strategies/any_named.py +35 -0
- angr/concretization_strategies/base.py +81 -0
- angr/concretization_strategies/controlled_data.py +58 -0
- angr/concretization_strategies/eval.py +19 -0
- angr/concretization_strategies/logging.py +35 -0
- angr/concretization_strategies/max.py +25 -0
- angr/concretization_strategies/nonzero.py +16 -0
- angr/concretization_strategies/nonzero_range.py +22 -0
- angr/concretization_strategies/norepeats.py +37 -0
- angr/concretization_strategies/norepeats_range.py +37 -0
- angr/concretization_strategies/range.py +19 -0
- angr/concretization_strategies/signed_add.py +31 -0
- angr/concretization_strategies/single.py +15 -0
- angr/concretization_strategies/solutions.py +20 -0
- angr/concretization_strategies/unlimited_range.py +17 -0
- angr/distributed/__init__.py +9 -0
- angr/distributed/server.py +197 -0
- angr/distributed/worker.py +185 -0
- angr/emulator.py +144 -0
- angr/engines/__init__.py +69 -0
- angr/engines/ail/__init__.py +16 -0
- angr/engines/ail/callstack.py +58 -0
- angr/engines/ail/engine_light.py +903 -0
- angr/engines/ail/engine_successors.py +24 -0
- angr/engines/ail/setup.py +57 -0
- angr/engines/concrete.py +66 -0
- angr/engines/engine.py +29 -0
- angr/engines/failure.py +27 -0
- angr/engines/hook.py +93 -0
- angr/engines/icicle.py +294 -0
- angr/engines/light/__init__.py +23 -0
- angr/engines/light/data.py +681 -0
- angr/engines/light/engine.py +1297 -0
- angr/engines/pcode/__init__.py +9 -0
- angr/engines/pcode/behavior.py +998 -0
- angr/engines/pcode/cc.py +148 -0
- angr/engines/pcode/emulate.py +440 -0
- angr/engines/pcode/engine.py +242 -0
- angr/engines/pcode/lifter.py +1428 -0
- angr/engines/procedure.py +70 -0
- angr/engines/soot/__init__.py +5 -0
- angr/engines/soot/engine.py +410 -0
- angr/engines/soot/exceptions.py +17 -0
- angr/engines/soot/expressions/__init__.py +87 -0
- angr/engines/soot/expressions/arrayref.py +22 -0
- angr/engines/soot/expressions/base.py +21 -0
- angr/engines/soot/expressions/binop.py +28 -0
- angr/engines/soot/expressions/cast.py +22 -0
- angr/engines/soot/expressions/condition.py +35 -0
- angr/engines/soot/expressions/constants.py +47 -0
- angr/engines/soot/expressions/instanceOf.py +15 -0
- angr/engines/soot/expressions/instancefieldref.py +8 -0
- angr/engines/soot/expressions/invoke.py +114 -0
- angr/engines/soot/expressions/length.py +8 -0
- angr/engines/soot/expressions/local.py +8 -0
- angr/engines/soot/expressions/new.py +16 -0
- angr/engines/soot/expressions/newArray.py +54 -0
- angr/engines/soot/expressions/newMultiArray.py +86 -0
- angr/engines/soot/expressions/paramref.py +8 -0
- angr/engines/soot/expressions/phi.py +30 -0
- angr/engines/soot/expressions/staticfieldref.py +8 -0
- angr/engines/soot/expressions/thisref.py +7 -0
- angr/engines/soot/expressions/unsupported.py +7 -0
- angr/engines/soot/field_dispatcher.py +46 -0
- angr/engines/soot/method_dispatcher.py +46 -0
- angr/engines/soot/statements/__init__.py +44 -0
- angr/engines/soot/statements/assign.py +30 -0
- angr/engines/soot/statements/base.py +79 -0
- angr/engines/soot/statements/goto.py +14 -0
- angr/engines/soot/statements/identity.py +15 -0
- angr/engines/soot/statements/if_.py +19 -0
- angr/engines/soot/statements/invoke.py +12 -0
- angr/engines/soot/statements/return_.py +20 -0
- angr/engines/soot/statements/switch.py +41 -0
- angr/engines/soot/statements/throw.py +15 -0
- angr/engines/soot/values/__init__.py +38 -0
- angr/engines/soot/values/arrayref.py +122 -0
- angr/engines/soot/values/base.py +7 -0
- angr/engines/soot/values/constants.py +18 -0
- angr/engines/soot/values/instancefieldref.py +44 -0
- angr/engines/soot/values/local.py +18 -0
- angr/engines/soot/values/paramref.py +18 -0
- angr/engines/soot/values/staticfieldref.py +38 -0
- angr/engines/soot/values/strref.py +38 -0
- angr/engines/soot/values/thisref.py +149 -0
- angr/engines/successors.py +608 -0
- angr/engines/syscall.py +51 -0
- angr/engines/unicorn.py +490 -0
- angr/engines/vex/__init__.py +20 -0
- angr/engines/vex/claripy/__init__.py +5 -0
- angr/engines/vex/claripy/ccall.py +2097 -0
- angr/engines/vex/claripy/datalayer.py +141 -0
- angr/engines/vex/claripy/irop.py +1276 -0
- angr/engines/vex/heavy/__init__.py +16 -0
- angr/engines/vex/heavy/actions.py +231 -0
- angr/engines/vex/heavy/concretizers.py +403 -0
- angr/engines/vex/heavy/dirty.py +466 -0
- angr/engines/vex/heavy/heavy.py +370 -0
- angr/engines/vex/heavy/inspect.py +52 -0
- angr/engines/vex/heavy/resilience.py +85 -0
- angr/engines/vex/heavy/super_fastpath.py +34 -0
- angr/engines/vex/lifter.py +420 -0
- angr/engines/vex/light/__init__.py +11 -0
- angr/engines/vex/light/light.py +551 -0
- angr/engines/vex/light/resilience.py +74 -0
- angr/engines/vex/light/slicing.py +52 -0
- angr/errors.py +611 -0
- angr/exploration_techniques/__init__.py +53 -0
- angr/exploration_techniques/base.py +126 -0
- angr/exploration_techniques/bucketizer.py +94 -0
- angr/exploration_techniques/common.py +56 -0
- angr/exploration_techniques/dfs.py +37 -0
- angr/exploration_techniques/director.py +520 -0
- angr/exploration_techniques/driller_core.py +100 -0
- angr/exploration_techniques/explorer.py +152 -0
- angr/exploration_techniques/lengthlimiter.py +22 -0
- angr/exploration_techniques/local_loop_seer.py +65 -0
- angr/exploration_techniques/loop_seer.py +236 -0
- angr/exploration_techniques/manual_mergepoint.py +82 -0
- angr/exploration_techniques/memory_watcher.py +43 -0
- angr/exploration_techniques/oppologist.py +92 -0
- angr/exploration_techniques/slicecutor.py +118 -0
- angr/exploration_techniques/spiller.py +280 -0
- angr/exploration_techniques/spiller_db.py +27 -0
- angr/exploration_techniques/stochastic.py +56 -0
- angr/exploration_techniques/stub_stasher.py +19 -0
- angr/exploration_techniques/suggestions.py +159 -0
- angr/exploration_techniques/tech_builder.py +49 -0
- angr/exploration_techniques/threading.py +69 -0
- angr/exploration_techniques/timeout.py +34 -0
- angr/exploration_techniques/tracer.py +1098 -0
- angr/exploration_techniques/unique.py +106 -0
- angr/exploration_techniques/veritesting.py +37 -0
- angr/factory.py +413 -0
- angr/flirt/__init__.py +124 -0
- angr/flirt/build_sig.py +305 -0
- angr/graph_utils.py +0 -0
- angr/keyed_region.py +525 -0
- angr/knowledge_base.py +146 -0
- angr/knowledge_plugins/__init__.py +43 -0
- angr/knowledge_plugins/callsite_prototypes.py +95 -0
- angr/knowledge_plugins/cfg/__init__.py +18 -0
- angr/knowledge_plugins/cfg/cfg_manager.py +95 -0
- angr/knowledge_plugins/cfg/cfg_model.py +1043 -0
- angr/knowledge_plugins/cfg/cfg_node.py +536 -0
- angr/knowledge_plugins/cfg/indirect_jump.py +131 -0
- angr/knowledge_plugins/cfg/memory_data.py +156 -0
- angr/knowledge_plugins/comments.py +16 -0
- angr/knowledge_plugins/custom_strings.py +38 -0
- angr/knowledge_plugins/data.py +22 -0
- angr/knowledge_plugins/debug_variables.py +216 -0
- angr/knowledge_plugins/functions/__init__.py +9 -0
- angr/knowledge_plugins/functions/function.py +1830 -0
- angr/knowledge_plugins/functions/function_manager.py +621 -0
- angr/knowledge_plugins/functions/function_parser.py +360 -0
- angr/knowledge_plugins/functions/soot_function.py +128 -0
- angr/knowledge_plugins/indirect_jumps.py +35 -0
- angr/knowledge_plugins/key_definitions/__init__.py +17 -0
- angr/knowledge_plugins/key_definitions/atoms.py +374 -0
- angr/knowledge_plugins/key_definitions/constants.py +29 -0
- angr/knowledge_plugins/key_definitions/definition.py +216 -0
- angr/knowledge_plugins/key_definitions/environment.py +96 -0
- angr/knowledge_plugins/key_definitions/heap_address.py +33 -0
- angr/knowledge_plugins/key_definitions/key_definition_manager.py +82 -0
- angr/knowledge_plugins/key_definitions/live_definitions.py +1020 -0
- angr/knowledge_plugins/key_definitions/liveness.py +165 -0
- angr/knowledge_plugins/key_definitions/rd_model.py +171 -0
- angr/knowledge_plugins/key_definitions/tag.py +78 -0
- angr/knowledge_plugins/key_definitions/undefined.py +70 -0
- angr/knowledge_plugins/key_definitions/unknown_size.py +86 -0
- angr/knowledge_plugins/key_definitions/uses.py +178 -0
- angr/knowledge_plugins/labels.py +110 -0
- angr/knowledge_plugins/obfuscations.py +40 -0
- angr/knowledge_plugins/patches.py +126 -0
- angr/knowledge_plugins/plugin.py +24 -0
- angr/knowledge_plugins/propagations/__init__.py +10 -0
- angr/knowledge_plugins/propagations/prop_value.py +191 -0
- angr/knowledge_plugins/propagations/propagation_manager.py +60 -0
- angr/knowledge_plugins/propagations/propagation_model.py +80 -0
- angr/knowledge_plugins/propagations/states.py +552 -0
- angr/knowledge_plugins/structured_code.py +63 -0
- angr/knowledge_plugins/types.py +95 -0
- angr/knowledge_plugins/variables/__init__.py +8 -0
- angr/knowledge_plugins/variables/variable_access.py +113 -0
- angr/knowledge_plugins/variables/variable_manager.py +1375 -0
- angr/knowledge_plugins/xrefs/__init__.py +12 -0
- angr/knowledge_plugins/xrefs/xref.py +150 -0
- angr/knowledge_plugins/xrefs/xref_manager.py +127 -0
- angr/knowledge_plugins/xrefs/xref_types.py +16 -0
- angr/misc/__init__.py +19 -0
- angr/misc/ansi.py +47 -0
- angr/misc/autoimport.py +90 -0
- angr/misc/bug_report.py +126 -0
- angr/misc/hookset.py +106 -0
- angr/misc/loggers.py +130 -0
- angr/misc/picklable_lock.py +46 -0
- angr/misc/plugins.py +289 -0
- angr/misc/telemetry.py +54 -0
- angr/misc/testing.py +24 -0
- angr/misc/ux.py +31 -0
- angr/procedures/__init__.py +12 -0
- angr/procedures/advapi32/__init__.py +0 -0
- angr/procedures/cgc/__init__.py +3 -0
- angr/procedures/cgc/_terminate.py +11 -0
- angr/procedures/cgc/allocate.py +75 -0
- angr/procedures/cgc/deallocate.py +67 -0
- angr/procedures/cgc/fdwait.py +65 -0
- angr/procedures/cgc/random.py +67 -0
- angr/procedures/cgc/receive.py +93 -0
- angr/procedures/cgc/transmit.py +65 -0
- angr/procedures/definitions/__init__.py +1043 -0
- angr/procedures/definitions/cgc.py +23 -0
- angr/procedures/definitions/common/glibc.json +3516 -0
- angr/procedures/definitions/gnulib.py +41 -0
- angr/procedures/definitions/libstdcpp.py +25 -0
- angr/procedures/definitions/linux_kernel.py +8382 -0
- angr/procedures/definitions/linux_loader.py +7 -0
- angr/procedures/definitions/macho_libsystem.py +18 -0
- angr/procedures/definitions/msvcr.py +25 -0
- angr/procedures/definitions/parse_glibc.py +77 -0
- angr/procedures/definitions/parse_syscalls_from_local_system.py +54 -0
- angr/procedures/definitions/parse_win32json.py +2540 -0
- angr/procedures/definitions/types_stl.py +22 -0
- angr/procedures/definitions/wdk/api-ms-win-dx-d3dkmt-l1-1-4.json +24 -0
- angr/procedures/definitions/wdk/api-ms-win-dx-d3dkmt-l1-1-6.json +18 -0
- angr/procedures/definitions/wdk/clfs.json +189 -0
- angr/procedures/definitions/wdk/fltmgr.json +813 -0
- angr/procedures/definitions/wdk/fwpkclnt.json +24 -0
- angr/procedures/definitions/wdk/fwpuclnt.json +453 -0
- angr/procedures/definitions/wdk/gdi32.json +528 -0
- angr/procedures/definitions/wdk/hal.json +96 -0
- angr/procedures/definitions/wdk/ksecdd.json +72 -0
- angr/procedures/definitions/wdk/ndis.json +336 -0
- angr/procedures/definitions/wdk/ntoskrnl.json +5158 -0
- angr/procedures/definitions/wdk/offreg.json +87 -0
- angr/procedures/definitions/wdk/pshed.json +33 -0
- angr/procedures/definitions/wdk/secur32.json +39 -0
- angr/procedures/definitions/wdk/vhfum.json +30 -0
- angr/procedures/definitions/win32/_types_win32.json +34480 -0
- angr/procedures/definitions/win32/aclui.json +24 -0
- angr/procedures/definitions/win32/activeds.json +81 -0
- angr/procedures/definitions/win32/advapi32.json +2505 -0
- angr/procedures/definitions/win32/advpack.json +165 -0
- angr/procedures/definitions/win32/amsi.json +36 -0
- angr/procedures/definitions/win32/api-ms-win-appmodel-runtime-l1-1-1.json +45 -0
- angr/procedures/definitions/win32/api-ms-win-appmodel-runtime-l1-1-3.json +30 -0
- angr/procedures/definitions/win32/api-ms-win-appmodel-runtime-l1-1-6.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-core-apiquery-l2-1-0.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-core-backgroundtask-l1-1-0.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-core-comm-l1-1-1.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-core-comm-l1-1-2.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-core-enclave-l1-1-1.json +24 -0
- angr/procedures/definitions/win32/api-ms-win-core-errorhandling-l1-1-3.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-core-featurestaging-l1-1-0.json +30 -0
- angr/procedures/definitions/win32/api-ms-win-core-featurestaging-l1-1-1.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-core-file-fromapp-l1-1-0.json +48 -0
- angr/procedures/definitions/win32/api-ms-win-core-handle-l1-1-0.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-core-ioring-l1-1-0.json +51 -0
- angr/procedures/definitions/win32/api-ms-win-core-marshal-l1-1-0.json +27 -0
- angr/procedures/definitions/win32/api-ms-win-core-memory-l1-1-3.json +27 -0
- angr/procedures/definitions/win32/api-ms-win-core-memory-l1-1-4.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-core-memory-l1-1-5.json +24 -0
- angr/procedures/definitions/win32/api-ms-win-core-memory-l1-1-6.json +27 -0
- angr/procedures/definitions/win32/api-ms-win-core-memory-l1-1-7.json +21 -0
- angr/procedures/definitions/win32/api-ms-win-core-memory-l1-1-8.json +24 -0
- angr/procedures/definitions/win32/api-ms-win-core-path-l1-1-0.json +81 -0
- angr/procedures/definitions/win32/api-ms-win-core-psm-appnotify-l1-1-0.json +21 -0
- angr/procedures/definitions/win32/api-ms-win-core-psm-appnotify-l1-1-1.json +21 -0
- angr/procedures/definitions/win32/api-ms-win-core-realtime-l1-1-1.json +24 -0
- angr/procedures/definitions/win32/api-ms-win-core-realtime-l1-1-2.json +24 -0
- angr/procedures/definitions/win32/api-ms-win-core-slapi-l1-1-0.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-core-state-helpers-l1-1-0.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-core-synch-l1-2-0.json +24 -0
- angr/procedures/definitions/win32/api-ms-win-core-sysinfo-l1-2-0.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-core-sysinfo-l1-2-3.json +21 -0
- angr/procedures/definitions/win32/api-ms-win-core-sysinfo-l1-2-4.json +21 -0
- angr/procedures/definitions/win32/api-ms-win-core-sysinfo-l1-2-6.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-core-util-l1-1-1.json +21 -0
- angr/procedures/definitions/win32/api-ms-win-core-wow64-l1-1-1.json +24 -0
- angr/procedures/definitions/win32/api-ms-win-devices-query-l1-1-0.json +42 -0
- angr/procedures/definitions/win32/api-ms-win-devices-query-l1-1-1.json +30 -0
- angr/procedures/definitions/win32/api-ms-win-dx-d3dkmt-l1-1-0.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-gaming-deviceinformation-l1-1-0.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-gaming-expandedresources-l1-1-0.json +24 -0
- angr/procedures/definitions/win32/api-ms-win-gaming-tcui-l1-1-0.json +36 -0
- angr/procedures/definitions/win32/api-ms-win-gaming-tcui-l1-1-1.json +21 -0
- angr/procedures/definitions/win32/api-ms-win-gaming-tcui-l1-1-2.json +36 -0
- angr/procedures/definitions/win32/api-ms-win-gaming-tcui-l1-1-3.json +21 -0
- angr/procedures/definitions/win32/api-ms-win-gaming-tcui-l1-1-4.json +39 -0
- angr/procedures/definitions/win32/api-ms-win-mm-misc-l1-1-1.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-net-isolation-l1-1-0.json +39 -0
- angr/procedures/definitions/win32/api-ms-win-security-base-l1-2-2.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-security-isolatedcontainer-l1-1-0.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-security-isolatedcontainer-l1-1-1.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-service-core-l1-1-3.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-service-core-l1-1-4.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-service-core-l1-1-5.json +21 -0
- angr/procedures/definitions/win32/api-ms-win-shcore-scaling-l1-1-0.json +24 -0
- angr/procedures/definitions/win32/api-ms-win-shcore-scaling-l1-1-1.json +33 -0
- angr/procedures/definitions/win32/api-ms-win-shcore-scaling-l1-1-2.json +18 -0
- angr/procedures/definitions/win32/api-ms-win-wsl-api-l1-1-0.json +36 -0
- angr/procedures/definitions/win32/apphelp.json +18 -0
- angr/procedures/definitions/win32/authz.json +114 -0
- angr/procedures/definitions/win32/avicap32.json +27 -0
- angr/procedures/definitions/win32/avifil32.json +195 -0
- angr/procedures/definitions/win32/avrt.json +57 -0
- angr/procedures/definitions/win32/bcp47mrm.json +21 -0
- angr/procedures/definitions/win32/bcrypt.json +174 -0
- angr/procedures/definitions/win32/bcryptprimitives.json +21 -0
- angr/procedures/definitions/win32/bluetoothapis.json +138 -0
- angr/procedures/definitions/win32/bthprops_cpl.json +33 -0
- angr/procedures/definitions/win32/cabinet.json +81 -0
- angr/procedures/definitions/win32/certadm.json +69 -0
- angr/procedures/definitions/win32/certpoleng.json +39 -0
- angr/procedures/definitions/win32/cfgmgr32.json +732 -0
- angr/procedures/definitions/win32/chakra.json +270 -0
- angr/procedures/definitions/win32/cldapi.json +123 -0
- angr/procedures/definitions/win32/clfsw32.json +192 -0
- angr/procedures/definitions/win32/clusapi.json +855 -0
- angr/procedures/definitions/win32/comctl32.json +360 -0
- angr/procedures/definitions/win32/comdlg32.json +78 -0
- angr/procedures/definitions/win32/compstui.json +27 -0
- angr/procedures/definitions/win32/computecore.json +177 -0
- angr/procedures/definitions/win32/computenetwork.json +144 -0
- angr/procedures/definitions/win32/computestorage.json +51 -0
- angr/procedures/definitions/win32/comsvcs.json +36 -0
- angr/procedures/definitions/win32/credui.json +72 -0
- angr/procedures/definitions/win32/crypt32.json +702 -0
- angr/procedures/definitions/win32/cryptnet.json +30 -0
- angr/procedures/definitions/win32/cryptui.json +45 -0
- angr/procedures/definitions/win32/cryptxml.json +72 -0
- angr/procedures/definitions/win32/cscapi.json +27 -0
- angr/procedures/definitions/win32/d2d1.json +54 -0
- angr/procedures/definitions/win32/d3d10.json +96 -0
- angr/procedures/definitions/win32/d3d10_1.json +21 -0
- angr/procedures/definitions/win32/d3d11.json +24 -0
- angr/procedures/definitions/win32/d3d12.json +39 -0
- angr/procedures/definitions/win32/d3d9.json +48 -0
- angr/procedures/definitions/win32/d3dcompiler_47.json +93 -0
- angr/procedures/definitions/win32/d3dcsx.json +42 -0
- angr/procedures/definitions/win32/davclnt.json +69 -0
- angr/procedures/definitions/win32/dbgeng.json +27 -0
- angr/procedures/definitions/win32/dbghelp.json +663 -0
- angr/procedures/definitions/win32/dbgmodel.json +18 -0
- angr/procedures/definitions/win32/dciman32.json +75 -0
- angr/procedures/definitions/win32/dcomp.json +51 -0
- angr/procedures/definitions/win32/ddraw.json +36 -0
- angr/procedures/definitions/win32/deviceaccess.json +18 -0
- angr/procedures/definitions/win32/dflayout.json +18 -0
- angr/procedures/definitions/win32/dhcpcsvc.json +60 -0
- angr/procedures/definitions/win32/dhcpcsvc6.json +33 -0
- angr/procedures/definitions/win32/dhcpsapi.json +603 -0
- angr/procedures/definitions/win32/diagnosticdataquery.json +120 -0
- angr/procedures/definitions/win32/dinput8.json +18 -0
- angr/procedures/definitions/win32/directml.json +21 -0
- angr/procedures/definitions/win32/dmprocessxmlfiltered.json +18 -0
- angr/procedures/definitions/win32/dnsapi.json +207 -0
- angr/procedures/definitions/win32/drt.json +63 -0
- angr/procedures/definitions/win32/drtprov.json +42 -0
- angr/procedures/definitions/win32/drttransport.json +21 -0
- angr/procedures/definitions/win32/dsound.json +45 -0
- angr/procedures/definitions/win32/dsparse.json +72 -0
- angr/procedures/definitions/win32/dsprop.json +36 -0
- angr/procedures/definitions/win32/dssec.json +27 -0
- angr/procedures/definitions/win32/dsuiext.json +27 -0
- angr/procedures/definitions/win32/dwmapi.json +108 -0
- angr/procedures/definitions/win32/dwrite.json +18 -0
- angr/procedures/definitions/win32/dxcompiler.json +21 -0
- angr/procedures/definitions/win32/dxcore.json +18 -0
- angr/procedures/definitions/win32/dxgi.json +33 -0
- angr/procedures/definitions/win32/dxva2.json +129 -0
- angr/procedures/definitions/win32/eappcfg.json +57 -0
- angr/procedures/definitions/win32/eappprxy.json +69 -0
- angr/procedures/definitions/win32/efswrt.json +21 -0
- angr/procedures/definitions/win32/elscore.json +30 -0
- angr/procedures/definitions/win32/esent.json +702 -0
- angr/procedures/definitions/win32/evr.json +36 -0
- angr/procedures/definitions/win32/faultrep.json +27 -0
- angr/procedures/definitions/win32/fhsvcctl.json +36 -0
- angr/procedures/definitions/win32/firewallapi.json +24 -0
- angr/procedures/definitions/win32/fltlib.json +99 -0
- angr/procedures/definitions/win32/fontsub.json +21 -0
- angr/procedures/definitions/win32/forceinline.json +24 -0
- angr/procedures/definitions/win32/fwpuclnt.json +591 -0
- angr/procedures/definitions/win32/fxsutility.json +21 -0
- angr/procedures/definitions/win32/gdi32.json +1308 -0
- angr/procedures/definitions/win32/gdiplus.json +1902 -0
- angr/procedures/definitions/win32/glu32.json +171 -0
- angr/procedures/definitions/win32/gpedit.json +33 -0
- angr/procedures/definitions/win32/hhctrl_ocx.json +21 -0
- angr/procedures/definitions/win32/hid.json +150 -0
- angr/procedures/definitions/win32/hlink.json +99 -0
- angr/procedures/definitions/win32/hrtfapo.json +18 -0
- angr/procedures/definitions/win32/httpapi.json +144 -0
- angr/procedures/definitions/win32/icm32.json +78 -0
- angr/procedures/definitions/win32/icmui.json +21 -0
- angr/procedures/definitions/win32/icu.json +3090 -0
- angr/procedures/definitions/win32/ieframe.json +102 -0
- angr/procedures/definitions/win32/imagehlp.json +84 -0
- angr/procedures/definitions/win32/imgutil.json +42 -0
- angr/procedures/definitions/win32/imm32.json +261 -0
- angr/procedures/definitions/win32/infocardapi.json +66 -0
- angr/procedures/definitions/win32/inkobjcore.json +96 -0
- angr/procedures/definitions/win32/iphlpapi.json +618 -0
- angr/procedures/definitions/win32/iscsidsc.json +252 -0
- angr/procedures/definitions/win32/isolatedwindowsenvironmentutils.json +21 -0
- angr/procedures/definitions/win32/kernel32.json +4566 -0
- angr/procedures/definitions/win32/kernelbase.json +33 -0
- angr/procedures/definitions/win32/keycredmgr.json +27 -0
- angr/procedures/definitions/win32/ksproxy_ax.json +33 -0
- angr/procedures/definitions/win32/ksuser.json +39 -0
- angr/procedures/definitions/win32/ktmw32.json +132 -0
- angr/procedures/definitions/win32/licenseprotection.json +21 -0
- angr/procedures/definitions/win32/loadperf.json +51 -0
- angr/procedures/definitions/win32/magnification.json +72 -0
- angr/procedures/definitions/win32/mapi32.json +213 -0
- angr/procedures/definitions/win32/mdmlocalmanagement.json +24 -0
- angr/procedures/definitions/win32/mdmregistration.json +60 -0
- angr/procedures/definitions/win32/mf.json +201 -0
- angr/procedures/definitions/win32/mfcore.json +21 -0
- angr/procedures/definitions/win32/mfplat.json +450 -0
- angr/procedures/definitions/win32/mfplay.json +18 -0
- angr/procedures/definitions/win32/mfreadwrite.json +30 -0
- angr/procedures/definitions/win32/mfsensorgroup.json +45 -0
- angr/procedures/definitions/win32/mfsrcsnk.json +21 -0
- angr/procedures/definitions/win32/mgmtapi.json +42 -0
- angr/procedures/definitions/win32/mi.json +18 -0
- angr/procedures/definitions/win32/mmdevapi.json +18 -0
- angr/procedures/definitions/win32/mpr.json +156 -0
- angr/procedures/definitions/win32/mprapi.json +351 -0
- angr/procedures/definitions/win32/mqrt.json +117 -0
- angr/procedures/definitions/win32/mrmsupport.json +96 -0
- angr/procedures/definitions/win32/msacm32.json +141 -0
- angr/procedures/definitions/win32/msajapi.json +1656 -0
- angr/procedures/definitions/win32/mscms.json +252 -0
- angr/procedures/definitions/win32/mscoree.json +96 -0
- angr/procedures/definitions/win32/msctfmonitor.json +24 -0
- angr/procedures/definitions/win32/msdelta.json +63 -0
- angr/procedures/definitions/win32/msdmo.json +48 -0
- angr/procedures/definitions/win32/msdrm.json +267 -0
- angr/procedures/definitions/win32/msi.json +807 -0
- angr/procedures/definitions/win32/msimg32.json +24 -0
- angr/procedures/definitions/win32/mspatcha.json +63 -0
- angr/procedures/definitions/win32/mspatchc.json +42 -0
- angr/procedures/definitions/win32/msports.json +36 -0
- angr/procedures/definitions/win32/msrating.json +72 -0
- angr/procedures/definitions/win32/mssign32.json +45 -0
- angr/procedures/definitions/win32/mstask.json +21 -0
- angr/procedures/definitions/win32/msvfw32.json +144 -0
- angr/procedures/definitions/win32/mswsock.json +63 -0
- angr/procedures/definitions/win32/mtxdm.json +18 -0
- angr/procedures/definitions/win32/ncrypt.json +132 -0
- angr/procedures/definitions/win32/ndfapi.json +63 -0
- angr/procedures/definitions/win32/netapi32.json +633 -0
- angr/procedures/definitions/win32/netsh.json +39 -0
- angr/procedures/definitions/win32/netshell.json +21 -0
- angr/procedures/definitions/win32/newdev.json +48 -0
- angr/procedures/definitions/win32/ninput.json +105 -0
- angr/procedures/definitions/win32/normaliz.json +21 -0
- angr/procedures/definitions/win32/ntdll.json +234 -0
- angr/procedures/definitions/win32/ntdllk.json +18 -0
- angr/procedures/definitions/win32/ntdsapi.json +258 -0
- angr/procedures/definitions/win32/ntlanman.json +45 -0
- angr/procedures/definitions/win32/odbc32.json +477 -0
- angr/procedures/definitions/win32/odbcbcp.json +96 -0
- angr/procedures/definitions/win32/ole32.json +966 -0
- angr/procedures/definitions/win32/oleacc.json +66 -0
- angr/procedures/definitions/win32/oleaut32.json +1230 -0
- angr/procedures/definitions/win32/oledlg.json +84 -0
- angr/procedures/definitions/win32/ondemandconnroutehelper.json +30 -0
- angr/procedures/definitions/win32/opengl32.json +1080 -0
- angr/procedures/definitions/win32/opmxbox.json +24 -0
- angr/procedures/definitions/win32/p2p.json +339 -0
- angr/procedures/definitions/win32/p2pgraph.json +126 -0
- angr/procedures/definitions/win32/pdh.json +309 -0
- angr/procedures/definitions/win32/peerdist.json +99 -0
- angr/procedures/definitions/win32/powrprof.json +267 -0
- angr/procedures/definitions/win32/prntvpt.json +48 -0
- angr/procedures/definitions/win32/projectedfslib.json +72 -0
- angr/procedures/definitions/win32/propsys.json +669 -0
- angr/procedures/definitions/win32/psapi.json +96 -0
- angr/procedures/definitions/win32/quartz.json +21 -0
- angr/procedures/definitions/win32/query.json +27 -0
- angr/procedures/definitions/win32/qwave.json +48 -0
- angr/procedures/definitions/win32/rasapi32.json +267 -0
- angr/procedures/definitions/win32/rasdlg.json +33 -0
- angr/procedures/definitions/win32/resutils.json +375 -0
- angr/procedures/definitions/win32/rpcns4.json +198 -0
- angr/procedures/definitions/win32/rpcproxy.json +27 -0
- angr/procedures/definitions/win32/rpcrt4.json +1356 -0
- angr/procedures/definitions/win32/rstrtmgr.json +48 -0
- angr/procedures/definitions/win32/rtm.json +243 -0
- angr/procedures/definitions/win32/rtutils.json +138 -0
- angr/procedures/definitions/win32/rtworkq.json +114 -0
- angr/procedures/definitions/win32/sas.json +18 -0
- angr/procedures/definitions/win32/scarddlg.json +30 -0
- angr/procedures/definitions/win32/schannel.json +42 -0
- angr/procedures/definitions/win32/sechost.json +21 -0
- angr/procedures/definitions/win32/secur32.json +282 -0
- angr/procedures/definitions/win32/sensapi.json +24 -0
- angr/procedures/definitions/win32/sensorsutilsv2.json +135 -0
- angr/procedures/definitions/win32/setupapi.json +1017 -0
- angr/procedures/definitions/win32/sfc.json +33 -0
- angr/procedures/definitions/win32/shdocvw.json +24 -0
- angr/procedures/definitions/win32/shell32.json +747 -0
- angr/procedures/definitions/win32/shlwapi.json +1095 -0
- angr/procedures/definitions/win32/slc.json +111 -0
- angr/procedures/definitions/win32/slcext.json +27 -0
- angr/procedures/definitions/win32/slwga.json +18 -0
- angr/procedures/definitions/win32/snmpapi.json +93 -0
- angr/procedures/definitions/win32/spoolss.json +93 -0
- angr/procedures/definitions/win32/srclient.json +18 -0
- angr/procedures/definitions/win32/srpapi.json +48 -0
- angr/procedures/definitions/win32/sspicli.json +36 -0
- angr/procedures/definitions/win32/sti.json +18 -0
- angr/procedures/definitions/win32/t2embed.json +57 -0
- angr/procedures/definitions/win32/tapi32.json +762 -0
- angr/procedures/definitions/win32/tbs.json +57 -0
- angr/procedures/definitions/win32/tdh.json +96 -0
- angr/procedures/definitions/win32/tokenbinding.json +45 -0
- angr/procedures/definitions/win32/traffic.json +75 -0
- angr/procedures/definitions/win32/txfw32.json +42 -0
- angr/procedures/definitions/win32/ualapi.json +27 -0
- angr/procedures/definitions/win32/uiautomationcore.json +309 -0
- angr/procedures/definitions/win32/urlmon.json +246 -0
- angr/procedures/definitions/win32/user32.json +2298 -0
- angr/procedures/definitions/win32/userenv.json +147 -0
- angr/procedures/definitions/win32/usp10.json +135 -0
- angr/procedures/definitions/win32/uxtheme.json +246 -0
- angr/procedures/definitions/win32/verifier.json +18 -0
- angr/procedures/definitions/win32/version.json +57 -0
- angr/procedures/definitions/win32/vertdll.json +36 -0
- angr/procedures/definitions/win32/virtdisk.json +102 -0
- angr/procedures/definitions/win32/vmdevicehost.json +54 -0
- angr/procedures/definitions/win32/vmsavedstatedumpprovider.json +144 -0
- angr/procedures/definitions/win32/vssapi.json +18 -0
- angr/procedures/definitions/win32/wcmapi.json +30 -0
- angr/procedures/definitions/win32/wdsbp.json +36 -0
- angr/procedures/definitions/win32/wdsclientapi.json +126 -0
- angr/procedures/definitions/win32/wdsmc.json +33 -0
- angr/procedures/definitions/win32/wdspxe.json +108 -0
- angr/procedures/definitions/win32/wdstptc.json +54 -0
- angr/procedures/definitions/win32/webauthn.json +54 -0
- angr/procedures/definitions/win32/webservices.json +594 -0
- angr/procedures/definitions/win32/websocket.json +54 -0
- angr/procedures/definitions/win32/wecapi.json +60 -0
- angr/procedures/definitions/win32/wer.json +78 -0
- angr/procedures/definitions/win32/wevtapi.json +120 -0
- angr/procedures/definitions/win32/winbio.json +177 -0
- angr/procedures/definitions/win32/windows_ai_machinelearning.json +18 -0
- angr/procedures/definitions/win32/windows_media_mediacontrol.json +39 -0
- angr/procedures/definitions/win32/windows_networking.json +18 -0
- angr/procedures/definitions/win32/windows_ui_xaml.json +21 -0
- angr/procedures/definitions/win32/windowscodecs.json +42 -0
- angr/procedures/definitions/win32/winfax.json +183 -0
- angr/procedures/definitions/win32/winhttp.json +183 -0
- angr/procedures/definitions/win32/winhvemulation.json +27 -0
- angr/procedures/definitions/win32/winhvplatform.json +213 -0
- angr/procedures/definitions/win32/wininet.json +903 -0
- angr/procedures/definitions/win32/winml.json +18 -0
- angr/procedures/definitions/win32/winmm.json +543 -0
- angr/procedures/definitions/win32/winscard.json +225 -0
- angr/procedures/definitions/win32/winspool_drv.json +531 -0
- angr/procedures/definitions/win32/wintrust.json +195 -0
- angr/procedures/definitions/win32/winusb.json +117 -0
- angr/procedures/definitions/win32/wlanapi.json +195 -0
- angr/procedures/definitions/win32/wlanui.json +18 -0
- angr/procedures/definitions/win32/wldap32.json +744 -0
- angr/procedures/definitions/win32/wldp.json +42 -0
- angr/procedures/definitions/win32/wmvcore.json +48 -0
- angr/procedures/definitions/win32/wnvapi.json +21 -0
- angr/procedures/definitions/win32/wofutil.json +48 -0
- angr/procedures/definitions/win32/ws2_32.json +495 -0
- angr/procedures/definitions/win32/wscapi.json +33 -0
- angr/procedures/definitions/win32/wsclient.json +24 -0
- angr/procedures/definitions/win32/wsdapi.json +111 -0
- angr/procedures/definitions/win32/wsmsvc.json +114 -0
- angr/procedures/definitions/win32/wsnmp32.json +162 -0
- angr/procedures/definitions/win32/wtsapi32.json +204 -0
- angr/procedures/definitions/win32/xaudio2_8.json +27 -0
- angr/procedures/definitions/win32/xinput1_4.json +36 -0
- angr/procedures/definitions/win32/xmllite.json +33 -0
- angr/procedures/definitions/win32/xolehlp.json +27 -0
- angr/procedures/definitions/win32/xpsprint.json +21 -0
- angr/procedures/glibc/__ctype_b_loc.py +21 -0
- angr/procedures/glibc/__ctype_tolower_loc.py +21 -0
- angr/procedures/glibc/__ctype_toupper_loc.py +21 -0
- angr/procedures/glibc/__errno_location.py +7 -0
- angr/procedures/glibc/__init__.py +3 -0
- angr/procedures/glibc/__libc_init.py +37 -0
- angr/procedures/glibc/__libc_start_main.py +301 -0
- angr/procedures/glibc/dynamic_loading.py +20 -0
- angr/procedures/glibc/scanf.py +19 -0
- angr/procedures/glibc/sscanf.py +10 -0
- angr/procedures/gnulib/__init__.py +3 -0
- angr/procedures/gnulib/xalloc_die.py +14 -0
- angr/procedures/gnulib/xstrtol_fatal.py +14 -0
- angr/procedures/java/__init__.py +42 -0
- angr/procedures/java/unconstrained.py +65 -0
- angr/procedures/java_io/__init__.py +0 -0
- angr/procedures/java_io/read.py +12 -0
- angr/procedures/java_io/write.py +17 -0
- angr/procedures/java_jni/__init__.py +482 -0
- angr/procedures/java_jni/array_operations.py +312 -0
- angr/procedures/java_jni/class_and_interface_operations.py +31 -0
- angr/procedures/java_jni/field_access.py +173 -0
- angr/procedures/java_jni/global_and_local_refs.py +57 -0
- angr/procedures/java_jni/method_calls.py +365 -0
- angr/procedures/java_jni/not_implemented.py +26 -0
- angr/procedures/java_jni/object_operations.py +94 -0
- angr/procedures/java_jni/string_operations.py +87 -0
- angr/procedures/java_jni/version_information.py +12 -0
- angr/procedures/java_lang/__init__.py +0 -0
- angr/procedures/java_lang/character.py +30 -0
- angr/procedures/java_lang/double.py +24 -0
- angr/procedures/java_lang/exit.py +13 -0
- angr/procedures/java_lang/getsimplename.py +18 -0
- angr/procedures/java_lang/integer.py +43 -0
- angr/procedures/java_lang/load_library.py +9 -0
- angr/procedures/java_lang/math.py +15 -0
- angr/procedures/java_lang/string.py +78 -0
- angr/procedures/java_lang/stringbuilder.py +44 -0
- angr/procedures/java_lang/system.py +18 -0
- angr/procedures/java_util/__init__.py +0 -0
- angr/procedures/java_util/collection.py +35 -0
- angr/procedures/java_util/iterator.py +46 -0
- angr/procedures/java_util/list.py +99 -0
- angr/procedures/java_util/map.py +131 -0
- angr/procedures/java_util/random.py +14 -0
- angr/procedures/java_util/scanner_nextline.py +23 -0
- angr/procedures/libc/__init__.py +3 -0
- angr/procedures/libc/abort.py +9 -0
- angr/procedures/libc/access.py +13 -0
- angr/procedures/libc/atoi.py +14 -0
- angr/procedures/libc/atol.py +13 -0
- angr/procedures/libc/calloc.py +8 -0
- angr/procedures/libc/closelog.py +10 -0
- angr/procedures/libc/err.py +14 -0
- angr/procedures/libc/error.py +54 -0
- angr/procedures/libc/exit.py +11 -0
- angr/procedures/libc/fclose.py +19 -0
- angr/procedures/libc/feof.py +21 -0
- angr/procedures/libc/fflush.py +16 -0
- angr/procedures/libc/fgetc.py +27 -0
- angr/procedures/libc/fgets.py +69 -0
- angr/procedures/libc/fopen.py +63 -0
- angr/procedures/libc/fprintf.py +25 -0
- angr/procedures/libc/fputc.py +23 -0
- angr/procedures/libc/fputs.py +24 -0
- angr/procedures/libc/fread.py +24 -0
- angr/procedures/libc/free.py +9 -0
- angr/procedures/libc/fscanf.py +20 -0
- angr/procedures/libc/fseek.py +34 -0
- angr/procedures/libc/ftell.py +22 -0
- angr/procedures/libc/fwrite.py +19 -0
- angr/procedures/libc/getchar.py +13 -0
- angr/procedures/libc/getdelim.py +99 -0
- angr/procedures/libc/getegid.py +8 -0
- angr/procedures/libc/geteuid.py +8 -0
- angr/procedures/libc/getgid.py +8 -0
- angr/procedures/libc/gets.py +68 -0
- angr/procedures/libc/getuid.py +8 -0
- angr/procedures/libc/malloc.py +12 -0
- angr/procedures/libc/memcmp.py +69 -0
- angr/procedures/libc/memcpy.py +45 -0
- angr/procedures/libc/memset.py +72 -0
- angr/procedures/libc/openlog.py +10 -0
- angr/procedures/libc/perror.py +13 -0
- angr/procedures/libc/printf.py +34 -0
- angr/procedures/libc/putchar.py +13 -0
- angr/procedures/libc/puts.py +19 -0
- angr/procedures/libc/rand.py +8 -0
- angr/procedures/libc/realloc.py +8 -0
- angr/procedures/libc/rewind.py +12 -0
- angr/procedures/libc/scanf.py +20 -0
- angr/procedures/libc/setbuf.py +9 -0
- angr/procedures/libc/setvbuf.py +7 -0
- angr/procedures/libc/snprintf.py +36 -0
- angr/procedures/libc/sprintf.py +25 -0
- angr/procedures/libc/srand.py +7 -0
- angr/procedures/libc/sscanf.py +13 -0
- angr/procedures/libc/stpcpy.py +18 -0
- angr/procedures/libc/strcat.py +14 -0
- angr/procedures/libc/strchr.py +48 -0
- angr/procedures/libc/strcmp.py +31 -0
- angr/procedures/libc/strcpy.py +13 -0
- angr/procedures/libc/strlen.py +114 -0
- angr/procedures/libc/strncat.py +19 -0
- angr/procedures/libc/strncmp.py +183 -0
- angr/procedures/libc/strncpy.py +22 -0
- angr/procedures/libc/strnlen.py +13 -0
- angr/procedures/libc/strstr.py +101 -0
- angr/procedures/libc/strtol.py +261 -0
- angr/procedures/libc/strtoul.py +9 -0
- angr/procedures/libc/system.py +13 -0
- angr/procedures/libc/time.py +9 -0
- angr/procedures/libc/tmpnam.py +20 -0
- angr/procedures/libc/tolower.py +10 -0
- angr/procedures/libc/toupper.py +10 -0
- angr/procedures/libc/ungetc.py +20 -0
- angr/procedures/libc/vsnprintf.py +17 -0
- angr/procedures/libc/wchar.py +16 -0
- angr/procedures/libstdcpp/__init__.py +0 -0
- angr/procedures/libstdcpp/_unwind_resume.py +11 -0
- angr/procedures/libstdcpp/std____throw_bad_alloc.py +13 -0
- angr/procedures/libstdcpp/std____throw_bad_cast.py +13 -0
- angr/procedures/libstdcpp/std____throw_length_error.py +13 -0
- angr/procedures/libstdcpp/std____throw_logic_error.py +13 -0
- angr/procedures/libstdcpp/std__terminate.py +13 -0
- angr/procedures/linux_kernel/__init__.py +3 -0
- angr/procedures/linux_kernel/access.py +18 -0
- angr/procedures/linux_kernel/arch_prctl.py +34 -0
- angr/procedures/linux_kernel/arm_user_helpers.py +59 -0
- angr/procedures/linux_kernel/brk.py +18 -0
- angr/procedures/linux_kernel/cwd.py +28 -0
- angr/procedures/linux_kernel/fstat.py +138 -0
- angr/procedures/linux_kernel/fstat64.py +170 -0
- angr/procedures/linux_kernel/futex.py +17 -0
- angr/procedures/linux_kernel/getegid.py +17 -0
- angr/procedures/linux_kernel/geteuid.py +17 -0
- angr/procedures/linux_kernel/getgid.py +17 -0
- angr/procedures/linux_kernel/getpid.py +14 -0
- angr/procedures/linux_kernel/getrlimit.py +24 -0
- angr/procedures/linux_kernel/gettid.py +9 -0
- angr/procedures/linux_kernel/getuid.py +17 -0
- angr/procedures/linux_kernel/iovec.py +47 -0
- angr/procedures/linux_kernel/lseek.py +42 -0
- angr/procedures/linux_kernel/mmap.py +16 -0
- angr/procedures/linux_kernel/mprotect.py +42 -0
- angr/procedures/linux_kernel/munmap.py +8 -0
- angr/procedures/linux_kernel/openat.py +26 -0
- angr/procedures/linux_kernel/set_tid_address.py +8 -0
- angr/procedures/linux_kernel/sigaction.py +19 -0
- angr/procedures/linux_kernel/sigprocmask.py +23 -0
- angr/procedures/linux_kernel/stat.py +23 -0
- angr/procedures/linux_kernel/sysinfo.py +59 -0
- angr/procedures/linux_kernel/tgkill.py +10 -0
- angr/procedures/linux_kernel/time.py +34 -0
- angr/procedures/linux_kernel/uid.py +30 -0
- angr/procedures/linux_kernel/uname.py +29 -0
- angr/procedures/linux_kernel/unlink.py +22 -0
- angr/procedures/linux_kernel/vsyscall.py +16 -0
- angr/procedures/linux_loader/__init__.py +3 -0
- angr/procedures/linux_loader/_dl_initial_error_catch_tsd.py +7 -0
- angr/procedures/linux_loader/_dl_rtld_lock.py +15 -0
- angr/procedures/linux_loader/sim_loader.py +54 -0
- angr/procedures/linux_loader/tls.py +40 -0
- angr/procedures/msvcr/__getmainargs.py +16 -0
- angr/procedures/msvcr/__init__.py +4 -0
- angr/procedures/msvcr/_initterm.py +38 -0
- angr/procedures/msvcr/fmode.py +31 -0
- angr/procedures/ntdll/__init__.py +0 -0
- angr/procedures/ntdll/exceptions.py +60 -0
- angr/procedures/posix/__init__.py +3 -0
- angr/procedures/posix/accept.py +29 -0
- angr/procedures/posix/bind.py +13 -0
- angr/procedures/posix/bzero.py +9 -0
- angr/procedures/posix/chroot.py +27 -0
- angr/procedures/posix/close.py +9 -0
- angr/procedures/posix/closedir.py +7 -0
- angr/procedures/posix/dup.py +56 -0
- angr/procedures/posix/fcntl.py +10 -0
- angr/procedures/posix/fdopen.py +76 -0
- angr/procedures/posix/fileno.py +18 -0
- angr/procedures/posix/fork.py +13 -0
- angr/procedures/posix/getenv.py +35 -0
- angr/procedures/posix/gethostbyname.py +43 -0
- angr/procedures/posix/getpass.py +19 -0
- angr/procedures/posix/getsockopt.py +11 -0
- angr/procedures/posix/htonl.py +11 -0
- angr/procedures/posix/htons.py +11 -0
- angr/procedures/posix/inet_ntoa.py +59 -0
- angr/procedures/posix/listen.py +13 -0
- angr/procedures/posix/mmap.py +144 -0
- angr/procedures/posix/open.py +18 -0
- angr/procedures/posix/opendir.py +10 -0
- angr/procedures/posix/poll.py +55 -0
- angr/procedures/posix/pread64.py +46 -0
- angr/procedures/posix/pthread.py +87 -0
- angr/procedures/posix/pwrite64.py +46 -0
- angr/procedures/posix/read.py +13 -0
- angr/procedures/posix/readdir.py +62 -0
- angr/procedures/posix/recv.py +13 -0
- angr/procedures/posix/recvfrom.py +13 -0
- angr/procedures/posix/select.py +48 -0
- angr/procedures/posix/send.py +23 -0
- angr/procedures/posix/setsockopt.py +9 -0
- angr/procedures/posix/sigaction.py +23 -0
- angr/procedures/posix/sim_time.py +48 -0
- angr/procedures/posix/sleep.py +8 -0
- angr/procedures/posix/socket.py +18 -0
- angr/procedures/posix/strcasecmp.py +26 -0
- angr/procedures/posix/strdup.py +18 -0
- angr/procedures/posix/strtok_r.py +64 -0
- angr/procedures/posix/syslog.py +15 -0
- angr/procedures/posix/tz.py +9 -0
- angr/procedures/posix/unlink.py +11 -0
- angr/procedures/posix/usleep.py +8 -0
- angr/procedures/posix/write.py +13 -0
- angr/procedures/procedure_dict.py +50 -0
- angr/procedures/stubs/CallReturn.py +13 -0
- angr/procedures/stubs/NoReturnUnconstrained.py +13 -0
- angr/procedures/stubs/Nop.py +7 -0
- angr/procedures/stubs/PathTerminator.py +9 -0
- angr/procedures/stubs/Redirect.py +18 -0
- angr/procedures/stubs/ReturnChar.py +11 -0
- angr/procedures/stubs/ReturnUnconstrained.py +24 -0
- angr/procedures/stubs/UnresolvableCallTarget.py +9 -0
- angr/procedures/stubs/UnresolvableJumpTarget.py +9 -0
- angr/procedures/stubs/UserHook.py +18 -0
- angr/procedures/stubs/__init__.py +3 -0
- angr/procedures/stubs/b64_decode.py +15 -0
- angr/procedures/stubs/caller.py +14 -0
- angr/procedures/stubs/crazy_scanf.py +20 -0
- angr/procedures/stubs/format_parser.py +669 -0
- angr/procedures/stubs/syscall_stub.py +24 -0
- angr/procedures/testing/__init__.py +3 -0
- angr/procedures/testing/manyargs.py +9 -0
- angr/procedures/testing/retreg.py +8 -0
- angr/procedures/tracer/__init__.py +4 -0
- angr/procedures/tracer/random.py +9 -0
- angr/procedures/tracer/receive.py +23 -0
- angr/procedures/tracer/transmit.py +26 -0
- angr/procedures/uclibc/__init__.py +3 -0
- angr/procedures/uclibc/__uClibc_main.py +10 -0
- angr/procedures/win32/EncodePointer.py +7 -0
- angr/procedures/win32/ExitProcess.py +9 -0
- angr/procedures/win32/GetCommandLine.py +12 -0
- angr/procedures/win32/GetCurrentProcessId.py +7 -0
- angr/procedures/win32/GetCurrentThreadId.py +7 -0
- angr/procedures/win32/GetLastInputInfo.py +40 -0
- angr/procedures/win32/GetModuleHandle.py +29 -0
- angr/procedures/win32/GetProcessAffinityMask.py +37 -0
- angr/procedures/win32/InterlockedExchange.py +15 -0
- angr/procedures/win32/IsProcessorFeaturePresent.py +7 -0
- angr/procedures/win32/VirtualAlloc.py +114 -0
- angr/procedures/win32/VirtualProtect.py +60 -0
- angr/procedures/win32/__init__.py +3 -0
- angr/procedures/win32/critical_section.py +12 -0
- angr/procedures/win32/dynamic_loading.py +104 -0
- angr/procedures/win32/file_handles.py +47 -0
- angr/procedures/win32/gethostbyname.py +12 -0
- angr/procedures/win32/heap.py +45 -0
- angr/procedures/win32/is_bad_ptr.py +26 -0
- angr/procedures/win32/local_storage.py +88 -0
- angr/procedures/win32/mutex.py +11 -0
- angr/procedures/win32/sim_time.py +135 -0
- angr/procedures/win32/system_paths.py +35 -0
- angr/procedures/win32_kernel/ExAllocatePool.py +13 -0
- angr/procedures/win32_kernel/ExFreePoolWithTag.py +8 -0
- angr/procedures/win32_kernel/__fastfail.py +15 -0
- angr/procedures/win32_kernel/__init__.py +3 -0
- angr/procedures/win_user32/__init__.py +0 -0
- angr/procedures/win_user32/chars.py +15 -0
- angr/procedures/win_user32/keyboard.py +14 -0
- angr/procedures/win_user32/messagebox.py +49 -0
- angr/project.py +860 -0
- angr/protos/__init__.py +19 -0
- angr/protos/cfg_pb2.py +42 -0
- angr/protos/function_pb2.py +38 -0
- angr/protos/primitives_pb2.py +59 -0
- angr/protos/variables_pb2.py +55 -0
- angr/protos/xrefs_pb2.py +36 -0
- angr/py.typed +1 -0
- angr/rustylib.cpython-311-darwin.so +0 -0
- angr/serializable.py +66 -0
- angr/sim_manager.py +971 -0
- angr/sim_options.py +436 -0
- angr/sim_procedure.py +626 -0
- angr/sim_state.py +926 -0
- angr/sim_state_options.py +403 -0
- angr/sim_type.py +4026 -0
- angr/sim_variable.py +470 -0
- angr/simos/__init__.py +47 -0
- angr/simos/cgc.py +153 -0
- angr/simos/javavm.py +458 -0
- angr/simos/linux.py +509 -0
- angr/simos/simos.py +444 -0
- angr/simos/snimmuc_nxp.py +149 -0
- angr/simos/userland.py +163 -0
- angr/simos/windows.py +615 -0
- angr/simos/xbox.py +32 -0
- angr/slicer.py +352 -0
- angr/state_hierarchy.py +262 -0
- angr/state_plugins/__init__.py +84 -0
- angr/state_plugins/callstack.py +478 -0
- angr/state_plugins/cgc.py +155 -0
- angr/state_plugins/debug_variables.py +192 -0
- angr/state_plugins/filesystem.py +463 -0
- angr/state_plugins/gdb.py +148 -0
- angr/state_plugins/globals.py +65 -0
- angr/state_plugins/heap/__init__.py +15 -0
- angr/state_plugins/heap/heap_base.py +128 -0
- angr/state_plugins/heap/heap_brk.py +136 -0
- angr/state_plugins/heap/heap_freelist.py +213 -0
- angr/state_plugins/heap/heap_libc.py +46 -0
- angr/state_plugins/heap/heap_ptmalloc.py +620 -0
- angr/state_plugins/heap/utils.py +22 -0
- angr/state_plugins/history.py +564 -0
- angr/state_plugins/inspect.py +375 -0
- angr/state_plugins/javavm_classloader.py +134 -0
- angr/state_plugins/jni_references.py +95 -0
- angr/state_plugins/libc.py +1263 -0
- angr/state_plugins/light_registers.py +168 -0
- angr/state_plugins/log.py +84 -0
- angr/state_plugins/loop_data.py +92 -0
- angr/state_plugins/plugin.py +176 -0
- angr/state_plugins/posix.py +703 -0
- angr/state_plugins/preconstrainer.py +196 -0
- angr/state_plugins/scratch.py +173 -0
- angr/state_plugins/sim_action.py +326 -0
- angr/state_plugins/sim_action_object.py +271 -0
- angr/state_plugins/sim_event.py +59 -0
- angr/state_plugins/solver.py +1128 -0
- angr/state_plugins/symbolizer.py +291 -0
- angr/state_plugins/trace_additions.py +738 -0
- angr/state_plugins/uc_manager.py +94 -0
- angr/state_plugins/unicorn_engine.py +1920 -0
- angr/state_plugins/view.py +340 -0
- angr/storage/__init__.py +15 -0
- angr/storage/file.py +1210 -0
- angr/storage/memory_mixins/__init__.py +317 -0
- angr/storage/memory_mixins/actions_mixin.py +72 -0
- angr/storage/memory_mixins/address_concretization_mixin.py +384 -0
- angr/storage/memory_mixins/bvv_conversion_mixin.py +73 -0
- angr/storage/memory_mixins/clouseau_mixin.py +137 -0
- angr/storage/memory_mixins/conditional_store_mixin.py +25 -0
- angr/storage/memory_mixins/convenient_mappings_mixin.py +256 -0
- angr/storage/memory_mixins/default_filler_mixin.py +144 -0
- angr/storage/memory_mixins/dirty_addrs_mixin.py +11 -0
- angr/storage/memory_mixins/hex_dumper_mixin.py +82 -0
- angr/storage/memory_mixins/javavm_memory_mixin.py +392 -0
- angr/storage/memory_mixins/keyvalue_memory_mixin.py +43 -0
- angr/storage/memory_mixins/label_merger_mixin.py +31 -0
- angr/storage/memory_mixins/memory_mixin.py +175 -0
- angr/storage/memory_mixins/multi_value_merger_mixin.py +79 -0
- angr/storage/memory_mixins/name_resolution_mixin.py +67 -0
- angr/storage/memory_mixins/paged_memory/__init__.py +0 -0
- angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +266 -0
- angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +743 -0
- angr/storage/memory_mixins/paged_memory/paged_memory_multivalue_mixin.py +65 -0
- angr/storage/memory_mixins/paged_memory/pages/__init__.py +26 -0
- angr/storage/memory_mixins/paged_memory/pages/base.py +31 -0
- angr/storage/memory_mixins/paged_memory/pages/cooperation.py +341 -0
- angr/storage/memory_mixins/paged_memory/pages/history_tracking_mixin.py +92 -0
- angr/storage/memory_mixins/paged_memory/pages/ispo_mixin.py +55 -0
- angr/storage/memory_mixins/paged_memory/pages/list_page.py +338 -0
- angr/storage/memory_mixins/paged_memory/pages/multi_values.py +324 -0
- angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +419 -0
- angr/storage/memory_mixins/paged_memory/pages/permissions_mixin.py +36 -0
- angr/storage/memory_mixins/paged_memory/pages/refcount_mixin.py +52 -0
- angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +529 -0
- angr/storage/memory_mixins/paged_memory/privileged_mixin.py +36 -0
- angr/storage/memory_mixins/paged_memory/stack_allocation_mixin.py +74 -0
- angr/storage/memory_mixins/regioned_memory/__init__.py +17 -0
- angr/storage/memory_mixins/regioned_memory/abstract_address_descriptor.py +36 -0
- angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +31 -0
- angr/storage/memory_mixins/regioned_memory/region_category_mixin.py +9 -0
- angr/storage/memory_mixins/regioned_memory/region_data.py +246 -0
- angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +241 -0
- angr/storage/memory_mixins/regioned_memory/regioned_address_concretization_mixin.py +119 -0
- angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +442 -0
- angr/storage/memory_mixins/regioned_memory/static_find_mixin.py +69 -0
- angr/storage/memory_mixins/simple_interface_mixin.py +71 -0
- angr/storage/memory_mixins/simplification_mixin.py +15 -0
- angr/storage/memory_mixins/size_resolution_mixin.py +143 -0
- angr/storage/memory_mixins/slotted_memory.py +140 -0
- angr/storage/memory_mixins/smart_find_mixin.py +161 -0
- angr/storage/memory_mixins/symbolic_merger_mixin.py +16 -0
- angr/storage/memory_mixins/top_merger_mixin.py +25 -0
- angr/storage/memory_mixins/underconstrained_mixin.py +67 -0
- angr/storage/memory_mixins/unwrapper_mixin.py +26 -0
- angr/storage/memory_object.py +195 -0
- angr/tablespecs.py +91 -0
- angr/unicornlib.dylib +0 -0
- angr/utils/__init__.py +46 -0
- angr/utils/ail.py +176 -0
- angr/utils/algo.py +34 -0
- angr/utils/balancer.py +776 -0
- angr/utils/bits.py +46 -0
- angr/utils/constants.py +9 -0
- angr/utils/cowdict.py +63 -0
- angr/utils/cpp.py +17 -0
- angr/utils/doms.py +150 -0
- angr/utils/dynamic_dictlist.py +89 -0
- angr/utils/endness.py +18 -0
- angr/utils/enums_conv.py +97 -0
- angr/utils/env.py +12 -0
- angr/utils/formatting.py +128 -0
- angr/utils/funcid.py +244 -0
- angr/utils/graph.py +981 -0
- angr/utils/lazy_import.py +13 -0
- angr/utils/library.py +236 -0
- angr/utils/loader.py +55 -0
- angr/utils/mp.py +66 -0
- angr/utils/orderedset.py +74 -0
- angr/utils/ssa/__init__.py +455 -0
- angr/utils/ssa/tmp_uses_collector.py +23 -0
- angr/utils/ssa/vvar_uses_collector.py +36 -0
- angr/utils/strings.py +20 -0
- angr/utils/tagged_interval_map.py +112 -0
- angr/utils/timing.py +74 -0
- angr/utils/types.py +193 -0
- angr/utils/vex.py +11 -0
- angr/vaults.py +367 -0
- angr-9.2.192.dist-info/METADATA +112 -0
- angr-9.2.192.dist-info/RECORD +1442 -0
- angr-9.2.192.dist-info/WHEEL +6 -0
- angr-9.2.192.dist-info/entry_points.txt +2 -0
- angr-9.2.192.dist-info/licenses/LICENSE +27 -0
- angr-9.2.192.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,2246 @@
|
|
|
1
|
+
# pylint:disable=too-many-boolean-expressions,consider-using-enumerate
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from typing import Any, TYPE_CHECKING
|
|
4
|
+
from collections.abc import Container
|
|
5
|
+
from collections.abc import Iterable
|
|
6
|
+
from collections import defaultdict
|
|
7
|
+
from enum import Enum
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
import networkx
|
|
11
|
+
|
|
12
|
+
from angr.ailment import AILBlockRewriter, AILBlockViewer
|
|
13
|
+
from angr.ailment.block import Block
|
|
14
|
+
from angr.ailment.statement import (
|
|
15
|
+
Statement,
|
|
16
|
+
Assignment,
|
|
17
|
+
Store,
|
|
18
|
+
Call,
|
|
19
|
+
ConditionalJump,
|
|
20
|
+
DirtyStatement,
|
|
21
|
+
WeakAssignment,
|
|
22
|
+
Return,
|
|
23
|
+
)
|
|
24
|
+
from angr.ailment.expression import (
|
|
25
|
+
Register,
|
|
26
|
+
Convert,
|
|
27
|
+
Load,
|
|
28
|
+
StackBaseOffset,
|
|
29
|
+
Expression,
|
|
30
|
+
DirtyExpression,
|
|
31
|
+
VEXCCallExpression,
|
|
32
|
+
Tmp,
|
|
33
|
+
Const,
|
|
34
|
+
BinaryOp,
|
|
35
|
+
VirtualVariable,
|
|
36
|
+
UnaryOp,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
from angr.analyses.s_propagator import SPropagatorAnalysis
|
|
40
|
+
from angr.analyses.s_reaching_definitions import SRDAModel, SReachingDefinitionsAnalysis
|
|
41
|
+
from angr.utils.ail import is_phi_assignment, HasExprWalker, is_expr_used_as_reg_base_value
|
|
42
|
+
from angr.utils.ssa import (
|
|
43
|
+
has_call_in_between_stmts,
|
|
44
|
+
has_store_stmt_in_between_stmts,
|
|
45
|
+
has_load_expr_in_between_stmts,
|
|
46
|
+
is_vvar_eliminatable,
|
|
47
|
+
)
|
|
48
|
+
from angr.code_location import AILCodeLocation
|
|
49
|
+
from angr.sim_variable import SimStackVariable, SimMemoryVariable, SimVariable
|
|
50
|
+
from angr.knowledge_plugins.propagations.states import Equivalence
|
|
51
|
+
from angr.knowledge_plugins.key_definitions import atoms
|
|
52
|
+
from angr.knowledge_plugins.key_definitions.definition import Definition
|
|
53
|
+
from angr.knowledge_plugins.key_definitions.constants import OP_BEFORE
|
|
54
|
+
from angr.errors import AngrRuntimeError
|
|
55
|
+
from angr.analyses import Analysis, AnalysesHub
|
|
56
|
+
from angr.utils.timing import timethis
|
|
57
|
+
from .ailgraph_walker import AILGraphWalker
|
|
58
|
+
from .expression_narrower import ExprNarrowingInfo, NarrowingInfoExtractor, ExpressionNarrower
|
|
59
|
+
from .block_simplifier import BlockSimplifier
|
|
60
|
+
from .ccall_rewriters import CCALL_REWRITERS
|
|
61
|
+
from .dirty_rewriters import DIRTY_REWRITERS
|
|
62
|
+
from .counters.expression_counters import SingleExpressionCounter
|
|
63
|
+
|
|
64
|
+
if TYPE_CHECKING:
|
|
65
|
+
from angr.ailment.manager import Manager
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
_l = logging.getLogger(__name__)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class HasCallNotification(Exception):
|
|
72
|
+
"""
|
|
73
|
+
Notifies the existence of a call statement.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class HasVVarNotification(Exception):
|
|
78
|
+
"""
|
|
79
|
+
Notifies the existence of a VirtualVariable.
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class HasRefVVarNotification(Exception):
|
|
84
|
+
"""
|
|
85
|
+
Notifies the existence of a reference to a VirtualVariable.
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class AILBlockTempCollector(AILBlockViewer):
|
|
90
|
+
"""
|
|
91
|
+
Collects any temporaries used in a block.
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
def __init__(self, **kwargs):
|
|
95
|
+
super().__init__(**kwargs)
|
|
96
|
+
self.temps = set()
|
|
97
|
+
self.expr_handlers[Tmp] = self._handle_Tmp
|
|
98
|
+
|
|
99
|
+
# pylint:disable=unused-argument
|
|
100
|
+
def _handle_Tmp(self, expr_idx: int, expr: Expression, stmt_idx: int, stmt: Statement | None, block):
|
|
101
|
+
if isinstance(expr, Tmp):
|
|
102
|
+
self.temps.add(expr)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class DefEqRelation(Enum):
|
|
106
|
+
"""
|
|
107
|
+
Describes the location relationship between a virtual variable definition and the equivalence statement.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
UNKNOWN = 0
|
|
111
|
+
DEF_IS_FUNCARG = 1
|
|
112
|
+
DEF_EQ_SAME_BLOCK = 2
|
|
113
|
+
DEF_IN_EQ_PRED_BLOCK = 3
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class PartialConstantExprRewriter(AILBlockRewriter):
|
|
117
|
+
"""
|
|
118
|
+
Rewrites expressions whose high bits are definitely zero to constants (if possible) or mask them with masks
|
|
119
|
+
properly.
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
def __init__(self, varid: int, zero_high_bits: int):
|
|
123
|
+
super().__init__(update_block=False)
|
|
124
|
+
self.varid = varid
|
|
125
|
+
self.zero_high_bits = zero_high_bits
|
|
126
|
+
|
|
127
|
+
def _handle_BinaryOp( # type:ignore
|
|
128
|
+
self, expr_idx: int, expr: BinaryOp, stmt_idx: int, stmt: Statement, block: Block | None
|
|
129
|
+
):
|
|
130
|
+
if (
|
|
131
|
+
expr.op == "And"
|
|
132
|
+
and isinstance(expr.operands[0], VirtualVariable)
|
|
133
|
+
and expr.operands[0].varid == self.varid
|
|
134
|
+
and isinstance(expr.operands[1], Const)
|
|
135
|
+
and expr.operands[1].is_int
|
|
136
|
+
):
|
|
137
|
+
vvar = expr.operands[0]
|
|
138
|
+
mask_expr = expr.operands[1]
|
|
139
|
+
mask = mask_expr.value
|
|
140
|
+
assert isinstance(mask, int)
|
|
141
|
+
# high_bits_mask[vvar.bits - 1:vvar.bits - self.zero_high_bits] == 0
|
|
142
|
+
high_bits_mask = ((1 << vvar.bits) - 1) ^ ((1 << (vvar.bits - self.zero_high_bits)) - 1)
|
|
143
|
+
high_bits_mask &= mask # in case high bits of mask are zero
|
|
144
|
+
new_mask = mask ^ high_bits_mask
|
|
145
|
+
if new_mask == mask:
|
|
146
|
+
return expr
|
|
147
|
+
if new_mask == 0:
|
|
148
|
+
return Const(expr_idx, None, 0, expr.bits, **expr.tags)
|
|
149
|
+
new_mask_expr = Const(mask_expr.idx, mask_expr.variable, new_mask, mask_expr.bits, **mask_expr.tags)
|
|
150
|
+
return BinaryOp(expr_idx, expr.op, [vvar, new_mask_expr], bits=expr.bits, **expr.tags)
|
|
151
|
+
return super()._handle_BinaryOp(expr_idx, expr, stmt_idx, stmt, block)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class AILSimplifier(Analysis):
|
|
155
|
+
"""
|
|
156
|
+
Perform function-level simplifications.
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
def __init__(
|
|
160
|
+
self,
|
|
161
|
+
func,
|
|
162
|
+
func_graph=None,
|
|
163
|
+
remove_dead_memdefs=False,
|
|
164
|
+
stack_arg_offsets: set[tuple[int, int]] | None = None,
|
|
165
|
+
unify_variables=False,
|
|
166
|
+
ail_manager: Manager | None = None,
|
|
167
|
+
gp: int | None = None,
|
|
168
|
+
narrow_expressions=False,
|
|
169
|
+
only_consts=False,
|
|
170
|
+
fold_callexprs_into_conditions=False,
|
|
171
|
+
use_callee_saved_regs_at_return=True,
|
|
172
|
+
rewrite_ccalls=True,
|
|
173
|
+
rename_ccalls=True,
|
|
174
|
+
rewrite_dirty=True,
|
|
175
|
+
removed_vvar_ids: set[int] | None = None,
|
|
176
|
+
arg_vvars: dict[int, tuple[VirtualVariable, SimVariable]] | None = None,
|
|
177
|
+
avoid_vvar_ids: set[int] | None = None,
|
|
178
|
+
secondary_stackvars: set[int] | None = None,
|
|
179
|
+
):
|
|
180
|
+
self.func = func
|
|
181
|
+
self.func_graph = func_graph if func_graph is not None else func.graph
|
|
182
|
+
self._reaching_definitions: SRDAModel | None = None
|
|
183
|
+
self._propagator: SPropagatorAnalysis | None = None
|
|
184
|
+
|
|
185
|
+
self._remove_dead_memdefs = remove_dead_memdefs
|
|
186
|
+
self._stack_arg_offsets = stack_arg_offsets
|
|
187
|
+
self._unify_vars = unify_variables
|
|
188
|
+
self._ail_manager: Manager | None = ail_manager
|
|
189
|
+
self._gp = gp
|
|
190
|
+
self._narrow_expressions = narrow_expressions
|
|
191
|
+
self._only_consts = only_consts
|
|
192
|
+
self._fold_callexprs_into_conditions = fold_callexprs_into_conditions
|
|
193
|
+
self._use_callee_saved_regs_at_return = use_callee_saved_regs_at_return
|
|
194
|
+
self._should_rewrite_ccalls = rewrite_ccalls
|
|
195
|
+
self._should_rename_ccalls = rename_ccalls
|
|
196
|
+
self._should_rewrite_dirty = rewrite_dirty
|
|
197
|
+
self._removed_vvar_ids = removed_vvar_ids if removed_vvar_ids is not None else set()
|
|
198
|
+
self._arg_vvars = arg_vvars
|
|
199
|
+
self._avoid_vvar_ids = avoid_vvar_ids if avoid_vvar_ids is not None else set()
|
|
200
|
+
self._propagator_dead_vvar_ids: set[int] = set()
|
|
201
|
+
self._secondary_stackvars: set[int] = secondary_stackvars if secondary_stackvars is not None else set()
|
|
202
|
+
|
|
203
|
+
self._calls_to_remove: set[AILCodeLocation] = set()
|
|
204
|
+
self._assignments_to_remove: set[AILCodeLocation] = set()
|
|
205
|
+
self.blocks = {} # Mapping nodes to simplified blocks
|
|
206
|
+
|
|
207
|
+
self.simplified: bool = False
|
|
208
|
+
self._simplify()
|
|
209
|
+
|
|
210
|
+
def _simplify(self):
|
|
211
|
+
if self._narrow_expressions:
|
|
212
|
+
_l.debug("Removing dead assignments before narrowing expressions")
|
|
213
|
+
r = self._iteratively_remove_dead_assignments()
|
|
214
|
+
if r:
|
|
215
|
+
_l.debug("... dead assignments removed")
|
|
216
|
+
self.simplified = True
|
|
217
|
+
|
|
218
|
+
_l.debug("Narrowing expressions")
|
|
219
|
+
narrowed_exprs = self._narrow_exprs()
|
|
220
|
+
self.simplified |= narrowed_exprs
|
|
221
|
+
if narrowed_exprs:
|
|
222
|
+
_l.debug("... expressions narrowed")
|
|
223
|
+
self._rebuild_func_graph()
|
|
224
|
+
self._clear_cache()
|
|
225
|
+
|
|
226
|
+
_l.debug("Folding expressions")
|
|
227
|
+
folded_exprs = self._fold_exprs()
|
|
228
|
+
self.simplified |= folded_exprs
|
|
229
|
+
if folded_exprs:
|
|
230
|
+
_l.debug("... expressions folded")
|
|
231
|
+
self._rebuild_func_graph()
|
|
232
|
+
# reaching definition analysis results are no longer reliable
|
|
233
|
+
self._clear_cache()
|
|
234
|
+
|
|
235
|
+
_l.debug("Propagating partial-constant expressions")
|
|
236
|
+
pconst_propagated = self._propagate_partial_constant_exprs()
|
|
237
|
+
self.simplified |= pconst_propagated
|
|
238
|
+
if pconst_propagated:
|
|
239
|
+
_l.debug("... partial-constant expressions propagated")
|
|
240
|
+
self._rebuild_func_graph()
|
|
241
|
+
# reaching definition analysis results are no longer reliable
|
|
242
|
+
self._clear_cache()
|
|
243
|
+
|
|
244
|
+
_l.debug("Rewriting constant expressions with phi variables")
|
|
245
|
+
phi_const_rewritten = self._rewrite_phi_const_exprs()
|
|
246
|
+
self.simplified |= phi_const_rewritten
|
|
247
|
+
if phi_const_rewritten:
|
|
248
|
+
_l.debug("... constant expressions with phi variables rewritten")
|
|
249
|
+
self._rebuild_func_graph()
|
|
250
|
+
# reaching definition analysis results are no longer reliable
|
|
251
|
+
self._clear_cache()
|
|
252
|
+
|
|
253
|
+
if self._only_consts:
|
|
254
|
+
return
|
|
255
|
+
|
|
256
|
+
_l.debug("Removing dead assignments")
|
|
257
|
+
r = self._iteratively_remove_dead_assignments()
|
|
258
|
+
if r:
|
|
259
|
+
_l.debug("... dead assignments removed")
|
|
260
|
+
self.simplified = True
|
|
261
|
+
|
|
262
|
+
if self._should_rewrite_ccalls:
|
|
263
|
+
_l.debug("Rewriting ccalls")
|
|
264
|
+
ccalls_rewritten = self._rewrite_ccalls()
|
|
265
|
+
self.simplified |= ccalls_rewritten
|
|
266
|
+
if ccalls_rewritten:
|
|
267
|
+
_l.debug("... ccalls rewritten")
|
|
268
|
+
self._rebuild_func_graph()
|
|
269
|
+
self._clear_cache()
|
|
270
|
+
|
|
271
|
+
if self._should_rewrite_dirty:
|
|
272
|
+
_l.debug("Rewriting dirty expressions/statements")
|
|
273
|
+
dirty_rewritten = self._rewrite_dirty_calls()
|
|
274
|
+
self.simplified |= dirty_rewritten
|
|
275
|
+
if dirty_rewritten:
|
|
276
|
+
_l.debug("... dirty expressions/statements rewritten")
|
|
277
|
+
self._rebuild_func_graph()
|
|
278
|
+
self._clear_cache()
|
|
279
|
+
|
|
280
|
+
if self._unify_vars:
|
|
281
|
+
_l.debug("Removing dead assignments")
|
|
282
|
+
r = self._iteratively_remove_dead_assignments()
|
|
283
|
+
if r:
|
|
284
|
+
_l.debug("... dead assignments removed")
|
|
285
|
+
self.simplified = True
|
|
286
|
+
|
|
287
|
+
_l.debug("Unifying local variables")
|
|
288
|
+
r = self._unify_local_variables()
|
|
289
|
+
if r:
|
|
290
|
+
_l.debug("... local variables unified")
|
|
291
|
+
self.simplified = True
|
|
292
|
+
self._rebuild_func_graph()
|
|
293
|
+
|
|
294
|
+
# _fold_call_exprs() may set self._calls_to_remove, which will be honored in _remove_dead_assignments()
|
|
295
|
+
_l.debug("Folding call expressions")
|
|
296
|
+
r = self._fold_call_exprs()
|
|
297
|
+
if r:
|
|
298
|
+
_l.debug("... call expressions folded")
|
|
299
|
+
self.simplified = True
|
|
300
|
+
self._rebuild_func_graph()
|
|
301
|
+
self._clear_cache()
|
|
302
|
+
|
|
303
|
+
_l.debug("Removing dead assignments")
|
|
304
|
+
r = self._iteratively_remove_dead_assignments()
|
|
305
|
+
if r:
|
|
306
|
+
_l.debug("... dead assignments removed")
|
|
307
|
+
self.simplified = True
|
|
308
|
+
|
|
309
|
+
def _rebuild_func_graph(self):
|
|
310
|
+
def _handler(node):
|
|
311
|
+
return self.blocks.get(node, None)
|
|
312
|
+
|
|
313
|
+
AILGraphWalker(self.func_graph, _handler, replace_nodes=True).walk()
|
|
314
|
+
self.blocks = {}
|
|
315
|
+
|
|
316
|
+
def _compute_reaching_definitions(self) -> SRDAModel:
|
|
317
|
+
# Computing reaching definitions or return the cached one
|
|
318
|
+
if self._reaching_definitions is not None:
|
|
319
|
+
return self._reaching_definitions
|
|
320
|
+
func_args = {vvar for vvar, _ in self._arg_vvars.values()} if self._arg_vvars else set()
|
|
321
|
+
rd = (
|
|
322
|
+
self.project.analyses[SReachingDefinitionsAnalysis]
|
|
323
|
+
.prep()(
|
|
324
|
+
subject=self.func,
|
|
325
|
+
func_graph=self.func_graph,
|
|
326
|
+
func_args=func_args,
|
|
327
|
+
use_callee_saved_regs_at_return=self._use_callee_saved_regs_at_return,
|
|
328
|
+
# track_tmps=True,
|
|
329
|
+
)
|
|
330
|
+
.model
|
|
331
|
+
)
|
|
332
|
+
self._reaching_definitions = rd
|
|
333
|
+
return rd
|
|
334
|
+
|
|
335
|
+
@timethis
|
|
336
|
+
def _compute_propagation(self) -> SPropagatorAnalysis:
|
|
337
|
+
# Propagate expressions or return the existing result
|
|
338
|
+
if self._propagator is not None:
|
|
339
|
+
return self._propagator
|
|
340
|
+
func_args = {vvar for vvar, _ in self._arg_vvars.values()} if self._arg_vvars else set()
|
|
341
|
+
prop = self.project.analyses[SPropagatorAnalysis].prep(fail_fast=self._fail_fast)(
|
|
342
|
+
subject=self.func,
|
|
343
|
+
func_graph=self.func_graph,
|
|
344
|
+
func_args=func_args,
|
|
345
|
+
# gp=self._gp,
|
|
346
|
+
only_consts=self._only_consts,
|
|
347
|
+
)
|
|
348
|
+
self._propagator = prop
|
|
349
|
+
self._propagator_dead_vvar_ids = prop.dead_vvar_ids
|
|
350
|
+
return prop
|
|
351
|
+
|
|
352
|
+
@timethis
|
|
353
|
+
def _compute_equivalence(self) -> set[Equivalence]:
|
|
354
|
+
equivalence = set()
|
|
355
|
+
for block in self.func_graph:
|
|
356
|
+
for stmt_idx, stmt in enumerate(block.statements):
|
|
357
|
+
if isinstance(stmt, Assignment):
|
|
358
|
+
if isinstance(stmt.dst, VirtualVariable) and isinstance(
|
|
359
|
+
stmt.src, (VirtualVariable, Tmp, Call, Convert)
|
|
360
|
+
):
|
|
361
|
+
codeloc = AILCodeLocation(block.addr, block.idx, stmt_idx, stmt.tags.get("ins_addr"))
|
|
362
|
+
equivalence.add(Equivalence(codeloc, stmt.dst, stmt.src))
|
|
363
|
+
elif isinstance(stmt, WeakAssignment):
|
|
364
|
+
codeloc = AILCodeLocation(block.addr, block.idx, stmt_idx, stmt.tags.get("ins_addr"))
|
|
365
|
+
equivalence.add(Equivalence(codeloc, stmt.dst, stmt.src, is_weakassignment=True))
|
|
366
|
+
elif isinstance(stmt, Call):
|
|
367
|
+
if isinstance(stmt.ret_expr, (VirtualVariable, Load)):
|
|
368
|
+
codeloc = AILCodeLocation(block.addr, block.idx, stmt_idx, stmt.tags.get("ins_addr"))
|
|
369
|
+
equivalence.add(Equivalence(codeloc, stmt.ret_expr, stmt))
|
|
370
|
+
elif isinstance(stmt.fp_ret_expr, (VirtualVariable, Load)):
|
|
371
|
+
codeloc = AILCodeLocation(block.addr, block.idx, stmt_idx, stmt.tags.get("ins_addr"))
|
|
372
|
+
equivalence.add(Equivalence(codeloc, stmt.fp_ret_expr, stmt))
|
|
373
|
+
elif (
|
|
374
|
+
isinstance(stmt, Store)
|
|
375
|
+
and isinstance(stmt.size, int)
|
|
376
|
+
and isinstance(stmt.data, (VirtualVariable, Tmp, Call, Convert))
|
|
377
|
+
):
|
|
378
|
+
if isinstance(stmt.addr, StackBaseOffset) and isinstance(stmt.addr.offset, int):
|
|
379
|
+
# stack variable
|
|
380
|
+
atom = SimStackVariable(stmt.addr.offset, stmt.size)
|
|
381
|
+
codeloc = AILCodeLocation(block.addr, block.idx, stmt_idx, stmt.tags.get("ins_addr"))
|
|
382
|
+
equivalence.add(Equivalence(codeloc, atom, stmt.data))
|
|
383
|
+
elif isinstance(stmt.addr, Const):
|
|
384
|
+
# global variable
|
|
385
|
+
atom = SimMemoryVariable(stmt.addr.value, stmt.size)
|
|
386
|
+
codeloc = AILCodeLocation(block.addr, block.idx, stmt_idx, stmt.tags.get("ins_addr"))
|
|
387
|
+
equivalence.add(Equivalence(codeloc, atom, stmt.data))
|
|
388
|
+
return equivalence
|
|
389
|
+
|
|
390
|
+
def _clear_cache(self) -> None:
|
|
391
|
+
self._propagator = None
|
|
392
|
+
self._reaching_definitions = None
|
|
393
|
+
|
|
394
|
+
def _clear_propagator_cache(self) -> None:
|
|
395
|
+
self._propagator = None
|
|
396
|
+
|
|
397
|
+
def _clear_reaching_definitions_cache(self) -> None:
|
|
398
|
+
self._reaching_definitions = None
|
|
399
|
+
|
|
400
|
+
#
|
|
401
|
+
# Expression narrowing
|
|
402
|
+
#
|
|
403
|
+
|
|
404
|
+
@timethis
|
|
405
|
+
def _narrow_exprs(self) -> bool:
|
|
406
|
+
"""
|
|
407
|
+
A register may be used with full width even when only the lower bytes are really needed. This results in the
|
|
408
|
+
incorrect determination of wider variables while the actual variable is narrower (e.g., int64 vs char). This
|
|
409
|
+
optimization narrows a register definition if all its uses are narrower than the definition itself.
|
|
410
|
+
|
|
411
|
+
Note that at this point, we must account for all uses of any narrowed expressions. This means expression
|
|
412
|
+
narrowing must be done _after_ making call sites instead of before making call sites.
|
|
413
|
+
"""
|
|
414
|
+
|
|
415
|
+
narrowed = False
|
|
416
|
+
|
|
417
|
+
addr_and_idx_to_block: dict[tuple[int, int | None], Block] = {}
|
|
418
|
+
for block in self.func_graph.nodes():
|
|
419
|
+
addr_and_idx_to_block[(block.addr, block.idx)] = block
|
|
420
|
+
|
|
421
|
+
rd = self._compute_reaching_definitions()
|
|
422
|
+
sorted_defs = sorted(rd.all_definitions, key=lambda d: d.codeloc, reverse=True)
|
|
423
|
+
|
|
424
|
+
# compute effective sizes for each vvar
|
|
425
|
+
effective_sizes = self._compute_effective_sizes(rd, sorted_defs, addr_and_idx_to_block)
|
|
426
|
+
|
|
427
|
+
narrowing_candidates: dict[int, tuple[Definition, ExprNarrowingInfo]] = {}
|
|
428
|
+
for def_ in sorted_defs:
|
|
429
|
+
if isinstance(def_.atom, atoms.VirtualVariable) and (def_.atom.was_reg or def_.atom.was_parameter):
|
|
430
|
+
# only do this for general purpose register
|
|
431
|
+
skip_def = False
|
|
432
|
+
reg = None
|
|
433
|
+
for reg in self.project.arch.register_list:
|
|
434
|
+
if reg.vex_offset == def_.atom.reg_offset:
|
|
435
|
+
if not reg.artificial and not reg.general_purpose and not reg.vector:
|
|
436
|
+
skip_def = True
|
|
437
|
+
break
|
|
438
|
+
|
|
439
|
+
if skip_def:
|
|
440
|
+
continue
|
|
441
|
+
|
|
442
|
+
narrow = self._narrowing_needed(def_, rd, addr_and_idx_to_block, effective_sizes)
|
|
443
|
+
if narrow.narrowable:
|
|
444
|
+
# we cannot narrow it immediately because any definition that is used by phi variables must be
|
|
445
|
+
# narrowed together with all other definitions that can reach the phi variables.
|
|
446
|
+
# so we record the information and decide if we are going to narrow these expressions or not at the
|
|
447
|
+
# end of the loop.
|
|
448
|
+
narrowing_candidates[def_.atom.varid] = def_, narrow
|
|
449
|
+
|
|
450
|
+
# first, determine which phi vars need to be narrowed and can be narrowed.
|
|
451
|
+
# a phi var can only be narrowed if all its source vvars are narrowable
|
|
452
|
+
vvar_to_narrowing_size = {}
|
|
453
|
+
for def_varid, (_, narrow_info) in narrowing_candidates.items():
|
|
454
|
+
vvar_to_narrowing_size[def_varid] = narrow_info.to_size
|
|
455
|
+
|
|
456
|
+
blacklist_varids = set()
|
|
457
|
+
while True:
|
|
458
|
+
repeat, narrowables = self._compute_narrowables_once(
|
|
459
|
+
rd, narrowing_candidates, vvar_to_narrowing_size, blacklist_varids
|
|
460
|
+
)
|
|
461
|
+
if not repeat:
|
|
462
|
+
break
|
|
463
|
+
|
|
464
|
+
if not narrowables:
|
|
465
|
+
# nothing to narrow
|
|
466
|
+
return False
|
|
467
|
+
|
|
468
|
+
# let's narrow them (finally)
|
|
469
|
+
narrower = ExpressionNarrower(self.project, rd, narrowables, addr_and_idx_to_block, self.blocks)
|
|
470
|
+
for old_block in addr_and_idx_to_block.values():
|
|
471
|
+
new_block = self.blocks.get(old_block, old_block)
|
|
472
|
+
new_block = narrower.walk(new_block)
|
|
473
|
+
if narrower.narrowed_any:
|
|
474
|
+
narrowed = True
|
|
475
|
+
self.blocks[old_block] = new_block
|
|
476
|
+
|
|
477
|
+
# update self._arg_vvars if necessary
|
|
478
|
+
for new_vvars in narrower.replacement_core_vvars.values():
|
|
479
|
+
for new_vvar in new_vvars:
|
|
480
|
+
if new_vvar.was_parameter and self._arg_vvars:
|
|
481
|
+
for func_arg_idx in list(self._arg_vvars):
|
|
482
|
+
vvar, simvar = self._arg_vvars[func_arg_idx]
|
|
483
|
+
if vvar.varid == new_vvar.varid:
|
|
484
|
+
simvar_new = simvar.copy()
|
|
485
|
+
simvar_new._hash = None
|
|
486
|
+
simvar_new.size = new_vvar.size
|
|
487
|
+
self._arg_vvars[func_arg_idx] = new_vvar, simvar_new
|
|
488
|
+
|
|
489
|
+
return narrowed
|
|
490
|
+
|
|
491
|
+
def _compute_effective_sizes(self, rd, defs, addr_and_idx_to_block) -> dict[int, int]:
|
|
492
|
+
|
|
493
|
+
vvar_effective_sizes: dict[int, int] = {}
|
|
494
|
+
|
|
495
|
+
# determine effective sizes for non-phi vvars
|
|
496
|
+
for def_ in defs:
|
|
497
|
+
# find its def statement
|
|
498
|
+
old_block = addr_and_idx_to_block.get((def_.codeloc.block_addr, def_.codeloc.block_idx), None)
|
|
499
|
+
if old_block is None:
|
|
500
|
+
continue
|
|
501
|
+
block = self.blocks.get(old_block, old_block)
|
|
502
|
+
if def_.codeloc.stmt_idx is None or def_.codeloc.stmt_idx >= len(block.statements):
|
|
503
|
+
continue
|
|
504
|
+
def_stmt = block.statements[def_.codeloc.stmt_idx]
|
|
505
|
+
if (
|
|
506
|
+
isinstance(def_stmt, Assignment)
|
|
507
|
+
and isinstance(def_stmt.src, Convert)
|
|
508
|
+
and not def_stmt.src.is_signed
|
|
509
|
+
and def_stmt.src.from_type == Convert.TYPE_INT
|
|
510
|
+
and def_stmt.src.to_type == Convert.TYPE_INT
|
|
511
|
+
and def_stmt.src.from_bits < def_stmt.src.to_bits
|
|
512
|
+
):
|
|
513
|
+
effective_size = def_stmt.src.from_bits // self.project.arch.byte_width
|
|
514
|
+
vvar_effective_sizes[def_.atom.varid] = effective_size
|
|
515
|
+
|
|
516
|
+
# update effective sizes for phi vvars
|
|
517
|
+
changed = True
|
|
518
|
+
while changed:
|
|
519
|
+
changed = False
|
|
520
|
+
for phi_vvar in rd.phivarid_to_varids:
|
|
521
|
+
if phi_vvar in vvar_effective_sizes:
|
|
522
|
+
continue
|
|
523
|
+
if rd.phivarid_to_varids[phi_vvar] and all(
|
|
524
|
+
src_vvar in vvar_effective_sizes for src_vvar in rd.phivarid_to_varids[phi_vvar]
|
|
525
|
+
):
|
|
526
|
+
effective_size = max(vvar_effective_sizes[src_vvar] for src_vvar in rd.phivarid_to_varids[phi_vvar])
|
|
527
|
+
vvar_effective_sizes[phi_vvar] = effective_size
|
|
528
|
+
changed = True
|
|
529
|
+
|
|
530
|
+
return vvar_effective_sizes
|
|
531
|
+
|
|
532
|
+
@staticmethod
|
|
533
|
+
def _compute_narrowables_once(
|
|
534
|
+
rd, narrowing_candidates: dict, vvar_to_narrowing_size: dict[int, int], blacklist_varids: set
|
|
535
|
+
):
|
|
536
|
+
repeat = False
|
|
537
|
+
narrowable_phivarids = set()
|
|
538
|
+
for def_vvarid in narrowing_candidates:
|
|
539
|
+
if def_vvarid in blacklist_varids:
|
|
540
|
+
continue
|
|
541
|
+
if def_vvarid in rd.phi_vvar_ids:
|
|
542
|
+
narrowing_sizes = set()
|
|
543
|
+
src_vvarids = rd.phivarid_to_varids[def_vvarid]
|
|
544
|
+
for vvarid in src_vvarids:
|
|
545
|
+
if vvarid in blacklist_varids:
|
|
546
|
+
narrowing_sizes.add(None)
|
|
547
|
+
else:
|
|
548
|
+
narrowing_sizes.add(vvar_to_narrowing_size.get(vvarid))
|
|
549
|
+
if len(narrowing_sizes) == 1 and None not in narrowing_sizes:
|
|
550
|
+
# we can narrow this phi vvar!
|
|
551
|
+
narrowable_phivarids.add(def_vvarid)
|
|
552
|
+
else:
|
|
553
|
+
# blacklist it for now
|
|
554
|
+
blacklist_varids.add(def_vvarid)
|
|
555
|
+
|
|
556
|
+
# now determine what to narrow!
|
|
557
|
+
narrowables = []
|
|
558
|
+
|
|
559
|
+
for def_, narrow_info in narrowing_candidates.values():
|
|
560
|
+
if def_.atom.varid in blacklist_varids:
|
|
561
|
+
continue
|
|
562
|
+
if not narrow_info.phi_vars:
|
|
563
|
+
# not used by any other phi variables. good!
|
|
564
|
+
narrowables.append((def_, narrow_info))
|
|
565
|
+
else:
|
|
566
|
+
if {phivar.varid for phivar in narrow_info.phi_vars}.issubset(narrowable_phivarids):
|
|
567
|
+
# all phi vvars that use this definition can be narrowed
|
|
568
|
+
narrowables.append((def_, narrow_info))
|
|
569
|
+
else:
|
|
570
|
+
# this vvar cannot be narrowed
|
|
571
|
+
# note that all phi variables that relies on this vvar also cannot be narrowed! we must analyze
|
|
572
|
+
# again
|
|
573
|
+
repeat = True
|
|
574
|
+
blacklist_varids.add(def_.atom.varid)
|
|
575
|
+
blacklist_varids |= {phivar.varid for phivar in narrow_info.phi_vars}
|
|
576
|
+
|
|
577
|
+
return repeat, narrowables
|
|
578
|
+
|
|
579
|
+
def _narrowing_needed(
|
|
580
|
+
self, def_: Definition, rd: SRDAModel, addr_and_idx_to_block, effective_sizes: dict[int, int]
|
|
581
|
+
) -> ExprNarrowingInfo:
|
|
582
|
+
|
|
583
|
+
def_size = def_.size
|
|
584
|
+
# find its uses
|
|
585
|
+
# some use locations are phi assignments. we keep tracking the uses of phi variables and update the dictionary
|
|
586
|
+
result = self._get_vvar_use_and_exprs_recursive(def_.atom, rd, addr_and_idx_to_block)
|
|
587
|
+
if result is None:
|
|
588
|
+
return ExprNarrowingInfo(False)
|
|
589
|
+
use_and_exprs, phi_vars = result
|
|
590
|
+
|
|
591
|
+
all_used_sizes = set()
|
|
592
|
+
noncall_used_sizes = set()
|
|
593
|
+
used_by: list[tuple[atoms.VirtualVariable, AILCodeLocation, tuple[str, tuple[Expression, ...]]]] = []
|
|
594
|
+
used_by_loc = defaultdict(list)
|
|
595
|
+
|
|
596
|
+
for atom, loc, expr in use_and_exprs:
|
|
597
|
+
old_block = addr_and_idx_to_block.get((loc.block_addr, loc.block_idx), None)
|
|
598
|
+
if old_block is None:
|
|
599
|
+
# missing a block for whatever reason
|
|
600
|
+
return ExprNarrowingInfo(False)
|
|
601
|
+
|
|
602
|
+
block = self.blocks.get(old_block, old_block)
|
|
603
|
+
assert loc.stmt_idx is not None
|
|
604
|
+
if loc.stmt_idx >= len(block.statements):
|
|
605
|
+
# missing a statement for whatever reason
|
|
606
|
+
return ExprNarrowingInfo(False)
|
|
607
|
+
stmt = block.statements[loc.stmt_idx]
|
|
608
|
+
|
|
609
|
+
# special case: if the statement is a Call statement and expr is None, it means we have not been able to
|
|
610
|
+
# determine if the expression is really used by the call or not. skip it in this case
|
|
611
|
+
if isinstance(stmt, Call) and expr is None:
|
|
612
|
+
all_used_sizes.add(atom.size)
|
|
613
|
+
continue
|
|
614
|
+
# special case: if the statement is a phi statement, we ignore it
|
|
615
|
+
if is_phi_assignment(stmt):
|
|
616
|
+
continue
|
|
617
|
+
# special case: if the statement is an assignment to a destination vvar A, and the source is the bitwise-or
|
|
618
|
+
# of two expressions where one of them is the high bits of expr, and expr is a phi var that relies on
|
|
619
|
+
# vvar A, then we skip it.
|
|
620
|
+
if is_expr_used_as_reg_base_value(stmt, expr, rd):
|
|
621
|
+
continue
|
|
622
|
+
|
|
623
|
+
expr_size, used_by_exprs = self._extract_expression_effective_size(stmt, expr)
|
|
624
|
+
if expr_size is None:
|
|
625
|
+
# it's probably used in full width
|
|
626
|
+
return ExprNarrowingInfo(False)
|
|
627
|
+
|
|
628
|
+
all_used_sizes.add(expr_size)
|
|
629
|
+
if not isinstance(stmt, Call):
|
|
630
|
+
noncall_used_sizes.add(expr_size)
|
|
631
|
+
used_by_loc[loc].append((atom, used_by_exprs))
|
|
632
|
+
|
|
633
|
+
target_size = None
|
|
634
|
+
if len(all_used_sizes) >= 1 and max(all_used_sizes) < def_size:
|
|
635
|
+
target_size = max(all_used_sizes)
|
|
636
|
+
else:
|
|
637
|
+
effective_size = effective_sizes.get(def_.atom.varid, None)
|
|
638
|
+
if (
|
|
639
|
+
effective_size is not None
|
|
640
|
+
and any(used_size <= effective_size for used_size in all_used_sizes)
|
|
641
|
+
and all(used_size <= effective_size for used_size in noncall_used_sizes)
|
|
642
|
+
):
|
|
643
|
+
# special case: sometimes we have an explicit Convert that narrows the value, all other uses are either
|
|
644
|
+
# in the effective size or narrower, but we pass the full register to a function call as an argument
|
|
645
|
+
# because we do not know the real type of the argument, or there are cases like putchar(int ch) while
|
|
646
|
+
# ch is actually a char. We use effective size in such cases to narrow the variable.
|
|
647
|
+
target_size = effective_size
|
|
648
|
+
|
|
649
|
+
if target_size is not None:
|
|
650
|
+
for loc, atom_expr_pairs in used_by_loc.items():
|
|
651
|
+
if len(atom_expr_pairs) == 1:
|
|
652
|
+
atom, used_by_exprs = atom_expr_pairs[0]
|
|
653
|
+
used_by.append((atom, loc, used_by_exprs))
|
|
654
|
+
else:
|
|
655
|
+
# the order matters - we must replace the outer expressions first, then replace the inner
|
|
656
|
+
# expressions. replacing in the wrong order will lead to expressions that are not replaced in the
|
|
657
|
+
# end.
|
|
658
|
+
ordered = []
|
|
659
|
+
for atom, used_by_exprs in atom_expr_pairs:
|
|
660
|
+
last_inclusion = len(ordered) - 1 # by default we append at the end of the list
|
|
661
|
+
for idx in range(len(ordered)):
|
|
662
|
+
if self._is_expr0_included_in_expr1(ordered[idx][1], used_by_exprs):
|
|
663
|
+
# this element must be inserted before idx
|
|
664
|
+
ordered.insert(idx, (atom, used_by_exprs))
|
|
665
|
+
break
|
|
666
|
+
if self._is_expr0_included_in_expr1(used_by_exprs, ordered[idx][1]):
|
|
667
|
+
# this element can be inserted after this element. record the index
|
|
668
|
+
last_inclusion = idx
|
|
669
|
+
else:
|
|
670
|
+
ordered.insert(last_inclusion + 1, (atom, used_by_exprs))
|
|
671
|
+
|
|
672
|
+
for atom, used_by_exprs in ordered:
|
|
673
|
+
used_by.append((atom, loc, used_by_exprs))
|
|
674
|
+
|
|
675
|
+
return ExprNarrowingInfo(True, to_size=target_size, use_exprs=used_by, phi_vars=phi_vars)
|
|
676
|
+
|
|
677
|
+
return ExprNarrowingInfo(False)
|
|
678
|
+
|
|
679
|
+
@staticmethod
|
|
680
|
+
def _exprs_from_used_by_exprs(used_by_exprs) -> set[Expression]:
|
|
681
|
+
use_type, expr_tuple = used_by_exprs
|
|
682
|
+
match use_type:
|
|
683
|
+
case "expr" | "mask" | "convert":
|
|
684
|
+
return {expr_tuple[1]} if len(expr_tuple) == 2 else {expr_tuple[0]}
|
|
685
|
+
case "phi-src-expr":
|
|
686
|
+
return {expr_tuple[0]}
|
|
687
|
+
case "binop-convert":
|
|
688
|
+
return {expr_tuple[0], expr_tuple[1]}
|
|
689
|
+
case _:
|
|
690
|
+
return set()
|
|
691
|
+
|
|
692
|
+
def _is_expr0_included_in_expr1(self, used_by_exprs0, used_by_exprs1) -> bool:
|
|
693
|
+
# extract expressions
|
|
694
|
+
exprs0 = self._exprs_from_used_by_exprs(used_by_exprs0)
|
|
695
|
+
exprs1 = self._exprs_from_used_by_exprs(used_by_exprs1)
|
|
696
|
+
|
|
697
|
+
# test for inclusion
|
|
698
|
+
for expr1 in exprs1:
|
|
699
|
+
walker = HasExprWalker(exprs0)
|
|
700
|
+
walker.walk_expression(expr1)
|
|
701
|
+
if walker.contains_exprs:
|
|
702
|
+
return True
|
|
703
|
+
return False
|
|
704
|
+
|
|
705
|
+
def _get_vvar_use_and_exprs_recursive(
|
|
706
|
+
self, initial_atom: atoms.VirtualVariable, rd, block_dict: dict[tuple[int, int | None], Block]
|
|
707
|
+
) -> tuple[list[tuple[atoms.VirtualVariable, AILCodeLocation, Expression]], set[VirtualVariable]] | None:
|
|
708
|
+
result = []
|
|
709
|
+
atom_queue = [initial_atom]
|
|
710
|
+
phi_vars = set()
|
|
711
|
+
seen = set()
|
|
712
|
+
while atom_queue:
|
|
713
|
+
atom = atom_queue.pop(0)
|
|
714
|
+
seen.add(atom)
|
|
715
|
+
|
|
716
|
+
expr_and_uses = rd.all_vvar_uses[atom.varid]
|
|
717
|
+
|
|
718
|
+
for expr, loc in set(expr_and_uses):
|
|
719
|
+
old_block = block_dict.get((loc.block_addr, loc.block_idx), None)
|
|
720
|
+
if old_block is None:
|
|
721
|
+
# missing a block for whatever reason
|
|
722
|
+
return None
|
|
723
|
+
|
|
724
|
+
block: Block = self.blocks.get(old_block, old_block)
|
|
725
|
+
if loc.stmt_idx >= len(block.statements):
|
|
726
|
+
# missing a statement for whatever reason
|
|
727
|
+
return None
|
|
728
|
+
stmt = block.statements[loc.stmt_idx]
|
|
729
|
+
|
|
730
|
+
if is_phi_assignment(stmt):
|
|
731
|
+
phi_vars.add(stmt.dst)
|
|
732
|
+
new_atom = atoms.VirtualVariable(
|
|
733
|
+
stmt.dst.varid, stmt.dst.size, stmt.dst.category, oident=stmt.dst.oident
|
|
734
|
+
)
|
|
735
|
+
if new_atom not in seen:
|
|
736
|
+
atom_queue.append(new_atom)
|
|
737
|
+
seen.add(new_atom)
|
|
738
|
+
else:
|
|
739
|
+
result.append((atom, loc, expr))
|
|
740
|
+
return result, phi_vars
|
|
741
|
+
|
|
742
|
+
def _extract_expression_effective_size(
|
|
743
|
+
self, statement, expr
|
|
744
|
+
) -> tuple[int | None, tuple[str, tuple[Expression, ...]] | None]:
|
|
745
|
+
"""
|
|
746
|
+
Determine the effective size of an expression when it's used.
|
|
747
|
+
"""
|
|
748
|
+
|
|
749
|
+
walker = NarrowingInfoExtractor(expr)
|
|
750
|
+
walker.walk_statement(statement)
|
|
751
|
+
if not walker.operations:
|
|
752
|
+
if expr is None:
|
|
753
|
+
return None, None
|
|
754
|
+
return expr.size, ("expr", (expr,))
|
|
755
|
+
|
|
756
|
+
ops = walker.operations
|
|
757
|
+
first_op = ops[0]
|
|
758
|
+
if isinstance(first_op, BinaryOp) and first_op.op in {"Add", "Sub"}:
|
|
759
|
+
# expr + x
|
|
760
|
+
ops = ops[1:]
|
|
761
|
+
if not ops:
|
|
762
|
+
if expr is None:
|
|
763
|
+
return None, None
|
|
764
|
+
return expr.size, ("expr", (expr,))
|
|
765
|
+
first_op = ops[0]
|
|
766
|
+
if isinstance(first_op, Convert) and first_op.to_bits >= self.project.arch.byte_width:
|
|
767
|
+
# we need at least one byte!
|
|
768
|
+
if (
|
|
769
|
+
len({(op.from_bits, op.to_bits) for op in ops if isinstance(op, Convert) and op.operand.likes(expr)})
|
|
770
|
+
> 1
|
|
771
|
+
):
|
|
772
|
+
# there are more Convert operations; it's probably because there are multiple expressions involving the
|
|
773
|
+
# same core expr. just give up (for now)
|
|
774
|
+
return None, None
|
|
775
|
+
if any(op for op in ops if isinstance(op, BinaryOp) and op.op == "Shr" and op.operands[0].likes(expr)):
|
|
776
|
+
# the expression is right-shifted, which means higher bits might be used.
|
|
777
|
+
return None, None
|
|
778
|
+
return first_op.to_bits // self.project.arch.byte_width, ("convert", (first_op,))
|
|
779
|
+
if isinstance(first_op, BinaryOp):
|
|
780
|
+
second_op = None
|
|
781
|
+
if len(ops) >= 2:
|
|
782
|
+
second_op = ops[1]
|
|
783
|
+
if (
|
|
784
|
+
first_op.op == "And"
|
|
785
|
+
and isinstance(first_op.operands[1], Const)
|
|
786
|
+
and (
|
|
787
|
+
second_op is None or (isinstance(second_op, BinaryOp) and isinstance(second_op.operands[1], Const))
|
|
788
|
+
)
|
|
789
|
+
):
|
|
790
|
+
mask = first_op.operands[1].value
|
|
791
|
+
if mask == 0xFF:
|
|
792
|
+
return 1, ("mask", (first_op, second_op)) if second_op is not None else ("mask", (first_op,))
|
|
793
|
+
if mask == 0xFFFF:
|
|
794
|
+
return 2, ("mask", (first_op, second_op)) if second_op is not None else ("mask", (first_op,))
|
|
795
|
+
if mask == 0xFFFF_FFFF:
|
|
796
|
+
return 4, ("mask", (first_op, second_op)) if second_op is not None else ("mask", (first_op,))
|
|
797
|
+
if (
|
|
798
|
+
(first_op.operands[0] is expr or first_op.operands[1] is expr)
|
|
799
|
+
and first_op.op not in {"Shr", "Sar"}
|
|
800
|
+
and isinstance(second_op, Convert)
|
|
801
|
+
and second_op.from_bits == expr.bits
|
|
802
|
+
and second_op.to_bits >= self.project.arch.byte_width # we need at least one byte!
|
|
803
|
+
):
|
|
804
|
+
return min(expr.bits, second_op.to_bits) // self.project.arch.byte_width, (
|
|
805
|
+
"binop-convert",
|
|
806
|
+
(expr, first_op, second_op),
|
|
807
|
+
)
|
|
808
|
+
|
|
809
|
+
if expr is None:
|
|
810
|
+
return None, None
|
|
811
|
+
return expr.size, ("expr", (expr,))
|
|
812
|
+
|
|
813
|
+
#
|
|
814
|
+
# Expression folding
|
|
815
|
+
#
|
|
816
|
+
|
|
817
|
+
def _fold_exprs(self):
|
|
818
|
+
"""
|
|
819
|
+
Fold expressions: Fold assigned expressions that are constant or only used once.
|
|
820
|
+
"""
|
|
821
|
+
|
|
822
|
+
# propagator
|
|
823
|
+
propagator = self._compute_propagation()
|
|
824
|
+
replacements = propagator.replacements
|
|
825
|
+
|
|
826
|
+
# take replacements and rebuild the corresponding blocks
|
|
827
|
+
replacements_by_block_addrs_and_idx = defaultdict(dict)
|
|
828
|
+
for codeloc, reps in replacements.items():
|
|
829
|
+
if reps:
|
|
830
|
+
replacements_by_block_addrs_and_idx[(codeloc.block_addr, codeloc.block_idx)][codeloc] = reps
|
|
831
|
+
|
|
832
|
+
if not replacements_by_block_addrs_and_idx:
|
|
833
|
+
return False
|
|
834
|
+
|
|
835
|
+
return self._replace_exprs_in_blocks(replacements_by_block_addrs_and_idx)
|
|
836
|
+
|
|
837
|
+
def _replace_exprs_in_blocks(
|
|
838
|
+
self, replacements: dict[tuple[int, int | None], dict[AILCodeLocation, dict[Expression, Expression]]]
|
|
839
|
+
) -> bool:
|
|
840
|
+
blocks_by_addr_and_idx = {(node.addr, node.idx): node for node in self.func_graph.nodes()}
|
|
841
|
+
|
|
842
|
+
if self._stack_arg_offsets:
|
|
843
|
+
insn_addrs_using_stack_args = {ins_addr for ins_addr, _ in self._stack_arg_offsets}
|
|
844
|
+
else:
|
|
845
|
+
insn_addrs_using_stack_args = None
|
|
846
|
+
|
|
847
|
+
replaced = False
|
|
848
|
+
for (block_addr, block_idx), reps in replacements.items():
|
|
849
|
+
block = blocks_by_addr_and_idx[(block_addr, block_idx)]
|
|
850
|
+
|
|
851
|
+
# only replace loads if there are stack arguments in this block
|
|
852
|
+
replace_loads: bool = insn_addrs_using_stack_args is not None and bool(
|
|
853
|
+
{stmt.tags["ins_addr"] for stmt in block.statements}.intersection(insn_addrs_using_stack_args)
|
|
854
|
+
)
|
|
855
|
+
|
|
856
|
+
# remove virtual variables in the avoid list
|
|
857
|
+
if self._avoid_vvar_ids:
|
|
858
|
+
filtered_reps = {}
|
|
859
|
+
for loc, rep_dict in reps.items():
|
|
860
|
+
filtered_reps[loc] = {
|
|
861
|
+
k: v
|
|
862
|
+
for k, v in rep_dict.items()
|
|
863
|
+
if not (isinstance(k, VirtualVariable) and k.varid in self._avoid_vvar_ids)
|
|
864
|
+
}
|
|
865
|
+
reps = filtered_reps
|
|
866
|
+
|
|
867
|
+
r, new_block = BlockSimplifier._replace_and_build(block, reps, gp=self._gp, replace_loads=replace_loads)
|
|
868
|
+
replaced |= r
|
|
869
|
+
self.blocks[block] = new_block
|
|
870
|
+
|
|
871
|
+
if replaced:
|
|
872
|
+
# blocks have been rebuilt - expression propagation results are no longer reliable
|
|
873
|
+
self._clear_cache()
|
|
874
|
+
return replaced
|
|
875
|
+
|
|
876
|
+
#
|
|
877
|
+
# Partial constant expression propagation
|
|
878
|
+
#
|
|
879
|
+
|
|
880
|
+
def _propagate_partial_constant_exprs(self) -> bool:
|
|
881
|
+
"""
|
|
882
|
+
Discover virtual variables whose certain consecutive bits are constant and propagate these bits.
|
|
883
|
+
"""
|
|
884
|
+
|
|
885
|
+
# vvar_zero_bits[varid] = N ==> the high N bits of vvar varid are 0s
|
|
886
|
+
vvar_zero_bits: dict[int, int] = {}
|
|
887
|
+
|
|
888
|
+
# go over all vvar definitions and find the ones with partial constants
|
|
889
|
+
for block in self.func_graph:
|
|
890
|
+
for stmt in block.statements:
|
|
891
|
+
if (
|
|
892
|
+
isinstance(stmt, Assignment)
|
|
893
|
+
and isinstance(stmt.dst, VirtualVariable)
|
|
894
|
+
and isinstance(stmt.src, Convert)
|
|
895
|
+
and stmt.src.to_bits > stmt.src.from_bits
|
|
896
|
+
):
|
|
897
|
+
# this is a conversion from a wider to a narrower type; the top N bits are 0s
|
|
898
|
+
vvar_zero_bits[stmt.dst.varid] = stmt.src.to_bits - stmt.src.from_bits
|
|
899
|
+
|
|
900
|
+
if not vvar_zero_bits:
|
|
901
|
+
return False
|
|
902
|
+
|
|
903
|
+
# now replace the uses of these vvars
|
|
904
|
+
addr_and_idx_to_block: dict[tuple[int, int | None], Block] = {}
|
|
905
|
+
for block in self.func_graph:
|
|
906
|
+
addr_and_idx_to_block[(block.addr, block.idx)] = block
|
|
907
|
+
|
|
908
|
+
rda = self._compute_reaching_definitions()
|
|
909
|
+
changed = False
|
|
910
|
+
for vvarid, zero_high_bits in vvar_zero_bits.items():
|
|
911
|
+
rewriter = PartialConstantExprRewriter(vvarid, zero_high_bits)
|
|
912
|
+
for _, use_loc in rda.all_vvar_uses[vvarid]:
|
|
913
|
+
assert use_loc.block_addr is not None
|
|
914
|
+
original_block = addr_and_idx_to_block[(use_loc.block_addr, use_loc.block_idx)]
|
|
915
|
+
block = self.blocks.get(original_block, original_block)
|
|
916
|
+
stmt = block.statements[use_loc.stmt_idx]
|
|
917
|
+
new_stmt = rewriter.walk_statement(stmt, block)
|
|
918
|
+
|
|
919
|
+
if new_stmt is not None and new_stmt is not stmt:
|
|
920
|
+
statements = block.statements[::]
|
|
921
|
+
statements[use_loc.stmt_idx] = new_stmt
|
|
922
|
+
new_block = block.copy(statements=statements)
|
|
923
|
+
|
|
924
|
+
self.blocks[original_block] = new_block
|
|
925
|
+
changed = True
|
|
926
|
+
|
|
927
|
+
return changed
|
|
928
|
+
|
|
929
|
+
#
|
|
930
|
+
# Rewriting constant expressions with phi variables
|
|
931
|
+
#
|
|
932
|
+
|
|
933
|
+
def _rewrite_phi_const_exprs(self) -> bool:
|
|
934
|
+
"""
|
|
935
|
+
Rewrite phi variables that are definitely constant expressions to constants.
|
|
936
|
+
"""
|
|
937
|
+
|
|
938
|
+
# gather constant assignments
|
|
939
|
+
|
|
940
|
+
vvar_values: dict[int, tuple[int, int]] = {}
|
|
941
|
+
for block in self.func_graph:
|
|
942
|
+
for stmt in block.statements:
|
|
943
|
+
if (
|
|
944
|
+
isinstance(stmt, Assignment)
|
|
945
|
+
and isinstance(stmt.dst, VirtualVariable)
|
|
946
|
+
and stmt.dst.was_reg # values of stack variables might be updated in callees or via pointers
|
|
947
|
+
and isinstance(stmt.src, Const)
|
|
948
|
+
and isinstance(stmt.src.value, int)
|
|
949
|
+
):
|
|
950
|
+
vvar_values[stmt.dst.varid] = stmt.src.value, stmt.src.bits
|
|
951
|
+
|
|
952
|
+
srda = self._compute_reaching_definitions()
|
|
953
|
+
# compute vvar reachability for phi variables
|
|
954
|
+
# ensure that each phi variable is fully defined, i.e., all its source variables are defined
|
|
955
|
+
g = networkx.Graph()
|
|
956
|
+
for phi_vvar_id, vvar_ids in srda.phivarid_to_varids_with_unknown.items():
|
|
957
|
+
for vvar_id in vvar_ids:
|
|
958
|
+
# we cannot store None to networkx graph, so we use -1 to represent unknown source vvars
|
|
959
|
+
g.add_edge(phi_vvar_id, vvar_id if vvar_id is not None else -1)
|
|
960
|
+
|
|
961
|
+
phi_vvar_ids = srda.phi_vvar_ids
|
|
962
|
+
to_replace = {}
|
|
963
|
+
for cc in networkx.algorithms.connected_components(g):
|
|
964
|
+
if -1 in cc:
|
|
965
|
+
continue
|
|
966
|
+
normal_vvar_ids = cc.difference(phi_vvar_ids)
|
|
967
|
+
# ensure there is at least one phi variable and all remaining vvars are constant non-phi variables
|
|
968
|
+
if len(normal_vvar_ids) < len(cc) and len(normal_vvar_ids.intersection(vvar_values)) == len(
|
|
969
|
+
normal_vvar_ids
|
|
970
|
+
):
|
|
971
|
+
all_values = {vvar_values[vvar_id] for vvar_id in normal_vvar_ids}
|
|
972
|
+
if len(all_values) == 1:
|
|
973
|
+
# found it!
|
|
974
|
+
value, bits = next(iter(all_values))
|
|
975
|
+
for var_id in cc:
|
|
976
|
+
to_replace[var_id] = value, bits
|
|
977
|
+
|
|
978
|
+
# build the replacement dictionary
|
|
979
|
+
blocks_dict = {(node.addr, node.idx): node for node in self.func_graph.nodes()}
|
|
980
|
+
replacements: dict[tuple[int, int | None], dict[AILCodeLocation, dict[Expression, Expression]]] = defaultdict(
|
|
981
|
+
dict
|
|
982
|
+
)
|
|
983
|
+
for vvar_id, (value, bits) in to_replace.items():
|
|
984
|
+
for expr, use_loc in srda.all_vvar_uses[vvar_id]:
|
|
985
|
+
if expr is None:
|
|
986
|
+
continue
|
|
987
|
+
assert use_loc.block_addr is not None
|
|
988
|
+
key = use_loc.block_addr, use_loc.block_idx
|
|
989
|
+
stmt = blocks_dict[key].statements[use_loc.stmt_idx]
|
|
990
|
+
if is_phi_assignment(stmt):
|
|
991
|
+
continue
|
|
992
|
+
if use_loc not in replacements[key]:
|
|
993
|
+
replacements[key][use_loc] = {}
|
|
994
|
+
replacements[key][use_loc][expr] = Const(None, None, value, bits, **expr.tags)
|
|
995
|
+
|
|
996
|
+
return self._replace_exprs_in_blocks(replacements) if replacements else False
|
|
997
|
+
|
|
998
|
+
#
|
|
999
|
+
# Unifying local variables
|
|
1000
|
+
#
|
|
1001
|
+
|
|
1002
|
+
@timethis
|
|
1003
|
+
def _unify_local_variables(self) -> bool:
|
|
1004
|
+
"""
|
|
1005
|
+
Find variables that are definitely equivalent and then eliminate unnecessary copies.
|
|
1006
|
+
"""
|
|
1007
|
+
|
|
1008
|
+
simplified = False
|
|
1009
|
+
|
|
1010
|
+
equivalence = self._compute_equivalence()
|
|
1011
|
+
if not equivalence:
|
|
1012
|
+
return simplified
|
|
1013
|
+
|
|
1014
|
+
addr_and_idx_to_block: dict[tuple[int, int | None], Block] = {}
|
|
1015
|
+
for block in self.func_graph.nodes():
|
|
1016
|
+
addr_and_idx_to_block[(block.addr, block.idx)] = block
|
|
1017
|
+
|
|
1018
|
+
equivalences: dict[Any, set[Equivalence]] = defaultdict(set)
|
|
1019
|
+
atom_by_loc = set()
|
|
1020
|
+
for eq in equivalence:
|
|
1021
|
+
equivalences[eq.atom1].add(eq)
|
|
1022
|
+
atom_by_loc.add((eq.codeloc, eq.atom1))
|
|
1023
|
+
|
|
1024
|
+
# sort keys to ensure a reproducible result
|
|
1025
|
+
sorted_loc_and_atoms = sorted(atom_by_loc, key=lambda x: x[0])
|
|
1026
|
+
|
|
1027
|
+
# keep track of code locations where the statements have been updated; we can then skip Equivalences that are
|
|
1028
|
+
# out-of-date
|
|
1029
|
+
updated_locs: set[AILCodeLocation] = set()
|
|
1030
|
+
|
|
1031
|
+
for _, atom in sorted_loc_and_atoms:
|
|
1032
|
+
eqs = equivalences[atom]
|
|
1033
|
+
if len(eqs) > 1:
|
|
1034
|
+
continue
|
|
1035
|
+
|
|
1036
|
+
eq = next(iter(eqs))
|
|
1037
|
+
if eq.codeloc in updated_locs:
|
|
1038
|
+
continue
|
|
1039
|
+
|
|
1040
|
+
# Acceptable equivalence classes:
|
|
1041
|
+
#
|
|
1042
|
+
# stack variable == register
|
|
1043
|
+
# register variable == register
|
|
1044
|
+
# stack variable == Conv(register, M->N)
|
|
1045
|
+
# global variable == register
|
|
1046
|
+
#
|
|
1047
|
+
# Equivalence is generally created at assignment sites. Therefore, eq.atom0 is the definition and
|
|
1048
|
+
# eq.atom1 is the use.
|
|
1049
|
+
the_def = None
|
|
1050
|
+
if (isinstance(eq.atom0, VirtualVariable) and eq.atom0.was_stack) or (
|
|
1051
|
+
isinstance(eq.atom0, SimMemoryVariable)
|
|
1052
|
+
and not isinstance(eq.atom0, SimStackVariable)
|
|
1053
|
+
and isinstance(eq.atom0.addr, int)
|
|
1054
|
+
):
|
|
1055
|
+
if isinstance(eq.atom1, VirtualVariable) and eq.atom1.was_reg:
|
|
1056
|
+
# stack_var == register or global_var == register
|
|
1057
|
+
to_replace = eq.atom1
|
|
1058
|
+
to_replace_is_def = False
|
|
1059
|
+
elif (
|
|
1060
|
+
isinstance(eq.atom0, VirtualVariable)
|
|
1061
|
+
and eq.atom0.was_stack
|
|
1062
|
+
and isinstance(eq.atom1, VirtualVariable)
|
|
1063
|
+
and eq.atom1.was_parameter
|
|
1064
|
+
):
|
|
1065
|
+
# stack_var == parameter
|
|
1066
|
+
to_replace = eq.atom0
|
|
1067
|
+
to_replace_is_def = True
|
|
1068
|
+
elif (
|
|
1069
|
+
isinstance(eq.atom1, Convert)
|
|
1070
|
+
and isinstance(eq.atom1.operand, VirtualVariable)
|
|
1071
|
+
and eq.atom1.operand.was_reg
|
|
1072
|
+
):
|
|
1073
|
+
# stack_var == Conv(register, M->N)
|
|
1074
|
+
to_replace = eq.atom1.operand
|
|
1075
|
+
to_replace_is_def = False
|
|
1076
|
+
else:
|
|
1077
|
+
continue
|
|
1078
|
+
|
|
1079
|
+
elif isinstance(eq.atom0, VirtualVariable) and eq.atom0.was_reg:
|
|
1080
|
+
if isinstance(eq.atom1, VirtualVariable):
|
|
1081
|
+
if eq.atom1.was_reg or eq.atom1.was_parameter:
|
|
1082
|
+
# register == register
|
|
1083
|
+
if self.project.arch.is_artificial_register(eq.atom0.reg_offset, eq.atom0.size):
|
|
1084
|
+
to_replace = eq.atom0
|
|
1085
|
+
to_replace_is_def = True
|
|
1086
|
+
else:
|
|
1087
|
+
to_replace = eq.atom1
|
|
1088
|
+
to_replace_is_def = False
|
|
1089
|
+
elif eq.atom1.was_stack:
|
|
1090
|
+
# register == stack (but we try to replace the register vvar with the stack vvar)
|
|
1091
|
+
to_replace = eq.atom0
|
|
1092
|
+
to_replace_is_def = True
|
|
1093
|
+
else:
|
|
1094
|
+
continue
|
|
1095
|
+
else:
|
|
1096
|
+
continue
|
|
1097
|
+
|
|
1098
|
+
else:
|
|
1099
|
+
continue
|
|
1100
|
+
|
|
1101
|
+
assert isinstance(to_replace, VirtualVariable)
|
|
1102
|
+
|
|
1103
|
+
# find the definition of this virtual register
|
|
1104
|
+
rd = self._compute_reaching_definitions()
|
|
1105
|
+
if to_replace_is_def:
|
|
1106
|
+
# find defs
|
|
1107
|
+
defs: Container[Definition[atoms.VirtualVariable, AILCodeLocation]] = []
|
|
1108
|
+
for def_ in rd.all_definitions:
|
|
1109
|
+
if def_.atom.varid == to_replace.varid:
|
|
1110
|
+
defs.append(def_)
|
|
1111
|
+
if len(defs) != 1:
|
|
1112
|
+
continue
|
|
1113
|
+
the_def = defs[0]
|
|
1114
|
+
else:
|
|
1115
|
+
# find uses
|
|
1116
|
+
defs = rd.get_uses_by_location(eq.codeloc)
|
|
1117
|
+
if len(defs) != 1:
|
|
1118
|
+
# there are multiple defs for this register - we do not support replacing all of them
|
|
1119
|
+
continue
|
|
1120
|
+
for def_ in defs:
|
|
1121
|
+
if (
|
|
1122
|
+
isinstance(def_.atom, atoms.VirtualVariable)
|
|
1123
|
+
and def_.atom.category == to_replace.category
|
|
1124
|
+
and def_.atom.oident == to_replace.oident
|
|
1125
|
+
):
|
|
1126
|
+
# found it!
|
|
1127
|
+
the_def = def_
|
|
1128
|
+
break
|
|
1129
|
+
if the_def is None:
|
|
1130
|
+
continue
|
|
1131
|
+
|
|
1132
|
+
def_eq_rel: DefEqRelation = DefEqRelation.UNKNOWN
|
|
1133
|
+
if the_def.codeloc.is_extern or (isinstance(eq.atom1, VirtualVariable) and eq.atom1.was_parameter):
|
|
1134
|
+
# this is a function argument. we enter a slightly different logic and try to eliminate copies of this
|
|
1135
|
+
# argument if
|
|
1136
|
+
# (a) the on-stack or in-register copy of it has never been modified in this function
|
|
1137
|
+
# (b) the function argument register has never been updated.
|
|
1138
|
+
# TODO: we may loosen requirement (b) once we have real register versioning in AIL.
|
|
1139
|
+
defs = [def_ for def_ in rd.all_definitions if def_.codeloc == eq.codeloc]
|
|
1140
|
+
all_uses_with_def = None
|
|
1141
|
+
replace_with = None
|
|
1142
|
+
remove_initial_assignment = None
|
|
1143
|
+
def_eq_rel = DefEqRelation.DEF_IS_FUNCARG
|
|
1144
|
+
|
|
1145
|
+
if defs and len(defs) == 1:
|
|
1146
|
+
arg_copy_def = defs[0]
|
|
1147
|
+
if (isinstance(arg_copy_def.atom, atoms.VirtualVariable) and arg_copy_def.atom.was_stack) or (
|
|
1148
|
+
isinstance(arg_copy_def.atom, atoms.VirtualVariable) and arg_copy_def.atom.was_reg
|
|
1149
|
+
):
|
|
1150
|
+
# found the copied definition (either a stack variable or a register variable)
|
|
1151
|
+
|
|
1152
|
+
# Make sure there is no other write to this stack location if the copy is a stack variable
|
|
1153
|
+
if (
|
|
1154
|
+
isinstance(arg_copy_def.atom, atoms.VirtualVariable)
|
|
1155
|
+
and arg_copy_def.atom.was_stack
|
|
1156
|
+
and any(
|
|
1157
|
+
(def_ != arg_copy_def and def_.atom.stack_offset == arg_copy_def.atom.stack_offset)
|
|
1158
|
+
for def_ in rd.all_definitions
|
|
1159
|
+
if isinstance(def_.atom, atoms.VirtualVariable) and def_.atom.was_stack
|
|
1160
|
+
)
|
|
1161
|
+
):
|
|
1162
|
+
continue
|
|
1163
|
+
|
|
1164
|
+
# Make sure the register is never updated across this function
|
|
1165
|
+
if any(
|
|
1166
|
+
(def_ != the_def and def_.atom == the_def.atom)
|
|
1167
|
+
for def_ in rd.all_definitions
|
|
1168
|
+
if isinstance(def_.atom, atoms.VirtualVariable)
|
|
1169
|
+
and def_.atom.was_reg
|
|
1170
|
+
and rd.get_vvar_uses(def_.atom)
|
|
1171
|
+
):
|
|
1172
|
+
continue
|
|
1173
|
+
|
|
1174
|
+
# find all its uses
|
|
1175
|
+
all_arg_copy_var_uses = rd.get_vvar_uses_with_expr(arg_copy_def.atom)
|
|
1176
|
+
all_uses_with_def = set()
|
|
1177
|
+
|
|
1178
|
+
should_abort = False
|
|
1179
|
+
for use in all_arg_copy_var_uses:
|
|
1180
|
+
used_expr = use[0]
|
|
1181
|
+
if used_expr is not None and used_expr.size != arg_copy_def.size:
|
|
1182
|
+
should_abort = True
|
|
1183
|
+
break
|
|
1184
|
+
all_uses_with_def.add((arg_copy_def, use))
|
|
1185
|
+
if should_abort:
|
|
1186
|
+
continue
|
|
1187
|
+
|
|
1188
|
+
replace_with = eq.atom1
|
|
1189
|
+
remove_initial_assignment = True
|
|
1190
|
+
|
|
1191
|
+
if all_uses_with_def is None:
|
|
1192
|
+
continue
|
|
1193
|
+
|
|
1194
|
+
else:
|
|
1195
|
+
if (
|
|
1196
|
+
eq.codeloc.block_addr == the_def.codeloc.block_addr
|
|
1197
|
+
and eq.codeloc.block_idx == the_def.codeloc.block_idx
|
|
1198
|
+
):
|
|
1199
|
+
# the definition and the eq location are within the same block, and the definition is before
|
|
1200
|
+
# the eq location.
|
|
1201
|
+
if eq.codeloc.stmt_idx < the_def.codeloc.stmt_idx:
|
|
1202
|
+
continue
|
|
1203
|
+
def_eq_rel = DefEqRelation.DEF_EQ_SAME_BLOCK
|
|
1204
|
+
else:
|
|
1205
|
+
# the definition is in the predecessor block of the eq
|
|
1206
|
+
eq_block = next(
|
|
1207
|
+
iter(
|
|
1208
|
+
bb
|
|
1209
|
+
for bb in self.func_graph
|
|
1210
|
+
if bb.addr == eq.codeloc.block_addr and bb.idx == eq.codeloc.block_idx
|
|
1211
|
+
)
|
|
1212
|
+
)
|
|
1213
|
+
eq_block_preds = set(self.func_graph.predecessors(eq_block))
|
|
1214
|
+
if not any(
|
|
1215
|
+
pred.addr == the_def.codeloc.block_addr and pred.idx == the_def.codeloc.block_idx
|
|
1216
|
+
for pred in eq_block_preds
|
|
1217
|
+
):
|
|
1218
|
+
continue
|
|
1219
|
+
def_eq_rel = DefEqRelation.DEF_IN_EQ_PRED_BLOCK
|
|
1220
|
+
|
|
1221
|
+
if isinstance(eq.atom0, VirtualVariable) and eq.atom0.was_stack:
|
|
1222
|
+
# create the replacement expression
|
|
1223
|
+
if isinstance(eq.atom1, VirtualVariable) and eq.atom1.was_parameter:
|
|
1224
|
+
# replacing atom0
|
|
1225
|
+
new_idx = None if self._ail_manager is None else next(self._ail_manager.atom_ctr)
|
|
1226
|
+
replace_with = VirtualVariable(
|
|
1227
|
+
new_idx,
|
|
1228
|
+
eq.atom1.varid,
|
|
1229
|
+
eq.atom1.bits,
|
|
1230
|
+
category=eq.atom1.category,
|
|
1231
|
+
oident=eq.atom1.oident,
|
|
1232
|
+
**eq.atom1.tags,
|
|
1233
|
+
)
|
|
1234
|
+
else:
|
|
1235
|
+
# replacing atom1
|
|
1236
|
+
new_idx = None if self._ail_manager is None else next(self._ail_manager.atom_ctr)
|
|
1237
|
+
replace_with = VirtualVariable(
|
|
1238
|
+
new_idx,
|
|
1239
|
+
eq.atom0.varid,
|
|
1240
|
+
eq.atom0.bits,
|
|
1241
|
+
category=eq.atom0.category,
|
|
1242
|
+
oident=eq.atom0.oident,
|
|
1243
|
+
**eq.atom0.tags,
|
|
1244
|
+
)
|
|
1245
|
+
elif isinstance(eq.atom0, SimMemoryVariable) and isinstance(eq.atom0.addr, int):
|
|
1246
|
+
# create the memory loading expression
|
|
1247
|
+
new_idx = None if self._ail_manager is None else next(self._ail_manager.atom_ctr)
|
|
1248
|
+
replace_with = Load(
|
|
1249
|
+
new_idx,
|
|
1250
|
+
Const(None, None, eq.atom0.addr, self.project.arch.bits),
|
|
1251
|
+
eq.atom0.size,
|
|
1252
|
+
endness=self.project.arch.memory_endness,
|
|
1253
|
+
**eq.atom1.tags,
|
|
1254
|
+
)
|
|
1255
|
+
elif isinstance(eq.atom0, VirtualVariable) and eq.atom0.was_reg:
|
|
1256
|
+
if isinstance(eq.atom1, VirtualVariable):
|
|
1257
|
+
if eq.atom1.was_reg:
|
|
1258
|
+
if self.project.arch.is_artificial_register(eq.atom0.reg_offset, eq.atom0.size):
|
|
1259
|
+
replace_with = eq.atom1
|
|
1260
|
+
else:
|
|
1261
|
+
replace_with = eq.atom0
|
|
1262
|
+
elif eq.atom1.was_stack:
|
|
1263
|
+
replace_with = eq.atom1
|
|
1264
|
+
else:
|
|
1265
|
+
raise AngrRuntimeError(f"Unsupported atom1 vvar type {eq.atom1.category}.")
|
|
1266
|
+
else:
|
|
1267
|
+
raise AngrRuntimeError(f"Unsupported atom1 type {type(eq.atom1)}.")
|
|
1268
|
+
else:
|
|
1269
|
+
raise AngrRuntimeError(f"Unsupported atom0 type {type(eq.atom0)}.")
|
|
1270
|
+
|
|
1271
|
+
to_replace_def = the_def
|
|
1272
|
+
|
|
1273
|
+
# check: the definition of expression being replaced should not be a phi variable
|
|
1274
|
+
if (
|
|
1275
|
+
isinstance(to_replace_def.atom, atoms.VirtualVariable)
|
|
1276
|
+
and to_replace_def.atom.varid in rd.phi_vvar_ids
|
|
1277
|
+
):
|
|
1278
|
+
continue
|
|
1279
|
+
|
|
1280
|
+
# find all uses of this definition
|
|
1281
|
+
# we make a copy of the set since we may touch the set (uses) when replacing expressions
|
|
1282
|
+
all_uses = set(rd.all_vvar_uses[to_replace_def.atom.varid])
|
|
1283
|
+
# make sure none of these uses are phi nodes (depends on more than one def)
|
|
1284
|
+
all_uses_with_unique_def = set()
|
|
1285
|
+
for expr_and_use in all_uses:
|
|
1286
|
+
used_expr, use_loc = expr_and_use
|
|
1287
|
+
defs_and_exprs = rd.get_uses_by_location(use_loc, exprs=True)
|
|
1288
|
+
filtered_defs = {
|
|
1289
|
+
def_
|
|
1290
|
+
for def_, expr_ in defs_and_exprs
|
|
1291
|
+
if expr_ is not None and used_expr is not None and expr_.varid == used_expr.varid
|
|
1292
|
+
}
|
|
1293
|
+
if len(filtered_defs) == 1:
|
|
1294
|
+
all_uses_with_unique_def.add(expr_and_use)
|
|
1295
|
+
else:
|
|
1296
|
+
# optimization: break early
|
|
1297
|
+
break
|
|
1298
|
+
|
|
1299
|
+
if len(all_uses) != len(all_uses_with_unique_def):
|
|
1300
|
+
# only when all uses are determined by the same definition will we continue with the simplification
|
|
1301
|
+
continue
|
|
1302
|
+
|
|
1303
|
+
# one more check: there can be at most one assignment in all these use locations if the expression is
|
|
1304
|
+
# not going to be replaced with a parameter. the assignment can be an Assignment statement, but may also
|
|
1305
|
+
# be a Store if it's a global variable (via Load) that we are replacing with
|
|
1306
|
+
|
|
1307
|
+
if not (isinstance(replace_with, VirtualVariable) and replace_with.was_parameter):
|
|
1308
|
+
assignment_ctr = 0
|
|
1309
|
+
all_use_locs = {use_loc for _, use_loc in all_uses}
|
|
1310
|
+
for use_loc in all_use_locs:
|
|
1311
|
+
if use_loc == eq.codeloc:
|
|
1312
|
+
continue
|
|
1313
|
+
assert use_loc.block_addr is not None
|
|
1314
|
+
assert use_loc.stmt_idx is not None
|
|
1315
|
+
block = addr_and_idx_to_block[(use_loc.block_addr, use_loc.block_idx)]
|
|
1316
|
+
stmt = block.statements[use_loc.stmt_idx]
|
|
1317
|
+
if isinstance(stmt, Assignment) or (isinstance(replace_with, Load) and isinstance(stmt, Store)):
|
|
1318
|
+
assignment_ctr += 1
|
|
1319
|
+
if assignment_ctr > 1:
|
|
1320
|
+
continue
|
|
1321
|
+
|
|
1322
|
+
all_uses_with_def = {(to_replace_def, expr_and_use) for expr_and_use in all_uses}
|
|
1323
|
+
|
|
1324
|
+
remove_initial_assignment = False # expression folding will take care of it
|
|
1325
|
+
|
|
1326
|
+
assert replace_with is not None
|
|
1327
|
+
|
|
1328
|
+
to_replace_used_in_refs = False
|
|
1329
|
+
if isinstance(to_replace, VirtualVariable) and to_replace.was_stack:
|
|
1330
|
+
# if the variable being replaced has ever been accessed as a reference, we cannot replace it safely
|
|
1331
|
+
for _, (_, use_loc) in all_uses_with_def:
|
|
1332
|
+
assert use_loc.block_addr is not None and use_loc.stmt_idx is not None
|
|
1333
|
+
block = addr_and_idx_to_block[(use_loc.block_addr, use_loc.block_idx)]
|
|
1334
|
+
stmt = block.statements[use_loc.stmt_idx]
|
|
1335
|
+
if self._statement_uses_ref_vvar(stmt, to_replace.varid):
|
|
1336
|
+
to_replace_used_in_refs = True
|
|
1337
|
+
break
|
|
1338
|
+
if to_replace_used_in_refs:
|
|
1339
|
+
continue
|
|
1340
|
+
|
|
1341
|
+
if any(isinstance(expr_and_use[0], VirtualVariable) for _, expr_and_use in all_uses_with_def):
|
|
1342
|
+
# if any of the uses are phi assignments, we skip
|
|
1343
|
+
used_in_phi_assignment = False
|
|
1344
|
+
for _, expr_and_use in all_uses_with_def:
|
|
1345
|
+
u = expr_and_use[1]
|
|
1346
|
+
assert u.block_addr is not None
|
|
1347
|
+
assert u.stmt_idx is not None
|
|
1348
|
+
block = addr_and_idx_to_block[(u.block_addr, u.block_idx)]
|
|
1349
|
+
stmt = block.statements[u.stmt_idx]
|
|
1350
|
+
if is_phi_assignment(stmt):
|
|
1351
|
+
used_in_phi_assignment = True
|
|
1352
|
+
break
|
|
1353
|
+
if used_in_phi_assignment:
|
|
1354
|
+
continue
|
|
1355
|
+
|
|
1356
|
+
# ensure the uses we consider are all after the eq location
|
|
1357
|
+
filtered_all_uses_with_def = []
|
|
1358
|
+
for def_, expr_and_use in all_uses_with_def:
|
|
1359
|
+
u = expr_and_use[1]
|
|
1360
|
+
if (
|
|
1361
|
+
u.block_addr == eq.codeloc.block_addr
|
|
1362
|
+
and u.block_idx == eq.codeloc.block_idx
|
|
1363
|
+
and u.stmt_idx < eq.codeloc.stmt_idx
|
|
1364
|
+
):
|
|
1365
|
+
# this use happens before the assignment - ignore it
|
|
1366
|
+
continue
|
|
1367
|
+
if def_eq_rel == DefEqRelation.DEF_IN_EQ_PRED_BLOCK and u.block_addr == def_.codeloc.block_addr:
|
|
1368
|
+
# the definition is in a predecessor block of the eq location, so all uses must be in the same
|
|
1369
|
+
# block as the eq location. (technically it can also be in a successor block to the eq location, but
|
|
1370
|
+
# we don't support it yet).
|
|
1371
|
+
continue
|
|
1372
|
+
filtered_all_uses_with_def.append((def_, expr_and_use))
|
|
1373
|
+
all_uses_with_def = filtered_all_uses_with_def
|
|
1374
|
+
|
|
1375
|
+
if not all_uses_with_def:
|
|
1376
|
+
# definitions without uses may simply be our data-flow analysis being incorrect. do not remove them.
|
|
1377
|
+
continue
|
|
1378
|
+
|
|
1379
|
+
# TODO: We can only replace all these uses with the stack variable if the stack variable isn't
|
|
1380
|
+
# TODO: re-assigned of a new value. Perform this check.
|
|
1381
|
+
|
|
1382
|
+
# replace all uses
|
|
1383
|
+
all_uses_replaced = True
|
|
1384
|
+
for def_, expr_and_use in all_uses_with_def:
|
|
1385
|
+
used_expr, u = expr_and_use
|
|
1386
|
+
|
|
1387
|
+
use_expr_defns = []
|
|
1388
|
+
for d in rd.get_uses_by_location(u):
|
|
1389
|
+
if (
|
|
1390
|
+
isinstance(d.atom, atoms.VirtualVariable)
|
|
1391
|
+
and d.atom.was_reg
|
|
1392
|
+
and isinstance(def_.atom, atoms.VirtualVariable)
|
|
1393
|
+
and def_.atom.was_reg
|
|
1394
|
+
and d.atom.reg_offset == def_.atom.reg_offset
|
|
1395
|
+
) or d.atom == def_.atom:
|
|
1396
|
+
use_expr_defns.append(d)
|
|
1397
|
+
# you can never replace a use with dependencies from outside the checked defn
|
|
1398
|
+
if len(use_expr_defns) != 1 or next(iter(use_expr_defns)) != def_:
|
|
1399
|
+
if not use_expr_defns:
|
|
1400
|
+
_l.warning("There was no use_expr_defns for %s, this is likely a bug", u)
|
|
1401
|
+
# TODO: can you have multiple definitions which can all be eliminated?
|
|
1402
|
+
all_uses_replaced = False
|
|
1403
|
+
continue
|
|
1404
|
+
|
|
1405
|
+
if u == eq.codeloc:
|
|
1406
|
+
# skip the very initial assignment location
|
|
1407
|
+
continue
|
|
1408
|
+
old_block = addr_and_idx_to_block.get((u.block_addr, u.block_idx), None)
|
|
1409
|
+
if old_block is None:
|
|
1410
|
+
continue
|
|
1411
|
+
if used_expr is None:
|
|
1412
|
+
all_uses_replaced = False
|
|
1413
|
+
continue
|
|
1414
|
+
|
|
1415
|
+
# ensure the expression that we want to replace with is still up-to-date
|
|
1416
|
+
replace_with_original_def = self._find_atom_def_at(replace_with, rd, def_.codeloc)
|
|
1417
|
+
if replace_with_original_def is not None and not self._check_atom_last_def(
|
|
1418
|
+
replace_with, u, rd, replace_with_original_def
|
|
1419
|
+
):
|
|
1420
|
+
all_uses_replaced = False
|
|
1421
|
+
continue
|
|
1422
|
+
|
|
1423
|
+
# if there is an updated block, use it
|
|
1424
|
+
the_block = self.blocks.get(old_block, old_block)
|
|
1425
|
+
stmt: Statement = the_block.statements[u.stmt_idx]
|
|
1426
|
+
|
|
1427
|
+
replace_with_copy = replace_with.copy()
|
|
1428
|
+
if used_expr.size != replace_with_copy.size:
|
|
1429
|
+
new_idx = None if self._ail_manager is None else next(self._ail_manager.atom_ctr)
|
|
1430
|
+
replace_with_copy = Convert(
|
|
1431
|
+
new_idx,
|
|
1432
|
+
replace_with_copy.bits,
|
|
1433
|
+
used_expr.bits,
|
|
1434
|
+
False,
|
|
1435
|
+
replace_with_copy,
|
|
1436
|
+
)
|
|
1437
|
+
|
|
1438
|
+
r, new_block = self._replace_expr_and_update_block(
|
|
1439
|
+
the_block, u.stmt_idx, stmt, used_expr, replace_with_copy
|
|
1440
|
+
)
|
|
1441
|
+
if r:
|
|
1442
|
+
self.blocks[old_block] = new_block
|
|
1443
|
+
updated_locs.add(u)
|
|
1444
|
+
else:
|
|
1445
|
+
# failed to replace a use - we need to keep the initial assignment!
|
|
1446
|
+
all_uses_replaced = False
|
|
1447
|
+
simplified |= r
|
|
1448
|
+
|
|
1449
|
+
if all_uses_replaced and remove_initial_assignment:
|
|
1450
|
+
# the initial statement can be removed
|
|
1451
|
+
self._assignments_to_remove.add(eq.codeloc)
|
|
1452
|
+
|
|
1453
|
+
if simplified:
|
|
1454
|
+
self._clear_cache()
|
|
1455
|
+
return simplified
|
|
1456
|
+
|
|
1457
|
+
@staticmethod
|
|
1458
|
+
def _find_atom_def_at(atom, rd, codeloc: AILCodeLocation) -> Definition | None:
|
|
1459
|
+
if isinstance(atom, Register):
|
|
1460
|
+
defs = rd.get_defs(atom, codeloc, OP_BEFORE)
|
|
1461
|
+
return next(iter(defs)) if len(defs) == 1 else None
|
|
1462
|
+
|
|
1463
|
+
return None
|
|
1464
|
+
|
|
1465
|
+
@staticmethod
|
|
1466
|
+
def _check_atom_last_def(atom, codeloc, rd, the_def) -> bool:
|
|
1467
|
+
if isinstance(atom, Register):
|
|
1468
|
+
defs = rd.get_defs(atom, codeloc, OP_BEFORE)
|
|
1469
|
+
for d in defs:
|
|
1470
|
+
if d.codeloc != the_def.codeloc:
|
|
1471
|
+
return False
|
|
1472
|
+
|
|
1473
|
+
return True
|
|
1474
|
+
|
|
1475
|
+
#
|
|
1476
|
+
# Folding call expressions
|
|
1477
|
+
#
|
|
1478
|
+
|
|
1479
|
+
@staticmethod
|
|
1480
|
+
def _is_expr_using_temporaries(expr: Expression) -> bool:
|
|
1481
|
+
walker = AILBlockTempCollector()
|
|
1482
|
+
walker.walk_expression(expr)
|
|
1483
|
+
return len(walker.temps) > 0
|
|
1484
|
+
|
|
1485
|
+
@staticmethod
|
|
1486
|
+
def _is_stmt_using_temporaries(stmt: Statement) -> bool:
|
|
1487
|
+
walker = AILBlockTempCollector()
|
|
1488
|
+
walker.walk_statement(stmt)
|
|
1489
|
+
return len(walker.temps) > 0
|
|
1490
|
+
|
|
1491
|
+
@timethis
|
|
1492
|
+
def _fold_call_exprs(self) -> bool:
|
|
1493
|
+
"""
|
|
1494
|
+
Fold a call expression (statement) into other statements if the return value of the call expression (statement)
|
|
1495
|
+
is only used once, and the use site and the call site belongs to the same supernode.
|
|
1496
|
+
|
|
1497
|
+
Example::
|
|
1498
|
+
|
|
1499
|
+
s1 = func();
|
|
1500
|
+
s0 = s1;
|
|
1501
|
+
if (s0) ...
|
|
1502
|
+
|
|
1503
|
+
after folding, it will be transformed to::
|
|
1504
|
+
|
|
1505
|
+
s0 = func();
|
|
1506
|
+
if (s0) ...
|
|
1507
|
+
|
|
1508
|
+
s0 can be folded into the condition, which means this example can further be transformed to::
|
|
1509
|
+
|
|
1510
|
+
if (func()) ...
|
|
1511
|
+
|
|
1512
|
+
this behavior is controlled by fold_callexprs_into_conditions. This to avoid cases where func() is called more
|
|
1513
|
+
than once after simplification and graph structuring where conditions might be duplicated (e.g., in Dream).
|
|
1514
|
+
In such cases, the one-use expression folder in RegionSimplifier will perform this transformation.
|
|
1515
|
+
"""
|
|
1516
|
+
|
|
1517
|
+
# pylint:disable=unreachable
|
|
1518
|
+
simplified = False
|
|
1519
|
+
|
|
1520
|
+
equivalence = self._compute_equivalence()
|
|
1521
|
+
if not equivalence:
|
|
1522
|
+
return simplified
|
|
1523
|
+
|
|
1524
|
+
addr_and_idx_to_block: dict[tuple[int, int | None], Block] = {}
|
|
1525
|
+
for block in self.func_graph.nodes():
|
|
1526
|
+
addr_and_idx_to_block[(block.addr, block.idx)] = block
|
|
1527
|
+
|
|
1528
|
+
def_locations_to_remove: set[AILCodeLocation] = set()
|
|
1529
|
+
updated_use_locations: set[AILCodeLocation] = set()
|
|
1530
|
+
|
|
1531
|
+
for eq in equivalence:
|
|
1532
|
+
# register variable == Call
|
|
1533
|
+
if isinstance(eq.atom0, VirtualVariable) and (eq.atom0.was_reg or eq.atom0.was_tmp):
|
|
1534
|
+
if isinstance(eq.atom1, Call):
|
|
1535
|
+
# register variable = Call
|
|
1536
|
+
call: Expression = eq.atom1
|
|
1537
|
+
# call_addr = call.target.value if isinstance(call.target, Const) else None
|
|
1538
|
+
elif isinstance(eq.atom1, Convert) and isinstance(eq.atom1.operand, Call):
|
|
1539
|
+
# register variable = Convert(Call)
|
|
1540
|
+
call = eq.atom1
|
|
1541
|
+
# call_addr = call.operand.target.value if isinstance(call.operand.target, Const) else None
|
|
1542
|
+
elif eq.is_weakassignment:
|
|
1543
|
+
# variable =w something else
|
|
1544
|
+
call = eq.atom1
|
|
1545
|
+
else:
|
|
1546
|
+
continue
|
|
1547
|
+
|
|
1548
|
+
if self._is_expr_using_temporaries(call):
|
|
1549
|
+
continue
|
|
1550
|
+
|
|
1551
|
+
if eq.codeloc in updated_use_locations:
|
|
1552
|
+
# this def is now created by an updated use. the corresponding statement will be updated in the end.
|
|
1553
|
+
# we must rerun Propagator to get an updated definition (and Equivalence)
|
|
1554
|
+
continue
|
|
1555
|
+
|
|
1556
|
+
# find all uses of this virtual register
|
|
1557
|
+
rd = self._compute_reaching_definitions()
|
|
1558
|
+
|
|
1559
|
+
the_def: Definition = Definition(
|
|
1560
|
+
atoms.VirtualVariable(
|
|
1561
|
+
eq.atom0.varid, eq.atom0.size, category=eq.atom0.category, oident=eq.atom0.oident
|
|
1562
|
+
),
|
|
1563
|
+
eq.codeloc,
|
|
1564
|
+
)
|
|
1565
|
+
assert the_def.codeloc.block_addr is not None
|
|
1566
|
+
assert the_def.codeloc.stmt_idx is not None
|
|
1567
|
+
|
|
1568
|
+
all_uses = rd.get_vvar_uses_with_expr(the_def.atom)
|
|
1569
|
+
if eq.is_weakassignment:
|
|
1570
|
+
# eliminate the "use" at the weak assignment site
|
|
1571
|
+
all_uses = {use for use in all_uses if use[1] != eq.codeloc}
|
|
1572
|
+
|
|
1573
|
+
if len(all_uses) != 1:
|
|
1574
|
+
continue
|
|
1575
|
+
used_expr, u = next(iter(all_uses))
|
|
1576
|
+
if used_expr is None:
|
|
1577
|
+
continue
|
|
1578
|
+
assert u.block_addr is not None
|
|
1579
|
+
assert u.stmt_idx is not None
|
|
1580
|
+
|
|
1581
|
+
if u in def_locations_to_remove:
|
|
1582
|
+
# this use site has been altered by previous folding attempts. the corresponding statement will be
|
|
1583
|
+
# removed in the end. in this case, this Equivalence is probably useless, and we must rerun
|
|
1584
|
+
# Propagator to get an updated Equivalence.
|
|
1585
|
+
continue
|
|
1586
|
+
|
|
1587
|
+
if not self._fold_callexprs_into_conditions:
|
|
1588
|
+
# check the statement and make sure it's not a conditional jump
|
|
1589
|
+
the_block = addr_and_idx_to_block[(u.block_addr, u.block_idx)]
|
|
1590
|
+
if isinstance(the_block.statements[u.stmt_idx], ConditionalJump):
|
|
1591
|
+
continue
|
|
1592
|
+
|
|
1593
|
+
# check if the use and the definition is within the same supernode
|
|
1594
|
+
# also we do not allow any calls between the def site and the use site
|
|
1595
|
+
if not self._loc_within_superblock(
|
|
1596
|
+
addr_and_idx_to_block[(the_def.codeloc.block_addr, the_def.codeloc.block_idx)],
|
|
1597
|
+
u.block_addr,
|
|
1598
|
+
u.block_idx,
|
|
1599
|
+
terminate_with_calls=True,
|
|
1600
|
+
):
|
|
1601
|
+
continue
|
|
1602
|
+
|
|
1603
|
+
# ensure there are no other calls between the def site and the use site.
|
|
1604
|
+
# this is because we do not want to alter the order of calls.
|
|
1605
|
+
u_inclusive = AILCodeLocation(u.block_addr, u.block_idx, u.stmt_idx + 1)
|
|
1606
|
+
# note that the target statement being a store is fine
|
|
1607
|
+
if (
|
|
1608
|
+
has_call_in_between_stmts(
|
|
1609
|
+
self.func_graph,
|
|
1610
|
+
addr_and_idx_to_block,
|
|
1611
|
+
the_def.codeloc,
|
|
1612
|
+
u_inclusive,
|
|
1613
|
+
skip_if_contains_vvar=the_def.atom.varid,
|
|
1614
|
+
)
|
|
1615
|
+
or has_store_stmt_in_between_stmts(self.func_graph, addr_and_idx_to_block, the_def.codeloc, u)
|
|
1616
|
+
or has_load_expr_in_between_stmts(
|
|
1617
|
+
self.func_graph,
|
|
1618
|
+
addr_and_idx_to_block,
|
|
1619
|
+
the_def.codeloc,
|
|
1620
|
+
u_inclusive,
|
|
1621
|
+
skip_if_contains_vvar=the_def.atom.varid,
|
|
1622
|
+
)
|
|
1623
|
+
):
|
|
1624
|
+
continue
|
|
1625
|
+
|
|
1626
|
+
# replace all uses
|
|
1627
|
+
old_block = addr_and_idx_to_block.get((u.block_addr, u.block_idx), None)
|
|
1628
|
+
if old_block is None:
|
|
1629
|
+
continue
|
|
1630
|
+
|
|
1631
|
+
# if there is an updated block, use that
|
|
1632
|
+
the_block = self.blocks.get(old_block, old_block)
|
|
1633
|
+
stmt: Statement = the_block.statements[u.stmt_idx]
|
|
1634
|
+
|
|
1635
|
+
if isinstance(eq.atom0, VirtualVariable):
|
|
1636
|
+
src = used_expr
|
|
1637
|
+
dst: Expression = call.copy()
|
|
1638
|
+
|
|
1639
|
+
if isinstance(dst, Call) and dst.ret_expr is not None:
|
|
1640
|
+
dst_bits = dst.ret_expr.bits
|
|
1641
|
+
# clear the ret_expr and fp_ret_expr of dst, then set bits so that it can be used as an
|
|
1642
|
+
# expression
|
|
1643
|
+
dst.ret_expr = None
|
|
1644
|
+
dst.fp_ret_expr = None
|
|
1645
|
+
dst.bits = dst_bits
|
|
1646
|
+
|
|
1647
|
+
if src.bits != dst.bits and not eq.is_weakassignment:
|
|
1648
|
+
dst = Convert(None, dst.bits, src.bits, False, dst)
|
|
1649
|
+
else:
|
|
1650
|
+
continue
|
|
1651
|
+
|
|
1652
|
+
# ensure what we are going to replace only appears once
|
|
1653
|
+
expr_ctr = SingleExpressionCounter(stmt, src)
|
|
1654
|
+
if expr_ctr.count > 1:
|
|
1655
|
+
continue
|
|
1656
|
+
|
|
1657
|
+
replaced, new_block = self._replace_expr_and_update_block(the_block, u.stmt_idx, stmt, src, dst)
|
|
1658
|
+
|
|
1659
|
+
if replaced:
|
|
1660
|
+
self.blocks[old_block] = new_block
|
|
1661
|
+
# this call has been folded to the use site. we can remove this call.
|
|
1662
|
+
self._calls_to_remove.add(eq.codeloc)
|
|
1663
|
+
simplified = True
|
|
1664
|
+
def_locations_to_remove.add(eq.codeloc)
|
|
1665
|
+
updated_use_locations.add(u)
|
|
1666
|
+
|
|
1667
|
+
# no need to clear the cache at the end of this method
|
|
1668
|
+
return simplified
|
|
1669
|
+
|
|
1670
|
+
def _get_super_node_blocks(self, start_node: Block) -> list[Block]:
|
|
1671
|
+
lst: list[Block] = [start_node]
|
|
1672
|
+
while True:
|
|
1673
|
+
b = lst[-1]
|
|
1674
|
+
successors = list(self.func_graph.successors(b))
|
|
1675
|
+
if len(successors) == 0:
|
|
1676
|
+
break
|
|
1677
|
+
if len(successors) == 1:
|
|
1678
|
+
succ = successors[0]
|
|
1679
|
+
# check its predecessors
|
|
1680
|
+
succ_predecessors = list(self.func_graph.predecessors(succ))
|
|
1681
|
+
if len(succ_predecessors) == 1:
|
|
1682
|
+
if succ in lst:
|
|
1683
|
+
# we are about to form a loop - bad!
|
|
1684
|
+
# example: binary ce1897b492c80bf94083dd783aefb413ab1f6d8d4981adce8420f6669d0cb3e1, block
|
|
1685
|
+
# 0x2976EF7.
|
|
1686
|
+
break
|
|
1687
|
+
lst.append(succ)
|
|
1688
|
+
else:
|
|
1689
|
+
break
|
|
1690
|
+
else:
|
|
1691
|
+
# too many successors
|
|
1692
|
+
break
|
|
1693
|
+
return lst
|
|
1694
|
+
|
|
1695
|
+
def _loc_within_superblock(
|
|
1696
|
+
self, start_node: Block, block_addr: int, block_idx: int | None, terminate_with_calls=False
|
|
1697
|
+
) -> bool:
|
|
1698
|
+
b = start_node
|
|
1699
|
+
if block_addr == b.addr and block_idx == b.idx:
|
|
1700
|
+
return True
|
|
1701
|
+
|
|
1702
|
+
encountered_block_addrs: set[tuple[int, int | None]] = {(b.addr, b.idx)}
|
|
1703
|
+
while True:
|
|
1704
|
+
if terminate_with_calls and b.statements and isinstance(b.statements[-1], Call):
|
|
1705
|
+
return False
|
|
1706
|
+
|
|
1707
|
+
encountered_block_addrs.add((b.addr, b.idx))
|
|
1708
|
+
successors = list(self.func_graph.successors(b))
|
|
1709
|
+
if len(successors) == 0:
|
|
1710
|
+
# did not encounter the block before running out of successors
|
|
1711
|
+
return False
|
|
1712
|
+
if len(successors) == 1:
|
|
1713
|
+
succ = successors[0]
|
|
1714
|
+
# check its predecessors
|
|
1715
|
+
succ_predecessors = list(self.func_graph.predecessors(succ))
|
|
1716
|
+
if len(succ_predecessors) == 1:
|
|
1717
|
+
if (succ.addr, succ.idx) in encountered_block_addrs:
|
|
1718
|
+
# we are about to form a loop - bad!
|
|
1719
|
+
# example: binary ce1897b492c80bf94083dd783aefb413ab1f6d8d4981adce8420f6669d0cb3e1, block
|
|
1720
|
+
# 0x2976EF7.
|
|
1721
|
+
return False
|
|
1722
|
+
if block_addr == succ.addr and block_idx == succ.idx:
|
|
1723
|
+
return True
|
|
1724
|
+
b = succ
|
|
1725
|
+
else:
|
|
1726
|
+
return False
|
|
1727
|
+
else:
|
|
1728
|
+
# too many successors
|
|
1729
|
+
return False
|
|
1730
|
+
|
|
1731
|
+
@staticmethod
|
|
1732
|
+
def _replace_expr_and_update_block(block, stmt_idx, stmt, src_expr, dst_expr) -> tuple[bool, Block | None]:
|
|
1733
|
+
replaced, new_stmt = stmt.replace(src_expr, dst_expr)
|
|
1734
|
+
if replaced:
|
|
1735
|
+
new_block = block.copy()
|
|
1736
|
+
new_block.statements = block.statements[::]
|
|
1737
|
+
new_block.statements[stmt_idx] = new_stmt
|
|
1738
|
+
return True, new_block
|
|
1739
|
+
|
|
1740
|
+
return False, None
|
|
1741
|
+
|
|
1742
|
+
@timethis
|
|
1743
|
+
def _iteratively_remove_dead_assignments(self) -> bool:
|
|
1744
|
+
anything_removed = False
|
|
1745
|
+
while True:
|
|
1746
|
+
r = self._remove_dead_assignments()
|
|
1747
|
+
if not r:
|
|
1748
|
+
return anything_removed
|
|
1749
|
+
self._rebuild_func_graph()
|
|
1750
|
+
self._clear_cache()
|
|
1751
|
+
|
|
1752
|
+
@timethis
|
|
1753
|
+
def _remove_dead_assignments(self) -> bool:
|
|
1754
|
+
|
|
1755
|
+
# keeping tracking of statements to remove and statements (as well as dead vvars) to keep allows us to handle
|
|
1756
|
+
# cases where a statement defines more than one atom, e.g., a call statement that defines both the return
|
|
1757
|
+
# value and the floating-point return value.
|
|
1758
|
+
stmts_to_remove_per_block: dict[tuple[int, int | None], set[int]] = defaultdict(set)
|
|
1759
|
+
stmts_to_keep_per_block: dict[tuple[int, int | None], set[int]] = defaultdict(set)
|
|
1760
|
+
dead_vvar_ids: set[int] = self._removed_vvar_ids.copy()
|
|
1761
|
+
dead_vvar_codelocs: set[AILCodeLocation] = set()
|
|
1762
|
+
blocks: dict[tuple[int, int | None], Block] = {
|
|
1763
|
+
(node.addr, node.idx): self.blocks.get(node, node) for node in self.func_graph.nodes()
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
# Find all statements that should be removed
|
|
1767
|
+
mask = (1 << self.project.arch.bits) - 1
|
|
1768
|
+
|
|
1769
|
+
rd = self._compute_reaching_definitions()
|
|
1770
|
+
stackarg_offsets = (
|
|
1771
|
+
{(tpl[1] & mask) for tpl in self._stack_arg_offsets} if self._stack_arg_offsets is not None else None
|
|
1772
|
+
)
|
|
1773
|
+
retpoints: set[tuple[int, int]] = {
|
|
1774
|
+
(node.addr, node.idx)
|
|
1775
|
+
for node in self.func_graph
|
|
1776
|
+
if node.statements and isinstance(node.statements[-1], Return) and self.func_graph.out_degree[node] == 0
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
while True:
|
|
1780
|
+
new_dead_vars_found = False
|
|
1781
|
+
|
|
1782
|
+
# traverse all virtual variable definitions
|
|
1783
|
+
for vvar_id, codeloc in rd.all_vvar_definitions.items():
|
|
1784
|
+
if vvar_id in dead_vvar_ids:
|
|
1785
|
+
continue
|
|
1786
|
+
uses = None
|
|
1787
|
+
if vvar_id in self._propagator_dead_vvar_ids:
|
|
1788
|
+
# we are definitely removing this variable if it has no uses
|
|
1789
|
+
uses = rd.all_vvar_uses[vvar_id]
|
|
1790
|
+
|
|
1791
|
+
if uses is None:
|
|
1792
|
+
vvar = rd.varid_to_vvar[vvar_id]
|
|
1793
|
+
def_codeloc = rd.all_vvar_definitions[vvar_id]
|
|
1794
|
+
if def_codeloc.is_extern:
|
|
1795
|
+
def_stmt = None
|
|
1796
|
+
else:
|
|
1797
|
+
assert def_codeloc.block_addr is not None and def_codeloc.stmt_idx is not None
|
|
1798
|
+
def_stmt = blocks[(def_codeloc.block_addr, def_codeloc.block_idx)].statements[
|
|
1799
|
+
def_codeloc.stmt_idx
|
|
1800
|
+
]
|
|
1801
|
+
if is_vvar_eliminatable(vvar, def_stmt):
|
|
1802
|
+
uses = rd.all_vvar_uses[vvar_id]
|
|
1803
|
+
elif vvar.was_stack:
|
|
1804
|
+
if not self._remove_dead_memdefs:
|
|
1805
|
+
if rd.is_phi_vvar_id(vvar_id):
|
|
1806
|
+
# we always remove unused phi variables
|
|
1807
|
+
pass
|
|
1808
|
+
elif vvar_id in self._secondary_stackvars:
|
|
1809
|
+
# secondary stack variables are potentially removable
|
|
1810
|
+
pass
|
|
1811
|
+
elif (def_codeloc.block_addr, def_codeloc.block_idx) in retpoints:
|
|
1812
|
+
# slack variable assignments in endpoint blocks are potentially removable.
|
|
1813
|
+
# note that this is a hack! we should rely on more reliable stack variable
|
|
1814
|
+
# eliminatability detection.
|
|
1815
|
+
pass
|
|
1816
|
+
elif stackarg_offsets is not None:
|
|
1817
|
+
# we always remove definitions for stack arguments
|
|
1818
|
+
assert vvar.stack_offset is not None
|
|
1819
|
+
if (vvar.stack_offset & mask) not in stackarg_offsets:
|
|
1820
|
+
continue
|
|
1821
|
+
else:
|
|
1822
|
+
continue
|
|
1823
|
+
uses = rd.all_vvar_uses[vvar_id]
|
|
1824
|
+
|
|
1825
|
+
else:
|
|
1826
|
+
uses = set()
|
|
1827
|
+
|
|
1828
|
+
# remove uses where vvars are going to be removed
|
|
1829
|
+
filtered_uses_count = 0
|
|
1830
|
+
for _, loc in uses:
|
|
1831
|
+
if loc in dead_vvar_codelocs and loc.block_addr is not None and loc.stmt_idx is not None:
|
|
1832
|
+
stmt = blocks[(loc.block_addr, loc.block_idx)].statements[loc.stmt_idx]
|
|
1833
|
+
if not self._statement_has_call_exprs(stmt) and not isinstance(stmt, (DirtyStatement, Call)):
|
|
1834
|
+
continue
|
|
1835
|
+
filtered_uses_count += 1
|
|
1836
|
+
|
|
1837
|
+
if filtered_uses_count == 0:
|
|
1838
|
+
new_dead_vars_found = True
|
|
1839
|
+
dead_vvar_ids.add(vvar_id)
|
|
1840
|
+
dead_vvar_codelocs.add(codeloc)
|
|
1841
|
+
if not codeloc.is_extern:
|
|
1842
|
+
stmts_to_remove_per_block[(codeloc.block_addr, codeloc.block_idx)].add(codeloc.stmt_idx)
|
|
1843
|
+
stmts_to_keep_per_block[(codeloc.block_addr, codeloc.block_idx)].discard(codeloc.stmt_idx)
|
|
1844
|
+
else:
|
|
1845
|
+
if not codeloc.is_extern:
|
|
1846
|
+
stmts_to_keep_per_block[(codeloc.block_addr, codeloc.block_idx)].add(codeloc.stmt_idx)
|
|
1847
|
+
|
|
1848
|
+
if not new_dead_vars_found:
|
|
1849
|
+
# nothing more is found. let's end the loop
|
|
1850
|
+
break
|
|
1851
|
+
|
|
1852
|
+
# find all phi variables that rely on variables that no longer exist
|
|
1853
|
+
removed_vvar_ids = self._removed_vvar_ids
|
|
1854
|
+
while True:
|
|
1855
|
+
new_removed_vvar_ids = set()
|
|
1856
|
+
for phi_varid, phi_use_varids in rd.phivarid_to_varids.items():
|
|
1857
|
+
if phi_varid not in dead_vvar_ids and any(vvarid in removed_vvar_ids for vvarid in phi_use_varids):
|
|
1858
|
+
loc = rd.all_vvar_definitions[phi_varid]
|
|
1859
|
+
assert loc.block_addr is not None and loc.stmt_idx is not None
|
|
1860
|
+
if loc.stmt_idx not in stmts_to_remove_per_block[(loc.block_addr, loc.block_idx)]:
|
|
1861
|
+
stmts_to_remove_per_block[(loc.block_addr, loc.block_idx)].add(loc.stmt_idx)
|
|
1862
|
+
new_removed_vvar_ids.add(phi_varid)
|
|
1863
|
+
dead_vvar_ids.add(phi_varid)
|
|
1864
|
+
if not new_removed_vvar_ids:
|
|
1865
|
+
break
|
|
1866
|
+
removed_vvar_ids = new_removed_vvar_ids
|
|
1867
|
+
|
|
1868
|
+
# find all phi variables that are only ever used by other phi variables
|
|
1869
|
+
redundant_phi_and_dirty_varids = self._find_cyclic_dependent_phis_and_dirty_vvars(rd, dead_vvar_ids)
|
|
1870
|
+
for varid in redundant_phi_and_dirty_varids:
|
|
1871
|
+
loc = rd.all_vvar_definitions[varid]
|
|
1872
|
+
assert loc.block_addr is not None and loc.stmt_idx is not None
|
|
1873
|
+
if loc.stmt_idx not in stmts_to_remove_per_block[(loc.block_addr, loc.block_idx)]:
|
|
1874
|
+
stmts_to_remove_per_block[(loc.block_addr, loc.block_idx)].add(loc.stmt_idx)
|
|
1875
|
+
stmts_to_keep_per_block[(loc.block_addr, loc.block_idx)].discard(loc.stmt_idx)
|
|
1876
|
+
|
|
1877
|
+
for codeloc in self._calls_to_remove | self._assignments_to_remove:
|
|
1878
|
+
# this call can be removed. make sure it exists in stmts_to_remove_per_block
|
|
1879
|
+
assert codeloc.block_addr is not None and codeloc.stmt_idx is not None
|
|
1880
|
+
stmts_to_remove_per_block[codeloc.block_addr, codeloc.block_idx].add(codeloc.stmt_idx)
|
|
1881
|
+
|
|
1882
|
+
simplified = False
|
|
1883
|
+
|
|
1884
|
+
# Remove the statements
|
|
1885
|
+
for old_block in self.func_graph.nodes():
|
|
1886
|
+
# if there is an updated block, use it
|
|
1887
|
+
block = self.blocks.get(old_block, old_block)
|
|
1888
|
+
|
|
1889
|
+
if not isinstance(block, Block):
|
|
1890
|
+
continue
|
|
1891
|
+
|
|
1892
|
+
if (block.addr, block.idx) not in stmts_to_remove_per_block:
|
|
1893
|
+
continue
|
|
1894
|
+
|
|
1895
|
+
new_statements = []
|
|
1896
|
+
stmts_to_remove = stmts_to_remove_per_block[(block.addr, block.idx)]
|
|
1897
|
+
stmts_to_keep = stmts_to_keep_per_block[(block.addr, block.idx)]
|
|
1898
|
+
|
|
1899
|
+
if not stmts_to_remove:
|
|
1900
|
+
continue
|
|
1901
|
+
|
|
1902
|
+
for idx, stmt in enumerate(block.statements):
|
|
1903
|
+
if idx in stmts_to_remove and idx in stmts_to_keep and isinstance(stmt, Call):
|
|
1904
|
+
# this statement declares more than one variable. we should handle it surgically
|
|
1905
|
+
# case 1: stmt.ret_expr and stmt.fp_ret_expr are both set, but one of them is not used
|
|
1906
|
+
if isinstance(stmt.ret_expr, VirtualVariable) and stmt.ret_expr.varid in dead_vvar_ids:
|
|
1907
|
+
stmt = stmt.copy()
|
|
1908
|
+
stmt.ret_expr = None
|
|
1909
|
+
simplified = True
|
|
1910
|
+
if isinstance(stmt.fp_ret_expr, VirtualVariable) and stmt.fp_ret_expr.varid in dead_vvar_ids:
|
|
1911
|
+
stmt = stmt.copy()
|
|
1912
|
+
stmt.fp_ret_expr = None
|
|
1913
|
+
simplified = True
|
|
1914
|
+
|
|
1915
|
+
if idx in stmts_to_remove and idx not in stmts_to_keep and not isinstance(stmt, DirtyStatement):
|
|
1916
|
+
if isinstance(stmt, (Assignment, WeakAssignment, Store)):
|
|
1917
|
+
# Special logic for Assignment and Store statements
|
|
1918
|
+
|
|
1919
|
+
# if this statement writes to a virtual variable that must be preserved, we ignore it
|
|
1920
|
+
if (
|
|
1921
|
+
isinstance(stmt, Assignment)
|
|
1922
|
+
and isinstance(stmt.dst, VirtualVariable)
|
|
1923
|
+
and stmt.dst.varid in self._avoid_vvar_ids
|
|
1924
|
+
):
|
|
1925
|
+
new_statements.append(stmt)
|
|
1926
|
+
continue
|
|
1927
|
+
|
|
1928
|
+
# if this statement triggers a call, it should only be removed if it's in self._calls_to_remove
|
|
1929
|
+
codeloc = AILCodeLocation(block.addr, block.idx, idx, stmt.tags.get("ins_addr"))
|
|
1930
|
+
if codeloc in self._assignments_to_remove:
|
|
1931
|
+
# it should be removed
|
|
1932
|
+
simplified = True
|
|
1933
|
+
continue
|
|
1934
|
+
|
|
1935
|
+
if self._statement_has_call_exprs(stmt):
|
|
1936
|
+
if codeloc in self._calls_to_remove:
|
|
1937
|
+
# it has a call and must be removed
|
|
1938
|
+
simplified = True
|
|
1939
|
+
continue
|
|
1940
|
+
if isinstance(stmt, Assignment) and isinstance(stmt.dst, VirtualVariable):
|
|
1941
|
+
# no one is using the returned virtual variable.
|
|
1942
|
+
# now the things are a bit tricky here
|
|
1943
|
+
if isinstance(stmt.src, Call):
|
|
1944
|
+
# replace this assignment statement with a call statement
|
|
1945
|
+
stmt = stmt.src
|
|
1946
|
+
elif isinstance(stmt.src, Convert) and isinstance(stmt.src.operand, Call):
|
|
1947
|
+
# the convert is useless now
|
|
1948
|
+
stmt = stmt.src.operand
|
|
1949
|
+
else:
|
|
1950
|
+
# we can't change this stmt at all because it has an expression with Calls inside
|
|
1951
|
+
pass
|
|
1952
|
+
else:
|
|
1953
|
+
# no calls. remove it
|
|
1954
|
+
simplified = True
|
|
1955
|
+
continue
|
|
1956
|
+
elif isinstance(stmt, Call):
|
|
1957
|
+
codeloc = AILCodeLocation(block.addr, block.idx, idx, stmt.tags.get("ins_addr"))
|
|
1958
|
+
if codeloc in self._calls_to_remove:
|
|
1959
|
+
# this call can be removed
|
|
1960
|
+
simplified = True
|
|
1961
|
+
continue
|
|
1962
|
+
|
|
1963
|
+
if stmt.ret_expr is not None or stmt.fp_ret_expr is not None:
|
|
1964
|
+
# both the return expr and the fp_ret_expr are not used
|
|
1965
|
+
stmt = stmt.copy()
|
|
1966
|
+
stmt.ret_expr = None
|
|
1967
|
+
stmt.fp_ret_expr = None
|
|
1968
|
+
simplified = True
|
|
1969
|
+
else:
|
|
1970
|
+
# Should not happen!
|
|
1971
|
+
raise NotImplementedError
|
|
1972
|
+
|
|
1973
|
+
new_statements.append(stmt)
|
|
1974
|
+
|
|
1975
|
+
new_block = block.copy()
|
|
1976
|
+
new_block.statements = new_statements
|
|
1977
|
+
self.blocks[old_block] = new_block
|
|
1978
|
+
|
|
1979
|
+
# we can only use calls_to_remove and assignments_to_remove once; if any statements in blocks are removed, then
|
|
1980
|
+
# the statement IDs in calls_to_remove and assignments_to_remove no longer match!
|
|
1981
|
+
self._calls_to_remove.clear()
|
|
1982
|
+
self._assignments_to_remove.clear()
|
|
1983
|
+
|
|
1984
|
+
return simplified
|
|
1985
|
+
|
|
1986
|
+
@staticmethod
|
|
1987
|
+
def _get_vvar_used_by(
|
|
1988
|
+
vvar_id: int, rd: SRDAModel, blocks_dict: dict[tuple[int, int | None], Block]
|
|
1989
|
+
) -> set[int | None]:
|
|
1990
|
+
"""
|
|
1991
|
+
Get all atoms that use a specified virtual variable. The atoms are in the form of virtual variable ID or None
|
|
1992
|
+
(indicating the virtual variable is used by another statement like Store).
|
|
1993
|
+
|
|
1994
|
+
:param vvar_id: ID of the virtual variable.
|
|
1995
|
+
:param rd: The SRDA model.
|
|
1996
|
+
:return: The set of vvar use atoms.
|
|
1997
|
+
"""
|
|
1998
|
+
|
|
1999
|
+
used_by: set[int | None] = set()
|
|
2000
|
+
for used_vvar, loc in rd.all_vvar_uses[vvar_id]:
|
|
2001
|
+
if used_vvar is None:
|
|
2002
|
+
# no explicit reference
|
|
2003
|
+
used_by.add(None)
|
|
2004
|
+
elif loc.block_addr is not None:
|
|
2005
|
+
assert loc.stmt_idx is not None
|
|
2006
|
+
stmt = blocks_dict[(loc.block_addr, loc.block_idx)].statements[loc.stmt_idx]
|
|
2007
|
+
if isinstance(stmt, Assignment) and isinstance(stmt.dst, VirtualVariable):
|
|
2008
|
+
used_by.add(stmt.dst.varid)
|
|
2009
|
+
else:
|
|
2010
|
+
used_by.add(None)
|
|
2011
|
+
return used_by
|
|
2012
|
+
|
|
2013
|
+
def _find_cyclic_dependent_phis_and_dirty_vvars(self, rd: SRDAModel, dead_vvar_ids: set[int]) -> set[int]:
|
|
2014
|
+
blocks_dict: dict[tuple[int, int | None], Block] = {(bb.addr, bb.idx): bb for bb in self.func_graph}
|
|
2015
|
+
|
|
2016
|
+
# find dirty vvars and vexccall vvars
|
|
2017
|
+
dirty_vvar_ids = set()
|
|
2018
|
+
for bb in self.func_graph:
|
|
2019
|
+
for stmt in bb.statements:
|
|
2020
|
+
if (
|
|
2021
|
+
isinstance(stmt, Assignment)
|
|
2022
|
+
and isinstance(stmt.dst, VirtualVariable)
|
|
2023
|
+
and stmt.dst.was_reg
|
|
2024
|
+
and isinstance(stmt.src, (DirtyExpression, VEXCCallExpression))
|
|
2025
|
+
):
|
|
2026
|
+
dirty_vvar_ids.add(stmt.dst.varid)
|
|
2027
|
+
|
|
2028
|
+
phi_and_dirty_vvar_ids = (rd.phi_vvar_ids | dirty_vvar_ids).difference(dead_vvar_ids)
|
|
2029
|
+
|
|
2030
|
+
vvar_used_by: dict[int, set[int | None]] = defaultdict(set)
|
|
2031
|
+
for var_id in phi_and_dirty_vvar_ids:
|
|
2032
|
+
if var_id in rd.phivarid_to_varids:
|
|
2033
|
+
for used_by_varid in rd.phivarid_to_varids[var_id]:
|
|
2034
|
+
if used_by_varid in dead_vvar_ids:
|
|
2035
|
+
# this variable no longer exists
|
|
2036
|
+
continue
|
|
2037
|
+
if used_by_varid not in vvar_used_by:
|
|
2038
|
+
vvar_used_by[used_by_varid] |= self._get_vvar_used_by(
|
|
2039
|
+
used_by_varid, rd, blocks_dict
|
|
2040
|
+
).difference(dead_vvar_ids)
|
|
2041
|
+
vvar_used_by[used_by_varid].add(var_id) # probably unnecessary
|
|
2042
|
+
vvar_used_by[var_id] |= self._get_vvar_used_by(var_id, rd, blocks_dict).difference(dead_vvar_ids)
|
|
2043
|
+
|
|
2044
|
+
g = networkx.DiGraph()
|
|
2045
|
+
dummy_vvar_id = -1
|
|
2046
|
+
for var_id, used_by_initial in vvar_used_by.items():
|
|
2047
|
+
for u in used_by_initial:
|
|
2048
|
+
if u is None:
|
|
2049
|
+
# we can't have None in networkx.DiGraph
|
|
2050
|
+
g.add_edge(var_id, dummy_vvar_id)
|
|
2051
|
+
else:
|
|
2052
|
+
g.add_edge(var_id, u)
|
|
2053
|
+
|
|
2054
|
+
cyclic_dependent_phi_varids = set()
|
|
2055
|
+
for scc in networkx.strongly_connected_components(g):
|
|
2056
|
+
if len(scc) == 1:
|
|
2057
|
+
continue
|
|
2058
|
+
|
|
2059
|
+
bail = False
|
|
2060
|
+
for varid in scc:
|
|
2061
|
+
# ensure this vvar is not used by anything else outside the scc (regardless of whether this vvar is a
|
|
2062
|
+
# phi variable or not)
|
|
2063
|
+
if varid in vvar_used_by and None in vvar_used_by[varid]:
|
|
2064
|
+
bail = True
|
|
2065
|
+
break
|
|
2066
|
+
if bail is False:
|
|
2067
|
+
succs = list(g.successors(varid))
|
|
2068
|
+
if any(succ_varid not in scc for succ_varid in succs):
|
|
2069
|
+
bail = True
|
|
2070
|
+
break
|
|
2071
|
+
if bail:
|
|
2072
|
+
continue
|
|
2073
|
+
|
|
2074
|
+
if all(
|
|
2075
|
+
varid in phi_and_dirty_vvar_ids or rd.varid_to_vvar[varid].was_reg or varid in self._secondary_stackvars
|
|
2076
|
+
for varid in scc
|
|
2077
|
+
):
|
|
2078
|
+
cyclic_dependent_phi_varids |= set(scc)
|
|
2079
|
+
|
|
2080
|
+
return cyclic_dependent_phi_varids
|
|
2081
|
+
|
|
2082
|
+
#
|
|
2083
|
+
# Rewriting ccalls
|
|
2084
|
+
#
|
|
2085
|
+
|
|
2086
|
+
def _rewrite_ccalls(self):
|
|
2087
|
+
rewriter_cls = CCALL_REWRITERS.get(self.project.arch.name, None)
|
|
2088
|
+
if rewriter_cls is None:
|
|
2089
|
+
return False
|
|
2090
|
+
|
|
2091
|
+
walker = AILBlockRewriter()
|
|
2092
|
+
|
|
2093
|
+
class _any_update:
|
|
2094
|
+
"""
|
|
2095
|
+
Dummy class for storing if any result has been updated.
|
|
2096
|
+
"""
|
|
2097
|
+
|
|
2098
|
+
v = False
|
|
2099
|
+
|
|
2100
|
+
def _handle_VEXCCallExpression(
|
|
2101
|
+
expr_idx: int, expr: VEXCCallExpression, stmt_idx: int, stmt: Statement | None, block: Block | None
|
|
2102
|
+
) -> Expression:
|
|
2103
|
+
r_expr = AILBlockRewriter._handle_VEXCCallExpression(walker, expr_idx, expr, stmt_idx, stmt, block)
|
|
2104
|
+
rewriter = rewriter_cls(r_expr, self.project, rename_ccalls=self._should_rename_ccalls)
|
|
2105
|
+
if rewriter.result is not None:
|
|
2106
|
+
_any_update.v = True
|
|
2107
|
+
return rewriter.result
|
|
2108
|
+
return r_expr
|
|
2109
|
+
|
|
2110
|
+
blocks_by_addr_and_idx = {(node.addr, node.idx): node for node in self.func_graph.nodes()}
|
|
2111
|
+
walker.expr_handlers[VEXCCallExpression] = _handle_VEXCCallExpression
|
|
2112
|
+
|
|
2113
|
+
updated = False
|
|
2114
|
+
for block in blocks_by_addr_and_idx.values():
|
|
2115
|
+
_any_update.v = False
|
|
2116
|
+
old_block = block.copy()
|
|
2117
|
+
walker.walk(block)
|
|
2118
|
+
if _any_update.v:
|
|
2119
|
+
self.blocks[old_block] = block
|
|
2120
|
+
updated = True
|
|
2121
|
+
|
|
2122
|
+
return updated
|
|
2123
|
+
|
|
2124
|
+
#
|
|
2125
|
+
# Rewriting dirty calls
|
|
2126
|
+
#
|
|
2127
|
+
|
|
2128
|
+
def _rewrite_dirty_calls(self):
|
|
2129
|
+
rewriter_cls = DIRTY_REWRITERS.get(self.project.arch.name, None)
|
|
2130
|
+
if rewriter_cls is None:
|
|
2131
|
+
return False
|
|
2132
|
+
|
|
2133
|
+
walker = AILBlockRewriter()
|
|
2134
|
+
|
|
2135
|
+
class _any_update:
|
|
2136
|
+
"""
|
|
2137
|
+
Dummy class for storing if any result has been updated.
|
|
2138
|
+
"""
|
|
2139
|
+
|
|
2140
|
+
v = False
|
|
2141
|
+
|
|
2142
|
+
def _handle_DirtyStatement( # pylint:disable=unused-argument
|
|
2143
|
+
stmt_idx: int, stmt: DirtyStatement, block: Block | None
|
|
2144
|
+
) -> Statement:
|
|
2145
|
+
# we do not want to trigger _handle_DirtyExpression, which is why we do not call the superclass method
|
|
2146
|
+
rewriter = rewriter_cls(stmt, self.project.arch)
|
|
2147
|
+
if rewriter.result is not None:
|
|
2148
|
+
_any_update.v = True
|
|
2149
|
+
if walker._update_block and block is not None:
|
|
2150
|
+
block.statements[stmt_idx] = rewriter.result # type:ignore
|
|
2151
|
+
assert isinstance(rewriter.result, Statement)
|
|
2152
|
+
return rewriter.result
|
|
2153
|
+
return stmt
|
|
2154
|
+
|
|
2155
|
+
def _handle_DirtyExpression(
|
|
2156
|
+
expr_idx: int, expr: DirtyExpression, stmt_idx: int, stmt: Statement | None, block: Block | None
|
|
2157
|
+
):
|
|
2158
|
+
r_expr = AILBlockRewriter._handle_DirtyExpression(walker, expr_idx, expr, stmt_idx, stmt, block)
|
|
2159
|
+
assert isinstance(r_expr, DirtyExpression)
|
|
2160
|
+
rewriter = rewriter_cls(r_expr, self.project.arch)
|
|
2161
|
+
if rewriter.result is not None:
|
|
2162
|
+
_any_update.v = True
|
|
2163
|
+
assert isinstance(rewriter.result, Expression)
|
|
2164
|
+
return rewriter.result
|
|
2165
|
+
return r_expr
|
|
2166
|
+
|
|
2167
|
+
blocks_by_addr_and_idx = {(node.addr, node.idx): node for node in self.func_graph.nodes()}
|
|
2168
|
+
walker.expr_handlers[DirtyExpression] = _handle_DirtyExpression
|
|
2169
|
+
walker.stmt_handlers[DirtyStatement] = _handle_DirtyStatement
|
|
2170
|
+
|
|
2171
|
+
updated = False
|
|
2172
|
+
for block in blocks_by_addr_and_idx.values():
|
|
2173
|
+
_any_update.v = False
|
|
2174
|
+
old_block = block.copy()
|
|
2175
|
+
walker.walk(block)
|
|
2176
|
+
if _any_update.v:
|
|
2177
|
+
self.blocks[old_block] = block
|
|
2178
|
+
updated = True
|
|
2179
|
+
|
|
2180
|
+
return updated
|
|
2181
|
+
|
|
2182
|
+
#
|
|
2183
|
+
# Util functions
|
|
2184
|
+
#
|
|
2185
|
+
|
|
2186
|
+
@staticmethod
|
|
2187
|
+
def _statement_has_call_exprs(stmt: Statement) -> bool:
|
|
2188
|
+
def _handle_callexpr(expr_idx, expr, stmt_idx, stmt, block): # pylint:disable=unused-argument
|
|
2189
|
+
raise HasCallNotification
|
|
2190
|
+
|
|
2191
|
+
walker = AILBlockViewer()
|
|
2192
|
+
walker.expr_handlers[Call] = _handle_callexpr
|
|
2193
|
+
try:
|
|
2194
|
+
walker.walk_statement(stmt)
|
|
2195
|
+
except HasCallNotification:
|
|
2196
|
+
return True
|
|
2197
|
+
|
|
2198
|
+
return False
|
|
2199
|
+
|
|
2200
|
+
@staticmethod
|
|
2201
|
+
def _expression_has_call_exprs(expr: Expression) -> bool:
|
|
2202
|
+
def _handle_callexpr(expr_idx, expr, stmt_idx, stmt, block): # pylint:disable=unused-argument
|
|
2203
|
+
raise HasCallNotification
|
|
2204
|
+
|
|
2205
|
+
walker = AILBlockViewer()
|
|
2206
|
+
walker.expr_handlers[Call] = _handle_callexpr
|
|
2207
|
+
try:
|
|
2208
|
+
walker.walk_expression(expr)
|
|
2209
|
+
except HasCallNotification:
|
|
2210
|
+
return True
|
|
2211
|
+
|
|
2212
|
+
return False
|
|
2213
|
+
|
|
2214
|
+
@staticmethod
|
|
2215
|
+
def _exprs_contain_vvar(exprs: Iterable[Expression], vvar_ids: set[int]) -> bool:
|
|
2216
|
+
def _handle_VirtualVariable(expr_idx, expr, stmt_idx, stmt, block): # pylint:disable=unused-argument
|
|
2217
|
+
if expr.varid in vvar_ids:
|
|
2218
|
+
raise HasVVarNotification
|
|
2219
|
+
|
|
2220
|
+
walker = AILBlockViewer()
|
|
2221
|
+
walker.expr_handlers[VirtualVariable] = _handle_VirtualVariable
|
|
2222
|
+
|
|
2223
|
+
for expr in exprs:
|
|
2224
|
+
try:
|
|
2225
|
+
walker.walk_expression(expr)
|
|
2226
|
+
except HasVVarNotification:
|
|
2227
|
+
return True
|
|
2228
|
+
return False
|
|
2229
|
+
|
|
2230
|
+
@staticmethod
|
|
2231
|
+
def _statement_uses_ref_vvar(stmt: Statement, vvar_id: int) -> bool:
|
|
2232
|
+
def _handle_UnaryOp(expr_idx, expr, stmt_idx, stmt, block): # pylint:disable=unused-argument
|
|
2233
|
+
if expr.op == "Reference" and isinstance(expr.operand, VirtualVariable) and expr.operand.varid == vvar_id:
|
|
2234
|
+
raise HasRefVVarNotification
|
|
2235
|
+
|
|
2236
|
+
walker = AILBlockViewer()
|
|
2237
|
+
walker.expr_handlers[UnaryOp] = _handle_UnaryOp
|
|
2238
|
+
try:
|
|
2239
|
+
walker.walk_statement(stmt)
|
|
2240
|
+
except HasRefVVarNotification:
|
|
2241
|
+
return True
|
|
2242
|
+
|
|
2243
|
+
return False
|
|
2244
|
+
|
|
2245
|
+
|
|
2246
|
+
AnalysesHub.register_default("AILSimplifier", AILSimplifier)
|