angr 9.2.61__py3-none-macosx_10_9_x86_64.whl → 9.2.63__py3-none-macosx_10_9_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.

Potentially problematic release.


This version of angr might be problematic. Click here for more details.

Files changed (37) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/cfg/cfg_fast.py +18 -20
  3. angr/analyses/decompiler/ail_simplifier.py +15 -30
  4. angr/analyses/decompiler/block_simplifier.py +11 -7
  5. angr/analyses/decompiler/clinic.py +144 -0
  6. angr/analyses/decompiler/condition_processor.py +4 -2
  7. angr/analyses/decompiler/peephole_optimizations/eager_eval.py +2 -0
  8. angr/analyses/decompiler/structured_codegen/c.py +20 -16
  9. angr/analyses/decompiler/structuring/phoenix.py +6 -10
  10. angr/analyses/disassembly.py +7 -11
  11. angr/analyses/propagator/engine_ail.py +14 -42
  12. angr/analyses/propagator/outdated_definition_walker.py +17 -53
  13. angr/analyses/propagator/propagator.py +1 -0
  14. angr/analyses/reaching_definitions/engine_ail.py +20 -9
  15. angr/analyses/reaching_definitions/engine_vex.py +20 -5
  16. angr/analyses/reaching_definitions/function_handler.py +9 -3
  17. angr/analyses/reaching_definitions/rd_state.py +34 -13
  18. angr/analyses/reaching_definitions/reaching_definitions.py +92 -16
  19. angr/analyses/variable_recovery/engine_vex.py +20 -0
  20. angr/analyses/variable_recovery/variable_recovery_fast.py +5 -0
  21. angr/calling_conventions.py +28 -0
  22. angr/knowledge_plugins/key_definitions/live_definitions.py +15 -5
  23. angr/knowledge_plugins/key_definitions/liveness.py +94 -0
  24. angr/knowledge_plugins/key_definitions/rd_model.py +90 -9
  25. angr/knowledge_plugins/propagations/states.py +3 -0
  26. angr/knowledge_plugins/variables/variable_manager.py +26 -4
  27. angr/lib/angr_native.dylib +0 -0
  28. angr/project.py +2 -2
  29. angr/sim_type.py +2 -2
  30. angr/state_plugins/unicorn_engine.py +9 -1
  31. angr/storage/memory_mixins/multi_value_merger_mixin.py +7 -2
  32. angr/utils/timing.py +12 -5
  33. {angr-9.2.61.dist-info → angr-9.2.63.dist-info}/METADATA +15 -15
  34. {angr-9.2.61.dist-info → angr-9.2.63.dist-info}/RECORD +37 -36
  35. {angr-9.2.61.dist-info → angr-9.2.63.dist-info}/WHEEL +1 -1
  36. {angr-9.2.61.dist-info → angr-9.2.63.dist-info}/LICENSE +0 -0
  37. {angr-9.2.61.dist-info → angr-9.2.63.dist-info}/top_level.txt +0 -0
angr/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
1
  # pylint: disable=wildcard-import
2
2
  # pylint: disable=wrong-import-position
3
3
 
4
- __version__ = "9.2.61"
4
+ __version__ = "9.2.63"
5
5
 
6
6
  if bytes is str:
7
7
  raise Exception(
@@ -2714,30 +2714,28 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
2714
2714
  for segment in self.project.loader.main_object.segments:
2715
2715
  if segment.vaddr + segment.memsize == data_addr:
2716
2716
  # yeah!
2717
- new_data = self.model.add_memory_data(data_addr, MemoryDataSort.SegmentBoundary, data_size=0)
2718
- if new_data or self._cross_references:
2719
- cr = XRef(
2720
- ins_addr=insn_addr,
2721
- block_addr=irsb_addr,
2722
- stmt_idx=stmt_idx,
2723
- memory_data=self.model.memory_data[data_addr],
2724
- xref_type=XRefType.Offset,
2725
- )
2726
- self.kb.xrefs.add_xref(cr)
2717
+ self.model.add_memory_data(data_addr, MemoryDataSort.SegmentBoundary, data_size=0)
2718
+ cr = XRef(
2719
+ ins_addr=insn_addr,
2720
+ block_addr=irsb_addr,
2721
+ stmt_idx=stmt_idx,
2722
+ memory_data=self.model.memory_data[data_addr],
2723
+ xref_type=XRefType.Offset,
2724
+ )
2725
+ self.kb.xrefs.add_xref(cr)
2727
2726
  break
2728
2727
 
2729
2728
  return
2730
2729
 
2731
- new_data = self.model.add_memory_data(data_addr, data_type, data_size=data_size)
2732
- if new_data or self._cross_references:
2733
- cr = XRef(
2734
- ins_addr=insn_addr,
2735
- block_addr=irsb_addr,
2736
- stmt_idx=stmt_idx,
2737
- memory_data=self.model.memory_data[data_addr],
2738
- xref_type=XRefType.Offset,
2739
- )
2740
- self.kb.xrefs.add_xref(cr)
2730
+ self.model.add_memory_data(data_addr, data_type, data_size=data_size)
2731
+ cr = XRef(
2732
+ ins_addr=insn_addr,
2733
+ block_addr=irsb_addr,
2734
+ stmt_idx=stmt_idx,
2735
+ memory_data=self.model.memory_data[data_addr],
2736
+ xref_type=XRefType.Offset,
2737
+ )
2738
+ self.kb.xrefs.add_xref(cr)
2741
2739
 
2742
2740
  if is_arm_arch(self.project.arch):
2743
2741
  if (irsb_addr & 1) == 1 and data_addr == (insn_addr & 0xFFFF_FFFF_FFFF_FFFE) + 4:
@@ -18,7 +18,6 @@ from ailment.expression import (
18
18
  BinaryOp,
19
19
  )
20
20
 
21
- from ...errors import SimMemoryMissingError
22
21
  from ...engines.light import SpOffset
23
22
  from ...code_location import CodeLocation
24
23
  from ...analyses.reaching_definitions.external_codeloc import ExternalCodeLocation
@@ -35,7 +34,7 @@ from .ccall_rewriters import CCALL_REWRITERS
35
34
 
36
35
  if TYPE_CHECKING:
37
36
  from ailment.manager import Manager
38
- from angr.analyses.reaching_definitions import ReachingDefinitionsAnalysis
37
+ from angr.analyses.reaching_definitions import ReachingDefinitionsModel
39
38
 
40
39
 
41
40
  _l = logging.getLogger(__name__)
@@ -103,7 +102,7 @@ class AILSimplifier(Analysis):
103
102
  ):
104
103
  self.func = func
105
104
  self.func_graph = func_graph if func_graph is not None else func.graph
106
- self._reaching_definitions: Optional[ReachingDefinitionsAnalysis] = None
105
+ self._reaching_definitions: Optional["ReachingDefinitionsModel"] = None
107
106
  self._propagator = None
108
107
 
109
108
  self._remove_dead_memdefs = remove_dead_memdefs
@@ -191,7 +190,7 @@ class AILSimplifier(Analysis):
191
190
  AILGraphWalker(self.func_graph, _handler, replace_nodes=True).walk()
192
191
  self.blocks = {}
193
192
 
194
- def _compute_reaching_definitions(self) -> "ReachingDefinitionsAnalysis":
193
+ def _compute_reaching_definitions(self) -> "ReachingDefinitionsModel":
195
194
  # Computing reaching definitions or return the cached one
196
195
  if self._reaching_definitions is not None:
197
196
  return self._reaching_definitions
@@ -199,17 +198,12 @@ class AILSimplifier(Analysis):
199
198
  subject=self.func,
200
199
  func_graph=self.func_graph,
201
200
  # init_context=(), <-- in case of fire break glass
202
- observe_all=True, # observe_callback=self._simplify_function_rd_observe_callback
201
+ observe_all=False,
203
202
  use_callee_saved_regs_at_return=self._use_callee_saved_regs_at_return,
204
- )
203
+ ).model
205
204
  self._reaching_definitions = rd
206
205
  return rd
207
206
 
208
- @staticmethod
209
- # pylint:disable=unused-argument
210
- def _simplify_function_rd_observe_callback(ob_type, **kwargs):
211
- return ob_type == "node" or (ob_type == "insn" and kwargs.get("op_type", None) == OP_BEFORE)
212
-
213
207
  def _compute_propagation(self):
214
208
  # Propagate expressions or return the existing result
215
209
  if self._propagator is not None:
@@ -772,7 +766,7 @@ class AILSimplifier(Analysis):
772
766
  # ensure the expression that we want to replace with is still up-to-date
773
767
  replace_with_original_def = self._find_atom_def_at(replace_with, rd, def_.codeloc)
774
768
  if replace_with_original_def is not None and not self._check_atom_last_def(
775
- replace_with, used_expr.size, u.ins_addr, rd, replace_with_original_def
769
+ replace_with, u, rd, replace_with_original_def
776
770
  ):
777
771
  all_uses_replaced = False
778
772
  continue
@@ -813,26 +807,18 @@ class AILSimplifier(Analysis):
813
807
  @staticmethod
814
808
  def _find_atom_def_at(atom, rd, codeloc: CodeLocation) -> Optional[Definition]:
815
809
  if isinstance(atom, Register):
816
- observ = rd.observed_results[("insn", codeloc.ins_addr, OP_BEFORE)]
817
- try:
818
- reg_vals = observ.register_definitions.load(atom.reg_offset, size=atom.size)
819
- defs = list(observ.extract_defs_from_mv(reg_vals))
820
- return defs[0] if len(defs) == 1 else None
821
- except SimMemoryMissingError:
822
- pass
810
+ defs = rd.get_defs(atom, codeloc, OP_BEFORE)
811
+ return next(iter(defs)) if len(defs) == 1 else None
812
+
823
813
  return None
824
814
 
825
815
  @staticmethod
826
- def _check_atom_last_def(atom, size, ins_addr, rd, the_def) -> bool:
816
+ def _check_atom_last_def(atom, codeloc, rd, the_def) -> bool:
827
817
  if isinstance(atom, Register):
828
- observ = rd.observed_results[("insn", ins_addr, OP_BEFORE)]
829
- try:
830
- reg_vals = observ.register_definitions.load(atom.reg_offset, size=size)
831
- for existing_def in observ.extract_defs_from_mv(reg_vals):
832
- if existing_def.codeloc != the_def.codeloc:
833
- return False
834
- except SimMemoryMissingError:
835
- pass
818
+ defs = rd.get_defs(atom, codeloc, OP_BEFORE)
819
+ for d in defs:
820
+ if d.codeloc != the_def.codeloc:
821
+ return False
836
822
 
837
823
  return True
838
824
 
@@ -961,10 +947,9 @@ class AILSimplifier(Analysis):
961
947
  defsite_defs_per_atom = defaultdict(set)
962
948
  for dd in defsite_all_expr_uses:
963
949
  defsite_defs_per_atom[dd.atom].add(dd)
964
- usesite_rdstate = rd.observed_results[("stmt", (u.block_addr, u.block_idx, u.stmt_idx), 0)]
965
950
  usesite_expr_def_outdated = False
966
951
  for defsite_expr_atom, defsite_expr_uses in defsite_defs_per_atom.items():
967
- usesite_expr_uses = set(usesite_rdstate.get_definitions(defsite_expr_atom))
952
+ usesite_expr_uses = set(rd.get_defs(defsite_expr_atom, u, OP_BEFORE))
968
953
  if not usesite_expr_uses:
969
954
  # the atom is not defined at the use site - it's fine
970
955
  continue
@@ -123,15 +123,19 @@ class BlockSimplifier(Analysis):
123
123
 
124
124
  def _compute_reaching_definitions(self, block):
125
125
  def observe_callback(ob_type, addr=None, op_type=None, **kwargs) -> bool: # pylint:disable=unused-argument
126
- return ob_type == "stmt" or ob_type == "node" and addr == block.addr and op_type == OP_AFTER
126
+ return ob_type == "node" and addr == block.addr and op_type == OP_AFTER
127
127
 
128
128
  if self._reaching_definitions is None:
129
- self._reaching_definitions = self.project.analyses[ReachingDefinitionsAnalysis].prep()(
130
- subject=block,
131
- track_tmps=True,
132
- stack_pointer_tracker=self._stack_pointer_tracker,
133
- observe_all=False,
134
- observe_callback=observe_callback,
129
+ self._reaching_definitions = (
130
+ self.project.analyses[ReachingDefinitionsAnalysis]
131
+ .prep()(
132
+ subject=block,
133
+ track_tmps=True,
134
+ stack_pointer_tracker=self._stack_pointer_tracker,
135
+ observe_all=False,
136
+ observe_callback=observe_callback,
137
+ )
138
+ .model
135
139
  )
136
140
  return self._reaching_definitions
137
141
 
@@ -176,6 +176,7 @@ class Clinic(Analysis):
176
176
  self._convert_all()
177
177
 
178
178
  ail_graph = self._make_ailgraph()
179
+ self._rewrite_ite_expressions(ail_graph)
179
180
  self._remove_redundant_jump_blocks(ail_graph)
180
181
  if self._insert_labels:
181
182
  self._insert_block_labels(ail_graph)
@@ -1000,6 +1001,7 @@ class Clinic(Analysis):
1000
1001
  kb=tmp_kb,
1001
1002
  track_sp=False,
1002
1003
  func_args=arg_list,
1004
+ unify_variables=False,
1003
1005
  )
1004
1006
  # get ground-truth types
1005
1007
  var_manager = tmp_kb.variables[self.function.addr]
@@ -1284,6 +1286,148 @@ class Clinic(Analysis):
1284
1286
 
1285
1287
  return graph
1286
1288
 
1289
+ def _rewrite_ite_expressions(self, ail_graph):
1290
+ for block in list(ail_graph):
1291
+ ite_ins_addrs = []
1292
+ for stmt in block.statements:
1293
+ if isinstance(stmt, ailment.Stmt.Assignment) and isinstance(stmt.src, ailment.Expr.ITE):
1294
+ if stmt.ins_addr not in ite_ins_addrs:
1295
+ ite_ins_addrs.append(stmt.ins_addr)
1296
+
1297
+ if ite_ins_addrs:
1298
+ block_addr = block.addr
1299
+ for ite_ins_addr in ite_ins_addrs:
1300
+ block_addr = self._create_triangle_for_ite_expression(ail_graph, block_addr, ite_ins_addr)
1301
+ if block_addr is None or block_addr >= block.addr + block.original_size:
1302
+ break
1303
+
1304
+ def _create_triangle_for_ite_expression(self, ail_graph, block_addr: int, ite_ins_addr: int):
1305
+ # lift the ite instruction to get its size
1306
+ ite_insn_size = self.project.factory.block(ite_ins_addr, num_inst=1).size
1307
+ if ite_insn_size <= 1: # we need an address for true_block and another address for false_block
1308
+ return None
1309
+
1310
+ # relift the head and the ITE instruction
1311
+ new_head = self.project.factory.block(
1312
+ block_addr, size=ite_ins_addr - block_addr + ite_insn_size, cross_insn_opt=False
1313
+ )
1314
+ new_head_ail = ailment.IRSBConverter.convert(new_head.vex, self._ail_manager)
1315
+ # remove all statements between the ITE expression and the very end of the block
1316
+ ite_expr_stmt_idx = None
1317
+ ite_expr_stmt = None
1318
+ for idx, stmt in enumerate(new_head_ail.statements):
1319
+ if isinstance(stmt, ailment.Stmt.Assignment) and isinstance(stmt.src, ailment.Expr.ITE):
1320
+ ite_expr_stmt_idx = idx
1321
+ ite_expr_stmt = stmt
1322
+ break
1323
+ if ite_expr_stmt_idx is None:
1324
+ return None
1325
+
1326
+ ite_expr: ailment.Expr.ITE = ite_expr_stmt.src
1327
+ new_head_ail.statements = new_head_ail.statements[:ite_expr_stmt_idx]
1328
+ # build the conditional jump
1329
+ true_block_addr = ite_ins_addr
1330
+ false_block_addr = ite_ins_addr + 1
1331
+ cond_jump_stmt = ailment.Stmt.ConditionalJump(
1332
+ ite_expr_stmt.idx,
1333
+ ite_expr.cond,
1334
+ ailment.Expr.Const(None, None, true_block_addr, self.project.arch.bits),
1335
+ ailment.Expr.Const(None, None, false_block_addr, self.project.arch.bits),
1336
+ **ite_expr_stmt.tags,
1337
+ )
1338
+ new_head_ail.statements.append(cond_jump_stmt)
1339
+
1340
+ # build the true block
1341
+ true_block = self.project.factory.block(ite_ins_addr, num_inst=1)
1342
+ true_block_ail = ailment.IRSBConverter.convert(true_block.vex, self._ail_manager)
1343
+ true_block_ail.addr = true_block_addr
1344
+
1345
+ ite_expr_stmt_idx = None
1346
+ ite_expr_stmt = None
1347
+ for idx, stmt in enumerate(true_block_ail.statements):
1348
+ if isinstance(stmt, ailment.Stmt.Assignment) and isinstance(stmt.src, ailment.Expr.ITE):
1349
+ ite_expr_stmt_idx = idx
1350
+ ite_expr_stmt = stmt
1351
+ break
1352
+ if ite_expr_stmt_idx is None:
1353
+ return None
1354
+
1355
+ true_block_ail.statements[ite_expr_stmt_idx] = ailment.Stmt.Assignment(
1356
+ ite_expr_stmt.idx, ite_expr_stmt.dst, ite_expr_stmt.src.iftrue, **ite_expr_stmt.tags
1357
+ )
1358
+
1359
+ # build the false block
1360
+ false_block = self.project.factory.block(ite_ins_addr, num_inst=1)
1361
+ false_block_ail = ailment.IRSBConverter.convert(false_block.vex, self._ail_manager)
1362
+ false_block_ail.addr = false_block_addr
1363
+
1364
+ ite_expr_stmt_idx = None
1365
+ ite_expr_stmt = None
1366
+ for idx, stmt in enumerate(false_block_ail.statements):
1367
+ if isinstance(stmt, ailment.Stmt.Assignment) and isinstance(stmt.src, ailment.Expr.ITE):
1368
+ ite_expr_stmt_idx = idx
1369
+ ite_expr_stmt = stmt
1370
+ break
1371
+ if ite_expr_stmt_idx is None:
1372
+ return None
1373
+
1374
+ false_block_ail.statements[ite_expr_stmt_idx] = ailment.Stmt.Assignment(
1375
+ ite_expr_stmt.idx, ite_expr_stmt.dst, ite_expr_stmt.src.iffalse, **ite_expr_stmt.tags
1376
+ )
1377
+
1378
+ original_block = next(iter(b for b in ail_graph if b.addr == block_addr))
1379
+
1380
+ original_block_in_edges = list(ail_graph.in_edges(original_block))
1381
+ original_block_out_edges = list(ail_graph.out_edges(original_block))
1382
+
1383
+ # build the target block if the target block does not exist in the current function
1384
+ end_block_addr = ite_ins_addr + ite_insn_size
1385
+ if block_addr < end_block_addr < block_addr + original_block.original_size:
1386
+ end_block = self.project.factory.block(
1387
+ ite_ins_addr + ite_insn_size,
1388
+ size=block_addr + original_block.original_size - (ite_ins_addr + ite_insn_size),
1389
+ cross_insn_opt=False,
1390
+ )
1391
+ end_block_ail = ailment.IRSBConverter.convert(end_block.vex, self._ail_manager)
1392
+ else:
1393
+ end_block_ail = next(iter(b for b in ail_graph if b.addr == end_block_addr))
1394
+
1395
+ # last check: if the first instruction of the end block has Sar, then we bail (due to the peephole optimization
1396
+ # SarToSignedDiv)
1397
+ for stmt in end_block_ail.statements:
1398
+ if stmt.ins_addr > end_block_ail.addr:
1399
+ break
1400
+ if (
1401
+ isinstance(stmt, ailment.Stmt.Assignment)
1402
+ and isinstance(stmt.src, ailment.Expr.BinaryOp)
1403
+ and stmt.src.op == "Sar"
1404
+ ):
1405
+ return None
1406
+
1407
+ ail_graph.remove_node(original_block)
1408
+
1409
+ if end_block_ail not in ail_graph:
1410
+ # newly created. add it and the necessary edges into the graph
1411
+ for _, dst in original_block_out_edges:
1412
+ if dst is original_block:
1413
+ ail_graph.add_edge(end_block_ail, new_head_ail)
1414
+ else:
1415
+ ail_graph.add_edge(end_block_ail, dst)
1416
+
1417
+ # in edges
1418
+ for src, _ in original_block_in_edges:
1419
+ if src is original_block:
1420
+ raise ValueError("Unexpected...")
1421
+ ail_graph.add_edge(src, new_head_ail)
1422
+
1423
+ # triangle
1424
+ ail_graph.add_edge(new_head_ail, true_block_ail)
1425
+ ail_graph.add_edge(new_head_ail, false_block_ail)
1426
+ ail_graph.add_edge(true_block_ail, end_block_ail)
1427
+ ail_graph.add_edge(false_block_ail, end_block_ail)
1428
+
1429
+ return end_block_ail.addr
1430
+
1287
1431
  @staticmethod
1288
1432
  def _remove_redundant_jump_blocks(ail_graph):
1289
1433
  def first_conditional_jump(block: ailment.Block) -> Optional[ailment.Stmt.ConditionalJump]:
@@ -93,7 +93,8 @@ _ail2claripy_op_mapping = {
93
93
  "Div": lambda expr, conv, _: conv(expr.operands[0], nobool=True) / conv(expr.operands[1], nobool=True),
94
94
  "Mod": lambda expr, conv, _: conv(expr.operands[0], nobool=True) % conv(expr.operands[1], nobool=True),
95
95
  "Not": lambda expr, conv, _: claripy.Not(conv(expr.operand)),
96
- "Neg": lambda expr, conv, _: ~conv(expr.operand),
96
+ "Neg": lambda expr, conv, _: -conv(expr.operand),
97
+ "BitwiseNeg": lambda expr, conv, _: ~conv(expr.operand),
97
98
  "Xor": lambda expr, conv, _: conv(expr.operands[0], nobool=True) ^ conv(expr.operands[1], nobool=True),
98
99
  "And": lambda expr, conv, _: conv(expr.operands[0], nobool=True) & conv(expr.operands[1], nobool=True),
99
100
  "Or": lambda expr, conv, _: conv(expr.operands[0], nobool=True) | conv(expr.operands[1], nobool=True),
@@ -642,7 +643,8 @@ class ConditionProcessor:
642
643
 
643
644
  _mapping = {
644
645
  "Not": lambda cond_, tags: _unary_op_reduce("Not", cond_.args[0], tags),
645
- "__invert__": lambda cond_, tags: _unary_op_reduce("Neg", cond_.args[0], tags),
646
+ "__neg__": lambda cond_, tags: _unary_op_reduce("Not", cond_.args[0], tags),
647
+ "__invert__": lambda cond_, tags: _unary_op_reduce("BitwiseNeg", cond_.args[0], tags),
646
648
  "And": lambda cond_, tags: _binary_op_reduce("LogicalAnd", cond_.args, tags),
647
649
  "Or": lambda cond_, tags: _binary_op_reduce("LogicalOr", cond_.args, tags),
648
650
  "__le__": lambda cond_, tags: _binary_op_reduce("CmpLE", cond_.args, tags, signed=True),
@@ -88,6 +88,8 @@ class EagerEvaluation(PeepholeOptimizationExprBase):
88
88
  expr.signed,
89
89
  **expr.tags,
90
90
  )
91
+ if isinstance(expr.operands[0], Const) and expr.operands[0].value == 0:
92
+ return UnaryOp(expr.idx, "Neg", expr.operands[1], **expr.tags)
91
93
 
92
94
  elif expr.op == "And":
93
95
  if isinstance(expr.operands[0], Const) and isinstance(expr.operands[1], Const):
@@ -829,12 +829,13 @@ class CForLoop(CStatement):
829
829
  yield from self.iterator.c_repr_chunks(indent=0, asexpr=True)
830
830
  yield ")", paren
831
831
 
832
- if self.codegen.braces_on_own_lines:
833
- yield "\n", None
834
- yield indent_str, None
835
- else:
836
- yield " ", None
837
832
  if self.body is not None:
833
+ if self.codegen.braces_on_own_lines:
834
+ yield "\n", None
835
+ yield indent_str, None
836
+ else:
837
+ yield " ", None
838
+
838
839
  yield "{", brace
839
840
  yield "\n", None
840
841
  yield from self.body.c_repr_chunks(indent=indent + INDENT_DELTA)
@@ -937,17 +938,12 @@ class CIfElse(CStatement):
937
938
  yield from self.else_node.c_repr_chunks(indent=indent)
938
939
  else:
939
940
  if single_stmt_else:
940
- if self.codegen.braces_on_own_lines:
941
- yield indent_str, None
942
- else:
943
- yield " ", None
944
- yield indent_str, None
941
+ yield indent_str, None
942
+ elif self.codegen.braces_on_own_lines:
943
+ yield "\n", None
944
+ yield indent_str, None
945
945
  else:
946
- if self.codegen.braces_on_own_lines:
947
- yield "\n", None
948
- yield indent_str, None
949
- else:
950
- yield " ", None
946
+ yield " ", None
951
947
 
952
948
  yield "else", self
953
949
  if self.codegen.braces_on_own_lines or single_stmt_else:
@@ -1580,6 +1576,7 @@ class CUnaryOp(CExpression):
1580
1576
  OP_MAP = {
1581
1577
  "Not": self._c_repr_chunks_not,
1582
1578
  "Neg": self._c_repr_chunks_neg,
1579
+ "BitwiseNeg": self._c_repr_chunks_bitwiseneg,
1583
1580
  "Reference": self._c_repr_chunks_reference,
1584
1581
  "Dereference": self._c_repr_chunks_dereference,
1585
1582
  }
@@ -1601,13 +1598,20 @@ class CUnaryOp(CExpression):
1601
1598
  yield from CExpression._try_c_repr_chunks(self.operand)
1602
1599
  yield ")", paren
1603
1600
 
1604
- def _c_repr_chunks_neg(self):
1601
+ def _c_repr_chunks_bitwiseneg(self):
1605
1602
  paren = CClosingObject("(")
1606
1603
  yield "~", self
1607
1604
  yield "(", paren
1608
1605
  yield from CExpression._try_c_repr_chunks(self.operand)
1609
1606
  yield ")", paren
1610
1607
 
1608
+ def _c_repr_chunks_neg(self):
1609
+ paren = CClosingObject("(")
1610
+ yield "-", self
1611
+ yield "(", paren
1612
+ yield from CExpression._try_c_repr_chunks(self.operand)
1613
+ yield ")", paren
1614
+
1611
1615
  def _c_repr_chunks_reference(self):
1612
1616
  yield "&", self
1613
1617
  yield from CExpression._try_c_repr_chunks(self.operand)
@@ -13,7 +13,7 @@ from ailment.expression import Const, UnaryOp, MultiStatementExpression
13
13
  from angr.utils.graph import GraphUtils
14
14
  from ....knowledge_plugins.cfg import IndirectJumpType
15
15
  from ....utils.constants import SWITCH_MISSING_DEFAULT_NODE_ADDR
16
- from ....utils.graph import dominates, inverted_idoms, to_acyclic_graph
16
+ from ....utils.graph import dominates, to_acyclic_graph
17
17
  from ..sequence_walker import SequenceWalker
18
18
  from ..utils import (
19
19
  remove_last_statement,
@@ -1913,21 +1913,16 @@ class PhoenixStructurer(StructurerBase):
1913
1913
  other_edges = []
1914
1914
  idoms = networkx.immediate_dominators(full_graph, head)
1915
1915
  if networkx.is_directed_acyclic_graph(full_graph):
1916
- _, inv_idoms = inverted_idoms(full_graph)
1917
1916
  acyclic_graph = full_graph
1918
1917
  else:
1919
1918
  acyclic_graph = to_acyclic_graph(full_graph, loop_heads=[head])
1920
- _, inv_idoms = inverted_idoms(acyclic_graph)
1921
1919
  for src, dst in acyclic_graph.edges:
1922
1920
  if src is dst:
1923
1921
  continue
1924
- if not graph.has_edge(src, dst):
1925
- # the edge might be from full_graph but not in graph
1926
- continue
1927
- if not dominates(idoms, src, dst) and not dominates(inv_idoms, dst, src):
1922
+ if not dominates(idoms, src, dst) and not dominates(idoms, dst, src):
1928
1923
  if (src.addr, dst.addr) not in self.whitelist_edges:
1929
1924
  all_edges_wo_dominance.append((src, dst))
1930
- elif not dominates(idoms, src, dst) and dominates(inv_idoms, dst, src):
1925
+ elif not dominates(idoms, src, dst):
1931
1926
  if (src.addr, dst.addr) not in self.whitelist_edges:
1932
1927
  secondary_edges.append((src, dst))
1933
1928
  else:
@@ -1935,7 +1930,7 @@ class PhoenixStructurer(StructurerBase):
1935
1930
  other_edges.append((src, dst))
1936
1931
 
1937
1932
  ordered_nodes = GraphUtils.quasi_topological_sort_nodes(acyclic_graph, loop_heads=[head])
1938
- node_seq = {nn: idx for (idx, nn) in enumerate(ordered_nodes)}
1933
+ node_seq = {nn: (len(ordered_nodes) - idx) for (idx, nn) in enumerate(ordered_nodes)} # post-order
1939
1934
 
1940
1935
  if all_edges_wo_dominance:
1941
1936
  all_edges_wo_dominance = self._chick_order_edges(all_edges_wo_dominance, node_seq)
@@ -2008,7 +2003,8 @@ class PhoenixStructurer(StructurerBase):
2008
2003
  )
2009
2004
  new_src = SequenceNode(src.addr, nodes=[src, goto_node])
2010
2005
 
2011
- graph.remove_edge(src, dst)
2006
+ if graph.has_edge(src, dst):
2007
+ graph.remove_edge(src, dst)
2012
2008
  if new_src is not None:
2013
2009
  self.replace_nodes(graph, src, new_src)
2014
2010
  if full_graph is not None:
@@ -214,10 +214,6 @@ class Instruction(DisassemblyPiece):
214
214
  assert hasattr(self.insn, "operands")
215
215
 
216
216
  op_str = self.insn.op_str
217
- # NOTE: the size of dummy_operands is not necessarily equal to
218
- # operands count of capstone disasm result. If we check
219
- # len(self.operands) == len(self.insn.operands)
220
- # special cases in arm disassembly will mess up the code
221
217
  dummy_operands = self.split_arm_op_string(op_str)
222
218
 
223
219
  for operand in dummy_operands:
@@ -278,16 +274,16 @@ class Instruction(DisassemblyPiece):
278
274
 
279
275
  @staticmethod
280
276
  def split_arm_op_string(op_str: str):
281
- # Split arm operand string by comma outside brackets
277
+ # Split arm operand string with commas outside the square brackets
282
278
  pieces = []
283
- outside_brackets = True
279
+ in_square_brackets = False
284
280
  cur_opr = ""
285
281
  for c in op_str:
286
- if c == "[" or c == "{":
287
- outside_brackets = False
288
- if c == "]" or c == "}":
289
- outside_brackets = True
290
- if c == "," and outside_brackets:
282
+ if c == "[":
283
+ in_square_brackets = True
284
+ if c == "]":
285
+ in_square_brackets = False
286
+ if c == "," and not in_square_brackets:
291
287
  pieces.append(cur_opr)
292
288
  cur_opr = ""
293
289
  continue
@@ -5,13 +5,13 @@ import logging
5
5
  import claripy
6
6
  from ailment import Stmt, Expr
7
7
 
8
- from angr.errors import SimMemoryMissingError
9
8
  from angr.knowledge_plugins.propagations.prop_value import PropValue, Detail
10
9
  from angr.analyses.reaching_definitions.external_codeloc import ExternalCodeLocation
10
+ from angr.knowledge_plugins.key_definitions.atoms import Register
11
11
  from ...utils.constants import is_alignment_mask
12
12
  from ...engines.light import SimEngineLightAILMixin
13
13
  from ...sim_variable import SimStackVariable, SimMemoryVariable
14
- from ..reaching_definitions.reaching_definitions import OP_BEFORE, OP_AFTER
14
+ from ..reaching_definitions.reaching_definitions import OP_BEFORE
15
15
  from .engine_base import SimEnginePropagatorBase
16
16
 
17
17
  if TYPE_CHECKING:
@@ -378,26 +378,17 @@ class SimEnginePropagatorAIL(
378
378
  reg_defat = None
379
379
  if self._reaching_definitions is not None:
380
380
  codeloc = self._codeloc()
381
- key = "stmt", (codeloc.block_addr, codeloc.block_idx, codeloc.stmt_idx), OP_BEFORE
382
- if key in self._reaching_definitions.observed_results:
383
- o = self._reaching_definitions.observed_results[key]
384
- try:
385
- mv = o.register_definitions.load(expr.reg_offset, size=expr.size)
386
- except SimMemoryMissingError:
387
- mv = None
388
- if mv is not None:
389
- reg_defs = o.extract_defs_from_mv(mv)
390
- reg_defat_codelocs = {reg_def.codeloc for reg_def in reg_defs}
391
- if len(reg_defat_codelocs) == 1:
392
- reg_defat = next(iter(reg_defat_codelocs))
393
- defat_key = "stmt", (reg_defat.block_addr, reg_defat.block_idx, reg_defat.stmt_idx), OP_BEFORE
394
- if defat_key not in self._reaching_definitions.observed_results:
395
- # the observation point does not exist. probably it's because te observation point is in a
396
- # callee function.
397
- reg_defat = None
398
- if isinstance(reg_defat, ExternalCodeLocation):
399
- # there won't be an observed result for external code location. give up
400
- reg_defat = None
381
+ reg_defat_defs = self._reaching_definitions.get_defs(
382
+ Register(expr.reg_offset, expr.size), codeloc, OP_BEFORE
383
+ )
384
+ reg_defat_codelocs = {reg_def.codeloc for reg_def in reg_defat_defs}
385
+ if len(reg_defat_codelocs) == 1:
386
+ reg_defat = next(iter(reg_defat_codelocs))
387
+ if reg_defat.stmt_idx is None:
388
+ # the observation point is in a callee function
389
+ reg_defat = None
390
+ if isinstance(reg_defat, ExternalCodeLocation):
391
+ reg_defat = None
401
392
 
402
393
  if new_expr is not None:
403
394
  # check if this new_expr uses any expression that has been overwritten
@@ -1139,36 +1130,17 @@ class SimEnginePropagatorAIL(
1139
1130
  l.warning("Unknown where the expression is defined. Assume the definition is out-dated.")
1140
1131
  return True, False
1141
1132
 
1142
- key_defat = "stmt", (expr_defat.block_addr, expr_defat.block_idx, expr_defat.stmt_idx), OP_AFTER
1143
- if key_defat not in self._reaching_definitions.observed_results:
1144
- l.warning(
1145
- "Required reaching definition state at instruction address %#x is not found. Assume the definition is "
1146
- "out-dated.",
1147
- expr_defat.ins_addr,
1148
- )
1149
- return True, False
1150
-
1151
- key_currloc = "stmt", (current_loc.block_addr, current_loc.block_idx, current_loc.stmt_idx), OP_BEFORE
1152
- if key_currloc not in self._reaching_definitions.observed_results:
1153
- l.warning(
1154
- "Required reaching definition state at instruction address %#x is not found. Assume the definition is "
1155
- "out-dated.",
1156
- current_loc.ins_addr,
1157
- )
1158
- return True, False
1159
-
1160
1133
  from .outdated_definition_walker import OutdatedDefinitionWalker # pylint:disable=import-outside-toplevel
1161
1134
 
1162
1135
  walker = OutdatedDefinitionWalker(
1163
1136
  expr,
1164
1137
  expr_defat,
1165
- self._reaching_definitions.observed_results[key_defat],
1166
1138
  current_loc,
1167
- self._reaching_definitions.observed_results[key_currloc],
1168
1139
  self.state,
1169
1140
  self.arch,
1170
1141
  avoid=avoid,
1171
1142
  extract_offset_to_sp=self.extract_offset_to_sp,
1143
+ rda=self._reaching_definitions,
1172
1144
  )
1173
1145
  walker.walk_expression(expr)
1174
1146
  return walker.out_dated, walker.has_avoid