angr 9.2.93__py3-none-manylinux2014_x86_64.whl → 9.2.94__py3-none-manylinux2014_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 (33) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/cfg/cfg_base.py +20 -10
  3. angr/analyses/cfg/indirect_jump_resolvers/amd64_elf_got.py +1 -1
  4. angr/analyses/cfg/indirect_jump_resolvers/arm_elf_fast.py +89 -32
  5. angr/analyses/decompiler/ail_simplifier.py +20 -0
  6. angr/analyses/decompiler/callsite_maker.py +5 -0
  7. angr/analyses/decompiler/clinic.py +103 -1
  8. angr/analyses/decompiler/decompilation_cache.py +2 -0
  9. angr/analyses/decompiler/decompiler.py +21 -4
  10. angr/analyses/decompiler/optimization_passes/code_motion.py +8 -3
  11. angr/analyses/decompiler/optimization_passes/optimization_pass.py +1 -0
  12. angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +30 -18
  13. angr/analyses/decompiler/peephole_optimizations/bswap.py +53 -2
  14. angr/analyses/decompiler/peephole_optimizations/eager_eval.py +20 -1
  15. angr/analyses/decompiler/structured_codegen/c.py +56 -40
  16. angr/analyses/propagator/engine_ail.py +3 -0
  17. angr/analyses/reaching_definitions/engine_ail.py +3 -0
  18. angr/analyses/reaching_definitions/reaching_definitions.py +7 -0
  19. angr/analyses/stack_pointer_tracker.py +60 -10
  20. angr/analyses/typehoon/simple_solver.py +19 -16
  21. angr/calling_conventions.py +0 -3
  22. angr/engines/pcode/cc.py +1 -1
  23. angr/engines/successors.py +6 -0
  24. angr/knowledge_plugins/propagations/states.py +2 -1
  25. angr/procedures/definitions/glibc.py +3 -1
  26. angr/sim_type.py +2 -0
  27. angr/utils/library.py +1 -1
  28. {angr-9.2.93.dist-info → angr-9.2.94.dist-info}/METADATA +6 -6
  29. {angr-9.2.93.dist-info → angr-9.2.94.dist-info}/RECORD +33 -33
  30. {angr-9.2.93.dist-info → angr-9.2.94.dist-info}/WHEEL +1 -1
  31. {angr-9.2.93.dist-info → angr-9.2.94.dist-info}/LICENSE +0 -0
  32. {angr-9.2.93.dist-info → angr-9.2.94.dist-info}/entry_points.txt +0 -0
  33. {angr-9.2.93.dist-info → angr-9.2.94.dist-info}/top_level.txt +0 -0
@@ -3,7 +3,6 @@ from typing import Optional, Dict, List, Tuple, Set, Any, Union, TYPE_CHECKING,
3
3
  from collections import defaultdict
4
4
  import logging
5
5
  import struct
6
- from functools import reduce
7
6
 
8
7
  from ailment import Block, Expr, Stmt, Tmp
9
8
  from ailment.expression import StackBaseOffset, BinaryOp
@@ -587,7 +586,7 @@ class CFunction(CConstruct): # pylint:disable=abstract-method
587
586
  yield " ", None
588
587
  # function name
589
588
  if self.demangled_name and self.show_demangled_name:
590
- normalized_name = get_cpp_function_name(self.demangled_name, specialized=False, qualified=False)
589
+ normalized_name = get_cpp_function_name(self.demangled_name, specialized=False, qualified=True)
591
590
  else:
592
591
  normalized_name = self.name
593
592
  yield normalized_name, self
@@ -2184,29 +2183,24 @@ class CConstant(CExpression):
2184
2183
 
2185
2184
  if self.fmt_float:
2186
2185
  if 0 < value <= 0xFFFF_FFFF:
2187
- str_value = str(struct.unpack("f", struct.pack("I", value))[0])
2188
- return str_value
2186
+ return str(struct.unpack("f", struct.pack("I", value))[0])
2187
+
2188
+ if self.fmt_char:
2189
+ if value < 0:
2190
+ value += 2**self._type.size
2191
+ value &= 0xFF
2192
+ return repr(chr(value)) if value < 0x80 else f"'\\x{value:x}'"
2189
2193
 
2190
2194
  if self.fmt_neg:
2191
2195
  if value > 0:
2192
- value = value - 2**self._type.size
2196
+ value -= 2**self._type.size
2193
2197
  elif value < 0:
2194
- value = value + 2**self._type.size
2195
-
2196
- str_value = None
2197
- if self.fmt_char:
2198
- try:
2199
- str_value = f"'{chr(value)}'"
2200
- except ValueError:
2201
- str_value = None
2198
+ value += 2**self._type.size
2202
2199
 
2203
- if str_value is None:
2204
- if self.fmt_hex:
2205
- str_value = hex(value)
2206
- else:
2207
- str_value = str(value)
2200
+ if self.fmt_hex:
2201
+ return hex(value)
2208
2202
 
2209
- return str_value
2203
+ return str(value)
2210
2204
 
2211
2205
 
2212
2206
  class CRegister(CExpression):
@@ -2609,6 +2603,15 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
2609
2603
  if isinstance(var, CVariable):
2610
2604
  var.variable_type = self._get_variable_type(var.variable, is_global=True)
2611
2605
 
2606
+ for cvar in self.cfunc.arg_list:
2607
+ vartype = self._get_variable_type(
2608
+ cvar.variable,
2609
+ is_global=isinstance(cvar.variable, SimMemoryVariable)
2610
+ and not isinstance(cvar.variable, SimStackVariable),
2611
+ )
2612
+ if vartype is not None:
2613
+ cvar.variable_type = vartype.with_arch(self.project.arch)
2614
+
2612
2615
  #
2613
2616
  # Util methods
2614
2617
  #
@@ -2842,30 +2845,40 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
2842
2845
  if len(o_terms) == 0:
2843
2846
  # probably a plain integer, return as is
2844
2847
  return expr
2845
- result = reduce(
2846
- lambda a1, a2: CBinaryOp("Add", a1, a2, codegen=self),
2847
- (
2848
- (
2849
- CBinaryOp(
2850
- "Mul",
2851
- CConstant(c, t.type, codegen=self),
2852
- (
2853
- t
2854
- if not isinstance(t.type, SimTypePointer)
2855
- else CTypeCast(t.type, SimTypePointer(SimTypeChar()), t, codegen=self)
2856
- ),
2857
- codegen=self,
2858
- )
2859
- if c != 1
2860
- else (
2848
+ result = None
2849
+ pointer_length_int_type = (
2850
+ SimTypeLongLong(signed=False) if self.project.arch.bits == 64 else SimTypeInt(signed=False)
2851
+ )
2852
+ for c, t in o_terms:
2853
+ op = "Add"
2854
+ if c == -1 and result is not None:
2855
+ op = "Sub"
2856
+ piece = (
2857
+ t
2858
+ if not isinstance(t.type, SimTypePointer)
2859
+ else CTypeCast(t.type, SimTypePointer(SimTypeChar()), t, codegen=self)
2860
+ )
2861
+ elif c == 1:
2862
+ piece = (
2863
+ t
2864
+ if not isinstance(t.type, SimTypePointer)
2865
+ else CTypeCast(t.type, SimTypePointer(SimTypeChar()), t, codegen=self)
2866
+ )
2867
+ else:
2868
+ piece = CBinaryOp(
2869
+ "Mul",
2870
+ CConstant(c, t.type, codegen=self),
2871
+ (
2861
2872
  t
2862
2873
  if not isinstance(t.type, SimTypePointer)
2863
- else CTypeCast(t.type, SimTypePointer(SimTypeChar()), t, codegen=self)
2864
- )
2874
+ else CTypeCast(t.type, pointer_length_int_type, t, codegen=self)
2875
+ ),
2876
+ codegen=self,
2865
2877
  )
2866
- for c, t in o_terms
2867
- ),
2868
- )
2878
+ if result is None:
2879
+ result = piece
2880
+ else:
2881
+ result = CBinaryOp(op, result, piece, codegen=self)
2869
2882
  if o_constant != 0:
2870
2883
  result = CBinaryOp("Add", CConstant(o_constant, SimTypeInt(), codegen=self), result, codegen=self)
2871
2884
 
@@ -2888,6 +2901,9 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
2888
2901
  if kernel is not None:
2889
2902
  l.warning("Summing two different pointers together. Uh oh!")
2890
2903
  return bail_out()
2904
+ if c == -1:
2905
+ # legit case: you can deduct a pointer from another pointer and get an integer as result in C
2906
+ return bail_out()
2891
2907
  if c != 1:
2892
2908
  l.warning("Multiplying a pointer by a constant??")
2893
2909
  return bail_out()
@@ -1148,6 +1148,9 @@ class SimEnginePropagatorAIL(
1148
1148
  )
1149
1149
  return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1150
1150
 
1151
+ _ail_handle_AddV = _ail_handle_Add
1152
+ _ail_handle_MulV = _ail_handle_Mul
1153
+
1151
1154
  def _ail_handle_Mull(self, expr):
1152
1155
  o0_value = self._expr(expr.operands[0])
1153
1156
  o1_value = self._expr(expr.operands[1])
@@ -728,6 +728,9 @@ class SimEngineRDAIL(
728
728
  r = MultiValues(self.state.top(bits))
729
729
  return r
730
730
 
731
+ _ail_handle_AddV = _ail_handle_Add
732
+ _ail_handle_MulV = _ail_handle_Mul
733
+
731
734
  def _ail_handle_Mull(self, expr):
732
735
  arg0, arg1 = expr.operands
733
736
 
@@ -539,6 +539,13 @@ class ReachingDefinitionsAnalysis(
539
539
  for use in [state.stack_uses, state.heap_uses, state.register_uses, state.memory_uses]:
540
540
  self.all_uses.merge(use)
541
541
 
542
+ if self._track_tmps:
543
+ # merge tmp uses to all_uses
544
+ for tmp_idx, locs in state.tmp_uses.items():
545
+ tmp_def = next(iter(state.tmps[tmp_idx]))
546
+ for loc in locs:
547
+ self.all_uses.add_use(tmp_def, loc)
548
+
542
549
  # drop definitions and uses because we will not need them anymore
543
550
  state.downsize()
544
551
 
@@ -3,6 +3,7 @@
3
3
  from typing import Set, List, Optional, TYPE_CHECKING
4
4
  import re
5
5
  import logging
6
+ from collections import defaultdict
6
7
 
7
8
  import pyvex
8
9
 
@@ -148,6 +149,21 @@ class OffsetVal:
148
149
  return f"reg({self.reg}){(self.offset - 2**self.reg.bitlen) if self.offset != 0 else 0:+}"
149
150
 
150
151
 
152
+ class Eq:
153
+ """
154
+ Represent an equivalence condition.
155
+ """
156
+
157
+ __slots__ = ("val0", "val1")
158
+
159
+ def __init__(self, val0, val1):
160
+ self.val0 = val0
161
+ self.val1 = val1
162
+
163
+ def __hash__(self):
164
+ return hash((type(self), self.val0, self.val1))
165
+
166
+
151
167
  class FrozenStackPointerTrackerState:
152
168
  """
153
169
  Abstract state for StackPointerTracker analysis with registers and memory values being in frozensets.
@@ -296,7 +312,12 @@ class StackPointerTracker(Analysis, ForwardAnalysis):
296
312
  """
297
313
 
298
314
  def __init__(
299
- self, func: Optional[Function], reg_offsets: Set[int], block: Optional["Block"] = None, track_memory=True
315
+ self,
316
+ func: Optional[Function],
317
+ reg_offsets: Set[int],
318
+ block: Optional["Block"] = None,
319
+ track_memory=True,
320
+ cross_insn_opt=True,
300
321
  ):
301
322
  if func is not None:
302
323
  if not func.normalized:
@@ -316,6 +337,8 @@ class StackPointerTracker(Analysis, ForwardAnalysis):
316
337
  self.reg_offsets = reg_offsets
317
338
  self.states = {}
318
339
  self._blocks = {}
340
+ self._reg_value_at_block_start = defaultdict(dict)
341
+ self.cross_insn_opt = cross_insn_opt
319
342
 
320
343
  _l.debug("Running on function %r", self._func)
321
344
  self._analyze()
@@ -468,7 +491,7 @@ class StackPointerTracker(Analysis, ForwardAnalysis):
468
491
  self._set_state(addr, new_val, "pre")
469
492
 
470
493
  def _run_on_node(self, node: BlockNode, state):
471
- block = self.project.factory.block(node.addr, size=node.size)
494
+ block = self.project.factory.block(node.addr, size=node.size, cross_insn_opt=self.cross_insn_opt)
472
495
  self._blocks[node.addr] = block
473
496
 
474
497
  state = state.unfreeze()
@@ -483,6 +506,10 @@ class StackPointerTracker(Analysis, ForwardAnalysis):
483
506
  except SimTranslationError:
484
507
  pass
485
508
 
509
+ if node.addr in self._reg_value_at_block_start:
510
+ for reg, val in self._reg_value_at_block_start[node.addr].items():
511
+ state.put(reg, val)
512
+
486
513
  if vex_block is not None:
487
514
  if isinstance(vex_block, pyvex.IRSB):
488
515
  curr_stmt_start_addr = self._process_vex_irsb(node, vex_block, state)
@@ -548,7 +575,12 @@ class StackPointerTracker(Analysis, ForwardAnalysis):
548
575
  and is_alignment_mask(arg1_expr.val)
549
576
  ):
550
577
  return arg0_expr
551
- raise CouldNotResolveException()
578
+ elif expr.op.startswith("Iop_CmpEQ"):
579
+ arg0_expr = _resolve_expr(arg0)
580
+ arg1_expr = _resolve_expr(arg1)
581
+ if isinstance(arg0_expr, (Register, OffsetVal)) and isinstance(arg1_expr, (Register, OffsetVal)):
582
+ return Eq(arg0_expr, arg1_expr)
583
+ raise CouldNotResolveException()
552
584
  elif type(expr) is pyvex.IRExpr.RdTmp and expr.tmp in tmps and tmps[expr.tmp] is not None:
553
585
  return tmps[expr.tmp]
554
586
  elif type(expr) is pyvex.IRExpr.Const:
@@ -563,13 +595,15 @@ class StackPointerTracker(Analysis, ForwardAnalysis):
563
595
  to_bits = int(m.group(3))
564
596
  # to_unsigned = m.group(4) == "U"
565
597
  v = resolve_expr(expr.args[0])
566
- if not isinstance(v, Constant):
567
- return TOP
568
- if from_bits > to_bits:
569
- # truncation
570
- mask = (1 << to_bits) - 1
571
- return Constant(v.val & mask)
572
- return v
598
+ if isinstance(v, Constant):
599
+ if from_bits > to_bits:
600
+ # truncation
601
+ mask = (1 << to_bits) - 1
602
+ return Constant(v.val & mask)
603
+ return v
604
+ elif isinstance(v, Eq):
605
+ return v
606
+ return TOP
573
607
  elif self.track_mem and type(expr) is pyvex.IRExpr.Load:
574
608
  return state.load(_resolve_expr(expr.addr))
575
609
  raise CouldNotResolveException()
@@ -606,6 +640,22 @@ class StackPointerTracker(Analysis, ForwardAnalysis):
606
640
  and vex_block.instruction_addresses.index(curr_stmt_start_addr) == vex_block.instructions - 1
607
641
  ):
608
642
  exit_observed = True
643
+ if (
644
+ type(stmt.guard) is pyvex.IRExpr.RdTmp
645
+ and stmt.guard.tmp in tmps
646
+ and isinstance(stmt.dst, pyvex.IRConst.IRConst)
647
+ ):
648
+ guard = tmps[stmt.guard.tmp]
649
+ if isinstance(guard, Eq):
650
+ for reg, val in state.regs.items():
651
+ if reg in {self.project.arch.sp_offset, self.project.arch.bp_offset}:
652
+ cond = None
653
+ if val == guard.val0:
654
+ cond = guard.val1
655
+ elif val == guard.val1:
656
+ cond = guard.val0
657
+ if cond is not None:
658
+ self._reg_value_at_block_start[stmt.dst.value][reg] = cond
609
659
  else:
610
660
  try:
611
661
  resolve_stmt(stmt)
@@ -1079,6 +1079,8 @@ class SimpleSolver:
1079
1079
  last_labels.append(labels[-1])
1080
1080
 
1081
1081
  # now, what is this variable?
1082
+ result = None
1083
+
1082
1084
  if last_labels and all(isinstance(label, (FuncIn, FuncOut)) for label in last_labels):
1083
1085
  # create a dummy result and dump it to the cache
1084
1086
  func_type = Function([], [])
@@ -1117,22 +1119,8 @@ class SimpleSolver:
1117
1119
  for node in nodes:
1118
1120
  solution[node.typevar] = result
1119
1121
 
1120
- elif not path_and_successors:
1121
- # this is a primitive variable
1122
- lower_bound = Bottom_
1123
- upper_bound = Top_
1124
-
1125
- for node in nodes:
1126
- lower_bound = self.join(lower_bound, node.lower_bound)
1127
- upper_bound = self.meet(upper_bound, node.upper_bound)
1128
- # TODO: Support variables that are accessed via differently sized pointers
1129
-
1130
- result = lower_bound if not isinstance(lower_bound, BottomType) else upper_bound
1131
- for node in nodes:
1132
- solution[node.typevar] = result
1133
- self._solution_cache[node.typevar] = result
1134
-
1135
- else:
1122
+ elif path_and_successors:
1123
+ # maybe this is a pointer to a struct?
1136
1124
  if len(nodes) == 1:
1137
1125
  the_node = next(iter(nodes))
1138
1126
  if (
@@ -1204,6 +1192,21 @@ class SimpleSolver:
1204
1192
  for node in nodes:
1205
1193
  solution[node.typevar] = result
1206
1194
 
1195
+ if not path_and_successors or result in {Top_, None}:
1196
+ # this is probably a primitive variable
1197
+ lower_bound = Bottom_
1198
+ upper_bound = Top_
1199
+
1200
+ for node in nodes:
1201
+ lower_bound = self.join(lower_bound, node.lower_bound)
1202
+ upper_bound = self.meet(upper_bound, node.upper_bound)
1203
+ # TODO: Support variables that are accessed via differently sized pointers
1204
+
1205
+ result = lower_bound if not isinstance(lower_bound, BottomType) else upper_bound
1206
+ for node in nodes:
1207
+ solution[node.typevar] = result
1208
+ self._solution_cache[node.typevar] = result
1209
+
1207
1210
  # import pprint
1208
1211
 
1209
1212
  # print("Solution")
@@ -1774,9 +1774,6 @@ class SimCCARMHF(SimCCARM):
1774
1774
  RETURN_VAL = SimRegArg("r0", 4) # TODO Return val can also include reg r1
1775
1775
  ARCH = archinfo.ArchARMHF
1776
1776
 
1777
- def next_arg(self, session, arg_type):
1778
- return SimCC.next_arg(self, session, arg_type)
1779
-
1780
1777
 
1781
1778
  class SimCCARMLinuxSyscall(SimCCSyscall):
1782
1779
  # TODO: Make sure all the information is correct
angr/engines/pcode/cc.py CHANGED
@@ -43,7 +43,7 @@ class SimCCSPARC(SimCC):
43
43
  Default CC for SPARC
44
44
  """
45
45
 
46
- ARG_REGS = ["o0", "o1"]
46
+ ARG_REGS = ["o0", "o1", "o2", "o3", "o4", "o5"]
47
47
  RETURN_VAL = SimRegArg("o0", 8)
48
48
  RETURN_ADDR = SimRegArg("o7", 8)
49
49
 
@@ -271,6 +271,12 @@ class SimSuccessors:
271
271
  self.unsat_successors.append(state)
272
272
  elif o.NO_SYMBOLIC_JUMP_RESOLUTION in state.options and state.solver.symbolic(target):
273
273
  self.unconstrained_successors.append(state)
274
+ elif o.CALLLESS in state.options and state.history.jumpkind == "Ijk_Call" and state.solver.symbolic(target):
275
+ # If CALLESS is set, even a symbolic call target is allowed, because we don't want to resolve the target
276
+ # anyway
277
+ # The actual state will be fixed up later during `VEXMixin.process_successors`
278
+ self.successors.append(state)
279
+ self.flat_successors.append(state)
274
280
  elif not state.solver.symbolic(target) and not state.history.jumpkind.startswith("Ijk_Sys"):
275
281
  # a successor with a concrete IP, and it's not a syscall
276
282
  self.successors.append(state)
@@ -899,7 +899,8 @@ class PropagatorAILState(PropagatorState):
899
899
  def_ = next(iter(defs))
900
900
  if def_ is not None:
901
901
  self._expr_used_locs[def_].append(codeloc)
902
- prop_count = len(self._expr_used_locs[def_])
902
+ # we must consider known future uses of this definition as well
903
+ prop_count = max(len(self._expr_used_locs[def_]), len(self.rda.all_uses.get_uses(def_)))
903
904
  else:
904
905
  # multiple definitions or no definitions - do not propagate
905
906
  return False
@@ -43,7 +43,6 @@ libc.set_non_returning(
43
43
  "__longjmp_chk",
44
44
  "__siglongjmp_chk",
45
45
  )
46
- libc.add_alias("exit", "_exit", "_Exit")
47
46
 
48
47
 
49
48
  #
@@ -6849,6 +6848,9 @@ libc.add_alias("getc", "_IO_getc")
6849
6848
  libc.add_alias("putc", "_IO_putc")
6850
6849
  libc.add_alias("gets", "_IO_gets")
6851
6850
  libc.add_alias("puts", "_IO_puts")
6851
+ libc.add_alias("exit", "_exit", "_Exit")
6852
+ libc.add_alias("sprintf", "siprintf")
6853
+ libc.add_alias("snprintf", "sniprintf")
6852
6854
 
6853
6855
 
6854
6856
  #
angr/sim_type.py CHANGED
@@ -60,6 +60,8 @@ class SimType:
60
60
  attr_self = getattr(self, attr)
61
61
  attr_other = getattr(other, attr)
62
62
  if isinstance(attr_self, SimType):
63
+ if attr_other is attr_self:
64
+ return True
63
65
  if avoid is not None and attr_self in avoid["self"] and attr_other in avoid["other"]:
64
66
  continue
65
67
  if not attr_self.__eq__(attr_other, avoid=avoid):
angr/utils/library.py CHANGED
@@ -205,7 +205,7 @@ def get_cpp_function_name(demangled_name, specialized=True, qualified=True):
205
205
  if not qualified:
206
206
  # remove leading namespaces
207
207
  chunks = name.split("::")
208
- name = "::".join(chunks[-2:])
208
+ name = "::".join(chunks[2:])
209
209
 
210
210
  # remove arguments
211
211
  if "(" in name:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: angr
3
- Version: 9.2.93
3
+ Version: 9.2.94
4
4
  Summary: A multi-architecture binary analysis toolkit, with the ability to perform dynamic symbolic execution and various static analyses on binaries
5
5
  Home-page: https://github.com/angr/angr
6
6
  License: BSD-2-Clause
@@ -17,13 +17,13 @@ Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
18
  Requires-Dist: CppHeaderParser
19
19
  Requires-Dist: GitPython
20
- Requires-Dist: ailment ==9.2.93
21
- Requires-Dist: archinfo ==9.2.93
20
+ Requires-Dist: ailment ==9.2.94
21
+ Requires-Dist: archinfo ==9.2.94
22
22
  Requires-Dist: cachetools
23
23
  Requires-Dist: capstone ==5.0.0.post1
24
24
  Requires-Dist: cffi >=1.14.0
25
- Requires-Dist: claripy ==9.2.93
26
- Requires-Dist: cle ==9.2.93
25
+ Requires-Dist: claripy ==9.2.94
26
+ Requires-Dist: cle ==9.2.94
27
27
  Requires-Dist: dpkt
28
28
  Requires-Dist: itanium-demangler
29
29
  Requires-Dist: mulpyplexer
@@ -33,7 +33,7 @@ Requires-Dist: protobuf >=3.19.0
33
33
  Requires-Dist: psutil
34
34
  Requires-Dist: pycparser >=2.18
35
35
  Requires-Dist: pyformlang
36
- Requires-Dist: pyvex ==9.2.93
36
+ Requires-Dist: pyvex ==9.2.94
37
37
  Requires-Dist: rich >=13.1.0
38
38
  Requires-Dist: rpyc
39
39
  Requires-Dist: sortedcontainers