blob: 0826ef55751e89403a93469f8655cd2563991dcd [file] [log] [blame]
#!/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
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 check_py_version, convert_loglevel, fail_exit, get_path
from autosync.IncGenerator import IncGenerator
class USteps(StrEnum):
INC_GEN = "IncGen"
TRANS = "Translate"
DIFF = "Diff"
ALL = "All"
class ASUpdater:
"""
The auto-sync updater.
"""
def __init__(
self,
arch: str,
write: bool,
steps: list[USteps],
inc_list: list,
no_clean: bool,
refactor: bool,
differ_no_auto_apply: bool,
wait_for_user: bool = True,
) -> None:
self.arch = 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]
else:
self.steps = steps
self.refactor = refactor
self.differ_no_auto_apply = differ_no_auto_apply
self.arch_dir = get_path("{CS_ARCH_MODULE_DIR}").joinpath(self.arch)
if not self.no_clean_build:
self.clean_build_dir()
self.inc_generator = IncGenerator(
self.arch,
self.inc_list,
)
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":
# Update the compatibility header
builder = CompatHeaderBuilder(
aarch64_h=main_header,
arm64_h=get_path("{CS_INCLUDE_DIR}").joinpath(f"arm64.h"),
)
builder.generate_aarch64_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()
# Runtime for large files is huge
# Use helper clang-format
# self.run_clang_format(self.conf["build_dir_path"].joinpath(C_INC_OUT_DIR))
patched = self.patch_main_header()
for file in get_path("{C_INC_OUT_DIR}").iterdir():
if file in patched:
continue
self.copy_files(file, self.arch_dir)
if USteps.TRANS in self.steps:
self.translate()
if USteps.DIFF in self.steps:
self.diff()
# Write 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=["ARM", "PPC", "AArch64", "Alpha"],
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",
],
nargs="+",
type=USteps,
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(
"--refactor",
dest="refactor",
help="Sets change update behavior to ease refactoring and new implementations.",
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
if __name__ == "__main__":
check_py_version()
args = parse_args()
log.basicConfig(
level=convert_loglevel(args.verbosity),
stream=sys.stdout,
format="%(levelname)-5s - %(message)s",
)
Updater = ASUpdater(
args.arch,
args.write,
args.steps,
args.inc_list,
args.no_clean,
args.refactor,
args.no_auto_apply,
args.wait_for_user,
)
Updater.update()