|  | @@ -48,10 +48,17 @@ def convert_types(*types):
 | 
	
		
			
				|  |  |  # or bytesigs + offsets
 | 
	
		
			
				|  |  |  ResultValues = dict[string.Template, typing.Any]
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +# some virtual functions cannot be disambiguated outright, or need to check the resolved
 | 
	
		
			
				|  |  | +# state of the rest of the table - for the former we have to disambiguate them out-of-band
 | 
	
		
			
				|  |  | +#
 | 
	
		
			
				|  |  | +# ideally we would do some linear constraint on ordering, but for now we just spec the offset
 | 
	
		
			
				|  |  | +VTableConstraintDict = dict[str, dict[str, int]]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  class BaseBinary:
 | 
	
		
			
				|  |  |      path: pathlib.Path
 | 
	
		
			
				|  |  |      angr: angr.Project
 | 
	
		
			
				|  |  | +    hash: str
 | 
	
		
			
				|  |  |      _file: io.IOBase
 | 
	
		
			
				|  |  |      _mm: mmap.mmap
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -59,8 +66,8 @@ class BaseBinary:
 | 
	
		
			
				|  |  |          self.path = path
 | 
	
		
			
				|  |  |          self._file = open(self.path, "rb")
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        file_hash = hashlib.file_digest(self._file, "sha256")
 | 
	
		
			
				|  |  | -        cached_proj = (cache_path or pathlib.Path()) / f"{file_hash.hexdigest()}.angr.pkl"
 | 
	
		
			
				|  |  | +        self.hash = hashlib.file_digest(self._file, "sha256").hexdigest()
 | 
	
		
			
				|  |  | +        cached_proj = (cache_path or pathlib.Path()) / f"{self.hash}.angr.pkl"
 | 
	
		
			
				|  |  |          if not cached_proj.exists():
 | 
	
		
			
				|  |  |              self.angr = angr.Project(self.path, load_options={"auto_load_libs": False})
 | 
	
		
			
				|  |  |              cached_proj.write_bytes(pickle.dumps(self.angr))
 | 
	
	
		
			
				|  | @@ -83,8 +90,17 @@ class WindowsBinary(BaseBinary):
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  class LinuxBinary(BaseBinary):
 | 
	
		
			
				|  |  | +    vtable_constraint: VTableConstraintDict
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      def __init__(self, path: pathlib.Path, cache_path: pathlib.Path | None = None):
 | 
	
		
			
				|  |  |          super().__init__(path, cache_path)
 | 
	
		
			
				|  |  | +        self.vtable_constraint = {}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        constraints_file = (cache_path or pathlib.Path()) / f"{self.hash}.constraints.toml"
 | 
	
		
			
				|  |  | +        if constraints_file.exists():
 | 
	
		
			
				|  |  | +            self.vtable_constraint = msgspec.toml.decode(
 | 
	
		
			
				|  |  | +                constraints_file.read_bytes(), type=VTableConstraintDict
 | 
	
		
			
				|  |  | +            )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      @functools.cached_property
 | 
	
		
			
				|  |  |      def vtable_disambiguator(self) -> VtableDisambiguator:
 |