Squashed 'external/capstone/' content from commit e46f64fa

git-subtree-dir: external/capstone
git-subtree-split: e46f64fadb351e9ecd05264fab26f2772feb0994
This commit is contained in:
2026-05-11 11:55:07 +02:00
commit 802798ce3c
3968 changed files with 2967598 additions and 0 deletions
+354
View File
@@ -0,0 +1,354 @@
#!/usr/bin/env python3
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import argparse
import logging as log
import os
import shutil
import subprocess
import sys
import json
from enum import StrEnum
from pathlib import Path
from autosync.cpptranslator.Configurator import Configurator
from autosync.cpptranslator.CppTranslator import Translator
from autosync.HeaderPatcher import CompatHeaderBuilder, HeaderPatcher
from autosync.Helper import convert_loglevel, fail_exit, get_path
from autosync.IncGenerator import IncGenerator
from autosync.MCUpdater import MCUpdater
from autosync.Targets import ARCH_LLVM_NAMING, TARGET_TO_DIR_NAME
class USteps(StrEnum):
INC_GEN = "IncGen"
TRANS = "Translate"
DIFF = "Diff"
MC = "MCUpdate"
PATCH_HEADER = "PatchArchHeader"
ALL = "All"
class ASUpdater:
"""
The auto-sync updater.
"""
def __init__(
self,
arch: str,
write: bool,
steps: list[USteps],
inc_list: list,
no_clean: bool,
copy_translated: bool,
differ_no_auto_apply: bool,
wait_for_user: bool = True,
) -> None:
self.arch = arch
self.arch_dir_name = TARGET_TO_DIR_NAME[self.arch]
self.write = write
self.no_clean_build = no_clean
self.inc_list = inc_list
self.wait_for_user = wait_for_user
if USteps.ALL in steps:
self.steps = [
USteps.INC_GEN,
USteps.TRANS,
USteps.DIFF,
USteps.MC,
USteps.PATCH_HEADER,
]
else:
self.steps = steps
self.copy_translated = copy_translated
self.differ_no_auto_apply = differ_no_auto_apply
self.arch_dir = get_path("{CS_ARCH_MODULE_DIR}").joinpath(
TARGET_TO_DIR_NAME[self.arch]
)
if not self.no_clean_build:
self.clean_build_dir()
self.inc_generator = IncGenerator(
self.arch,
self.inc_list,
)
with open(get_path("{MCUPDATER_CONFIG_FILE}")) as f:
self.mcupdater_conf = json.loads(f.read())
self.mc_updater = MCUpdater(
self.arch,
get_path("{LLVM_MC_TEST_DIR}"),
None,
None,
self.arch in self.mcupdater_conf["unify_test_cases"],
multi_mode=True,
)
def clean_build_dir(self) -> None:
log.info("Clean build directory")
path: Path
for path in get_path("{BUILD_DIR}").iterdir():
log.debug(f"Delete {path}")
if path.is_dir():
shutil.rmtree(path)
else:
os.remove(path)
def patch_main_header(self) -> list:
"""
Patches the main header of the arch with the .inc files.
It returns a list of files it has patched into the main header.
"""
if not self.write:
return []
main_header = get_path("{CS_INCLUDE_DIR}").joinpath(f"{self.arch.lower()}.h")
# Just try every inc file
patched = []
for file in get_path("{C_INC_OUT_DIR}").iterdir():
patcher = HeaderPatcher(main_header, file)
if patcher.patch_header():
# Save the path. This file should not be moved.
patched.append(file)
if self.arch == "AArch64":
builder = CompatHeaderBuilder(
v6=main_header,
v5=get_path("{CS_INCLUDE_DIR}").joinpath(f"arm64.h"),
arch="aarch64",
)
builder.generate_v5_compat_header()
elif self.arch == "AArch64":
builder = CompatHeaderBuilder(
v6=main_header,
v5=get_path("{CS_INCLUDE_DIR}").joinpath(f"systemz_compatibility.h"),
arch="systemz",
)
builder.generate_v5_compat_header()
return patched
def copy_files(self, path: Path, dest: Path) -> None:
"""
Copies files from path to dest.
If path is a directory it copies all files in it.
If it is a file, it only copies it.
"""
if not self.write:
return
if not dest.is_dir():
fail_exit(f"{dest} is not a directory.")
if path.is_file():
log.debug(f"Copy {path} to {dest}")
shutil.copy(path, dest)
return
for file in path.iterdir():
log.debug(f"Copy {path} to {dest}")
shutil.copy(file, dest)
def check_tree_sitter(self) -> None:
ts_dir = get_path("{VENDOR_DIR}").joinpath("tree-sitter-cpp")
if not ts_dir.exists():
log.info("tree-sitter was not fetched. Cloning it now...")
subprocess.run(
["git", "submodule", "update", "--init", "--recursive"], check=True
)
def translate(self) -> None:
self.check_tree_sitter()
translator_config = get_path("{CPP_TRANSLATOR_CONFIG}")
configurator = Configurator(self.arch, translator_config)
translator = Translator(configurator, self.wait_for_user)
translator.translate()
translator.remark_manual_files()
def diff(self) -> None:
translator_config = get_path("{CPP_TRANSLATOR_CONFIG}")
configurator = Configurator(self.arch, translator_config)
from autosync.cpptranslator.Differ import Differ
differ = Differ(configurator, self.differ_no_auto_apply)
differ.diff()
def update(self) -> None:
if USteps.INC_GEN in self.steps:
self.inc_generator.generate()
if USteps.PATCH_HEADER in self.steps:
if self.write:
patched = self.patch_main_header()
log.info(f"Patched {len(patched)} .inc files into the main header.")
else:
log.info("Patching the main header requires the -w flag.")
if USteps.TRANS in self.steps:
self.translate()
if USteps.DIFF in self.steps:
self.diff()
if USteps.MC in self.steps:
self.mc_updater.gen_all()
self.mc_updater.write_to_build_dir()
self.mc_updater.write_to_build_dir(fuzzer_tests=True)
if not self.write:
if self.inc_generator.has_inc_patches():
log.warning(
f"Patches to inc files are only applied with the -w flag. This wasn't done. Find them in {get_path('{INC_PATCH_DIR}')}"
)
# Done
exit(0)
# Copy .inc files
log.info(f"Copy .inc files to {self.arch_dir}")
i = 0
arch_header = get_path("{CS_INCLUDE_DIR}").joinpath(f"{self.arch.lower()}.h")
for file in get_path("{C_INC_OUT_DIR}").iterdir():
if HeaderPatcher.file_in_main_header(arch_header, file.name):
continue
self.copy_files(file, self.arch_dir)
i += 1
self.inc_generator.apply_patches()
log.info(f"Copied {i} files")
i = 0
if self.copy_translated:
# Diffed files
log.info(f"Copy translated files to {self.arch_dir}")
for file in get_path("{CPP_TRANSLATOR_TRANSLATION_OUT_DIR}").iterdir():
self.copy_files(file, self.arch_dir)
i += 1
else:
# Diffed files
log.info(f"Copy diffed files to {self.arch_dir}")
for file in get_path("{CPP_TRANSLATOR_DIFF_OUT_DIR}").iterdir():
self.copy_files(file, self.arch_dir)
i += 1
log.info(f"Copied {i} files")
# MC tests
i = 0
mc_dir = get_path("{MC_DIR}").joinpath(self.arch_dir_name)
log.info(f"Copy MC test files to {mc_dir}")
for file in get_path("{MCUPDATER_OUT_DIR}").iterdir():
self.copy_files(file, mc_dir)
i += 1
legacy_mc_dir = get_path("{LEGACY_MC_DIR}").joinpath(self.arch_dir_name)
for file in get_path("{MCUPDATER_OUT_FUZZ_DIR}").iterdir():
self.copy_files(file, legacy_mc_dir)
i += 1
log.info(f"Copied {i} files")
exit(0)
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
prog="Auto-Sync-Updater",
description="Capstones architecture module updater.",
)
parser.add_argument(
"-a",
dest="arch",
help="Name of target architecture.",
choices=ARCH_LLVM_NAMING,
required=True,
)
parser.add_argument(
"-d",
dest="no_clean",
help="Don't clean build dir before updating.",
action="store_true",
)
parser.add_argument(
"-w",
dest="write",
help="Write generated/translated files to arch/<ARCH>/",
action="store_true",
)
parser.add_argument(
"-v",
dest="verbosity",
help="Verbosity of the log messages.",
choices=["debug", "info", "warning", "fatal"],
default="info",
)
parser.add_argument(
"-e",
dest="no_auto_apply",
help="Differ: Do not apply saved diff resolutions. Ask for every diff again.",
action="store_true",
)
parser.add_argument(
"-s",
dest="steps",
help="List of update steps to perform. If omitted, it performs all update steps.",
choices=[
"All",
"IncGen",
"Translate",
"Diff",
"MCUpdate",
"PatchArchHeader",
],
nargs="+",
default=["All"],
)
parser.add_argument(
"--inc-list",
dest="inc_list",
help="Only generate the following inc files.",
choices=[
"All",
"Disassembler",
"AsmWriter",
"RegisterInfo",
"InstrInfo",
"SubtargetInfo",
"Mapping",
"SystemOperand",
],
nargs="+",
type=str,
default=["All"],
)
parser.add_argument(
"--copy-translated",
dest="copy_translated",
help="Copy the translated files and not the files produced by the Differ.",
action="store_true",
)
parser.add_argument(
"--ci",
dest="wait_for_user",
help="The translator will not wait for user input when printing important logs.",
action="store_false",
)
arguments = parser.parse_args()
return arguments
def main():
args = parse_args()
log.basicConfig(
level=convert_loglevel(args.verbosity),
stream=sys.stdout,
format="%(levelname)-5s - %(message)s",
force=True,
)
Updater = ASUpdater(
args.arch,
args.write,
args.steps,
args.inc_list,
args.no_clean,
args.copy_translated,
args.no_auto_apply,
args.wait_for_user,
)
Updater.update()
if __name__ == "__main__":
main()