Browse Source

Perform second pass on vtable with resolved ambiguities

nosoop 10 months ago
parent
commit
614766ae18
1 changed files with 13 additions and 3 deletions
  1. 13 3
      src/smgdc/vtable.py

+ 13 - 3
src/smgdc/vtable.py

@@ -4,6 +4,7 @@
 # this should probably be cleaned up and moved somewhere else
 
 import collections
+import dataclasses
 import itertools
 import operator
 import typing
@@ -105,10 +106,12 @@ def get_vtables_from_address(bin: "LinuxBinary", vt: Symbol) -> list[VTable]:
     vtda = bin.vtable_disambiguator
 
     # returns a list of vtables for each vtable present on the class
-    class VTableFunction(typing.NamedTuple):
+    @dataclasses.dataclass
+    class VTableFunction:
         tblidx: int
         possible_syms: set[Symbol]
 
+    disambiguated_functions = set()
     function_list: list[VTableFunction] = []
     vptr_lists = vtda.get_vfptrs_from_table(vt)
     for table_index, vptrs in enumerate(vptr_lists):
@@ -141,9 +144,11 @@ def get_vtables_from_address(bin: "LinuxBinary", vt: Symbol) -> list[VTable]:
                         break
 
                 # it's possible that the other function(s) is/are resolveable.
-                # without doing multiple passes and saving the disambiguity somewhere it'll be difficult to match
 
                 if matched_overload:
+                    # within a vtable we expect a non-extern symbol to resolvee exactly once,
+                    # so we can eliminate it from candidacy elsewhere
+                    disambiguated_functions.add(matched_overload)
                     function_list.append(VTableFunction(table_index, {matched_overload}))
                     continue
 
@@ -157,10 +162,15 @@ def get_vtables_from_address(bin: "LinuxBinary", vt: Symbol) -> list[VTable]:
         elif len(vfn.possible_syms) == 1:
             continue
 
+        remaining_syms = vfn.possible_syms - disambiguated_functions
+        if len(remaining_syms) == 1:
+            vfn.possible_syms = remaining_syms
+            continue
+
         # we should never receive an empty ``VTableFunction.possible_syms``
         # for now we need to assert that a function address is unambiguous given the context
         vt_name = demangler.parse(vt.name)
-        candidate_names = set(sym.name for sym in vfn.possible_syms)
+        candidate_names = set(sym.name for sym in remaining_syms)
         raise Exception(f"Ambiguity in {vt_name} position {n}; candidates {candidate_names}")
 
     return [