summaryrefslogtreecommitdiff
path: root/view/sharedcache/tests
diff options
context:
space:
mode:
authorMason Reed <mason@vector35.com>2025-03-10 11:05:40 -0400
committerMason Reed <mason@vector35.com>2025-04-02 05:36:54 -0400
commit25cc02431b61097b2adfc2fbc493b648b0300c3b (patch)
treea79d9c4f4f67234d3bf9bda413e8608f479a4cc8 /view/sharedcache/tests
parentfa85bf28502286c4821427c5d0ed91a7ed46f8f6 (diff)
[SharedCache] Refactor Shared Cache
In absence of a better name, this commit refactors the shared cache code.
Diffstat (limited to 'view/sharedcache/tests')
-rw-r--r--view/sharedcache/tests/validate_images.py94
1 files changed, 94 insertions, 0 deletions
diff --git a/view/sharedcache/tests/validate_images.py b/view/sharedcache/tests/validate_images.py
new file mode 100644
index 00000000..40eb37db
--- /dev/null
+++ b/view/sharedcache/tests/validate_images.py
@@ -0,0 +1,94 @@
+import re
+import sys
+import os
+from binaryninja import sharedcache, load
+
+
+# This is some apple map file thingy, you will know if you have one because you will have a .map file.
+def parse_map_file(map_file_path):
+ mappings = []
+ libraries = []
+
+ with open(map_file_path, 'r') as file:
+ lines = file.readlines()
+
+ mapping_pattern = re.compile(
+ r"mapping\s+(?P<type>[A-Z]+)\s+(?P<size>[\dMKB]+)\s+0x(?P<start>[a-fA-F0-9]+)\s+->\s+0x(?P<end>[a-fA-F0-9]+)"
+ )
+ library_pattern = re.compile(
+ r"^(?P<library>.+)$"
+ )
+ section_pattern = re.compile(
+ r"\s+(?P<section>[^\s]+)\s+0x(?P<start>[a-fA-F0-9]+)\s+->\s+0x[a-fA-F0-9]+"
+ )
+
+ current_library = None
+
+ for line in lines:
+ # Check for a region mapping line
+ mapping_match = mapping_pattern.match(line)
+ if mapping_match:
+ mappings.append({
+ "type": mapping_match.group("type"),
+ "size": mapping_match.group("size"),
+ "start": int(mapping_match.group("start"), 16)
+ })
+ continue
+
+ # Check for a section line within a library
+ section_match = section_pattern.match(line)
+ if section_match and current_library is not None:
+ current_library["sections"].append({
+ "section": section_match.group("section"),
+ "start": int(section_match.group("start"), 16)
+ })
+ continue
+
+ # Check for a library name line
+ library_match = library_pattern.match(line)
+ if library_match:
+ current_library = {
+ "name": library_match.group("library"),
+ "sections": []
+ }
+ libraries.append(current_library)
+ continue
+
+ return mappings, libraries
+
+
+def main():
+ if len(sys.argv) < 2:
+ print("Please provide a shared cache binary path to validate. There must be an adjacent .map file.")
+ sys.exit(1)
+
+ binary_path = sys.argv[1]
+ bv = load(binary_path)
+ assert bv is not None, f"Failed to create BinaryView for {str(binary_path)}"
+ controller = sharedcache.SharedCacheController(bv)
+ assert controller.is_valid
+
+ map_file_path = bv.file.filename + ".map"
+ if not os.path.exists(map_file_path):
+ print(f"Error: Map file does not exist at path: {map_file_path}")
+ sys.exit(1)
+
+ mappings, map_images = parse_map_file(map_file_path)
+
+ # Validate images and sections
+ for map_image in map_images:
+ image = controller.get_image_with_name(map_image["name"])
+ if not image:
+ raise ValueError(f"Image not found: {map_image['name']}")
+ print(f"Checking image... {image.name}")
+
+ for section in map_image["sections"]:
+ if not section["start"] in image.region_starts:
+ raise ValueError(
+ f"Section not found in image '{image.name}': {section['start']} -> {image.region_starts}")
+
+ print("Validation successful!")
+
+
+if __name__ == "__main__":
+ main()