angr 9.2.96__py3-none-win_amd64.whl → 9.2.98__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 (52) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/cfg/cfg_base.py +14 -1
  3. angr/analyses/cfg/indirect_jump_resolvers/propagator_utils.py +10 -6
  4. angr/analyses/complete_calling_conventions.py +27 -11
  5. angr/analyses/decompiler/ail_simplifier.py +20 -8
  6. angr/analyses/decompiler/condition_processor.py +2 -0
  7. angr/analyses/decompiler/optimization_passes/__init__.py +2 -0
  8. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +380 -0
  9. angr/analyses/decompiler/optimization_passes/x86_gcc_getpc_simplifier.py +4 -1
  10. angr/analyses/decompiler/peephole_optimizations/__init__.py +1 -0
  11. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +71 -3
  12. angr/analyses/decompiler/peephole_optimizations/inlined_wstrcpy.py +162 -0
  13. angr/analyses/decompiler/structured_codegen/__init__.py +1 -1
  14. angr/analyses/decompiler/structured_codegen/c.py +72 -99
  15. angr/analyses/decompiler/utils.py +5 -1
  16. angr/analyses/find_objects_static.py +15 -10
  17. angr/analyses/forward_analysis/forward_analysis.py +15 -1
  18. angr/analyses/propagator/engine_ail.py +2 -0
  19. angr/analyses/propagator/engine_vex.py +15 -0
  20. angr/analyses/propagator/propagator.py +6 -3
  21. angr/analyses/reaching_definitions/engine_vex.py +6 -0
  22. angr/analyses/reaching_definitions/rd_state.py +14 -1
  23. angr/analyses/reaching_definitions/reaching_definitions.py +19 -2
  24. angr/analyses/variable_recovery/engine_ail.py +6 -6
  25. angr/analyses/variable_recovery/engine_vex.py +6 -0
  26. angr/analyses/variable_recovery/irsb_scanner.py +12 -0
  27. angr/analyses/variable_recovery/variable_recovery_base.py +4 -1
  28. angr/engines/light/engine.py +134 -16
  29. angr/knowledge_plugins/functions/function.py +4 -0
  30. angr/knowledge_plugins/key_definitions/environment.py +11 -0
  31. angr/knowledge_plugins/key_definitions/live_definitions.py +41 -8
  32. angr/knowledge_plugins/key_definitions/uses.py +18 -4
  33. angr/knowledge_plugins/propagations/states.py +22 -3
  34. angr/knowledge_plugins/types.py +6 -0
  35. angr/knowledge_plugins/variables/variable_manager.py +31 -5
  36. angr/lib/angr_native.dll +0 -0
  37. angr/simos/simos.py +2 -0
  38. angr/storage/memory_mixins/__init__.py +3 -0
  39. angr/storage/memory_mixins/multi_value_merger_mixin.py +22 -11
  40. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +20 -2
  41. angr/storage/memory_mixins/paged_memory/pages/list_page.py +20 -5
  42. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +82 -44
  43. angr/storage/memory_mixins/simple_interface_mixin.py +4 -0
  44. angr/utils/cowdict.py +4 -2
  45. angr/utils/funcid.py +6 -0
  46. angr/utils/mp.py +1 -1
  47. {angr-9.2.96.dist-info → angr-9.2.98.dist-info}/METADATA +6 -6
  48. {angr-9.2.96.dist-info → angr-9.2.98.dist-info}/RECORD +52 -50
  49. {angr-9.2.96.dist-info → angr-9.2.98.dist-info}/LICENSE +0 -0
  50. {angr-9.2.96.dist-info → angr-9.2.98.dist-info}/WHEEL +0 -0
  51. {angr-9.2.96.dist-info → angr-9.2.98.dist-info}/entry_points.txt +0 -0
  52. {angr-9.2.96.dist-info → angr-9.2.98.dist-info}/top_level.txt +0 -0
@@ -163,6 +163,9 @@ class SimEnginePropagatorVEX(
163
163
  self.state.store_register(stmt.offset, size, data)
164
164
  self.state.add_replacement(self._codeloc(block_only=False), VEXReg(stmt.offset, size), data)
165
165
 
166
+ def _handle_PutI(self, stmt):
167
+ self._expr(stmt.data)
168
+
166
169
  def _store_data(self, addr, data, size, endness):
167
170
  # pylint: disable=unused-argument,no-self-use
168
171
  if isinstance(addr, claripy.ast.Base):
@@ -260,6 +263,9 @@ class SimEnginePropagatorVEX(
260
263
  size = expr.result_size(self.tyenv) // self.arch.byte_width
261
264
  return self.state.load_register(expr.offset, size)
262
265
 
266
+ def _handle_GetI(self, expr):
267
+ return self.state.top(expr.result_size(self.tyenv))
268
+
263
269
  def _handle_Load(self, expr):
264
270
  addr = self._expr(expr.addr)
265
271
  if addr is None or type(addr) in (Top, Bottom):
@@ -278,6 +284,13 @@ class SimEnginePropagatorVEX(
278
284
  # print(expr.op, r)
279
285
  return r
280
286
 
287
+ def _handle_Triop(self, expr: pyvex.IRExpr.Triop):
288
+ if not self.state.do_binops:
289
+ return self.state.top(expr.result_size(self.tyenv))
290
+
291
+ r = super()._handle_Triop(expr)
292
+ return r
293
+
281
294
  def _handle_Conversion(self, expr):
282
295
  expr_ = self._expr(expr.args[0])
283
296
  to_size = expr.result_size(self.tyenv)
@@ -311,3 +324,5 @@ class SimEnginePropagatorVEX(
311
324
  self.state.block_initial_reg_values[self.block.addr, dst.concrete_value].append(v)
312
325
 
313
326
  super()._handle_Exit(stmt)
327
+
328
+ _handle_CmpF = _handle_CmpEQ
@@ -53,7 +53,7 @@ class PropagatorAnalysis(ForwardAnalysis, Analysis): # pylint:disable=abstract-
53
53
  block=None,
54
54
  func_graph=None,
55
55
  base_state=None,
56
- max_iterations=3,
56
+ max_iterations=30,
57
57
  load_callback=None,
58
58
  stack_pointer_tracker=None,
59
59
  only_consts=False,
@@ -79,7 +79,10 @@ class PropagatorAnalysis(ForwardAnalysis, Analysis): # pylint:disable=abstract-
79
79
  else:
80
80
  raise ValueError("Unsupported analysis target.")
81
81
 
82
- start = time.perf_counter_ns() / 1000000
82
+ if profiling:
83
+ start = time.perf_counter_ns() / 1000000
84
+ else:
85
+ start = 0
83
86
 
84
87
  self._base_state = base_state
85
88
  self._function = func
@@ -320,7 +323,7 @@ class PropagatorAnalysis(ForwardAnalysis, Analysis): # pylint:disable=abstract-
320
323
  # TODO: Clear registers according to calling conventions
321
324
 
322
325
  if self.model.node_iterations[block_key] < self._max_iterations:
323
- return True, state
326
+ return None, state
324
327
  else:
325
328
  return False, state
326
329
 
@@ -176,6 +176,9 @@ class SimEngineRDVEX(
176
176
  return
177
177
  self.state.kill_and_add_definition(reg, data)
178
178
 
179
+ def _handle_PutI(self, stmt):
180
+ pass
181
+
179
182
  # e.g. STle(t6) = t21, t6 and/or t21 might include multiple values
180
183
  def _handle_Store(self, stmt):
181
184
  addr = self._expr(stmt.addr)
@@ -404,6 +407,9 @@ class SimEngineRDVEX(
404
407
 
405
408
  return values
406
409
 
410
+ def _handle_GetI(self, expr: pyvex.IRExpr.GetI) -> MultiValues:
411
+ return MultiValues(self.state.top(expr.result_size(self.tyenv)))
412
+
407
413
  # e.g. t27 = LDle:I64(t9), t9 might include multiple values
408
414
  # caution: Is also called from StoreG
409
415
  def _handle_Load(self, expr) -> MultiValues:
@@ -72,6 +72,7 @@ class ReachingDefinitionsState:
72
72
  "_track_consts",
73
73
  "_sp_adjusted",
74
74
  "exit_observed",
75
+ "_element_limit",
75
76
  )
76
77
 
77
78
  def __init__(
@@ -90,6 +91,7 @@ class ReachingDefinitionsState:
90
91
  sp_adjusted: bool = False,
91
92
  all_definitions: Optional[Set[Definition]] = None,
92
93
  initializer: Optional["RDAStateInitializer"] = None,
94
+ element_limit: int = 5,
93
95
  ):
94
96
  # handy short-hands
95
97
  self.codeloc = codeloc
@@ -100,6 +102,7 @@ class ReachingDefinitionsState:
100
102
  self.analysis = analysis
101
103
  self._canonical_size: int = canonical_size
102
104
  self._sp_adjusted: bool = sp_adjusted
105
+ self._element_limit: int = element_limit
103
106
 
104
107
  self.all_definitions: Set[Definition] = set() if all_definitions is None else all_definitions
105
108
 
@@ -122,7 +125,10 @@ class ReachingDefinitionsState:
122
125
  if live_definitions is None:
123
126
  # the first time this state is created. initialize it
124
127
  self.live_definitions = LiveDefinitions(
125
- self.arch, track_tmps=self._track_tmps, canonical_size=canonical_size
128
+ self.arch,
129
+ track_tmps=self._track_tmps,
130
+ canonical_size=canonical_size,
131
+ element_limit=element_limit,
126
132
  )
127
133
  if self.analysis is not None:
128
134
  self.live_definitions.project = self.analysis.project
@@ -310,6 +316,7 @@ class ReachingDefinitionsState:
310
316
  environment=self._environment,
311
317
  sp_adjusted=self._sp_adjusted,
312
318
  all_definitions=self.all_definitions.copy(),
319
+ element_limit=self._element_limit,
313
320
  )
314
321
 
315
322
  return rd
@@ -323,6 +330,12 @@ class ReachingDefinitionsState:
323
330
 
324
331
  return state, merged_0 or merged_1
325
332
 
333
+ def compare(self, other: "ReachingDefinitionsState") -> bool:
334
+ r0 = self.live_definitions.compare(other.live_definitions)
335
+ r1 = self.environment.compare(other.environment)
336
+
337
+ return r0 and r1
338
+
326
339
  def move_codelocs(self, new_codeloc: CodeLocation) -> None:
327
340
  if self.codeloc != new_codeloc:
328
341
  self.codeloc = new_codeloc
@@ -55,7 +55,7 @@ class ReachingDefinitionsAnalysis(
55
55
  self,
56
56
  subject: Union[Subject, ailment.Block, Block, Function, str] = None,
57
57
  func_graph=None,
58
- max_iterations=3,
58
+ max_iterations=30,
59
59
  track_tmps=False,
60
60
  track_consts=True,
61
61
  observation_points: "Iterable[ObservationPoint]" = None,
@@ -74,6 +74,7 @@ class ReachingDefinitionsAnalysis(
74
74
  interfunction_level: int = 0,
75
75
  track_liveness: bool = True,
76
76
  func_addr: Optional[int] = None,
77
+ element_limit: int = 5,
77
78
  ):
78
79
  """
79
80
  :param subject: The subject of the analysis: a function, or a single basic block
@@ -131,6 +132,7 @@ class ReachingDefinitionsAnalysis(
131
132
  self._canonical_size = canonical_size
132
133
  self._use_callee_saved_regs_at_return = use_callee_saved_regs_at_return
133
134
  self._func_addr = func_addr
135
+ self._element_limit = element_limit
134
136
 
135
137
  if dep_graph is None or dep_graph is False:
136
138
  self._dep_graph = None
@@ -469,13 +471,28 @@ class ReachingDefinitionsAnalysis(
469
471
  analysis=self,
470
472
  canonical_size=self._canonical_size,
471
473
  initializer=self._state_initializer,
474
+ element_limit=self._element_limit,
472
475
  )
473
476
 
474
477
  # pylint: disable=no-self-use,arguments-differ
475
478
  def _merge_states(self, _node, *states: ReachingDefinitionsState):
479
+ assert len(states) >= 2
476
480
  merged_state, merge_occurred = states[0].merge(*states[1:])
477
481
  return merged_state, not merge_occurred
478
482
 
483
+ def _compare_states(self, node, old_state: ReachingDefinitionsState, new_state: ReachingDefinitionsState) -> bool:
484
+ """
485
+ Return True if new_state >= old_state in the lattice.
486
+
487
+ :param node:
488
+ :param old_state:
489
+ :param new_state:
490
+ :return:
491
+ """
492
+
493
+ reached_fixedpoint = new_state.compare(old_state)
494
+ return reached_fixedpoint
495
+
479
496
  def _run_on_node(self, node, state: ReachingDefinitionsState):
480
497
  """
481
498
 
@@ -550,7 +567,7 @@ class ReachingDefinitionsAnalysis(
550
567
  state.downsize()
551
568
 
552
569
  if self._node_iterations[block_key] < self._max_iterations:
553
- return True, state
570
+ return None, state
554
571
  else:
555
572
  return False, state
556
573
 
@@ -469,20 +469,20 @@ class SimEngineVRAIL(
469
469
 
470
470
  r0 = self._expr(arg0)
471
471
  r1 = self._expr(arg1)
472
- from_size = r1.bits
473
- to_size = r0.bits
472
+ from_size = expr.from_bits
473
+ to_size = expr.to_bits
474
474
 
475
475
  if expr.signed:
476
- quotient = r0.data.SDiv(claripy.SignExt(to_size - from_size, r1.data))
477
- remainder = r0.data.SMod(claripy.SignExt(to_size - from_size, r1.data))
476
+ quotient = r0.data.SDiv(claripy.SignExt(from_size - to_size, r1.data))
477
+ remainder = r0.data.SMod(claripy.SignExt(from_size - to_size, r1.data))
478
478
  quotient_size = to_size
479
479
  remainder_size = to_size
480
480
  r = claripy.Concat(
481
481
  claripy.Extract(remainder_size - 1, 0, remainder), claripy.Extract(quotient_size - 1, 0, quotient)
482
482
  )
483
483
  else:
484
- quotient = r0.data // claripy.ZeroExt(to_size - from_size, r1.data)
485
- remainder = r0.data % claripy.ZeroExt(to_size - from_size, r1.data)
484
+ quotient = r0.data // claripy.ZeroExt(from_size - to_size, r1.data)
485
+ remainder = r0.data % claripy.ZeroExt(from_size - to_size, r1.data)
486
486
  quotient_size = to_size
487
487
  remainder_size = to_size
488
488
  r = claripy.Concat(
@@ -61,6 +61,9 @@ class SimEngineVRVEX(
61
61
  return
62
62
  self._assign_to_register(offset, r, size)
63
63
 
64
+ def _handle_PutI(self, stmt):
65
+ pass
66
+
64
67
  def _handle_Store(self, stmt):
65
68
  addr_r = self._expr(stmt.addr)
66
69
  size = stmt.data.result_size(self.tyenv) // 8
@@ -159,6 +162,9 @@ class SimEngineVRVEX(
159
162
  create_variable=self.stmt_idx not in self.reg_read_stmts_to_ignore,
160
163
  )
161
164
 
165
+ def _handle_GetI(self, expr: pyvex.IRExpr.GetI):
166
+ return RichR(self.state.top(expr.result_size(self.tyenv)))
167
+
162
168
  def _handle_Load(self, expr: pyvex.IRExpr.Load) -> RichR:
163
169
  addr = self._expr(expr.addr)
164
170
  size = expr.result_size(self.tyenv) // 8
@@ -33,6 +33,12 @@ class VEXIRSBScanner(SimEngineLightVEXMixin):
33
33
  self.reg_read_stmt_id: Dict[int, int] = {}
34
34
  self.reg_read_stmts_to_ignore: Set[int] = set()
35
35
 
36
+ def _top(self, size: int):
37
+ return None
38
+
39
+ def _is_top(self, expr) -> bool:
40
+ return True
41
+
36
42
  def _process_Stmt(self, whitelist=None):
37
43
  self.tmps_with_64bit_regs = set()
38
44
  self.tmps_assignment_stmtidx = {}
@@ -55,6 +61,9 @@ class VEXIRSBScanner(SimEngineLightVEXMixin):
55
61
  self.reg_read_stmts_to_ignore.add(self.reg_read_stmt_id[old_reg_offset])
56
62
  self.reg_with_reg_as_value[stmt.offset] = self.tmp_with_reg_as_value[stmt.data.tmp]
57
63
 
64
+ def _handle_PutI(self, stmt):
65
+ pass
66
+
58
67
  def _handle_Load(self, expr):
59
68
  pass
60
69
 
@@ -85,6 +94,9 @@ class VEXIRSBScanner(SimEngineLightVEXMixin):
85
94
  if expr.offset in self.reg_with_reg_as_value:
86
95
  del self.reg_with_reg_as_value[expr.offset]
87
96
 
97
+ def _handle_GetI(self, expr):
98
+ pass
99
+
88
100
  def _handle_RdTmp(self, expr):
89
101
  if expr.tmp in self.tmps_converted_to_32bit:
90
102
  self.tmps_converted_to_32bit.remove(expr.tmp)
@@ -175,6 +175,7 @@ class VariableRecoveryStateBase:
175
175
  self.stack_region: MultiValuedMemory = MultiValuedMemory(
176
176
  memory_id="mem",
177
177
  top_func=self.top,
178
+ is_top_func=self.is_top,
178
179
  phi_maker=self._make_phi_variable,
179
180
  skip_missing_values_during_merging=True,
180
181
  page_kwargs={"mo_cmp": self._mo_cmp},
@@ -188,6 +189,7 @@ class VariableRecoveryStateBase:
188
189
  self.register_region: MultiValuedMemory = MultiValuedMemory(
189
190
  memory_id="reg",
190
191
  top_func=self.top,
192
+ is_top_func=self.is_top,
191
193
  phi_maker=self._make_phi_variable,
192
194
  skip_missing_values_during_merging=True,
193
195
  page_kwargs={"mo_cmp": self._mo_cmp},
@@ -201,6 +203,7 @@ class VariableRecoveryStateBase:
201
203
  self.global_region: MultiValuedMemory = MultiValuedMemory(
202
204
  memory_id="mem",
203
205
  top_func=self.top,
206
+ is_top_func=self.is_top,
204
207
  phi_maker=self._make_phi_variable,
205
208
  skip_missing_values_during_merging=True,
206
209
  page_kwargs={"mo_cmp": self._mo_cmp},
@@ -215,7 +218,7 @@ class VariableRecoveryStateBase:
215
218
  self.type_constraints = defaultdict(set) if type_constraints is None else type_constraints
216
219
  self.func_typevar = func_typevar
217
220
  self.delayed_type_constraints = (
218
- DefaultChainMapCOW(set, collapse_threshold=25)
221
+ DefaultChainMapCOW(default_factory=set, collapse_threshold=25)
219
222
  if delayed_type_constraints is None
220
223
  else delayed_type_constraints
221
224
  )
@@ -239,10 +239,55 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
239
239
  return None
240
240
 
241
241
  def _handle_Triop(self, expr: pyvex.IRExpr.Triop): # pylint: disable=useless-return
242
- if self.l is not None:
242
+ handler = None
243
+ if expr.op.startswith("Iop_AddF"):
244
+ handler = "_handle_AddF"
245
+ elif expr.op.startswith("Iop_SubF"):
246
+ handler = "_handle_AddF"
247
+ elif expr.op.startswith("Iop_MulF"):
248
+ handler = "_handle_MulF"
249
+ elif expr.op.startswith("Iop_DivF"):
250
+ handler = "_handle_DivF"
251
+ elif expr.op.startswith("Iop_SinF"):
252
+ handler = "_handle_SinF"
253
+ elif expr.op.startswith("Iop_ScaleF"):
254
+ handler = "_handle_ScaleF"
255
+
256
+ if handler is not None and hasattr(self, handler):
257
+ return getattr(self, handler)(expr)
258
+
259
+ if once(expr.op) and self.l is not None:
243
260
  self.l.error("Unsupported Triop %s.", expr.op)
261
+
244
262
  return None
245
263
 
264
+ def _handle_AddF(self, expr):
265
+ return self._top(expr.result_size(self.tyenv))
266
+
267
+ def _handle_SubF(self, expr):
268
+ return self._top(expr.result_size(self.tyenv))
269
+
270
+ def _handle_MulF(self, expr):
271
+ return self._top(expr.result_size(self.tyenv))
272
+
273
+ def _handle_DivF(self, expr):
274
+ return self._top(expr.result_size(self.tyenv))
275
+
276
+ def _handle_NegF(self, expr):
277
+ return self._top(expr.result_size(self.tyenv))
278
+
279
+ def _handle_AbsF(self, expr):
280
+ return self._top(expr.result_size(self.tyenv))
281
+
282
+ def _handle_SinF(self, expr):
283
+ return self._top(expr.result_size(self.tyenv))
284
+
285
+ def _handle_CosF(self, expr):
286
+ return self._top(expr.result_size(self.tyenv))
287
+
288
+ def _handle_ScaleF(self, expr):
289
+ return self._top(expr.result_size(self.tyenv))
290
+
246
291
  def _handle_RdTmp(self, expr):
247
292
  tmp = expr.tmp
248
293
 
@@ -294,6 +339,10 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
294
339
  handler = "_handle_Clz"
295
340
  elif expr.op.startswith("Iop_Ctz"):
296
341
  handler = "_handle_Ctz"
342
+ elif expr.op.startswith("Iop_NegF"):
343
+ handler = "_handle_NegF"
344
+ elif expr.op.startswith("Iop_AbsF"):
345
+ handler = "_handle_AbsF"
297
346
 
298
347
  if handler is not None and hasattr(self, handler):
299
348
  return getattr(self, handler)(expr)
@@ -361,6 +410,10 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
361
410
  handler = "_handle_16HLto32"
362
411
  elif expr.op.startswith("Iop_ExpCmpNE64"):
363
412
  handler = "_handle_ExpCmpNE64"
413
+ elif expr.op.startswith("Iop_SinF"):
414
+ handler = "_handle_SinF"
415
+ elif expr.op.startswith("Iop_CosF"):
416
+ handler = "_handle_CosF"
364
417
 
365
418
  vector_size, vector_count = None, None
366
419
  if handler is not None:
@@ -539,6 +592,10 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
539
592
 
540
593
  return expr_0 * expr_1
541
594
 
595
+ def _handle_Mull(self, expr):
596
+ self._binop_get_args(expr)
597
+ return self._top(expr.result_size(self.tyenv))
598
+
542
599
  def _handle_DivMod(self, expr):
543
600
  args, r = self._binop_get_args(expr)
544
601
  if args is None:
@@ -938,35 +995,47 @@ class SimEngineLightAILMixin(SimEngineLightMixin):
938
995
  return expr
939
996
 
940
997
  def _ail_handle_UnaryOp(self, expr):
941
- handler_name = "_ail_handle_%s" % expr.op
998
+ handler_name = f"_handle_{expr.op}"
942
999
  try:
943
1000
  handler = getattr(self, handler_name)
944
1001
  except AttributeError:
945
- if self.l is not None:
946
- self.l.warning("Unsupported UnaryOp %s.", expr.op)
947
- return None
1002
+ handler_name = "_ail_handle_%s" % expr.op
1003
+ try:
1004
+ handler = getattr(self, handler_name)
1005
+ except AttributeError:
1006
+ if self.l is not None:
1007
+ self.l.warning("Unsupported UnaryOp %s.", expr.op)
1008
+ return None
948
1009
 
949
1010
  return handler(expr)
950
1011
 
951
1012
  def _ail_handle_BinaryOp(self, expr):
952
- handler_name = "_ail_handle_%s" % expr.op
1013
+ handler_name = f"_handle_{expr.op}"
953
1014
  try:
954
1015
  handler = getattr(self, handler_name)
955
1016
  except AttributeError:
956
- if self.l is not None:
957
- self.l.warning("Unsupported BinaryOp %s.", expr.op)
958
- return None
1017
+ handler_name = "_ail_handle_%s" % expr.op
1018
+ try:
1019
+ handler = getattr(self, handler_name)
1020
+ except AttributeError:
1021
+ if self.l is not None:
1022
+ self.l.warning("Unsupported BinaryOp %s.", expr.op)
1023
+ return None
959
1024
 
960
1025
  return handler(expr)
961
1026
 
962
1027
  def _ail_handle_TernaryOp(self, expr):
963
- handler_name = "_ail_handle_%s" % expr.op
1028
+ handler_name = f"_handle_{expr.op}"
964
1029
  try:
965
1030
  handler = getattr(self, handler_name)
966
1031
  except AttributeError:
967
- if self.l is not None:
968
- self.l.warning("Unsupported Ternary %s.", expr.op)
969
- return None
1032
+ handler_name = "_ail_handle_%s" % expr.op
1033
+ try:
1034
+ handler = getattr(self, handler_name)
1035
+ except AttributeError:
1036
+ if self.l is not None:
1037
+ self.l.warning("Unsupported Ternary %s.", expr.op)
1038
+ return None
970
1039
 
971
1040
  return handler(expr)
972
1041
 
@@ -974,6 +1043,44 @@ class SimEngineLightAILMixin(SimEngineLightMixin):
974
1043
  # Binary operation handlers
975
1044
  #
976
1045
 
1046
+ def _ail_handle_CmpEQ(self, expr):
1047
+ arg0, arg1 = expr.operands
1048
+
1049
+ expr_0 = self._expr(arg0)
1050
+ expr_1 = self._expr(arg1)
1051
+ if expr_0 is None:
1052
+ expr_0 = arg0
1053
+ if expr_1 is None:
1054
+ expr_1 = arg1
1055
+
1056
+ try:
1057
+ if isinstance(expr_0, ailment.Expr.Const) and isinstance(expr_1, ailment.Expr.Const):
1058
+ if expr_0.value == expr_1.value:
1059
+ return ailment.Expr.Const(None, None, 1, 1)
1060
+ return ailment.Expr.Const(None, None, 0, 1)
1061
+ except TypeError:
1062
+ pass
1063
+ return ailment.Expr.BinaryOp(expr.idx, "CmpEQ", [expr_0, expr_1], expr.signed, **expr.tags)
1064
+
1065
+ def _ail_handle_CmpNE(self, expr):
1066
+ arg0, arg1 = expr.operands
1067
+
1068
+ expr_0 = self._expr(arg0)
1069
+ expr_1 = self._expr(arg1)
1070
+ if expr_0 is None:
1071
+ expr_0 = arg0
1072
+ if expr_1 is None:
1073
+ expr_1 = arg1
1074
+
1075
+ try:
1076
+ if isinstance(expr_0, ailment.Expr.Const) and isinstance(expr_1, ailment.Expr.Const):
1077
+ if expr_0.value != expr_1.value:
1078
+ return ailment.Expr.Const(None, None, 1, 1)
1079
+ return ailment.Expr.Const(None, None, 0, 1)
1080
+ except TypeError:
1081
+ pass
1082
+ return ailment.Expr.BinaryOp(expr.idx, "CmpNE", [expr_0, expr_1], expr.signed, **expr.tags)
1083
+
977
1084
  def _ail_handle_CmpLT(self, expr):
978
1085
  arg0, arg1 = expr.operands
979
1086
 
@@ -985,9 +1092,13 @@ class SimEngineLightAILMixin(SimEngineLightMixin):
985
1092
  expr_1 = arg1
986
1093
 
987
1094
  try:
988
- return expr_0 <= expr_1
1095
+ if isinstance(expr_0, ailment.Expr.Const) and isinstance(expr_1, ailment.Expr.Const):
1096
+ if expr_0.value < expr_1.value:
1097
+ return ailment.Expr.Const(None, None, 1, 1)
1098
+ return ailment.Expr.Const(None, None, 0, 1)
989
1099
  except TypeError:
990
- return ailment.Expr.BinaryOp(expr.idx, "CmpLT", [expr_0, expr_1], expr.signed, **expr.tags)
1100
+ pass
1101
+ return ailment.Expr.BinaryOp(expr.idx, "CmpLT", [expr_0, expr_1], expr.signed, **expr.tags)
991
1102
 
992
1103
  def _ail_handle_Add(self, expr):
993
1104
  arg0, arg1 = expr.operands
@@ -1078,7 +1189,14 @@ class SimEngineLightAILMixin(SimEngineLightMixin):
1078
1189
  expr_1 = arg1
1079
1190
 
1080
1191
  return ailment.Expr.BinaryOp(
1081
- expr.idx, "DivMod", [expr_0, expr_1], expr.signed, bits=expr_0.bits * 2, **expr.tags
1192
+ expr.idx,
1193
+ "DivMod",
1194
+ [expr_0, expr_1],
1195
+ expr.signed,
1196
+ bits=expr.bits,
1197
+ from_bits=expr.from_bits,
1198
+ to_bits=expr.to_bits,
1199
+ **expr.tags,
1082
1200
  )
1083
1201
 
1084
1202
  def _ail_handle_Mod(self, expr):
@@ -1535,6 +1535,10 @@ class Function(Serializable):
1535
1535
 
1536
1536
  for library in libraries:
1537
1537
  for name in name_variants:
1538
+ if isinstance(library, SimSyscallLibrary):
1539
+ # FIXME: we don't support getting declaration from a syscall library yet. we don't have the concept
1540
+ # of abi at this point.
1541
+ continue
1538
1542
  if not library.has_prototype(name):
1539
1543
  continue
1540
1544
 
@@ -14,6 +14,8 @@ class Environment:
14
14
  **Note**: The <Environment> object does not store the values associated with variables themselves.
15
15
  """
16
16
 
17
+ __slots__ = ("_environment",)
18
+
17
19
  def __init__(self, environment: Dict[Union[str, Undefined], Set[claripy.ast.Base]] = None):
18
20
  self._environment: Dict[Union[str, Undefined], Set[claripy.ast.Base]] = environment or {}
19
21
 
@@ -81,3 +83,12 @@ class Environment:
81
83
 
82
84
  merge_occurred = new_env != self._environment
83
85
  return Environment(environment=new_env), merge_occurred
86
+
87
+ def compare(self, other: "Environment") -> bool:
88
+ for k in set(self._environment.keys()).union(set(other._environment.keys())):
89
+ if k not in self._environment:
90
+ return False
91
+ if k in self._environment and k in other._environment:
92
+ if not self._environment[k].issuperset(other._environment[k]):
93
+ return False
94
+ return True