angr 9.2.174__cp310-abi3-win_amd64.whl → 9.2.176__cp310-abi3-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.
- angr/__init__.py +1 -1
- angr/__main__.py +32 -2
- angr/analyses/calling_convention/calling_convention.py +12 -0
- angr/analyses/cfg/cfg_base.py +1 -1
- angr/analyses/cfg/cfg_fast.py +27 -8
- angr/analyses/complete_calling_conventions.py +39 -26
- angr/analyses/decompiler/ail_simplifier.py +13 -11
- angr/analyses/decompiler/ccall_rewriters/rewriter_base.py +5 -1
- angr/analyses/decompiler/clinic.py +54 -40
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +3 -3
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/__init__.py +4 -4
- angr/analyses/decompiler/peephole_optimizations/{inlined_wstrcpy.py → inlined_wcscpy.py} +16 -8
- angr/analyses/decompiler/peephole_optimizations/{inlined_wstrcpy_consolidation.py → inlined_wcscpy_consolidation.py} +13 -13
- angr/analyses/decompiler/ssailification/rewriting_engine.py +14 -1
- angr/analyses/decompiler/structured_codegen/c.py +6 -5
- angr/analyses/decompiler/structuring/dream.py +2 -2
- angr/analyses/decompiler/structuring/phoenix.py +101 -23
- angr/analyses/decompiler/utils.py +1 -1
- angr/analyses/smc.py +1 -1
- angr/analyses/stack_pointer_tracker.py +4 -3
- angr/analyses/typehoon/lifter.py +29 -18
- angr/analyses/typehoon/simple_solver.py +157 -50
- angr/analyses/typehoon/translator.py +34 -34
- angr/analyses/typehoon/typeconsts.py +33 -15
- angr/analyses/typehoon/typevars.py +9 -2
- angr/analyses/variable_recovery/engine_ail.py +4 -2
- angr/analyses/variable_recovery/engine_base.py +4 -1
- angr/analyses/variable_recovery/variable_recovery_fast.py +3 -1
- angr/calling_conventions.py +2 -1
- angr/engines/icicle.py +4 -4
- angr/engines/vex/claripy/ccall.py +3 -3
- angr/knowledge_plugins/functions/function.py +18 -1
- angr/misc/bug_report.py +11 -2
- angr/procedures/definitions/__init__.py +88 -20
- angr/procedures/definitions/common/glibc.json +3516 -0
- angr/procedures/definitions/parse_glibc.py +78 -0
- angr/procedures/libc/fgets.py +2 -1
- angr/procedures/posix/pthread.py +4 -4
- angr/procedures/stubs/format_parser.py +3 -3
- angr/rustylib.pyd +0 -0
- angr/sim_type.py +73 -11
- angr/simos/windows.py +1 -1
- angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +1 -1
- angr/unicornlib.dll +0 -0
- angr/utils/constants.py +1 -1
- angr/utils/library.py +1 -0
- angr/utils/strings.py +20 -0
- {angr-9.2.174.dist-info → angr-9.2.176.dist-info}/METADATA +5 -5
- {angr-9.2.174.dist-info → angr-9.2.176.dist-info}/RECORD +54 -52
- angr/procedures/definitions/glibc.py +0 -8372
- {angr-9.2.174.dist-info → angr-9.2.176.dist-info}/WHEEL +0 -0
- {angr-9.2.174.dist-info → angr-9.2.176.dist-info}/entry_points.txt +0 -0
- {angr-9.2.174.dist-info → angr-9.2.176.dist-info}/licenses/LICENSE +0 -0
- {angr-9.2.174.dist-info → angr-9.2.176.dist-info}/top_level.txt +0 -0
|
@@ -179,8 +179,11 @@ class RecursiveRefNode(SketchNodeBase):
|
|
|
179
179
|
This is equivalent to sketches.LabelNode in the reference implementation of retypd.
|
|
180
180
|
"""
|
|
181
181
|
|
|
182
|
-
def __init__(self, target: DerivedTypeVariable):
|
|
183
|
-
self.target: DerivedTypeVariable = target
|
|
182
|
+
def __init__(self, target: TypeVariable | DerivedTypeVariable):
|
|
183
|
+
self.target: TypeVariable | DerivedTypeVariable = target
|
|
184
|
+
|
|
185
|
+
def __repr__(self):
|
|
186
|
+
return f"Ref({self.target})"
|
|
184
187
|
|
|
185
188
|
def __hash__(self):
|
|
186
189
|
return hash((RecursiveRefNode, self.target))
|
|
@@ -265,7 +268,7 @@ class Sketch:
|
|
|
265
268
|
basetype = supertype
|
|
266
269
|
assert basetype.size is not None
|
|
267
270
|
max_size = self.solver.stackvar_max_sizes.get(subtype, None)
|
|
268
|
-
if max_size not in {0, None} and max_size // basetype.size > 0: # type: ignore
|
|
271
|
+
if max_size not in {0, None} and basetype.size > 0 and max_size // basetype.size > 0: # type: ignore
|
|
269
272
|
supertype = Array(element=basetype, count=max_size // basetype.size) # type: ignore
|
|
270
273
|
|
|
271
274
|
if SimpleSolver._typevar_inside_set(subtype, PRIMITIVE_TYPES) and not SimpleSolver._typevar_inside_set(
|
|
@@ -328,7 +331,7 @@ class ConstraintGraphNode:
|
|
|
328
331
|
|
|
329
332
|
def __init__(
|
|
330
333
|
self,
|
|
331
|
-
typevar: TypeVariable | DerivedTypeVariable,
|
|
334
|
+
typevar: TypeVariable | DerivedTypeVariable | TypeConstant,
|
|
332
335
|
variance: Variance,
|
|
333
336
|
tag: ConstraintGraphTag,
|
|
334
337
|
forgotten: FORGOTTEN,
|
|
@@ -512,10 +515,21 @@ class SimpleSolver:
|
|
|
512
515
|
typevars.add(repl)
|
|
513
516
|
|
|
514
517
|
constraints = set()
|
|
518
|
+
|
|
515
519
|
for tv in typevars:
|
|
516
520
|
if tv in self._constraints:
|
|
517
521
|
constraints |= self._constraints[tv]
|
|
518
522
|
|
|
523
|
+
equiv_classes, sketches = self.infer_shapes(typevars, constraints)
|
|
524
|
+
|
|
525
|
+
# only create sketches for the type variables representing their equivalence classes
|
|
526
|
+
tv_to_reptvs = {}
|
|
527
|
+
for tv_or_dtv, reptv in equiv_classes.items():
|
|
528
|
+
if not isinstance(tv_or_dtv, DerivedTypeVariable) and tv_or_dtv is not reptv:
|
|
529
|
+
tv_to_reptvs[tv_or_dtv] = reptv
|
|
530
|
+
# rewrite constraints to only use representative type variables
|
|
531
|
+
constraints = self._rewrite_constraints_with_replacements(constraints, tv_to_reptvs)
|
|
532
|
+
|
|
519
533
|
# collect typevars used in the constraint set
|
|
520
534
|
constrained_typevars = set()
|
|
521
535
|
for constraint in constraints:
|
|
@@ -527,7 +541,6 @@ class SimpleSolver:
|
|
|
527
541
|
elif isinstance(t, TypeVariable) and t in typevars:
|
|
528
542
|
constrained_typevars.add(t)
|
|
529
543
|
|
|
530
|
-
_, sketches = self.infer_shapes(typevars, constraints)
|
|
531
544
|
constraintset2tvs = defaultdict(set)
|
|
532
545
|
tvs_seen = set()
|
|
533
546
|
for idx, tv in enumerate(constrained_typevars):
|
|
@@ -579,6 +592,10 @@ class SimpleSolver:
|
|
|
579
592
|
filtered_constraint_subset, tvs | PRIMITIVE_TYPES
|
|
580
593
|
)
|
|
581
594
|
primitive_constraints = self._generate_primitive_constraints(tvs, base_constraint_graph)
|
|
595
|
+
if len(tvs) > 1:
|
|
596
|
+
primitive_constraints |= self._generate_transitive_subtype_constraints(
|
|
597
|
+
tvs, filtered_constraint_subset, primitive_constraints
|
|
598
|
+
)
|
|
582
599
|
tvs_with_primitive_constraints = set()
|
|
583
600
|
for primitive_constraint in primitive_constraints:
|
|
584
601
|
tv = self._typevar_from_primitive_constraint(primitive_constraint)
|
|
@@ -586,7 +603,9 @@ class SimpleSolver:
|
|
|
586
603
|
assert tv is not None, f"Cannot find type variable in primitive constraint {primitive_constraint}"
|
|
587
604
|
sketches[tv].add_constraint(primitive_constraint)
|
|
588
605
|
solutions = {}
|
|
589
|
-
self.determine(
|
|
606
|
+
self.determine(
|
|
607
|
+
sketches, sorted(tvs_with_primitive_constraints, key=lambda x: x.idx), equiv_classes, solutions
|
|
608
|
+
)
|
|
590
609
|
_l.debug("Determined solutions for %d type variable(s).", len(tvs_with_primitive_constraints))
|
|
591
610
|
|
|
592
611
|
leaf_solutions = 0
|
|
@@ -614,7 +633,12 @@ class SimpleSolver:
|
|
|
614
633
|
constraint_subset = self._filter_constraints(new_constraint_subset)
|
|
615
634
|
|
|
616
635
|
# set the solution for missing type vars to TOP
|
|
617
|
-
self.determine(sketches, set(sketches).difference(set(self.solution)), self.solution)
|
|
636
|
+
self.determine(sketches, set(sketches).difference(set(self.solution)), equiv_classes, self.solution)
|
|
637
|
+
|
|
638
|
+
# set solutions for non-representative type variables
|
|
639
|
+
for tv, reptv in equiv_classes.items():
|
|
640
|
+
if reptv in self.solution and tv not in self.solution:
|
|
641
|
+
self.solution[tv] = self.solution[reptv]
|
|
618
642
|
|
|
619
643
|
def infer_shapes(
|
|
620
644
|
self, typevars: set[TypeVariable], constraints: set[TypeConstraint]
|
|
@@ -627,14 +651,19 @@ class SimpleSolver:
|
|
|
627
651
|
|
|
628
652
|
sketches: dict[TypeVariable, Sketch] = {}
|
|
629
653
|
for tv in typevars:
|
|
654
|
+
if tv in equivalence_classes and equivalence_classes[tv] != tv:
|
|
655
|
+
# skip non-representative type variables
|
|
656
|
+
continue
|
|
630
657
|
sketches[tv] = Sketch(self, tv)
|
|
631
658
|
|
|
632
659
|
for tv, sketch in sketches.items():
|
|
633
660
|
sketch_node = sketch.lookup(tv)
|
|
634
661
|
graph_node = equivalence_classes.get(tv, None)
|
|
635
662
|
# assert graph_node is not None
|
|
636
|
-
if graph_node is None:
|
|
663
|
+
if graph_node is None or sketch_node is None:
|
|
637
664
|
continue
|
|
665
|
+
assert isinstance(graph_node, TypeVariable)
|
|
666
|
+
assert isinstance(sketch_node, SketchNode)
|
|
638
667
|
visited = {graph_node: sketch_node}
|
|
639
668
|
self._get_all_paths(quotient_graph, sketch, graph_node, visited)
|
|
640
669
|
return equivalence_classes, sketches
|
|
@@ -654,6 +683,7 @@ class SimpleSolver:
|
|
|
654
683
|
last_node = tv
|
|
655
684
|
prefix = tv
|
|
656
685
|
while isinstance(prefix, DerivedTypeVariable) and prefix.labels:
|
|
686
|
+
assert isinstance(last_node, DerivedTypeVariable)
|
|
657
687
|
prefix = prefix.longest_prefix()
|
|
658
688
|
if prefix is None:
|
|
659
689
|
continue
|
|
@@ -683,8 +713,8 @@ class SimpleSolver:
|
|
|
683
713
|
out_graph = networkx.MultiDiGraph() # there can be multiple edges between two nodes, each edge is associated
|
|
684
714
|
# with a different label
|
|
685
715
|
for src, dst, data in g.edges(data=True):
|
|
686
|
-
src_cls = equivalence_classes
|
|
687
|
-
dst_cls = equivalence_classes
|
|
716
|
+
src_cls = equivalence_classes.get(src, src)
|
|
717
|
+
dst_cls = equivalence_classes.get(dst, dst)
|
|
688
718
|
label = None if not data else data["label"]
|
|
689
719
|
if label is not None and out_graph.has_edge(src_cls, dst_cls):
|
|
690
720
|
# do not add the same edge twice
|
|
@@ -708,6 +738,41 @@ class SimpleSolver:
|
|
|
708
738
|
constraints_1 = self._solve_constraints_between(constraint_graph, PRIMITIVE_TYPES, non_primitive_endpoints)
|
|
709
739
|
return constraints_0 | constraints_1
|
|
710
740
|
|
|
741
|
+
@staticmethod
|
|
742
|
+
def _generate_transitive_subtype_constraints(
|
|
743
|
+
typevars: set[TypeVariable | DerivedTypeVariable],
|
|
744
|
+
constraints: set[TypeConstraint],
|
|
745
|
+
primitive_constraints: set[TypeConstraint],
|
|
746
|
+
) -> set[TypeConstraint]:
|
|
747
|
+
"""
|
|
748
|
+
Handling multiple type variables at once means we may miss some subtyping relationships between a type variable
|
|
749
|
+
and a primitive type (e.g., tv_1 <: tv_2 and tv_2 <: int, we may not see tv_1 <: int). This method attempts to
|
|
750
|
+
recover some of these missing constraints.
|
|
751
|
+
"""
|
|
752
|
+
|
|
753
|
+
tv_supertype = defaultdict(set)
|
|
754
|
+
for constraint in primitive_constraints:
|
|
755
|
+
if isinstance(constraint, Subtype) and SimpleSolver._typevar_inside_set(
|
|
756
|
+
constraint.super_type, PRIMITIVE_TYPES
|
|
757
|
+
):
|
|
758
|
+
tv_supertype[constraint.sub_type].add(constraint.super_type)
|
|
759
|
+
|
|
760
|
+
additional_constraints = set()
|
|
761
|
+
for constraint in constraints:
|
|
762
|
+
if (
|
|
763
|
+
isinstance(constraint, Subtype)
|
|
764
|
+
and isinstance(constraint.sub_type, TypeVariable)
|
|
765
|
+
and (
|
|
766
|
+
(isinstance(constraint.sub_type, DerivedTypeVariable) and constraint.sub_type.type_var in typevars)
|
|
767
|
+
or (not isinstance(constraint.sub_type, DerivedTypeVariable) and constraint.sub_type in typevars)
|
|
768
|
+
)
|
|
769
|
+
and constraint.super_type in tv_supertype
|
|
770
|
+
):
|
|
771
|
+
for supertype in tv_supertype[constraint.super_type]:
|
|
772
|
+
additional_constraints.add(Subtype(constraint.sub_type, supertype))
|
|
773
|
+
|
|
774
|
+
return additional_constraints
|
|
775
|
+
|
|
711
776
|
@staticmethod
|
|
712
777
|
def _typevars_from_constraints(constraints: set[TypeConstraint]) -> set[TypeVariable | DerivedTypeVariable]:
|
|
713
778
|
"""
|
|
@@ -717,8 +782,10 @@ class SimpleSolver:
|
|
|
717
782
|
typevars: set[TypeVariable | DerivedTypeVariable] = set()
|
|
718
783
|
for constraint in constraints:
|
|
719
784
|
if isinstance(constraint, Subtype):
|
|
720
|
-
|
|
721
|
-
|
|
785
|
+
if not isinstance(constraint.sub_type, TypeConstant):
|
|
786
|
+
typevars.add(constraint.sub_type)
|
|
787
|
+
if not isinstance(constraint.super_type, TypeConstant):
|
|
788
|
+
typevars.add(constraint.super_type)
|
|
722
789
|
# TODO: Other types of constraints?
|
|
723
790
|
return typevars
|
|
724
791
|
|
|
@@ -745,7 +812,7 @@ class SimpleSolver:
|
|
|
745
812
|
def _get_all_paths(
|
|
746
813
|
graph: networkx.DiGraph[TypeVariable | DerivedTypeVariable],
|
|
747
814
|
sketch: Sketch,
|
|
748
|
-
node:
|
|
815
|
+
node: TypeVariable,
|
|
749
816
|
visited: dict[TypeVariable | DerivedTypeVariable, SketchNode],
|
|
750
817
|
):
|
|
751
818
|
if node not in graph:
|
|
@@ -779,29 +846,45 @@ class SimpleSolver:
|
|
|
779
846
|
|
|
780
847
|
@staticmethod
|
|
781
848
|
def _unify(
|
|
782
|
-
equivalence_classes: dict,
|
|
849
|
+
equivalence_classes: dict,
|
|
850
|
+
cls0: TypeConstant | TypeVariable,
|
|
851
|
+
cls1: TypeConstant | TypeVariable,
|
|
852
|
+
graph: networkx.DiGraph,
|
|
783
853
|
) -> None:
|
|
784
854
|
# first convert cls0 and cls1 to their equivalence classes
|
|
785
|
-
cls0 = equivalence_classes
|
|
786
|
-
cls1 = equivalence_classes
|
|
855
|
+
cls0 = equivalence_classes.get(cls0, cls0)
|
|
856
|
+
cls1 = equivalence_classes.get(cls1, cls1)
|
|
787
857
|
|
|
788
858
|
# unify if needed
|
|
789
859
|
if cls0 != cls1:
|
|
790
860
|
# MakeEquiv
|
|
791
|
-
|
|
792
|
-
|
|
861
|
+
cls0_elems = {key for key, item in equivalence_classes.items() if item is cls0}
|
|
862
|
+
cls1_elems = {key for key, item in equivalence_classes.items() if item is cls1}
|
|
863
|
+
existing_elements = cls0_elems | cls1_elems
|
|
864
|
+
# pick a representative type variable and prioritize non-derived type variables
|
|
865
|
+
if not isinstance(cls0, DerivedTypeVariable):
|
|
866
|
+
rep_cls = cls0
|
|
867
|
+
elif not isinstance(cls1, DerivedTypeVariable):
|
|
868
|
+
rep_cls = cls1
|
|
869
|
+
else:
|
|
870
|
+
rep_cls = next(
|
|
871
|
+
iter(elem for elem in existing_elements if not isinstance(elem, DerivedTypeVariable)), cls0
|
|
872
|
+
)
|
|
793
873
|
for elem in existing_elements:
|
|
794
874
|
equivalence_classes[elem] = rep_cls
|
|
795
875
|
# the logic below refers to the retypd reference implementation. it is different from Algorithm E.1
|
|
796
876
|
# note that graph is used read-only in this method, so we do not need to make copy of edges
|
|
797
|
-
for _, dst0, data0 in graph.out_edges(
|
|
877
|
+
for _, dst0, data0 in graph.out_edges(cls0_elems, data=True):
|
|
798
878
|
if "label" in data0 and data0["label"] is not None:
|
|
799
|
-
for _, dst1, data1 in graph.out_edges(
|
|
879
|
+
for _, dst1, data1 in graph.out_edges(cls1_elems, data=True):
|
|
800
880
|
if data0["label"] == data1["label"] or (
|
|
801
881
|
isinstance(data0["label"], Load) and isinstance(data1["label"], Store)
|
|
802
882
|
):
|
|
803
883
|
SimpleSolver._unify(
|
|
804
|
-
equivalence_classes,
|
|
884
|
+
equivalence_classes,
|
|
885
|
+
equivalence_classes.get(dst0, dst0),
|
|
886
|
+
equivalence_classes.get(dst1, dst1),
|
|
887
|
+
graph,
|
|
805
888
|
)
|
|
806
889
|
|
|
807
890
|
def _eq_constraints_from_add(self, typevar: TypeVariable):
|
|
@@ -898,9 +981,12 @@ class SimpleSolver:
|
|
|
898
981
|
|
|
899
982
|
@staticmethod
|
|
900
983
|
def _rewrite_constraints_with_replacements(
|
|
901
|
-
constraints: set[TypeConstraint], replacements: dict[TypeVariable, TypeVariable]
|
|
984
|
+
constraints: set[TypeConstraint], replacements: dict[TypeVariable, TypeVariable | TypeConstant]
|
|
902
985
|
) -> set[TypeConstraint]:
|
|
903
986
|
# replace constraints according to a dictionary of type variable replacements
|
|
987
|
+
if not replacements:
|
|
988
|
+
return constraints
|
|
989
|
+
|
|
904
990
|
replaced_constraints = set()
|
|
905
991
|
for constraint in constraints:
|
|
906
992
|
if isinstance(constraint, Existence):
|
|
@@ -966,9 +1052,9 @@ class SimpleSolver:
|
|
|
966
1052
|
if isinstance(constraint.sub_type, TypeVariable):
|
|
967
1053
|
sub_typevars[constraint.sub_type].add(constraint.super_type)
|
|
968
1054
|
for tv in [constraint.sub_type, constraint.super_type]:
|
|
969
|
-
if isinstance(tv, DerivedTypeVariable):
|
|
1055
|
+
if isinstance(tv, DerivedTypeVariable) and not isinstance(constraint.sub_type, TypeConstant):
|
|
970
1056
|
tv_to_dtvs[tv.type_var].add(constraint.sub_type)
|
|
971
|
-
elif isinstance(tv, TypeVariable):
|
|
1057
|
+
elif isinstance(tv, TypeVariable) and not isinstance(constraint.sub_type, TypeConstant):
|
|
972
1058
|
tv_to_dtvs[tv].add(constraint.sub_type)
|
|
973
1059
|
|
|
974
1060
|
ub_subtypes: dict[TypeVariable, TypeVariable] = {}
|
|
@@ -980,8 +1066,11 @@ class SimpleSolver:
|
|
|
980
1066
|
|
|
981
1067
|
filtered_constraints = set()
|
|
982
1068
|
for constraint in constraints:
|
|
983
|
-
if isinstance(constraint, Subtype)
|
|
984
|
-
|
|
1069
|
+
if isinstance(constraint, Subtype):
|
|
1070
|
+
if constraint.sub_type in ub_subtypes:
|
|
1071
|
+
continue
|
|
1072
|
+
if constraint.sub_type == constraint.super_type:
|
|
1073
|
+
continue
|
|
985
1074
|
filtered_constraints.add(constraint)
|
|
986
1075
|
|
|
987
1076
|
return filtered_constraints, ub_subtypes
|
|
@@ -1136,9 +1225,9 @@ class SimpleSolver:
|
|
|
1136
1225
|
def _constraint_graph_add_edges(
|
|
1137
1226
|
self,
|
|
1138
1227
|
graph: networkx.DiGraph,
|
|
1139
|
-
subtype: TypeVariable | DerivedTypeVariable,
|
|
1140
|
-
supertype: TypeVariable | DerivedTypeVariable,
|
|
1141
|
-
interesting_variables: set[DerivedTypeVariable],
|
|
1228
|
+
subtype: TypeVariable | DerivedTypeVariable | TypeConstant,
|
|
1229
|
+
supertype: TypeVariable | DerivedTypeVariable | TypeConstant,
|
|
1230
|
+
interesting_variables: set[TypeVariable | DerivedTypeVariable | TypeConstant],
|
|
1142
1231
|
):
|
|
1143
1232
|
# left and right tags
|
|
1144
1233
|
if self._typevar_inside_set(self._to_typevar_or_typeconst(subtype), interesting_variables):
|
|
@@ -1173,7 +1262,7 @@ class SimpleSolver:
|
|
|
1173
1262
|
|
|
1174
1263
|
# initialize the reaching-push sets R(x)
|
|
1175
1264
|
for x, y, data in graph.edges(data=True):
|
|
1176
|
-
if "label" in data and data.get("label")[1] == "forget":
|
|
1265
|
+
if "label" in data and data.get("label")[1] == "forget": # type:ignore
|
|
1177
1266
|
d = data["label"][0], x
|
|
1178
1267
|
R[y].add(d)
|
|
1179
1268
|
|
|
@@ -1191,7 +1280,7 @@ class SimpleSolver:
|
|
|
1191
1280
|
lbl = data.get("label")
|
|
1192
1281
|
if lbl and lbl[1] == "recall":
|
|
1193
1282
|
for _label, z in R[x]:
|
|
1194
|
-
if not graph.has_edge(z, y):
|
|
1283
|
+
if lbl[0] == _label and not graph.has_edge(z, y):
|
|
1195
1284
|
changed = True
|
|
1196
1285
|
graph.add_edge(z, y)
|
|
1197
1286
|
v_contravariant = []
|
|
@@ -1376,6 +1465,7 @@ class SimpleSolver:
|
|
|
1376
1465
|
self,
|
|
1377
1466
|
sketches,
|
|
1378
1467
|
tvs,
|
|
1468
|
+
equivalence_classes: dict[TypeVariable, TypeVariable],
|
|
1379
1469
|
solution: dict,
|
|
1380
1470
|
nodes: set[SketchNode] | None = None,
|
|
1381
1471
|
) -> None:
|
|
@@ -1389,13 +1479,21 @@ class SimpleSolver:
|
|
|
1389
1479
|
"""
|
|
1390
1480
|
|
|
1391
1481
|
for typevar in tvs:
|
|
1392
|
-
self.
|
|
1482
|
+
self._solution_cache = {}
|
|
1483
|
+
self._determine(typevar, sketches[typevar], equivalence_classes, solution, nodes=nodes)
|
|
1393
1484
|
|
|
1394
1485
|
for v, eq in self._equivalence.items():
|
|
1395
1486
|
if v not in solution and eq in solution:
|
|
1396
1487
|
solution[v] = solution[eq]
|
|
1397
1488
|
|
|
1398
|
-
def _determine(
|
|
1489
|
+
def _determine(
|
|
1490
|
+
self,
|
|
1491
|
+
the_typevar,
|
|
1492
|
+
sketch,
|
|
1493
|
+
equivalence_classes: dict[TypeVariable, TypeVariable],
|
|
1494
|
+
solution: dict,
|
|
1495
|
+
nodes: set[SketchNode] | None = None,
|
|
1496
|
+
):
|
|
1399
1497
|
"""
|
|
1400
1498
|
Return the solution from sketches
|
|
1401
1499
|
"""
|
|
@@ -1409,8 +1507,9 @@ class SimpleSolver:
|
|
|
1409
1507
|
# consult the cache
|
|
1410
1508
|
cached_results = set()
|
|
1411
1509
|
for node in nodes:
|
|
1412
|
-
|
|
1413
|
-
|
|
1510
|
+
repr_tv = equivalence_classes.get(node.typevar, node.typevar)
|
|
1511
|
+
if repr_tv in self._solution_cache:
|
|
1512
|
+
cached_results.add(self._solution_cache[repr_tv])
|
|
1414
1513
|
if len(cached_results) == 1:
|
|
1415
1514
|
return next(iter(cached_results))
|
|
1416
1515
|
if len(cached_results) > 1:
|
|
@@ -1434,7 +1533,8 @@ class SimpleSolver:
|
|
|
1434
1533
|
func_type = Function([], [])
|
|
1435
1534
|
result = self._pointer_class()(basetype=func_type)
|
|
1436
1535
|
for node in nodes:
|
|
1437
|
-
|
|
1536
|
+
repr_tv = equivalence_classes.get(node.typevar, node.typevar)
|
|
1537
|
+
self._solution_cache[repr_tv] = result
|
|
1438
1538
|
|
|
1439
1539
|
# this is a function variable
|
|
1440
1540
|
func_inputs = defaultdict(set)
|
|
@@ -1455,7 +1555,7 @@ class SimpleSolver:
|
|
|
1455
1555
|
for vals, out in [(func_inputs, input_args), (func_outputs, output_values)]:
|
|
1456
1556
|
for idx in range(max(vals) + 1):
|
|
1457
1557
|
if idx in vals:
|
|
1458
|
-
sol = self._determine(the_typevar, sketch, solution, nodes=vals[idx])
|
|
1558
|
+
sol = self._determine(the_typevar, sketch, equivalence_classes, solution, nodes=vals[idx])
|
|
1459
1559
|
out.append(sol)
|
|
1460
1560
|
else:
|
|
1461
1561
|
out.append(None)
|
|
@@ -1483,15 +1583,19 @@ class SimpleSolver:
|
|
|
1483
1583
|
else the_node.upper_bound
|
|
1484
1584
|
)
|
|
1485
1585
|
for node in nodes:
|
|
1586
|
+
repr_tv = equivalence_classes.get(node.typevar, node.typevar)
|
|
1587
|
+
self._solution_cache[repr_tv] = result
|
|
1486
1588
|
solution[node.typevar] = result
|
|
1487
|
-
self._solution_cache[node.typevar] = result
|
|
1488
1589
|
return result
|
|
1489
1590
|
|
|
1490
1591
|
# create a dummy result and shove it into the cache
|
|
1491
1592
|
struct_type = Struct(fields={})
|
|
1492
1593
|
result = self._pointer_class()(struct_type)
|
|
1594
|
+
# print(f"Creating a struct type: {struct_type} for {the_typevar}")
|
|
1493
1595
|
for node in nodes:
|
|
1494
|
-
|
|
1596
|
+
# print(f"... assigned it to {node.typevar}")
|
|
1597
|
+
repr_tv = equivalence_classes.get(node.typevar, node.typevar)
|
|
1598
|
+
self._solution_cache[repr_tv] = result
|
|
1495
1599
|
|
|
1496
1600
|
# this might be a struct
|
|
1497
1601
|
fields = {}
|
|
@@ -1528,21 +1632,21 @@ class SimpleSolver:
|
|
|
1528
1632
|
offset_to_maxsize[base] = max(offset_to_maxsize[base], (last_label.offset - base) + access_size)
|
|
1529
1633
|
offset_to_sizes[base].add(access_size)
|
|
1530
1634
|
|
|
1531
|
-
|
|
1635
|
+
array_idx_to_base = {}
|
|
1532
1636
|
|
|
1533
1637
|
for idx, (labels, _) in enumerate(path_and_successors):
|
|
1534
1638
|
last_label = labels[-1] if labels else None
|
|
1535
|
-
if isinstance(last_label, HasField):
|
|
1639
|
+
if isinstance(last_label, HasField) and last_label.elem_count > 1:
|
|
1536
1640
|
prev_offset = next(offset_to_base.irange(maximum=last_label.offset, reverse=True))
|
|
1537
|
-
|
|
1641
|
+
array_idx_to_base[idx] = offset_to_base[prev_offset]
|
|
1538
1642
|
|
|
1539
1643
|
node_by_offset = defaultdict(set)
|
|
1540
1644
|
|
|
1541
1645
|
for idx, (labels, succ) in enumerate(path_and_successors):
|
|
1542
1646
|
last_label = labels[-1] if labels else None
|
|
1543
1647
|
if isinstance(last_label, HasField):
|
|
1544
|
-
if idx in
|
|
1545
|
-
node_by_offset[
|
|
1648
|
+
if idx in array_idx_to_base:
|
|
1649
|
+
node_by_offset[array_idx_to_base[idx]].add(succ)
|
|
1546
1650
|
else:
|
|
1547
1651
|
node_by_offset[last_label.offset].add(succ)
|
|
1548
1652
|
|
|
@@ -1551,8 +1655,8 @@ class SimpleSolver:
|
|
|
1551
1655
|
offset = sorted_offsets[i]
|
|
1552
1656
|
|
|
1553
1657
|
child_nodes = node_by_offset[offset]
|
|
1554
|
-
sol = self._determine(the_typevar, sketch, solution, nodes=child_nodes)
|
|
1555
|
-
if isinstance(sol, TopType):
|
|
1658
|
+
sol = self._determine(the_typevar, sketch, equivalence_classes, solution, nodes=child_nodes)
|
|
1659
|
+
if isinstance(sol, TopType) and offset in offset_to_sizes:
|
|
1556
1660
|
# make it an array if possible
|
|
1557
1661
|
elem_size = min(offset_to_sizes[offset])
|
|
1558
1662
|
array_size = offset_to_maxsize[offset]
|
|
@@ -1566,12 +1670,14 @@ class SimpleSolver:
|
|
|
1566
1670
|
if not fields:
|
|
1567
1671
|
result = Top_
|
|
1568
1672
|
for node in nodes:
|
|
1569
|
-
|
|
1673
|
+
repr_tv = equivalence_classes.get(node.typevar, node.typevar)
|
|
1674
|
+
self._solution_cache[repr_tv] = result
|
|
1570
1675
|
solution[node.typevar] = result
|
|
1571
|
-
elif any(off < 0 for off in fields):
|
|
1676
|
+
elif any(off < 0 for off in fields) or any(fld is Bottom_ for fld in fields.values()):
|
|
1572
1677
|
result = self._pointer_class()(Bottom_)
|
|
1573
1678
|
for node in nodes:
|
|
1574
|
-
|
|
1679
|
+
repr_tv = equivalence_classes.get(node.typevar, node.typevar)
|
|
1680
|
+
self._solution_cache[repr_tv] = result
|
|
1575
1681
|
solution[node.typevar] = result
|
|
1576
1682
|
else:
|
|
1577
1683
|
# back-patch
|
|
@@ -1599,8 +1705,9 @@ class SimpleSolver:
|
|
|
1599
1705
|
result = lower_bound if not isinstance(lower_bound, BottomType) else upper_bound
|
|
1600
1706
|
|
|
1601
1707
|
for node in nodes:
|
|
1708
|
+
repr_tv = equivalence_classes.get(node.typevar, node.typevar)
|
|
1709
|
+
self._solution_cache[repr_tv] = result
|
|
1602
1710
|
solution[node.typevar] = result
|
|
1603
|
-
self._solution_cache[node.typevar] = result
|
|
1604
1711
|
|
|
1605
1712
|
# import pprint
|
|
1606
1713
|
|
|
@@ -85,7 +85,7 @@ class TypeTranslator:
|
|
|
85
85
|
internal = sim_type.SimTypeBottom(label="void").with_arch(self.arch)
|
|
86
86
|
else:
|
|
87
87
|
internal = self._tc2simtype(tc.basetype)
|
|
88
|
-
return sim_type.SimTypePointer(internal).with_arch(self.arch)
|
|
88
|
+
return sim_type.SimTypePointer(internal, label=tc.name).with_arch(self.arch)
|
|
89
89
|
|
|
90
90
|
def _translate_Pointer32(self, tc):
|
|
91
91
|
if isinstance(tc.basetype, typeconsts.BottomType):
|
|
@@ -93,11 +93,11 @@ class TypeTranslator:
|
|
|
93
93
|
internal = sim_type.SimTypeBottom(label="void").with_arch(self.arch)
|
|
94
94
|
else:
|
|
95
95
|
internal = self._tc2simtype(tc.basetype)
|
|
96
|
-
return sim_type.SimTypePointer(internal).with_arch(self.arch)
|
|
96
|
+
return sim_type.SimTypePointer(internal, label=tc.name).with_arch(self.arch)
|
|
97
97
|
|
|
98
98
|
def _translate_Array(self, tc: typeconsts.Array) -> sim_type.SimTypeArray:
|
|
99
99
|
elem_type = self._tc2simtype(tc.element)
|
|
100
|
-
return sim_type.SimTypeArray(elem_type, length=tc.count).with_arch(self.arch)
|
|
100
|
+
return sim_type.SimTypeArray(elem_type, length=tc.count, label=tc.name).with_arch(self.arch)
|
|
101
101
|
|
|
102
102
|
def _translate_Struct(self, tc: typeconsts.Struct):
|
|
103
103
|
if tc in self.structs:
|
|
@@ -136,26 +136,26 @@ class TypeTranslator:
|
|
|
136
136
|
|
|
137
137
|
return s
|
|
138
138
|
|
|
139
|
-
def _translate_Int8(self, tc):
|
|
140
|
-
return sim_type.SimTypeChar(signed=False).with_arch(self.arch)
|
|
139
|
+
def _translate_Int8(self, tc):
|
|
140
|
+
return sim_type.SimTypeChar(signed=False, label=tc.name).with_arch(self.arch)
|
|
141
141
|
|
|
142
|
-
def _translate_Int16(self, tc):
|
|
143
|
-
return sim_type.SimTypeShort(signed=False).with_arch(self.arch)
|
|
142
|
+
def _translate_Int16(self, tc):
|
|
143
|
+
return sim_type.SimTypeShort(signed=False, label=tc.name).with_arch(self.arch)
|
|
144
144
|
|
|
145
|
-
def _translate_Int32(self, tc):
|
|
146
|
-
return sim_type.SimTypeInt(signed=False).with_arch(self.arch)
|
|
145
|
+
def _translate_Int32(self, tc):
|
|
146
|
+
return sim_type.SimTypeInt(signed=False, label=tc.name).with_arch(self.arch)
|
|
147
147
|
|
|
148
|
-
def _translate_Int64(self, tc):
|
|
149
|
-
return sim_type.SimTypeLongLong(signed=False).with_arch(self.arch)
|
|
148
|
+
def _translate_Int64(self, tc):
|
|
149
|
+
return sim_type.SimTypeLongLong(signed=False, label=tc.name).with_arch(self.arch)
|
|
150
150
|
|
|
151
|
-
def _translate_Int128(self, tc):
|
|
152
|
-
return sim_type.SimTypeInt128(signed=False).with_arch(self.arch)
|
|
151
|
+
def _translate_Int128(self, tc):
|
|
152
|
+
return sim_type.SimTypeInt128(signed=False, label=tc.name).with_arch(self.arch)
|
|
153
153
|
|
|
154
|
-
def _translate_Int256(self, tc):
|
|
155
|
-
return sim_type.SimTypeInt256(signed=False).with_arch(self.arch)
|
|
154
|
+
def _translate_Int256(self, tc):
|
|
155
|
+
return sim_type.SimTypeInt256(signed=False, label=tc.name).with_arch(self.arch)
|
|
156
156
|
|
|
157
|
-
def _translate_Int512(self, tc):
|
|
158
|
-
return sim_type.SimTypeInt512(signed=False).with_arch(self.arch)
|
|
157
|
+
def _translate_Int512(self, tc):
|
|
158
|
+
return sim_type.SimTypeInt512(signed=False, label=tc.name).with_arch(self.arch)
|
|
159
159
|
|
|
160
160
|
def _translate_TypeVariableReference(self, tc):
|
|
161
161
|
if tc.typevar in self.translated:
|
|
@@ -164,11 +164,11 @@ class TypeTranslator:
|
|
|
164
164
|
self._has_nonexistent_ref = True
|
|
165
165
|
return SimTypeTempRef(tc.typevar)
|
|
166
166
|
|
|
167
|
-
def _translate_Float32(self, tc: typeconsts.Float32) -> sim_type.SimTypeFloat:
|
|
168
|
-
return sim_type.SimTypeFloat().with_arch(self.arch)
|
|
167
|
+
def _translate_Float32(self, tc: typeconsts.Float32) -> sim_type.SimTypeFloat:
|
|
168
|
+
return sim_type.SimTypeFloat(label=tc.name).with_arch(self.arch)
|
|
169
169
|
|
|
170
|
-
def _translate_Float64(self, tc: typeconsts.Float64) -> sim_type.SimTypeDouble:
|
|
171
|
-
return sim_type.SimTypeDouble().with_arch(self.arch)
|
|
170
|
+
def _translate_Float64(self, tc: typeconsts.Float64) -> sim_type.SimTypeDouble:
|
|
171
|
+
return sim_type.SimTypeDouble(label=tc.name).with_arch(self.arch)
|
|
172
172
|
|
|
173
173
|
#
|
|
174
174
|
# Backpatching
|
|
@@ -197,25 +197,25 @@ class TypeTranslator:
|
|
|
197
197
|
#
|
|
198
198
|
|
|
199
199
|
def _translate_SimTypeInt128(self, st: sim_type.SimTypeChar) -> typeconsts.Int128:
|
|
200
|
-
return typeconsts.Int128()
|
|
200
|
+
return typeconsts.Int128(name=st.label)
|
|
201
201
|
|
|
202
202
|
def _translate_SimTypeInt256(self, st: sim_type.SimTypeChar) -> typeconsts.Int256:
|
|
203
|
-
return typeconsts.Int256()
|
|
203
|
+
return typeconsts.Int256(name=st.label)
|
|
204
204
|
|
|
205
205
|
def _translate_SimTypeInt512(self, st: sim_type.SimTypeChar) -> typeconsts.Int512:
|
|
206
|
-
return typeconsts.Int512()
|
|
206
|
+
return typeconsts.Int512(name=st.label)
|
|
207
207
|
|
|
208
208
|
def _translate_SimTypeInt(self, st: sim_type.SimTypeInt) -> typeconsts.Int32:
|
|
209
|
-
return typeconsts.Int32()
|
|
209
|
+
return typeconsts.Int32(name=st.label)
|
|
210
210
|
|
|
211
211
|
def _translate_SimTypeLong(self, st: sim_type.SimTypeLong) -> typeconsts.Int32:
|
|
212
|
-
return typeconsts.Int32()
|
|
212
|
+
return typeconsts.Int32(name=st.label)
|
|
213
213
|
|
|
214
214
|
def _translate_SimTypeLongLong(self, st: sim_type.SimTypeLongLong) -> typeconsts.Int64:
|
|
215
|
-
return typeconsts.Int64()
|
|
215
|
+
return typeconsts.Int64(name=st.label)
|
|
216
216
|
|
|
217
217
|
def _translate_SimTypeChar(self, st: sim_type.SimTypeChar) -> typeconsts.Int8:
|
|
218
|
-
return typeconsts.Int8()
|
|
218
|
+
return typeconsts.Int8(name=st.label)
|
|
219
219
|
|
|
220
220
|
def _translate_SimStruct(self, st: sim_type.SimStruct) -> typeconsts.Struct:
|
|
221
221
|
fields = {}
|
|
@@ -224,25 +224,25 @@ class TypeTranslator:
|
|
|
224
224
|
offset = offsets[name]
|
|
225
225
|
fields[offset] = self._simtype2tc(ty)
|
|
226
226
|
|
|
227
|
-
return typeconsts.Struct(fields=fields)
|
|
227
|
+
return typeconsts.Struct(fields=fields, name=st.label)
|
|
228
228
|
|
|
229
229
|
def _translate_SimTypeArray(self, st: sim_type.SimTypeArray) -> typeconsts.Array:
|
|
230
230
|
elem_type = self._simtype2tc(st.elem_type)
|
|
231
|
-
return typeconsts.Array(elem_type, count=st.length)
|
|
231
|
+
return typeconsts.Array(elem_type, count=st.length, name=st.label)
|
|
232
232
|
|
|
233
233
|
def _translate_SimTypePointer(self, st: sim_type.SimTypePointer) -> typeconsts.Pointer32 | typeconsts.Pointer64:
|
|
234
234
|
base = self._simtype2tc(st.pts_to)
|
|
235
235
|
if self.arch.bits == 32:
|
|
236
|
-
return typeconsts.Pointer32(base)
|
|
236
|
+
return typeconsts.Pointer32(base, name=st.label)
|
|
237
237
|
if self.arch.bits == 64:
|
|
238
|
-
return typeconsts.Pointer64(base)
|
|
238
|
+
return typeconsts.Pointer64(base, name=st.label)
|
|
239
239
|
raise TypeError(f"Unsupported pointer size {self.arch.bits}")
|
|
240
240
|
|
|
241
241
|
def _translate_SimTypeFloat(self, st: sim_type.SimTypeFloat) -> typeconsts.Float32:
|
|
242
|
-
return typeconsts.Float32()
|
|
242
|
+
return typeconsts.Float32(name=st.label)
|
|
243
243
|
|
|
244
244
|
def _translate_SimTypeDouble(self, st: sim_type.SimTypeDouble) -> typeconsts.Float64:
|
|
245
|
-
return typeconsts.Float64()
|
|
245
|
+
return typeconsts.Float64(name=st.label)
|
|
246
246
|
|
|
247
247
|
|
|
248
248
|
TypeConstHandlers = {
|