angr 9.2.83__py3-none-win_amd64.whl → 9.2.85__py3-none-win_amd64.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 (62) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/cfg/cfg_base.py +6 -1
  3. angr/analyses/cfg/cfg_fast.py +32 -10
  4. angr/analyses/decompiler/clinic.py +204 -4
  5. angr/analyses/decompiler/condition_processor.py +8 -2
  6. angr/analyses/decompiler/decompilation_options.py +10 -0
  7. angr/analyses/decompiler/decompiler.py +19 -17
  8. angr/analyses/decompiler/goto_manager.py +34 -51
  9. angr/analyses/decompiler/optimization_passes/__init__.py +5 -5
  10. angr/analyses/decompiler/optimization_passes/div_simplifier.py +2 -0
  11. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +1 -1
  12. angr/analyses/decompiler/optimization_passes/mod_simplifier.py +2 -0
  13. angr/analyses/decompiler/optimization_passes/multi_simplifier.py +2 -0
  14. angr/analyses/decompiler/optimization_passes/optimization_pass.py +131 -3
  15. angr/analyses/decompiler/optimization_passes/ret_deduplicator.py +3 -3
  16. angr/analyses/decompiler/optimization_passes/return_duplicator.py +519 -0
  17. angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +14 -2
  18. angr/analyses/decompiler/region_identifier.py +8 -2
  19. angr/analyses/decompiler/region_simplifiers/goto.py +5 -4
  20. angr/analyses/decompiler/structured_codegen/c.py +66 -5
  21. angr/analyses/decompiler/structuring/phoenix.py +3 -1
  22. angr/analyses/decompiler/structuring/structurer_nodes.py +11 -5
  23. angr/analyses/decompiler/utils.py +50 -0
  24. angr/analyses/disassembly.py +10 -3
  25. angr/analyses/propagator/engine_ail.py +125 -0
  26. angr/analyses/reaching_definitions/engine_ail.py +36 -2
  27. angr/analyses/reaching_definitions/rd_initializer.py +15 -1
  28. angr/analyses/reaching_definitions/rd_state.py +9 -4
  29. angr/analyses/stack_pointer_tracker.py +10 -17
  30. angr/analyses/variable_recovery/engine_ail.py +27 -1
  31. angr/angrdb/serializers/loader.py +10 -3
  32. angr/calling_conventions.py +2 -0
  33. angr/engines/pcode/behavior.py +7 -2
  34. angr/engines/pcode/cc.py +1 -0
  35. angr/engines/pcode/emulate.py +144 -104
  36. angr/engines/pcode/lifter.py +135 -79
  37. angr/knowledge_plugins/functions/function.py +28 -0
  38. angr/knowledge_plugins/functions/function_manager.py +48 -5
  39. angr/knowledge_plugins/propagations/states.py +14 -0
  40. angr/lib/angr_native.dll +0 -0
  41. angr/procedures/cgc/deallocate.py +5 -2
  42. angr/procedures/posix/gethostbyname.py +23 -8
  43. angr/project.py +4 -0
  44. angr/simos/__init__.py +2 -0
  45. angr/simos/simos.py +1 -0
  46. angr/simos/snimmuc_nxp.py +152 -0
  47. angr/state_plugins/history.py +3 -1
  48. angr/utils/graph.py +20 -18
  49. {angr-9.2.83.dist-info → angr-9.2.85.dist-info}/METADATA +9 -8
  50. {angr-9.2.83.dist-info → angr-9.2.85.dist-info}/RECORD +61 -59
  51. tests/analyses/cfg/test_cfg_rust_got_resolution.py +2 -1
  52. tests/analyses/cfg/test_jumptables.py +2 -1
  53. tests/analyses/decompiler/test_decompiler.py +155 -103
  54. tests/engines/pcode/test_emulate.py +607 -0
  55. tests/engines/test_java.py +609 -663
  56. tests/knowledge_plugins/functions/test_function_manager.py +13 -0
  57. tests/serialization/test_db.py +30 -0
  58. angr/analyses/decompiler/optimization_passes/eager_returns.py +0 -285
  59. {angr-9.2.83.dist-info → angr-9.2.85.dist-info}/LICENSE +0 -0
  60. {angr-9.2.83.dist-info → angr-9.2.85.dist-info}/WHEEL +0 -0
  61. {angr-9.2.83.dist-info → angr-9.2.85.dist-info}/entry_points.txt +0 -0
  62. {angr-9.2.83.dist-info → angr-9.2.85.dist-info}/top_level.txt +0 -0
@@ -2,10 +2,12 @@
2
2
  from typing import Optional, Dict, List, Tuple, Set, Any, Union, TYPE_CHECKING, Callable
3
3
  from collections import defaultdict
4
4
  import logging
5
+ import struct
5
6
  from functools import reduce
6
7
 
7
8
  from ailment import Block, Expr, Stmt, Tmp
8
9
  from ailment.expression import StackBaseOffset, BinaryOp
10
+ from unique_log_filter import UniqueLogFilter
9
11
 
10
12
  from ....sim_type import (
11
13
  SimTypeLongLong,
@@ -57,6 +59,8 @@ if TYPE_CHECKING:
57
59
 
58
60
 
59
61
  l = logging.getLogger(name=__name__)
62
+ l.addFilter(UniqueLogFilter())
63
+
60
64
 
61
65
  INDENT_DELTA = 4
62
66
 
@@ -1177,6 +1181,7 @@ class CFunctionCall(CStatement, CExpression):
1177
1181
  "tags",
1178
1182
  "is_expr",
1179
1183
  "show_demangled_name",
1184
+ "show_disambiguated_name",
1180
1185
  )
1181
1186
 
1182
1187
  def __init__(
@@ -1189,6 +1194,7 @@ class CFunctionCall(CStatement, CExpression):
1189
1194
  tags=None,
1190
1195
  is_expr: bool = False,
1191
1196
  show_demangled_name=True,
1197
+ show_disambiguated_name: bool = True,
1192
1198
  **kwargs,
1193
1199
  ):
1194
1200
  super().__init__(**kwargs)
@@ -1201,6 +1207,7 @@ class CFunctionCall(CStatement, CExpression):
1201
1207
  self.tags = tags
1202
1208
  self.is_expr = is_expr
1203
1209
  self.show_demangled_name = show_demangled_name
1210
+ self.show_disambiguated_name = show_disambiguated_name
1204
1211
 
1205
1212
  @property
1206
1213
  def prototype(self) -> Optional[SimTypeFunction]: # TODO there should be a prototype for each callsite!
@@ -1216,6 +1223,23 @@ class CFunctionCall(CStatement, CExpression):
1216
1223
  else:
1217
1224
  raise RuntimeError("CFunctionCall.type should not be accessed if the function call is used as a statement.")
1218
1225
 
1226
+ def _is_target_ambiguous(self, func_name: str) -> bool:
1227
+ """
1228
+ Check for call target name ambiguity.
1229
+ """
1230
+ caller, callee = self.codegen._func, self.callee_func
1231
+
1232
+ for var in self.codegen._variables_in_use.values():
1233
+ if func_name == var.name:
1234
+ return True
1235
+
1236
+ # FIXME: Handle name mangle
1237
+ for func in self.codegen.kb.functions.get_by_name(callee.name):
1238
+ if func is not callee and (caller.binary is not callee.binary or func.binary is callee.binary):
1239
+ return True
1240
+
1241
+ return False
1242
+
1219
1243
  def c_repr_chunks(self, indent=0, asexpr: bool = False):
1220
1244
  """
1221
1245
 
@@ -1235,6 +1259,8 @@ class CFunctionCall(CStatement, CExpression):
1235
1259
  func_name = get_cpp_function_name(self.callee_func.demangled_name, specialized=False, qualified=True)
1236
1260
  else:
1237
1261
  func_name = self.callee_func.name
1262
+ if self.show_disambiguated_name and self._is_target_ambiguous(func_name):
1263
+ func_name = self.callee_func.get_unambiguous_name(display_name=func_name)
1238
1264
  yield func_name, self
1239
1265
  else:
1240
1266
  yield from CExpression._try_c_repr_chunks(self.callee_target)
@@ -1443,15 +1469,19 @@ class CVariable(CExpression):
1443
1469
  def type(self):
1444
1470
  return self.variable_type
1445
1471
 
1446
- def c_repr_chunks(self, indent=0, asexpr=False):
1472
+ @property
1473
+ def name(self):
1447
1474
  v = self.variable if self.unified_variable is None else self.unified_variable
1448
1475
 
1449
1476
  if v.name:
1450
- yield v.name, self
1477
+ return v.name
1451
1478
  elif isinstance(v, SimTemporaryVariable):
1452
- yield "tmp_%d" % v.tmp_id, self
1479
+ return "tmp_%d" % v.tmp_id
1453
1480
  else:
1454
- yield str(v), self
1481
+ return str(v)
1482
+
1483
+ def c_repr_chunks(self, indent=0, asexpr=False):
1484
+ yield self.name, self
1455
1485
 
1456
1486
 
1457
1487
  class CIndexedVariable(CExpression):
@@ -1702,6 +1732,7 @@ class CBinaryOp(CExpression):
1702
1732
  # lowest precedence
1703
1733
  ["Concat"],
1704
1734
  ["LogicalOr"],
1735
+ ["LogicalXor"],
1705
1736
  ["LogicalAnd"],
1706
1737
  ["Or"],
1707
1738
  ["Xor"],
@@ -1711,6 +1742,7 @@ class CBinaryOp(CExpression):
1711
1742
  ["Shl", "Shr", "Sar"],
1712
1743
  ["Add", "Sub"],
1713
1744
  ["Mul", "Div"],
1745
+ ["SBorrow", "SCarry", "Carry"],
1714
1746
  # highest precedence
1715
1747
  ]
1716
1748
  for i, sublist in enumerate(precedence_list):
@@ -1739,6 +1771,7 @@ class CBinaryOp(CExpression):
1739
1771
  "Sar": self._c_repr_chunks_sar,
1740
1772
  "LogicalAnd": self._c_repr_chunks_logicaland,
1741
1773
  "LogicalOr": self._c_repr_chunks_logicalor,
1774
+ "LogicalXor": self._c_repr_chunks_logicalxor,
1742
1775
  "CmpLE": self._c_repr_chunks_cmple,
1743
1776
  "CmpLEs": self._c_repr_chunks_cmple,
1744
1777
  "CmpLT": self._c_repr_chunks_cmplt,
@@ -1758,7 +1791,7 @@ class CBinaryOp(CExpression):
1758
1791
  if handler is not None:
1759
1792
  yield from handler()
1760
1793
  else:
1761
- yield "BinaryOp %s" % (self.op), self
1794
+ yield from self._c_repr_chunks_opfirst(self.op)
1762
1795
 
1763
1796
  def _has_const_null_rhs(self) -> bool:
1764
1797
  return isinstance(self.rhs, CConstant) and self.rhs.value == 0
@@ -1799,6 +1832,15 @@ class CBinaryOp(CExpression):
1799
1832
  else:
1800
1833
  yield from self._try_c_repr_chunks(self.rhs)
1801
1834
 
1835
+ def _c_repr_chunks_opfirst(self, op):
1836
+ yield op, self
1837
+ paren = CClosingObject("(")
1838
+ yield "(", paren
1839
+ yield from self._try_c_repr_chunks(self.lhs)
1840
+ yield ", ", None
1841
+ yield from self._try_c_repr_chunks(self.rhs)
1842
+ yield ")", paren
1843
+
1802
1844
  def _c_repr_chunks_add(self):
1803
1845
  yield from self._c_repr_chunks(" + ")
1804
1846
 
@@ -1844,6 +1886,9 @@ class CBinaryOp(CExpression):
1844
1886
  def _c_repr_chunks_logicalor(self):
1845
1887
  yield from self._c_repr_chunks(" || ")
1846
1888
 
1889
+ def _c_repr_chunks_logicalxor(self):
1890
+ yield from self._c_repr_chunks(" ^ ")
1891
+
1847
1892
  def _c_repr_chunks_cmple(self):
1848
1893
  yield from self._c_repr_chunks(" <= ")
1849
1894
 
@@ -2004,6 +2049,14 @@ class CConstant(CExpression):
2004
2049
  def fmt_char(self, v: bool):
2005
2050
  self._fmt_setter["char"] = v
2006
2051
 
2052
+ @property
2053
+ def fmt_float(self):
2054
+ return self.fmt.get("float", False)
2055
+
2056
+ @fmt_float.setter
2057
+ def fmt_float(self, v: bool):
2058
+ self._fmt_setter["float"] = v
2059
+
2007
2060
  @property
2008
2061
  def type(self):
2009
2062
  return self._type
@@ -2088,6 +2141,11 @@ class CConstant(CExpression):
2088
2141
  :return: The formatted string.
2089
2142
  """
2090
2143
 
2144
+ if self.fmt_float:
2145
+ if 0 < value <= 0xFFFF_FFFF:
2146
+ str_value = str(struct.unpack("f", struct.pack("I", value))[0])
2147
+ return str_value
2148
+
2091
2149
  if self.fmt_neg:
2092
2150
  if value > 0:
2093
2151
  value = value - 2**self._type.size
@@ -2272,6 +2330,7 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
2272
2330
  externs=None,
2273
2331
  const_formats=None,
2274
2332
  show_demangled_name=True,
2333
+ show_disambiguated_name=True,
2275
2334
  ail_graph=None,
2276
2335
  simplify_else_scope=True,
2277
2336
  cstyle_ifs=True,
@@ -2338,6 +2397,7 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
2338
2397
  self.externs = externs or set()
2339
2398
  self.show_externs = show_externs
2340
2399
  self.show_demangled_name = show_demangled_name
2400
+ self.show_disambiguated_name = show_disambiguated_name
2341
2401
  self.ail_graph = ail_graph
2342
2402
  self.simplify_else_scope = simplify_else_scope
2343
2403
  self.cstyle_ifs = cstyle_ifs
@@ -3115,6 +3175,7 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
3115
3175
  tags=stmt.tags,
3116
3176
  is_expr=is_expr,
3117
3177
  show_demangled_name=self.show_demangled_name,
3178
+ show_disambiguated_name=self.show_disambiguated_name,
3118
3179
  codegen=self,
3119
3180
  )
3120
3181
 
@@ -114,6 +114,8 @@ class PhoenixStructurer(StructurerBase):
114
114
  self._edge_virtualization_hints = []
115
115
 
116
116
  self._use_multistmtexprs = use_multistmtexprs
117
+ if not self._phoenix_improved:
118
+ self._use_multistmtexprs = MultiStmtExprMode.NEVER
117
119
 
118
120
  self._analyze()
119
121
 
@@ -2141,7 +2143,7 @@ class PhoenixStructurer(StructurerBase):
2141
2143
  pass
2142
2144
  else:
2143
2145
  # insert a Jump at the end
2144
- stmt_addr = last_stmt.ins_addr if last_stmt is not None else src.addr
2146
+ stmt_addr = src.addr
2145
2147
  goto_node = Block(
2146
2148
  stmt_addr,
2147
2149
  0,
@@ -3,6 +3,7 @@ from typing import List, Tuple, Any, Optional, Union, OrderedDict as ODict
3
3
 
4
4
  import claripy
5
5
  import ailment
6
+ import ailment.utils
6
7
 
7
8
 
8
9
  INDENT_DELTA = 2
@@ -387,11 +388,7 @@ class IncompleteSwitchCaseHeadStatement(ailment.statement.Statement):
387
388
  Describes a switch-case head. This is only created by LoweredSwitchSimplifier.
388
389
  """
389
390
 
390
- __slots__ = (
391
- "addr",
392
- "switch_variable",
393
- "case_addrs",
394
- )
391
+ __slots__ = ("addr", "switch_variable", "case_addrs", "_case_addrs_str")
395
392
 
396
393
  def __init__(self, idx, switch_variable, case_addrs, **kwargs):
397
394
  super().__init__(idx, **kwargs)
@@ -399,9 +396,18 @@ class IncompleteSwitchCaseHeadStatement(ailment.statement.Statement):
399
396
  # original cmp node, case value | "default", address of the case node, idx of the case node,
400
397
  # address of the next cmp node
401
398
  self.case_addrs: List[Tuple[ailment.Block, Union[int, str], int, Optional[int], int]] = case_addrs
399
+ # a string representation of the addresses of all cases, used for hashing
400
+ self._case_addrs_str = str(sorted([c[0].addr for c in self.case_addrs if c[0] is not None]))
402
401
 
403
402
  def __repr__(self):
404
403
  return f"SwitchCaseHead: switch {self.switch_variable} with {len(self.case_addrs)} cases"
405
404
 
406
405
  def __str__(self):
407
406
  return f"switch ({str(self.switch_variable)}): {len(self.case_addrs)} cases"
407
+
408
+ __hash__ = ailment.statement.TaggedObject.__hash__
409
+
410
+ def _hash_core(self):
411
+ return ailment.utils.stable_hash(
412
+ (IncompleteSwitchCaseHeadStatement, self.idx, self.switch_variable, self._case_addrs_str)
413
+ )
@@ -1,4 +1,6 @@
1
+ # pylint:disable=wrong-import-position
1
2
  import pathlib
3
+ import copy
2
4
  from typing import Optional, Tuple, Any, Union, List, Iterable
3
5
  import logging
4
6
 
@@ -378,6 +380,30 @@ def remove_labels(graph: networkx.DiGraph):
378
380
  return new_graph
379
381
 
380
382
 
383
+ def add_labels(graph: networkx.DiGraph):
384
+ new_graph = networkx.DiGraph()
385
+ nodes_map = {}
386
+ for node in graph:
387
+ lbl = ailment.Stmt.Label(None, f"LABEL_{node.addr:x}", node.addr, block_idx=node.idx)
388
+ node_copy = node.copy()
389
+ node_copy.statements = [lbl] + node_copy.statements
390
+ nodes_map[node] = node_copy
391
+
392
+ new_graph.add_nodes_from(nodes_map.values())
393
+ for src, dst in graph.edges:
394
+ new_graph.add_edge(nodes_map[src], nodes_map[dst])
395
+
396
+ return new_graph
397
+
398
+
399
+ def update_labels(graph: networkx.DiGraph):
400
+ """
401
+ A utility function to recreate the labels for every node in an AIL graph. This useful when you are working with
402
+ a graph where only _some_ of the nodes have labels.
403
+ """
404
+ return add_labels(remove_labels(graph))
405
+
406
+
381
407
  def structured_node_is_simple_return(node: Union["SequenceNode", "MultiNode"], graph: networkx.DiGraph) -> bool:
382
408
  """
383
409
  Will check if a "simple return" is contained within the node a simple returns looks like this:
@@ -510,6 +536,30 @@ def peephole_optimize_expr(expr, expr_opts):
510
536
  return new_expr
511
537
 
512
538
 
539
+ def copy_graph(graph: networkx.DiGraph):
540
+ """
541
+ Copy AIL Graph.
542
+
543
+ :return: A copy of the AIl graph.
544
+ """
545
+ graph_copy = networkx.DiGraph()
546
+ block_mapping = {}
547
+ # copy all blocks
548
+ for block in graph.nodes():
549
+ new_block = copy.copy(block)
550
+ new_stmts = copy.copy(block.statements)
551
+ new_block.statements = new_stmts
552
+ block_mapping[block] = new_block
553
+ graph_copy.add_node(new_block)
554
+
555
+ # copy all edges
556
+ for src, dst, data in graph.edges(data=True):
557
+ new_src = block_mapping[src]
558
+ new_dst = block_mapping[dst]
559
+ graph_copy.add_edge(new_src, new_dst, **data)
560
+ return graph_copy
561
+
562
+
513
563
  def peephole_optimize_stmts(block, stmt_opts):
514
564
  any_update = False
515
565
  statements = []
@@ -133,6 +133,8 @@ class IROp(DisassemblyPiece):
133
133
  self.irsb = irsb
134
134
 
135
135
  def __str__(self):
136
+ if pcode and isinstance(self.obj, pypcode.PcodeOp):
137
+ return pypcode.PcodePrettyPrinter.fmt_op(self.obj)
136
138
  return str(self.obj)
137
139
 
138
140
  def _render(self, formatting): # pylint:disable=unused-argument
@@ -1078,9 +1080,14 @@ class Disassembly(Analysis):
1078
1080
 
1079
1081
  if irsb.statements is not None:
1080
1082
  if pcode is not None and isinstance(self.project.factory.default_engine, pcode.HeavyPcodeMixin):
1081
- for ins in irsb._instructions:
1082
- addr = ins.address.offset
1083
- addr_to_ops_map[addr].extend([IROp(addr, op.seq.uniq, op, irsb) for op in ins.ops])
1083
+ addr = None
1084
+ stmt_idx = 0
1085
+ for op in irsb._ops:
1086
+ if op.opcode == pypcode.OpCode.IMARK:
1087
+ addr = op.inputs[0].offset
1088
+ else:
1089
+ addr_to_ops_map[addr].append(IROp(addr, stmt_idx, op, irsb))
1090
+ stmt_idx += 1
1084
1091
  else:
1085
1092
  for seq, stmt in enumerate(irsb.statements):
1086
1093
  if isinstance(stmt, pyvex.stmt.IMark):
@@ -4,6 +4,7 @@ import logging
4
4
 
5
5
  import claripy
6
6
  from ailment import Stmt, Expr
7
+ from unique_log_filter import UniqueLogFilter
7
8
 
8
9
  from angr.knowledge_plugins.propagations.prop_value import PropValue, Detail
9
10
  from angr.knowledge_plugins.key_definitions.atoms import Register
@@ -20,6 +21,7 @@ if TYPE_CHECKING:
20
21
  from angr.code_location import CodeLocation
21
22
 
22
23
  l = logging.getLogger(name=__name__)
24
+ l.addFilter(UniqueLogFilter())
23
25
 
24
26
 
25
27
  class SimEnginePropagatorAIL(
@@ -1268,6 +1270,129 @@ class SimEnginePropagatorAIL(
1268
1270
  )
1269
1271
  return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1270
1272
 
1273
+ def _ail_handle_LogicalOr(self, expr: Expr.BinaryOp):
1274
+ o0_value = self._expr(expr.operands[0])
1275
+ o1_value = self._expr(expr.operands[1])
1276
+
1277
+ value = self.state.top(expr.bits)
1278
+ if o0_value is None or o1_value is None:
1279
+ new_expr = expr
1280
+ else:
1281
+ o0_expr = o0_value.one_expr
1282
+ o1_expr = o1_value.one_expr
1283
+
1284
+ value = self.state.top(expr.bits)
1285
+ new_expr = Expr.BinaryOp(
1286
+ expr.idx,
1287
+ "LogicalOr",
1288
+ [
1289
+ o0_expr if o0_expr is not None else expr.operands[0],
1290
+ o1_expr if o1_expr is not None else expr.operands[1],
1291
+ ],
1292
+ expr.signed,
1293
+ **expr.tags,
1294
+ )
1295
+ return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1296
+
1297
+ def _ail_handle_LogicalXor(self, expr: Expr.BinaryOp):
1298
+ o0_value = self._expr(expr.operands[0])
1299
+ o1_value = self._expr(expr.operands[1])
1300
+
1301
+ value = self.state.top(expr.bits)
1302
+ if o0_value is None or o1_value is None:
1303
+ new_expr = expr
1304
+ else:
1305
+ o0_expr = o0_value.one_expr
1306
+ o1_expr = o1_value.one_expr
1307
+
1308
+ value = self.state.top(expr.bits)
1309
+ new_expr = Expr.BinaryOp(
1310
+ expr.idx,
1311
+ "LogicalXor",
1312
+ [
1313
+ o0_expr if o0_expr is not None else expr.operands[0],
1314
+ o1_expr if o1_expr is not None else expr.operands[1],
1315
+ ],
1316
+ expr.signed,
1317
+ **expr.tags,
1318
+ )
1319
+ return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1320
+
1321
+ def _ail_handle_Carry(self, expr: Expr.BinaryOp):
1322
+ o0_value = self._expr(expr.operands[0])
1323
+ o1_value = self._expr(expr.operands[1])
1324
+
1325
+ value = self.state.top(expr.bits)
1326
+ if o0_value is None or o1_value is None:
1327
+ new_expr = expr
1328
+ else:
1329
+ o0_expr = o0_value.one_expr
1330
+ o1_expr = o1_value.one_expr
1331
+ new_expr = Expr.BinaryOp(
1332
+ expr.idx,
1333
+ "Carry",
1334
+ [
1335
+ o0_expr if o0_expr is not None else expr.operands[0],
1336
+ o1_expr if o1_expr is not None else expr.operands[1],
1337
+ ],
1338
+ expr.signed,
1339
+ bits=expr.bits,
1340
+ floating_point=expr.floating_point,
1341
+ rounding_mode=expr.rounding_mode,
1342
+ **expr.tags,
1343
+ )
1344
+ return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1345
+
1346
+ def _ail_handle_SCarry(self, expr: Expr.BinaryOp):
1347
+ o0_value = self._expr(expr.operands[0])
1348
+ o1_value = self._expr(expr.operands[1])
1349
+
1350
+ value = self.state.top(expr.bits)
1351
+ if o0_value is None or o1_value is None:
1352
+ new_expr = expr
1353
+ else:
1354
+ o0_expr = o0_value.one_expr
1355
+ o1_expr = o1_value.one_expr
1356
+ new_expr = Expr.BinaryOp(
1357
+ expr.idx,
1358
+ "SCarry",
1359
+ [
1360
+ o0_expr if o0_expr is not None else expr.operands[0],
1361
+ o1_expr if o1_expr is not None else expr.operands[1],
1362
+ ],
1363
+ expr.signed,
1364
+ bits=expr.bits,
1365
+ floating_point=expr.floating_point,
1366
+ rounding_mode=expr.rounding_mode,
1367
+ **expr.tags,
1368
+ )
1369
+ return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1370
+
1371
+ def _ail_handle_SBorrow(self, expr: Expr.BinaryOp):
1372
+ o0_value = self._expr(expr.operands[0])
1373
+ o1_value = self._expr(expr.operands[1])
1374
+
1375
+ value = self.state.top(expr.bits)
1376
+ if o0_value is None or o1_value is None:
1377
+ new_expr = expr
1378
+ else:
1379
+ o0_expr = o0_value.one_expr
1380
+ o1_expr = o1_value.one_expr
1381
+ new_expr = Expr.BinaryOp(
1382
+ expr.idx,
1383
+ "SBorrow",
1384
+ [
1385
+ o0_expr if o0_expr is not None else expr.operands[0],
1386
+ o1_expr if o1_expr is not None else expr.operands[1],
1387
+ ],
1388
+ expr.signed,
1389
+ bits=expr.bits,
1390
+ floating_point=expr.floating_point,
1391
+ rounding_mode=expr.rounding_mode,
1392
+ **expr.tags,
1393
+ )
1394
+ return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1395
+
1271
1396
  def _ail_handle_TernaryOp(self, expr: Expr.TernaryOp):
1272
1397
  o0_value = self._expr(expr.operands[0])
1273
1398
  o1_value = self._expr(expr.operands[1])
@@ -981,7 +981,6 @@ class SimEngineRDAIL(
981
981
  expr1: MultiValues = self._expr(expr.operands[1])
982
982
  bits = expr.bits
983
983
 
984
- r = None
985
984
  expr0_v = expr0.one_value()
986
985
  expr1_v = expr1.one_value()
987
986
 
@@ -999,7 +998,6 @@ class SimEngineRDAIL(
999
998
  expr1: MultiValues = self._expr(expr.operands[1])
1000
999
  bits = expr.bits
1001
1000
 
1002
- r = None
1003
1001
  expr0_v = expr0.one_value()
1004
1002
  expr1_v = expr1.one_value()
1005
1003
 
@@ -1010,6 +1008,21 @@ class SimEngineRDAIL(
1010
1008
  r = MultiValues(claripy.If(expr0_v != 0, expr0_v, expr1_v))
1011
1009
  return r
1012
1010
 
1011
+ def _ail_handle_LogicalXor(self, expr: ailment.Expr.BinaryOp) -> MultiValues:
1012
+ expr0: MultiValues = self._expr(expr.operands[0])
1013
+ expr1: MultiValues = self._expr(expr.operands[1])
1014
+ bits = expr.bits
1015
+
1016
+ expr0_v = expr0.one_value()
1017
+ expr1_v = expr1.one_value()
1018
+
1019
+ if expr0_v is None or expr1_v is None:
1020
+ r = MultiValues(self.state.top(bits))
1021
+ return r
1022
+
1023
+ r = MultiValues(claripy.If(expr0_v != 0, expr1_v, expr0_v))
1024
+ return r
1025
+
1013
1026
  def _ail_handle_Xor(self, expr: ailment.Expr.BinaryOp) -> MultiValues:
1014
1027
  expr0: MultiValues = self._expr(expr.operands[0])
1015
1028
  expr1: MultiValues = self._expr(expr.operands[1])
@@ -1042,6 +1055,27 @@ class SimEngineRDAIL(
1042
1055
 
1043
1056
  return r
1044
1057
 
1058
+ def _ail_handle_Carry(self, expr: ailment.Expr.BinaryOp) -> MultiValues:
1059
+ _ = self._expr(expr.operands[0])
1060
+ _ = self._expr(expr.operands[1])
1061
+ bits = expr.bits
1062
+ r = MultiValues(self.state.top(bits))
1063
+ return r
1064
+
1065
+ def _ail_handle_SCarry(self, expr: ailment.Expr.BinaryOp) -> MultiValues:
1066
+ _ = self._expr(expr.operands[0])
1067
+ _ = self._expr(expr.operands[1])
1068
+ bits = expr.bits
1069
+ r = MultiValues(self.state.top(bits))
1070
+ return r
1071
+
1072
+ def _ail_handle_SBorrow(self, expr: ailment.Expr.BinaryOp) -> MultiValues:
1073
+ _ = self._expr(expr.operands[0])
1074
+ _ = self._expr(expr.operands[1])
1075
+ bits = expr.bits
1076
+ r = MultiValues(self.state.top(bits))
1077
+ return r
1078
+
1045
1079
  def _ail_handle_Concat(self, expr: ailment.Expr.BinaryOp) -> MultiValues:
1046
1080
  expr0: MultiValues = self._expr(expr.operands[0])
1047
1081
  expr1: MultiValues = self._expr(expr.operands[1])
@@ -33,8 +33,9 @@ class RDAStateInitializer:
33
33
 
34
34
  """
35
35
 
36
- def __init__(self, arch: Arch):
36
+ def __init__(self, arch: Arch, project=None):
37
37
  self.arch: Arch = arch
38
+ self.project = project
38
39
 
39
40
  def initialize_function_state(
40
41
  self, state: "ReachingDefinitionsState", cc: Optional[SimCC], func_addr: int, rtoc_value: Optional[int] = None
@@ -171,6 +172,19 @@ class RDAStateInitializer:
171
172
  t9 = state.annotate_with_def(claripy.BVV(func_addr, self.arch.bits), t9_def)
172
173
  state.registers.store(t9_offset, t9)
173
174
 
175
+ # project-specific initialization
176
+ if self.project is not None:
177
+ if self.project.simos is not None and self.project.simos.function_initial_registers:
178
+ for reg_name, reg_value in self.project.simos.function_initial_registers.items():
179
+ reg_offset = self.arch.registers[reg_name][0]
180
+ reg_atom = Register(reg_offset, self.arch.registers[reg_name][1])
181
+ reg_def = Definition(reg_atom, ex_loc, tags={InitialValueTag()})
182
+ state.all_definitions.add(reg_def)
183
+ if state.analysis is not None:
184
+ state.analysis.model.add_def(reg_def)
185
+ reg = state.annotate_with_def(claripy.BVV(reg_value, self.arch.registers[reg_name][1]), reg_def)
186
+ state.registers.store(reg_offset, reg)
187
+
174
188
  def _initialize_function_argument_register(
175
189
  self,
176
190
  state: "ReachingDefinitionsState",
@@ -124,10 +124,11 @@ class ReachingDefinitionsState:
124
124
  self.live_definitions = LiveDefinitions(
125
125
  self.arch, track_tmps=self._track_tmps, canonical_size=canonical_size
126
126
  )
127
- self._set_initialization_values(subject, rtoc_value, initializer=initializer)
128
-
129
127
  if self.analysis is not None:
130
128
  self.live_definitions.project = self.analysis.project
129
+ self._set_initialization_values(
130
+ subject, rtoc_value, initializer=initializer, project=self.live_definitions.project
131
+ )
131
132
  else:
132
133
  # this state is a copy from a previous state. skip the initialization
133
134
  self.live_definitions = live_definitions
@@ -269,10 +270,14 @@ class ReachingDefinitionsState:
269
270
  return "{%s}" % ctnt
270
271
 
271
272
  def _set_initialization_values(
272
- self, subject: Subject, rtoc_value: Optional[int] = None, initializer: Optional[RDAStateInitializer] = None
273
+ self,
274
+ subject: Subject,
275
+ rtoc_value: Optional[int] = None,
276
+ initializer: Optional[RDAStateInitializer] = None,
277
+ project=None,
273
278
  ):
274
279
  if initializer is None:
275
- initializer = RDAStateInitializer(self.arch)
280
+ initializer = RDAStateInitializer(self.arch, project=project)
276
281
 
277
282
  if subject.type == SubjectType.Function:
278
283
  if isinstance(self.arch, archinfo.arch_ppc64.ArchPPC64) and not rtoc_value:
@@ -695,28 +695,21 @@ class StackPointerTracker(Analysis, ForwardAnalysis):
695
695
  else:
696
696
  raise CouldNotResolveException()
697
697
 
698
- for instr in pcode_irsb._instructions:
699
- if curr_stmt_start_addr is not None:
700
- # we've reached a new instruction. Time to store the post state
701
- self._set_post_state(curr_stmt_start_addr, state.freeze())
702
- curr_stmt_start_addr = instr.address.offset
703
- self._set_pre_state(curr_stmt_start_addr, state.freeze())
704
-
705
- for op in instr.ops:
706
- op: "pypcode.PcodeOp"
698
+ is_call = False
699
+ for op in pcode_irsb._ops:
700
+ if op.opcode == pypcode.OpCode.IMARK:
701
+ if curr_stmt_start_addr is not None:
702
+ # we've reached a new instruction. Time to store the post state
703
+ self._set_post_state(curr_stmt_start_addr, state.freeze())
704
+ curr_stmt_start_addr = op.inputs[0].offset
705
+ self._set_pre_state(curr_stmt_start_addr, state.freeze())
706
+ else:
707
707
  try:
708
708
  resolve_op(op)
709
709
  except CouldNotResolveException:
710
710
  pass
711
711
 
712
- # examine the last instruction and determine if this is a call instruction
713
- is_call = False
714
- if pcode_irsb._instructions:
715
- last_instr = pcode_irsb._instructions[-1]
716
- if last_instr.ops:
717
- last_op = last_instr.ops[-1]
718
- if last_op.opcode == pypcode.OpCode.CALL:
719
- is_call = True
712
+ is_call |= op.opcode == pypcode.OpCode.CALL
720
713
 
721
714
  # stack pointer adjustment
722
715
  if self.project.arch.sp_offset in self.reg_offsets and is_call: