Fuck git
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import json
|
||||
import logging as log
|
||||
from pathlib import Path
|
||||
|
||||
import tree_sitter_cpp as ts_cpp
|
||||
from tree_sitter import Language, Parser
|
||||
|
||||
from autosync.Helper import fail_exit
|
||||
|
||||
|
||||
class Configurator:
|
||||
"""
|
||||
Holds common setup procedures for the configuration.
|
||||
It reads the configuration file, compiles languages and initializes the Parser.
|
||||
"""
|
||||
|
||||
arch: str
|
||||
config_path: Path
|
||||
config: dict = None
|
||||
ts_cpp_lang: Language = None
|
||||
parser: Parser = None
|
||||
|
||||
def __init__(self, arch: str, config_path: Path) -> None:
|
||||
self.arch = arch
|
||||
self.config_path = config_path
|
||||
self.load_config()
|
||||
self.ts_set_cpp_language()
|
||||
self.init_parser()
|
||||
|
||||
def get_arch(self) -> str:
|
||||
return self.arch
|
||||
|
||||
def get_cpp_lang(self) -> Language:
|
||||
if self.ts_cpp_lang:
|
||||
return self.ts_cpp_lang
|
||||
self.ts_set_cpp_language()
|
||||
return self.ts_cpp_lang
|
||||
|
||||
def get_parser(self) -> Parser:
|
||||
if self.parser:
|
||||
return self.parser
|
||||
self.init_parser()
|
||||
return self.parser
|
||||
|
||||
def get_arch_config(self) -> dict:
|
||||
if self.config:
|
||||
return self.config[self.arch]
|
||||
self.load_config()
|
||||
return self.config[self.arch]
|
||||
|
||||
def get_general_config(self) -> dict:
|
||||
if self.config:
|
||||
return self.config["General"]
|
||||
self.load_config()
|
||||
return self.config["General"]
|
||||
|
||||
def get_patch_config(self) -> dict:
|
||||
if self.config:
|
||||
return self.config["General"]["patching"]
|
||||
self.load_config()
|
||||
return self.config["General"]["patching"]
|
||||
|
||||
def load_config(self) -> None:
|
||||
if not Path.exists(self.config_path):
|
||||
fail_exit(f"Could not load arch config file at '{self.config_path}'")
|
||||
with open(self.config_path) as f:
|
||||
conf = json.loads(f.read())
|
||||
if self.arch not in conf:
|
||||
fail_exit(
|
||||
f"{self.arch} has no configuration. Please add them in {self.config_path}!"
|
||||
)
|
||||
self.config = conf
|
||||
|
||||
def ts_set_cpp_language(self) -> None:
|
||||
self.ts_cpp_lang = Language(ts_cpp.language())
|
||||
|
||||
def init_parser(self) -> None:
|
||||
log.debug("Init parser")
|
||||
self.parser = Parser(self.ts_cpp_lang)
|
||||
+551
@@ -0,0 +1,551 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import argparse
|
||||
import logging as log
|
||||
import sys
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
import termcolor
|
||||
from tree_sitter import Language, Node, Parser, Query, Tree
|
||||
|
||||
from autosync.cpptranslator.Configurator import Configurator
|
||||
from autosync.cpptranslator.patches.AddCSDetail import AddCSDetail
|
||||
from autosync.cpptranslator.patches.AddOperand import AddOperand
|
||||
from autosync.cpptranslator.patches.Assert import Assert
|
||||
from autosync.cpptranslator.patches.BitCastStdArray import BitCastStdArray
|
||||
from autosync.cpptranslator.patches.CheckDecoderStatus import CheckDecoderStatus
|
||||
from autosync.cpptranslator.patches.ClassConstructorDef import ClassConstructorDef
|
||||
from autosync.cpptranslator.patches.ClassesDef import ClassesDef
|
||||
from autosync.cpptranslator.patches.ConstMCInstParameter import ConstMCInstParameter
|
||||
from autosync.cpptranslator.patches.ConstMCOperand import ConstMCOperand
|
||||
from autosync.cpptranslator.patches.CppInitCast import CppInitCast
|
||||
from autosync.cpptranslator.patches.CreateOperand0 import CreateOperand0
|
||||
from autosync.cpptranslator.patches.CreateOperand1 import CreateOperand1
|
||||
from autosync.cpptranslator.patches.Data import Data
|
||||
from autosync.cpptranslator.patches.DeclarationInConditionClause import (
|
||||
DeclarationInConditionalClause,
|
||||
)
|
||||
from autosync.cpptranslator.patches.DecodeInstruction import DecodeInstruction
|
||||
from autosync.cpptranslator.patches.DecoderCast import DecoderCast
|
||||
from autosync.cpptranslator.patches.DecoderParameter import DecoderParameter
|
||||
from autosync.cpptranslator.patches.FallThrough import FallThrough
|
||||
from autosync.cpptranslator.patches.FeatureBits import FeatureBits
|
||||
from autosync.cpptranslator.patches.FeatureBitsDecl import FeatureBitsDecl
|
||||
from autosync.cpptranslator.patches.FieldFromInstr import FieldFromInstr
|
||||
from autosync.cpptranslator.patches.GetNumOperands import GetNumOperands
|
||||
from autosync.cpptranslator.patches.GetOpcode import GetOpcode
|
||||
from autosync.cpptranslator.patches.GetOperand import GetOperand
|
||||
from autosync.cpptranslator.patches.GetOperandRegImm import GetOperandRegImm
|
||||
from autosync.cpptranslator.patches.GetRegClass import GetRegClass
|
||||
from autosync.cpptranslator.patches.GetRegFromClass import GetRegFromClass
|
||||
from autosync.cpptranslator.patches.GetSubReg import GetSubReg
|
||||
from autosync.cpptranslator.patches.Includes import Includes
|
||||
from autosync.cpptranslator.patches.InlineToStaticInline import InlineToStaticInline
|
||||
from autosync.cpptranslator.patches.IsOptionalDef import IsOptionalDef
|
||||
from autosync.cpptranslator.patches.IsPredicate import IsPredicate
|
||||
from autosync.cpptranslator.patches.IsRegImm import IsOperandRegImm
|
||||
from autosync.cpptranslator.patches.LLVMFallThrough import LLVMFallThrough
|
||||
from autosync.cpptranslator.patches.LLVMunreachable import LLVMUnreachable
|
||||
from autosync.cpptranslator.patches.BadConditionCode import BadConditionCode
|
||||
from autosync.cpptranslator.patches.LLVM_DEBUG import LLVM_DEBUG
|
||||
from autosync.cpptranslator.patches.MethodToFunctions import MethodToFunction
|
||||
from autosync.cpptranslator.patches.MethodTypeQualifier import MethodTypeQualifier
|
||||
from autosync.cpptranslator.patches.NamespaceAnon import NamespaceAnon
|
||||
from autosync.cpptranslator.patches.NamespaceArch import NamespaceArch
|
||||
from autosync.cpptranslator.patches.NamespaceLLVM import NamespaceLLVM
|
||||
from autosync.cpptranslator.patches.OutStreamParam import OutStreamParam
|
||||
from autosync.cpptranslator.patches.Override import Override
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
from autosync.cpptranslator.patches.PredicateBlockFunctions import (
|
||||
PredicateBlockFunctions,
|
||||
)
|
||||
from autosync.cpptranslator.patches.PrintAnnotation import PrintAnnotation
|
||||
from autosync.cpptranslator.patches.PrintRegImmShift import PrintRegImmShift
|
||||
from autosync.cpptranslator.patches.QualifiedIdentifier import QualifiedIdentifier
|
||||
from autosync.cpptranslator.patches.ReferencesDecl import ReferencesDecl
|
||||
from autosync.cpptranslator.patches.RegClassContains import RegClassContains
|
||||
from autosync.cpptranslator.patches.SetOpcode import SetOpcode
|
||||
from autosync.cpptranslator.patches.SignExtend import SignExtend
|
||||
from autosync.cpptranslator.patches.Size import Size
|
||||
from autosync.cpptranslator.patches.SizeAssignments import SizeAssignment
|
||||
from autosync.cpptranslator.patches.STIArgument import STIArgument
|
||||
from autosync.cpptranslator.patches.STIFeatureBits import STIFeatureBits
|
||||
from autosync.cpptranslator.patches.STParameter import SubtargetInfoParam
|
||||
from autosync.cpptranslator.patches.StreamOperation import StreamOperations
|
||||
from autosync.cpptranslator.patches.TemplateDeclaration import TemplateDeclaration
|
||||
from autosync.cpptranslator.patches.TemplateDefinition import TemplateDefinition
|
||||
from autosync.cpptranslator.patches.TemplateParamDecl import TemplateParamDecl
|
||||
from autosync.cpptranslator.patches.TemplateRefs import TemplateRefs
|
||||
from autosync.cpptranslator.patches.UseMarkup import UseMarkup
|
||||
from autosync.cpptranslator.patches.UsingDeclaration import UsingDeclaration
|
||||
from autosync.cpptranslator.TemplateCollector import TemplateCollector
|
||||
from autosync.Helper import (
|
||||
convert_loglevel,
|
||||
get_header,
|
||||
get_path,
|
||||
print_prominent_warning,
|
||||
run_clang_format,
|
||||
)
|
||||
from autosync.cpptranslator.patches.isUInt import IsUInt
|
||||
from autosync.cpptranslator.tree_sitter_compatibility import query_captures_22_3
|
||||
|
||||
|
||||
class Translator:
|
||||
ts_cpp_lang: Language = None
|
||||
parser: Parser = None
|
||||
template_collector: TemplateCollector = None
|
||||
src_paths: [Path]
|
||||
out_paths: [Path]
|
||||
conf: dict
|
||||
src = b""
|
||||
current_src_path_in: Path = None
|
||||
current_src_path_out: Path = None
|
||||
tree: Tree = None
|
||||
|
||||
# Patch priorities: The bigger the number the later the patch will be applied.
|
||||
# Patches which create templates must always be executed last. Since syntax
|
||||
# in macros is no longer parsed as such (but is only recognized as macro body).
|
||||
#
|
||||
# If a patch must be executed before another patch (because the matching rules depend on it)
|
||||
# mark this dependency as you see below.
|
||||
patches: [Patch] = list()
|
||||
|
||||
patch_priorities: {str: int} = {
|
||||
RegClassContains.__name__: 0,
|
||||
GetRegClass.__name__: 0,
|
||||
GetRegFromClass.__name__: 0,
|
||||
CppInitCast.__name__: 0,
|
||||
BitCastStdArray.__name__: 0,
|
||||
PrintRegImmShift.__name__: 0,
|
||||
InlineToStaticInline.__name__: 0,
|
||||
GetSubReg.__name__: 0,
|
||||
UseMarkup.__name__: 0,
|
||||
ConstMCOperand.__name__: 0,
|
||||
ClassConstructorDef.__name__: 0,
|
||||
ConstMCInstParameter.__name__: 0,
|
||||
PrintAnnotation.__name__: 0,
|
||||
GetNumOperands.__name__: 0,
|
||||
STIArgument.__name__: 0,
|
||||
DecodeInstruction.__name__: 0,
|
||||
FallThrough.__name__: 0,
|
||||
SizeAssignment.__name__: 0,
|
||||
FieldFromInstr.__name__: 0,
|
||||
FeatureBitsDecl.__name__: 0,
|
||||
FeatureBits.__name__: 0,
|
||||
STIFeatureBits.__name__: 0,
|
||||
Includes.__name__: 0,
|
||||
CreateOperand0.__name__: 0, # ◁───┐ `CreateOperand0` removes most calls to MI.addOperand().
|
||||
AddOperand.__name__: 1, # ────────┘ The ones left are fixed with the `AddOperand` patch.
|
||||
CreateOperand1.__name__: 0,
|
||||
IsUInt.__name__: 0,
|
||||
GetOpcode.__name__: 0,
|
||||
SetOpcode.__name__: 0,
|
||||
GetOperand.__name__: 0,
|
||||
GetOperandRegImm.__name__: 0,
|
||||
IsOperandRegImm.__name__: 0,
|
||||
SignExtend.__name__: 0,
|
||||
DecoderParameter.__name__: 0,
|
||||
UsingDeclaration.__name__: 0,
|
||||
DecoderCast.__name__: 0,
|
||||
IsPredicate.__name__: 0,
|
||||
IsOptionalDef.__name__: 0,
|
||||
Assert.__name__: 0, # ◁─────────┐ The llvm_unreachable calls are replaced with asserts.
|
||||
LLVMUnreachable.__name__: 1, # ─┘ Those assert should stay.
|
||||
LLVMFallThrough.__name__: 0,
|
||||
BadConditionCode.__name__: 0,
|
||||
LLVM_DEBUG.__name__: 0,
|
||||
DeclarationInConditionalClause.__name__: 0,
|
||||
StreamOperations.__name__: 0,
|
||||
OutStreamParam.__name__: 0, # ◁──────┐ add_cs_detail() is added to printOperand functions with a certain
|
||||
SubtargetInfoParam.__name__: 0, # ◁──┤ signature. This signature depends on those patches.
|
||||
MethodToFunction.__name__: 0, # ◁────┤
|
||||
AddCSDetail.__name__: 1, # ──────────┘
|
||||
NamespaceAnon.__name__: 0, # ◁─────┐ "llvm" and anonymous namespaces must be removed first,
|
||||
NamespaceLLVM.__name__: 0, # ◁─────┤ so they don't match in NamespaceArch.
|
||||
NamespaceArch.__name__: 1, # ──────┘
|
||||
PredicateBlockFunctions.__name__: 0,
|
||||
Override.__name__: 0,
|
||||
Size.__name__: 0,
|
||||
Data.__name__: 0,
|
||||
ClassesDef.__name__: 0, # ◁────────┐ Declarations must be extracted first from the classes.
|
||||
MethodTypeQualifier.__name__: 1, # ┘
|
||||
# All previous patches can contain qualified identifiers (Ids with the "::" operator) in their search patterns.
|
||||
# After this patch they are removed.
|
||||
QualifiedIdentifier.__name__: 2,
|
||||
ReferencesDecl.__name__: 3, # ◁────┐
|
||||
CheckDecoderStatus.__name__: 4, # ─┘ Reference declarations must be removed first.
|
||||
TemplateParamDecl.__name__: 5,
|
||||
TemplateRefs.__name__: 5,
|
||||
# Template declarations are replaced with macros.
|
||||
# Those declarations are parsed as macro afterwards
|
||||
TemplateDeclaration.__name__: 5,
|
||||
# Template definitions are replaced with macros.
|
||||
# Those template functions are parsed as macro afterwards.
|
||||
TemplateDefinition.__name__: 6,
|
||||
}
|
||||
|
||||
def __init__(self, configure: Configurator, wait_for_user: bool = False):
|
||||
self.configurator = configure
|
||||
self.wait_for_user = wait_for_user
|
||||
self.arch = self.configurator.get_arch()
|
||||
self.conf = self.configurator.get_arch_config()
|
||||
self.conf_general = self.configurator.get_general_config()
|
||||
self.ts_cpp_lang = self.configurator.get_cpp_lang()
|
||||
self.parser = self.configurator.get_parser()
|
||||
|
||||
self.src_paths: [Path] = [
|
||||
get_path(sp["in"]) for sp in self.conf["files_to_translate"]
|
||||
]
|
||||
t_out_dir: Path = get_path("{CPP_TRANSLATOR_TRANSLATION_OUT_DIR}")
|
||||
self.out_paths: [Path] = [
|
||||
t_out_dir.joinpath(sp["out"]) for sp in self.conf["files_to_translate"]
|
||||
]
|
||||
|
||||
self.collect_template_instances()
|
||||
self.init_patches()
|
||||
|
||||
def read_src_file(self, src_path: Path) -> None:
|
||||
"""Reads the file at src_path into self.src"""
|
||||
log.debug(f"Read {src_path}")
|
||||
if not Path.exists(src_path):
|
||||
log.fatal(f"Could not open the source file '{src_path}'")
|
||||
exit(1)
|
||||
with open(src_path) as f:
|
||||
self.src = bytes(f.read(), "utf8")
|
||||
|
||||
def init_patches(self):
|
||||
log.debug("Init patches")
|
||||
priorities = dict(
|
||||
sorted(self.patch_priorities.items(), key=lambda item: item[1])
|
||||
)
|
||||
for ptype, p in priorities.items():
|
||||
match ptype:
|
||||
case RegClassContains.__name__:
|
||||
patch = RegClassContains(p)
|
||||
case GetRegClass.__name__:
|
||||
patch = GetRegClass(p)
|
||||
case GetRegFromClass.__name__:
|
||||
patch = GetRegFromClass(p)
|
||||
case CppInitCast.__name__:
|
||||
patch = CppInitCast(p)
|
||||
case BitCastStdArray.__name__:
|
||||
patch = BitCastStdArray(p)
|
||||
case CheckDecoderStatus.__name__:
|
||||
patch = CheckDecoderStatus(p)
|
||||
case ReferencesDecl.__name__:
|
||||
patch = ReferencesDecl(p)
|
||||
case FieldFromInstr.__name__:
|
||||
patch = FieldFromInstr(p)
|
||||
case FeatureBitsDecl.__name__:
|
||||
patch = FeatureBitsDecl(p)
|
||||
case FeatureBits.__name__:
|
||||
patch = FeatureBits(p, bytes(self.arch, "utf8"))
|
||||
case STIFeatureBits.__name__:
|
||||
patch = STIFeatureBits(p, bytes(self.arch, "utf8"))
|
||||
case QualifiedIdentifier.__name__:
|
||||
patch = QualifiedIdentifier(p)
|
||||
case Includes.__name__:
|
||||
patch = Includes(p, self.arch)
|
||||
case ClassesDef.__name__:
|
||||
patch = ClassesDef(p)
|
||||
case CreateOperand0.__name__:
|
||||
patch = CreateOperand0(p)
|
||||
case CreateOperand1.__name__:
|
||||
patch = CreateOperand1(p)
|
||||
case IsUInt.__name__:
|
||||
patch = IsUInt(p)
|
||||
case GetOpcode.__name__:
|
||||
patch = GetOpcode(p)
|
||||
case SetOpcode.__name__:
|
||||
patch = SetOpcode(p)
|
||||
case GetOperand.__name__:
|
||||
patch = GetOperand(p)
|
||||
case SignExtend.__name__:
|
||||
patch = SignExtend(p)
|
||||
case TemplateDeclaration.__name__:
|
||||
patch = TemplateDeclaration(p, self.template_collector)
|
||||
case TemplateDefinition.__name__:
|
||||
patch = TemplateDefinition(p, self.template_collector)
|
||||
case DecoderParameter.__name__:
|
||||
patch = DecoderParameter(p)
|
||||
case TemplateRefs.__name__:
|
||||
patch = TemplateRefs(p)
|
||||
case TemplateParamDecl.__name__:
|
||||
patch = TemplateParamDecl(p)
|
||||
case MethodTypeQualifier.__name__:
|
||||
patch = MethodTypeQualifier(p)
|
||||
case UsingDeclaration.__name__:
|
||||
patch = UsingDeclaration(p)
|
||||
case NamespaceLLVM.__name__:
|
||||
patch = NamespaceLLVM(p)
|
||||
case DecoderCast.__name__:
|
||||
patch = DecoderCast(p)
|
||||
case IsPredicate.__name__:
|
||||
patch = IsPredicate(p)
|
||||
case IsOptionalDef.__name__:
|
||||
patch = IsOptionalDef(p)
|
||||
case Assert.__name__:
|
||||
patch = Assert(p)
|
||||
case LLVMFallThrough.__name__:
|
||||
patch = LLVMFallThrough(p)
|
||||
case BadConditionCode.__name__:
|
||||
patch = BadConditionCode(p)
|
||||
case DeclarationInConditionalClause.__name__:
|
||||
patch = DeclarationInConditionalClause(p)
|
||||
case OutStreamParam.__name__:
|
||||
patch = OutStreamParam(p)
|
||||
case MethodToFunction.__name__:
|
||||
patch = MethodToFunction(p)
|
||||
case GetOperandRegImm.__name__:
|
||||
patch = GetOperandRegImm(p)
|
||||
case StreamOperations.__name__:
|
||||
patch = StreamOperations(p)
|
||||
case SubtargetInfoParam.__name__:
|
||||
patch = SubtargetInfoParam(p)
|
||||
case SizeAssignment.__name__:
|
||||
patch = SizeAssignment(p)
|
||||
case NamespaceArch.__name__:
|
||||
patch = NamespaceArch(p)
|
||||
case NamespaceAnon.__name__:
|
||||
patch = NamespaceAnon(p)
|
||||
case PredicateBlockFunctions.__name__:
|
||||
patch = PredicateBlockFunctions(p)
|
||||
case FallThrough.__name__:
|
||||
patch = FallThrough(p)
|
||||
case DecodeInstruction.__name__:
|
||||
patch = DecodeInstruction(p)
|
||||
case STIArgument.__name__:
|
||||
patch = STIArgument(p)
|
||||
case GetNumOperands.__name__:
|
||||
patch = GetNumOperands(p)
|
||||
case AddOperand.__name__:
|
||||
patch = AddOperand(p)
|
||||
case PrintAnnotation.__name__:
|
||||
patch = PrintAnnotation(p)
|
||||
case ConstMCInstParameter.__name__:
|
||||
patch = ConstMCInstParameter(p)
|
||||
case LLVMUnreachable.__name__:
|
||||
patch = LLVMUnreachable(p)
|
||||
case LLVM_DEBUG.__name__:
|
||||
patch = LLVM_DEBUG(p)
|
||||
case ClassConstructorDef.__name__:
|
||||
patch = ClassConstructorDef(p)
|
||||
case ConstMCOperand.__name__:
|
||||
patch = ConstMCOperand(p)
|
||||
case UseMarkup.__name__:
|
||||
patch = UseMarkup(p)
|
||||
case GetSubReg.__name__:
|
||||
patch = GetSubReg(p)
|
||||
case InlineToStaticInline.__name__:
|
||||
patch = InlineToStaticInline(p)
|
||||
case AddCSDetail.__name__:
|
||||
patch = AddCSDetail(p, self.arch)
|
||||
case PrintRegImmShift.__name__:
|
||||
patch = PrintRegImmShift(p)
|
||||
case IsOperandRegImm.__name__:
|
||||
patch = IsOperandRegImm(p)
|
||||
case Override.__name__:
|
||||
patch = Override(p)
|
||||
case Size.__name__:
|
||||
patch = Size(p)
|
||||
case Data.__name__:
|
||||
patch = Data(p)
|
||||
case _:
|
||||
log.fatal(f"Patch type {ptype} not in Patch init routine.")
|
||||
exit(1)
|
||||
self.patches.append(patch)
|
||||
|
||||
def parse(self, src_path: Path) -> None:
|
||||
self.read_src_file(src_path)
|
||||
log.debug("Parse source code")
|
||||
self.tree = self.parser.parse(self.src)
|
||||
|
||||
def patch_src(self, p_list: [(bytes, Node)]) -> None:
|
||||
if len(p_list) == 0:
|
||||
return
|
||||
# Sort list of patches descending so the patches which are last in the file
|
||||
# get patched first. This way the indices of the code snippets before
|
||||
# don't change.
|
||||
patches = sorted(p_list, key=lambda x: x[1].start_byte, reverse=True)
|
||||
|
||||
new_src = b""
|
||||
patch: bytes
|
||||
node: Node
|
||||
for patch, node in patches:
|
||||
start_byte: int = node.start_byte
|
||||
old_end_byte: int = node.end_byte
|
||||
start_point: (int, int) = node.start_point
|
||||
old_end_point: (int, int) = node.end_point
|
||||
|
||||
new_src = self.src[:start_byte] + patch + self.src[old_end_byte:]
|
||||
self.src = new_src
|
||||
d = len(patch) - (old_end_byte - start_byte)
|
||||
self.tree.edit(
|
||||
start_byte=start_byte,
|
||||
old_end_byte=old_end_byte,
|
||||
new_end_byte=old_end_byte + d,
|
||||
start_point=start_point,
|
||||
old_end_point=old_end_point,
|
||||
new_end_point=(old_end_point[0], old_end_point[1] + d),
|
||||
)
|
||||
self.tree = self.parser.parse(new_src, self.tree)
|
||||
|
||||
def apply_patch(self, patch: Patch) -> bool:
|
||||
"""Tests if the given patch should be applied for the current architecture or file."""
|
||||
apply_only_to = self.configurator.get_patch_config()["apply_patch_only_to"]
|
||||
patch_name = patch.__class__.__name__
|
||||
if patch_name not in apply_only_to:
|
||||
# No constraints
|
||||
return True
|
||||
|
||||
file_constraints = apply_only_to[patch_name]
|
||||
if self.current_src_path_in.name in file_constraints["files"]:
|
||||
return True
|
||||
elif (
|
||||
re.search("InstPrinter.cpp", self.current_src_path_in.name)
|
||||
and patch_name == AddCSDetail.__name__
|
||||
):
|
||||
print_prominent_warning(
|
||||
(
|
||||
f"The AddCSDetail patch is not applied to {self.current_src_path_in.name}. "
|
||||
"Have you forgotten to add it to arch_config.json?"
|
||||
),
|
||||
False,
|
||||
)
|
||||
return False
|
||||
|
||||
def translate(self) -> None:
|
||||
for self.current_src_path_in, self.current_src_path_out in zip(
|
||||
self.src_paths, self.out_paths
|
||||
):
|
||||
log.info(f"Translate '{self.current_src_path_in}'")
|
||||
self.parse(self.current_src_path_in)
|
||||
patch: Patch
|
||||
for patch in self.patches:
|
||||
if not self.apply_patch(patch):
|
||||
log.debug(f"Skip patch {patch.__class__.__name__}")
|
||||
continue
|
||||
pattern: str = patch.get_search_pattern()
|
||||
|
||||
# Each patch has a capture which includes the whole subtree searched for.
|
||||
# Additionally, it can include captures within this subtree.
|
||||
# Here we bundle these captures together.
|
||||
query: Query = self.ts_cpp_lang.query(pattern)
|
||||
captures_bundle: [[(Node, str)]] = list()
|
||||
for q in query_captures_22_3(query, self.tree.root_node):
|
||||
if q[1] == patch.get_main_capture_name():
|
||||
# The main capture the patch is looking for.
|
||||
captures_bundle.append([q])
|
||||
else:
|
||||
# A capture which is part of the main capture.
|
||||
# Add it to the bundle.
|
||||
if len(captures_bundle) > 0:
|
||||
captures_bundle[-1].append(q)
|
||||
|
||||
log.debug(
|
||||
f"Patch {patch.__class__.__name__} (to patch: {len(captures_bundle)})."
|
||||
)
|
||||
|
||||
p_list: (bytes, Node) = list()
|
||||
cb: [(Node, str)]
|
||||
for cb in captures_bundle:
|
||||
patch_kwargs = self.get_patch_kwargs(patch)
|
||||
bytes_patch: bytes = patch.get_patch(cb, self.src, **patch_kwargs)
|
||||
p_list.append((bytes_patch, cb[0][0]))
|
||||
self.patch_src(p_list)
|
||||
if self.tree.root_node.type == "ERROR":
|
||||
log.fatal(
|
||||
f"Patch {patch.__class__.__name__} corrupts the tree for {self.current_src_path_in.name}!"
|
||||
)
|
||||
exit(1)
|
||||
log.info(f"Patched file at '{self.current_src_path_out}'")
|
||||
with open(self.current_src_path_out, "w") as f:
|
||||
f.write(get_header())
|
||||
f.write(self.src.decode("utf8"))
|
||||
run_clang_format(self.out_paths)
|
||||
|
||||
def collect_template_instances(self):
|
||||
search_paths = [get_path(p) for p in self.conf["files_for_template_search"]]
|
||||
temp_arg_deduction = [
|
||||
p.encode("utf8") for p in self.conf["templates_with_arg_deduction"]
|
||||
]
|
||||
self.template_collector = TemplateCollector(
|
||||
self.parser, self.ts_cpp_lang, search_paths, temp_arg_deduction
|
||||
)
|
||||
self.template_collector.collect()
|
||||
|
||||
def get_patch_kwargs(self, patch):
|
||||
default_kwargs = dict()
|
||||
default_kwargs["tree"] = self.tree
|
||||
default_kwargs["ts_cpp_lang"] = self.ts_cpp_lang
|
||||
if isinstance(patch, Includes) and self.current_src_path_in:
|
||||
default_kwargs["filename"] = self.current_src_path_in.name
|
||||
return default_kwargs
|
||||
|
||||
def remark_manual_files(self) -> None:
|
||||
manual_edited = self.conf["manually_edited_files"]
|
||||
msg = ""
|
||||
if len(manual_edited) > 0:
|
||||
msg += (
|
||||
termcolor.colored(
|
||||
"The following files are too complex to translate! Please check them by hand.",
|
||||
attrs=["bold"],
|
||||
)
|
||||
+ "\n"
|
||||
)
|
||||
else:
|
||||
return
|
||||
for f in manual_edited:
|
||||
msg += get_path(f).name + "\n"
|
||||
print_prominent_warning(msg, self.wait_for_user)
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="CppTranslator",
|
||||
description="Capstones C++ to C translator for LLVM source files",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-a",
|
||||
dest="arch",
|
||||
help="Name of target architecture.",
|
||||
choices=["ARM", "PPC", "AArch64", "Alpha"],
|
||||
required=True,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
dest="verbosity",
|
||||
help="Verbosity of the log messages.",
|
||||
choices=["debug", "info", "warning", "fatal"],
|
||||
default="info",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
dest="config_path",
|
||||
help="Config file for architectures.",
|
||||
default="arch_config.json",
|
||||
type=Path,
|
||||
)
|
||||
arguments = parser.parse_args()
|
||||
return arguments
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if not sys.hexversion >= 0x030B00F0:
|
||||
log.fatal("Python >= v3.11 required.")
|
||||
exit(1)
|
||||
|
||||
args = parse_args()
|
||||
log.basicConfig(
|
||||
level=convert_loglevel(args.verbosity),
|
||||
stream=sys.stdout,
|
||||
format="%(levelname)-5s - %(message)s",
|
||||
)
|
||||
configurator = Configurator(args.arch, args.config_path)
|
||||
translator = Translator(configurator)
|
||||
translator.translate()
|
||||
translator.remark_manual_files()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,166 @@
|
||||
<!--
|
||||
Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
SPDX-License-Identifier: BSD-3
|
||||
-->
|
||||
|
||||
# C++ Translator
|
||||
|
||||
Capstone uses source files from LLVM to disassemble opcodes.
|
||||
Because LLVM is written in C++ we must translate those files to C.
|
||||
|
||||
The task of the `CppTranslator` is to do just that.
|
||||
The translation will not result in a completely correct C file! But it takes away most of the manual work.
|
||||
|
||||
## The configuration file
|
||||
|
||||
The configuration for each architecture is set in `arch_config.json`.
|
||||
|
||||
The config values have the following meaning:
|
||||
|
||||
- `General`: Settings valid for all architectures.
|
||||
- `diff_color_new`: Color in the `Differ` for translated content.
|
||||
- `diff_color_old`: Color in the `Differ` for old/current Capstone content.
|
||||
- `diff_color_saved`: Color in the `Differ` for saved content.
|
||||
- `diff_color_edited`: Color in the `Differ` for edited content.
|
||||
- `patch_editor`: Editor to open for patch editing.
|
||||
- `nodes_to_diff`: List of parse tree nodes which get diffed - *Mind the note below*.
|
||||
- `node_type`: The `type` of the node to be diffed.
|
||||
- `identifier_node_type`: Types of child nodes which identify the node during diffing (the identifier must be the same in the translated and the old file!). Types can be of the form `<parent-type>/<child type>`.
|
||||
- `<ARCH>`: Settings valid for a specific architecture
|
||||
- `files_to_translate`: A list of file paths to translate.
|
||||
- `in`: *Path* to a specific source file.
|
||||
- `out`: The *filename* of the translated file.
|
||||
- `files_for_template_search`: List of file paths to search for calls to template functions.
|
||||
- `manually_edite_files`: List of files which are too complicated to translate. The user will be warned about them.
|
||||
- `templates_with_arg_deduction`: Template functions which uses [argument deduction](https://en.cppreference.com/w/cpp/language/template_argument_deduction). Those templates are translated to normal functions, not macro definition.
|
||||
|
||||
_Note_:
|
||||
- To understand the `nodes_to_diff` setting, check out `Differ.py`.
|
||||
- Paths can contain `{AUTO_SYNC_ROOT}`, `{CS_ROOT}` and `{CPP_TRANSLATOR_ROOT}`.
|
||||
They are replaced with the absolute paths to those directories.
|
||||
|
||||
## Translation process
|
||||
|
||||
The translation process simply searches for certain syntax and patches it.
|
||||
|
||||
To allow searches for complicated patterns we parse the C++ file with Tree-sitter.
|
||||
Afterward we can use [pattern queries](https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries)
|
||||
to find our syntax we would like to patch.
|
||||
|
||||
Here is an overview of the procedure:
|
||||
|
||||
- First the source file is parsed with Tree-Sitter.
|
||||
- Afterward the translator iterates of a number of patches.
|
||||
|
||||
For each patch we do the following.
|
||||
|
||||
```
|
||||
|
||||
Translator Patch
|
||||
+---+
|
||||
| | +----+
|
||||
| | Request pattern to search for | |
|
||||
| | ----------------------------------> | |
|
||||
| | | |
|
||||
| | Return pattern | |
|
||||
| | <--------------------------------- | |
|
||||
| | | |
|
||||
| | ---+ | |
|
||||
| | | Find | |
|
||||
| | | captures | |
|
||||
| | | in src | |
|
||||
| | <--+ | |
|
||||
| | | |
|
||||
| | Return captures found | |
|
||||
| | ----------------------------------> | |
|
||||
| | | |
|
||||
| | +-- | |
|
||||
| | Use capture | | |
|
||||
| | info to | | |
|
||||
| | build new | | |
|
||||
| | syntax str | | |
|
||||
| | +-> | |
|
||||
| | | |
|
||||
| | Return new syntax string to patch | |
|
||||
| | <---------------------------------- | |
|
||||
| | | |
|
||||
| | ---+ | |
|
||||
| | | Replace old | |
|
||||
| | | with new syntax | |
|
||||
| | | at all occurrences | |
|
||||
| | | in the file. | |
|
||||
| | <--+ | |
|
||||
| | | |
|
||||
+---+ +----+
|
||||
```
|
||||
|
||||
## C++ Template translation
|
||||
|
||||
Most of the C++ syntax is simple to translate. But unfortunately the one exception are C++ templates.
|
||||
|
||||
Translating template functions and calls from C++ to C is tricky.
|
||||
Since each template has a number of actual implementations we do the following.
|
||||
|
||||
- A template function definition is translated into a C macro.
|
||||
- The template parameters get translated to the macro parameters.
|
||||
- To differentiate the C implementations, the functions follow the naming pattern `fcn_[template_param_0]_[template_param_1]()`
|
||||
|
||||
<hr>
|
||||
|
||||
**Example**
|
||||
|
||||
This C++ template function
|
||||
|
||||
```cpp
|
||||
template<unsigned X>
|
||||
void fcn() {
|
||||
unsigned a = X * 8;
|
||||
}
|
||||
```
|
||||
becomes
|
||||
```
|
||||
#define DEFINE_FCN(X) \
|
||||
void fcn ## _ ## X() { \
|
||||
unsigned a = X * 8; \
|
||||
}
|
||||
```
|
||||
To define an implementation where `X = 0` we do
|
||||
```
|
||||
DEFINE_FCN(0)
|
||||
```
|
||||
To call this implementation we call `fcn_0()`.
|
||||
|
||||
_(There is a special case when a template parameter is passed on to a template call. But this is explained in the code.)_
|
||||
<hr>
|
||||
|
||||
### Enumerate template instances
|
||||
|
||||
In our C++ code a template function can be called with different template parameters.
|
||||
For each of those calls we need to define a template implementation in C.
|
||||
|
||||
To do that we first scan source files for calls to template functions (`TemplateCollector.py` does this).
|
||||
For each unique call we check the parameter list.
|
||||
Knowing the parameter list we can now define a C function which uses exactly those parameters.
|
||||
For the definition we use a macro as above.
|
||||
|
||||
<hr>
|
||||
|
||||
**Example**
|
||||
|
||||
Within this C++ code we see two template function calls:
|
||||
|
||||
```cpp
|
||||
void main() {
|
||||
fcn<0>();
|
||||
fcn<4>();
|
||||
}
|
||||
```
|
||||
With the knowledge that once parameter `1` and once parameter `4` was passed to the template,
|
||||
we can define the implementations with the help of our `DEFINE_FCN` macro.
|
||||
```c
|
||||
DEFINE_FCN(0)
|
||||
DEFINE_FCN(4)
|
||||
```
|
||||
|
||||
Within the C code we can now call those with `fcn_0()` and `fcn_4()`.
|
||||
<hr>
|
||||
+346
@@ -0,0 +1,346 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
from tree_sitter import Language, Node, Parser, Query
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.tree_sitter_compatibility import query_captures_22_3
|
||||
|
||||
|
||||
class TemplateRefInstance:
|
||||
"""
|
||||
Represents a concrete instance of a template function reference.
|
||||
E.g. DecodeT2Imm7<shift, 2>
|
||||
"""
|
||||
|
||||
name: bytes
|
||||
args: bytes
|
||||
args_list: list
|
||||
dependent_calls = list()
|
||||
|
||||
# Holds the indices of the caller template parameters which set the templ. parameters
|
||||
# of this TemplateCallInstance.
|
||||
# Structure: {caller_name: i, "self_i": k}
|
||||
#
|
||||
# Only used if this is an incomplete TemplateInstance
|
||||
# (parameters are set by the template parameters of the calling function).
|
||||
caller_param_indices: [{str: int}] = list()
|
||||
|
||||
def __init__(
|
||||
self, name: bytes, args: bytes, start_point, start_byte, end_point, end_byte
|
||||
):
|
||||
self.name = name
|
||||
self.args = args
|
||||
self.start_point = start_point
|
||||
self.start_byte = start_byte
|
||||
self.end_point = end_point
|
||||
self.end_byte = end_byte
|
||||
self.args_list = TemplateCollector.templ_params_to_list(args)
|
||||
self.templ_name = name + args
|
||||
|
||||
def __eq__(self, other):
|
||||
return (
|
||||
self.name == other.name
|
||||
and self.args == other.args
|
||||
and any(
|
||||
[
|
||||
a == b
|
||||
for a, b in zip(
|
||||
self.caller_param_indices, other.caller_param_indices
|
||||
)
|
||||
]
|
||||
)
|
||||
and self.start_byte == other.start_byte
|
||||
and self.start_point == other.start_point
|
||||
and self.end_byte == other.end_byte
|
||||
and self.end_point == other.end_point
|
||||
)
|
||||
|
||||
def set_dep_calls(self, deps: list):
|
||||
self.dependent_calls = deps
|
||||
|
||||
def get_c_name(self):
|
||||
return b"_".join([self.name] + self.args_list)
|
||||
|
||||
def get_args_for_decl(self) -> list[bytes]:
|
||||
"""Returns the list of arguments, but replaces all characters which
|
||||
can not be part of a C identifier with _
|
||||
"""
|
||||
args_list = [re.sub(b"'", b"", a) for a in self.args_list]
|
||||
return args_list
|
||||
|
||||
|
||||
class TemplateCollector:
|
||||
"""
|
||||
Searches through the given files for calls to template functions.
|
||||
And creates a list with concrete template instances.
|
||||
"""
|
||||
|
||||
# List of completed template instances indexed by their name.
|
||||
# One function can have multiple template instances. Depending on the template arguments
|
||||
template_refs: {bytes: [TemplateRefInstance]} = dict()
|
||||
# List of incomplete template instances indexed by the **function name they depend on**!
|
||||
incomplete_template_refs: {bytes: [TemplateRefInstance]} = dict()
|
||||
sources: [{str: bytes}] = list()
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
ts_parser: Parser,
|
||||
ts_cpp: Language,
|
||||
searchable_files: [Path],
|
||||
temp_arg_deduction: [bytes],
|
||||
):
|
||||
self.parser = ts_parser
|
||||
self.lang_cpp = ts_cpp
|
||||
self.searchable_files = searchable_files
|
||||
self.templates_with_arg_deduction = temp_arg_deduction
|
||||
|
||||
def collect(self):
|
||||
self.read_files()
|
||||
for x in self.sources:
|
||||
path = x["path"]
|
||||
src = x["content"]
|
||||
log.debug(f"Search for template references in {path}")
|
||||
|
||||
tree = self.parser.parse(src)
|
||||
query: Query = self.lang_cpp.query(self.get_template_pattern())
|
||||
capture_bundles = self.get_capture_bundles(query, tree)
|
||||
|
||||
for cb in capture_bundles:
|
||||
templ_name: Node = cb[1][0]
|
||||
templ_args: Node = cb[2][0]
|
||||
name = get_text(src, templ_name.start_byte, templ_name.end_byte)
|
||||
args = get_text(src, templ_args.start_byte, templ_args.end_byte)
|
||||
|
||||
ti = TemplateRefInstance(
|
||||
name,
|
||||
args,
|
||||
cb[0][0].start_point,
|
||||
cb[0][0].start_byte,
|
||||
cb[0][0].end_point,
|
||||
cb[0][0].end_byte,
|
||||
)
|
||||
|
||||
log.debug(
|
||||
f"Found new template ref: {name.decode('utf8')}{args.decode('utf8')}"
|
||||
)
|
||||
|
||||
if not self.contains_template_dependent_param(src, ti, cb[0]):
|
||||
if name not in self.template_refs:
|
||||
self.template_refs[name] = list()
|
||||
# The template function has no parameter which is part of a previous
|
||||
# template definition. So all template parameters are well-defined.
|
||||
# Add it to the well-defined list.
|
||||
if ti not in self.template_refs[name]:
|
||||
self.template_refs[name].append(ti)
|
||||
self.resolve_dependencies()
|
||||
|
||||
def resolve_dependencies(self):
|
||||
# Resolve dependencies of templates until nothing new was resolved.
|
||||
prev_len = 0
|
||||
while (
|
||||
len(self.incomplete_template_refs) > 0
|
||||
and len(self.incomplete_template_refs) != prev_len
|
||||
):
|
||||
# Dict with new template calls which were previously incomplete
|
||||
# because one or more parameters were unknown.
|
||||
new_completed_tcs: {str: list} = dict()
|
||||
tc_instance_list: [TemplateRefInstance]
|
||||
for caller_name, tc_instance_list in self.template_refs.items():
|
||||
# Check if this caller has a dependent template call.
|
||||
# In other words: If a template parameter of this caller is given
|
||||
# to another template call in the callers body.
|
||||
if caller_name not in self.incomplete_template_refs:
|
||||
# Not in the dependency list. Skip it.
|
||||
continue
|
||||
# For each configuration of template parameters we complete a template reference.
|
||||
for caller_template in tc_instance_list:
|
||||
incomplete_tc: TemplateRefInstance
|
||||
for incomplete_tc in self.incomplete_template_refs[caller_name]:
|
||||
new_tc: TemplateRefInstance = self.get_completed_tc(
|
||||
caller_template, incomplete_tc
|
||||
)
|
||||
callee_name = new_tc.name
|
||||
if callee_name not in new_completed_tcs:
|
||||
new_completed_tcs[callee_name] = list()
|
||||
if new_tc not in new_completed_tcs[callee_name]:
|
||||
new_completed_tcs[callee_name].append(new_tc)
|
||||
del self.incomplete_template_refs[caller_name]
|
||||
|
||||
for templ_name, tc_list in new_completed_tcs.items():
|
||||
if templ_name in self.template_refs:
|
||||
self.template_refs[templ_name] += tc_list
|
||||
else:
|
||||
self.template_refs[templ_name] = tc_list
|
||||
prev_len = len(self.incomplete_template_refs)
|
||||
if prev_len > 0:
|
||||
log.info(
|
||||
f"Unresolved template calls: {self.incomplete_template_refs.keys()}. Patch them by hand!"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_completed_tc(
|
||||
tc: TemplateRefInstance, itc: TemplateRefInstance
|
||||
) -> TemplateRefInstance:
|
||||
new_tc = TemplateRefInstance(
|
||||
itc.name,
|
||||
itc.args,
|
||||
itc.start_byte,
|
||||
itc.start_byte,
|
||||
itc.end_point,
|
||||
itc.end_byte,
|
||||
)
|
||||
for indices in itc.caller_param_indices:
|
||||
if tc.name not in indices:
|
||||
# Index of other caller function. Skip.
|
||||
continue
|
||||
caller_i = indices[tc.name]
|
||||
self_i = indices["self_i"]
|
||||
new_tc.args_list[self_i] = tc.args_list[caller_i]
|
||||
new_tc.args = TemplateCollector.list_to_templ_params(new_tc.args_list)
|
||||
new_tc.templ_name = new_tc.name + new_tc.args
|
||||
return new_tc
|
||||
|
||||
def contains_template_dependent_param(
|
||||
self, src, ti: TemplateRefInstance, parse_tree: (Node, str)
|
||||
) -> bool:
|
||||
"""Here we check if one of the template parameters of the given template call,
|
||||
is a parameter of the callers template definition.
|
||||
|
||||
Let's assume we find the template call `func_B<X>()`.
|
||||
Now look at the context `func_B<X>` is in:
|
||||
|
||||
template<X>
|
||||
void func_A() {
|
||||
func_B<X>(a)
|
||||
}
|
||||
|
||||
Since `X` is a template parameter of `func_A` we have to wait until we see a call
|
||||
to `func_A<X>` where `X` gets properly defined.
|
||||
|
||||
Until then we save the TemplateInstance of `func_B<X>` in a list of incomplete
|
||||
template calls and note that it depends on `func_A`.
|
||||
If later a call to function `func_A` is found (with a concrete value for `X`) we can add
|
||||
a concrete TemplateInstance of `func_B`.
|
||||
|
||||
:param: src The current source code to operate on.
|
||||
:param: ti The TemplateInstance for which to check dependencies.
|
||||
:param: parse_tree The parse tree of the template call.
|
||||
:return: True if a dependency was found. False otherwise.
|
||||
"""
|
||||
|
||||
# Search up to the function definition this call belongs to
|
||||
node: Node = parse_tree[0]
|
||||
while node.type != "function_definition":
|
||||
node = node.parent
|
||||
if not node.prev_named_sibling.type == "template_parameter_list":
|
||||
# Caller is a normal function definition.
|
||||
# Nothing to do here.
|
||||
return False
|
||||
|
||||
caller_fcn_id = node.named_children[2].named_children[0]
|
||||
caller_fcn_name = get_text(
|
||||
src, caller_fcn_id.start_byte, caller_fcn_id.end_byte
|
||||
)
|
||||
caller_templ_params = get_text(
|
||||
src, node.prev_sibling.start_byte, node.prev_sibling.end_byte
|
||||
)
|
||||
pl = TemplateCollector.templ_params_to_list(caller_templ_params)
|
||||
has_parameter_dependency = False
|
||||
for i, param in enumerate(pl):
|
||||
if param in ti.args_list:
|
||||
has_parameter_dependency = True
|
||||
ti.caller_param_indices.append(
|
||||
{caller_fcn_name: i, "self_i": ti.args_list.index(param)}
|
||||
)
|
||||
|
||||
if not has_parameter_dependency:
|
||||
return False
|
||||
|
||||
if caller_fcn_name not in self.incomplete_template_refs:
|
||||
self.incomplete_template_refs[caller_fcn_name] = list()
|
||||
if ti not in self.incomplete_template_refs[caller_fcn_name]:
|
||||
self.incomplete_template_refs[caller_fcn_name].append(ti)
|
||||
return True
|
||||
|
||||
def read_files(self):
|
||||
for sf in self.searchable_files:
|
||||
if not Path.exists(sf):
|
||||
log.fatal(f"TemplateCollector: Could not find '{sf}' for search.")
|
||||
exit(1)
|
||||
log.debug(f"TemplateCollector: Read {sf}")
|
||||
with open(sf) as f:
|
||||
file = {"path": sf, "content": bytes(f.read(), "utf8")}
|
||||
self.sources.append(file)
|
||||
|
||||
@staticmethod
|
||||
def get_capture_bundles(query, tree):
|
||||
captures_bundle: list[list[tuple[Node, str]]] = list()
|
||||
for q in query_captures_22_3(query, tree.root_node):
|
||||
if q[1] == "templ_ref":
|
||||
captures_bundle.append([q])
|
||||
else:
|
||||
captures_bundle[-1].append(q)
|
||||
return captures_bundle
|
||||
|
||||
@staticmethod
|
||||
def get_template_pattern():
|
||||
"""
|
||||
:return: A pattern which finds either a template function calls or references.
|
||||
"""
|
||||
return (
|
||||
"(template_function"
|
||||
" ((identifier) @name)"
|
||||
" ((template_argument_list) @templ_args)"
|
||||
") @templ_ref"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def templ_params_to_list(templ_params: bytes) -> list[bytes]:
|
||||
if not templ_params:
|
||||
return list()
|
||||
|
||||
params = templ_params.strip(b"<>").split(b",")
|
||||
params = [p.strip() for p in params]
|
||||
res = list()
|
||||
for p in params:
|
||||
if len(p.split(b" ")) == 2:
|
||||
# Typename specified for parameter. Remove it.
|
||||
# If it was more than one space, it is likely an operation like `size + 1`
|
||||
p = p.split(b" ")[1]
|
||||
# true and false get resolved to 1 and 0
|
||||
if p == "true":
|
||||
p = "1"
|
||||
elif p == "false":
|
||||
p = "0"
|
||||
res.append(p)
|
||||
return res
|
||||
|
||||
@staticmethod
|
||||
def list_to_templ_params(temp_param_list: list) -> bytes:
|
||||
return b"<" + b", ".join(temp_param_list) + b">"
|
||||
|
||||
@staticmethod
|
||||
def get_macro_c_call(name: bytes, arg_param_list: [bytes], fcn_args: bytes = b""):
|
||||
res = b""
|
||||
fa = [name] + arg_param_list
|
||||
for x in fa[:-1]:
|
||||
res += b"CONCAT(" + x + b", "
|
||||
res += fa[-1]
|
||||
return res + (b")" * (len(fa) - 1)) + fcn_args
|
||||
|
||||
@staticmethod
|
||||
def log_missing_ref_and_exit(func_ref: bytes) -> None:
|
||||
log.fatal(
|
||||
f"Template collector has no reference for {func_ref}.\n\n"
|
||||
f"The possible reasons are:\n"
|
||||
"\t\t\t- Not all C++ source files which call this function are listed in the config.\n"
|
||||
"\t\t\t- You removed the C++ template syntax from the .td file for this function.\n"
|
||||
"\t\t\t- The function is a template with argument deduction and has no `template<...>` preamble. "
|
||||
"Add it in the config as exception in this case."
|
||||
)
|
||||
exit(1)
|
||||
+318
@@ -0,0 +1,318 @@
|
||||
{
|
||||
"General": {
|
||||
"diff_color_new": "green",
|
||||
"diff_color_old": "light_blue",
|
||||
"diff_color_saved": "yellow",
|
||||
"diff_color_edited": "light_magenta",
|
||||
"patch_editor": "vim",
|
||||
"patching": {
|
||||
"apply_patch_only_to": {
|
||||
"AddCSDetail": {
|
||||
"files": [
|
||||
"ARMInstPrinter.cpp",
|
||||
"PPCInstPrinter.cpp",
|
||||
"AArch64InstPrinter.cpp",
|
||||
"LoongArchInstPrinter.cpp",
|
||||
"MipsInstPrinter.cpp",
|
||||
"SystemZInstPrinter.cpp",
|
||||
"XtensaInstPrinter.cpp",
|
||||
"SparcInstPrinter.cpp"
|
||||
]
|
||||
},
|
||||
"InlineToStaticInline": {
|
||||
"files": [
|
||||
"ARMAddressingModes.h"
|
||||
]
|
||||
},
|
||||
"PrintRegImmShift": {
|
||||
"files": [
|
||||
"ARMInstPrinter.cpp"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"nodes_to_diff": [
|
||||
{
|
||||
"node_type": "function_definition",
|
||||
"identifier_node_type": ["function_declarator/identifier"]
|
||||
},{
|
||||
"node_type": "preproc_function_def",
|
||||
"identifier_node_type": ["identifier"]
|
||||
},{
|
||||
"node_type": "preproc_include",
|
||||
"identifier_node_type": ["string_literal", "system_lib_string"]
|
||||
},{
|
||||
"node_type": "preproc_define",
|
||||
"identifier_node_type": ["identifier"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ARM": {
|
||||
"files_to_translate": [
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp",
|
||||
"out": "ARMDisassembler.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.cpp",
|
||||
"out": "ARMInstPrinter.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.h",
|
||||
"out": "ARMInstPrinter.h"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/ARM/MCTargetDesc/ARMAddressingModes.h",
|
||||
"out": "ARMAddressingModes.h"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/ARM/Utils/ARMBaseInfo.cpp",
|
||||
"out": "ARMBaseInfo.c"
|
||||
}
|
||||
],
|
||||
"files_for_template_search": [
|
||||
"{CPP_INC_OUT_DIR}/ARMGenDisassemblerTables.inc",
|
||||
"{CPP_INC_OUT_DIR}/ARMGenAsmWriter.inc",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.cpp"
|
||||
],
|
||||
"templates_with_arg_deduction": [],
|
||||
"manually_edited_files": [
|
||||
"{LLVM_ROOT}/llvm/lib/Target/ARM/Utils/ARMBaseInfo.h"
|
||||
]
|
||||
},
|
||||
"PPC": {
|
||||
"files_to_translate": [
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp",
|
||||
"out": "PPCDisassembler.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp",
|
||||
"out": "PPCInstPrinter.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h",
|
||||
"out": "PPCMCTargetDesc.h"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/PowerPC/MCTargetDesc/PPCPredicates.h",
|
||||
"out": "PPCPredicates.h"
|
||||
}
|
||||
],
|
||||
"files_for_template_search": [
|
||||
"{CPP_INC_OUT_DIR}/PPCGenDisassemblerTables.inc",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp"
|
||||
],
|
||||
"templates_with_arg_deduction": [
|
||||
"decodeRegisterClass"
|
||||
],
|
||||
"manually_edited_files": [
|
||||
"{LLVM_ROOT}/llvm/lib/Target/PowerPC/PPCInstrInfo.h",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/PowerPC/PPCRegisterInfo.h"
|
||||
]
|
||||
},
|
||||
"AArch64": {
|
||||
"files_to_translate": [
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp",
|
||||
"out": "AArch64Disassembler.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp",
|
||||
"out": "AArch64InstPrinter.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h",
|
||||
"out": "AArch64InstPrinter.h"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h",
|
||||
"out": "AArch64AddressingModes.h"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.cpp",
|
||||
"out": "AArch64BaseInfo.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h",
|
||||
"out": "AArch64BaseInfo.h"
|
||||
}
|
||||
],
|
||||
"files_for_template_search": [
|
||||
"{CPP_INC_OUT_DIR}/AArch64GenDisassemblerTables.inc",
|
||||
"{CPP_INC_OUT_DIR}/AArch64GenAsmWriter.inc",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp"
|
||||
],
|
||||
"templates_with_arg_deduction": [
|
||||
"printImmSVE",
|
||||
"printAMIndexedWB",
|
||||
"isSVECpyImm",
|
||||
"isSVEAddSubImm",
|
||||
"printVectorIndex"
|
||||
],
|
||||
"manually_edited_files": []
|
||||
},
|
||||
"Alpha": {
|
||||
"files_to_translate": [],
|
||||
"files_for_template_search": [
|
||||
"{CPP_INC_OUT_DIR}/AlphaGenDisassemblerTables.inc",
|
||||
"{CPP_INC_OUT_DIR}/AlphaGenAsmWriter.inc"
|
||||
],
|
||||
"templates_with_arg_deduction": [],
|
||||
"manually_edited_files": []
|
||||
},
|
||||
"LoongArch": {
|
||||
"files_to_translate": [
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/LoongArch/Disassembler/LoongArchDisassembler.cpp",
|
||||
"out": "LoongArchDisassembler.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchInstPrinter.cpp",
|
||||
"out": "LoongArchInstPrinter.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchInstPrinter.h",
|
||||
"out": "LoongArchInstPrinter.h"
|
||||
}
|
||||
],
|
||||
"files_for_template_search": [
|
||||
"{CPP_INC_OUT_DIR}/LoongArchGenDisassemblerTables.inc",
|
||||
"{CPP_INC_OUT_DIR}/LoongArchGenAsmWriter.inc",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/LoongArch/Disassembler/LoongArchDisassembler.cpp",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchInstPrinter.cpp"
|
||||
],
|
||||
"templates_with_arg_deduction": [],
|
||||
"manually_edited_files": []
|
||||
},
|
||||
"Mips": {
|
||||
"files_to_translate": [
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp",
|
||||
"out": "MipsDisassembler.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/Mips/MCTargetDesc/MipsInstPrinter.cpp",
|
||||
"out": "MipsInstPrinter.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/Mips/MCTargetDesc/MipsInstPrinter.h",
|
||||
"out": "MipsInstPrinter.h"
|
||||
}
|
||||
],
|
||||
"files_for_template_search": [
|
||||
"{CPP_INC_OUT_DIR}/MipsGenDisassemblerTables.inc",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/Mips/MCTargetDesc/MipsInstPrinter.cpp",
|
||||
"{CPP_INC_OUT_DIR}/MipsGenAsmWriter.inc"
|
||||
],
|
||||
"templates_with_arg_deduction": [
|
||||
"DecodeINSVE_DF",
|
||||
"DecodeDAHIDATIMMR6",
|
||||
"DecodeDAHIDATI",
|
||||
"DecodeAddiGroupBranch",
|
||||
"DecodePOP35GroupBranchMMR6",
|
||||
"DecodeDaddiGroupBranch",
|
||||
"DecodePOP37GroupBranchMMR6",
|
||||
"DecodePOP65GroupBranchMMR6",
|
||||
"DecodePOP75GroupBranchMMR6",
|
||||
"DecodeBlezlGroupBranch",
|
||||
"DecodeBgtzlGroupBranch",
|
||||
"DecodeBgtzGroupBranch",
|
||||
"DecodeBlezGroupBranch",
|
||||
"DecodeBgtzGroupBranchMMR6",
|
||||
"DecodeBlezGroupBranchMMR6",
|
||||
"DecodeDINS",
|
||||
"DecodeDEXT",
|
||||
"DecodeCRC",
|
||||
"isReg"
|
||||
],
|
||||
"manually_edited_files": []
|
||||
},
|
||||
"SystemZ": {
|
||||
"files_to_translate": [
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/SystemZ/Disassembler/SystemZDisassembler.cpp",
|
||||
"out": "SystemZDisassembler.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZInstPrinter.cpp",
|
||||
"out": "SystemZInstPrinter.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZInstPrinter.h",
|
||||
"out": "SystemZInstPrinter.h"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp",
|
||||
"out": "SystemZMCTargetDesc.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h",
|
||||
"out": "SystemZMCTargetDesc.h"
|
||||
}
|
||||
],
|
||||
"files_for_template_search": [
|
||||
"{CPP_INC_OUT_DIR}/SystemZGenDisassemblerTables.inc",
|
||||
"{CPP_INC_OUT_DIR}/SystemZGenAsmWriter.inc",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/SystemZ/Disassembler/SystemZDisassembler.cpp",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZInstPrinter.cpp"
|
||||
],
|
||||
"templates_with_arg_deduction": [],
|
||||
"manually_edited_files": []
|
||||
},
|
||||
"Xtensa": {
|
||||
"files_to_translate": [
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp",
|
||||
"out": "XtensaDisassembler.c"
|
||||
},
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp",
|
||||
"out": "XtensaInstPrinter.c"
|
||||
}
|
||||
],
|
||||
"files_for_template_search": [
|
||||
"{CPP_INC_OUT_DIR}/XtensaGenDisassemblerTables.inc",
|
||||
"{CPP_INC_OUT_DIR}/XtensaGenAsmWriter.inc"
|
||||
],
|
||||
"templates_with_arg_deduction": [],
|
||||
"manually_edited_files": []
|
||||
},
|
||||
"TriCore": {
|
||||
"files_to_translate": [],
|
||||
"files_for_template_search": [],
|
||||
"templates_with_arg_deduction": [],
|
||||
"manually_edited_files": []
|
||||
},
|
||||
"ARC": {
|
||||
"files_to_translate": [
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/ARC/Disassembler/ARCDisassembler.cpp",
|
||||
"out": "ARCDisassembler.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/ARC/MCTargetDesc/ARCInstPrinter.cpp",
|
||||
"out": "ARCInstPrinter.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/ARC/MCTargetDesc/ARCInstPrinter.h",
|
||||
"out": "ARCInstPrinter.h"
|
||||
},
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/ARC/MCTargetDesc/ARCInfo.h",
|
||||
"out": "ARCInfo.h"
|
||||
}
|
||||
],
|
||||
"files_for_template_search": [
|
||||
"{CPP_INC_OUT_DIR}/ARCGenDisassemblerTables.inc",
|
||||
"{CPP_INC_OUT_DIR}/ARCGenAsmWriter.inc",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/ARC/Disassembler/ARCDisassembler.cpp",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/ARC/MCTargetDesc/ARCInstPrinter.cpp"
|
||||
],
|
||||
"templates_with_arg_deduction": [],
|
||||
"manually_edited_files": []
|
||||
},
|
||||
"Sparc": {
|
||||
"files_to_translate": [
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp",
|
||||
"out": "SparcDisassembler.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp",
|
||||
"out": "SparcInstPrinter.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.h",
|
||||
"out": "SparcInstPrinter.h"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h",
|
||||
"out": "SparcMCTargetDesc.h"
|
||||
}
|
||||
],
|
||||
"files_for_template_search": [
|
||||
"{CPP_INC_OUT_DIR}/SparcGenDisassemblerTables.inc",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp"
|
||||
],
|
||||
"templates_with_arg_deduction": [],
|
||||
"manually_edited_files": []
|
||||
}
|
||||
}
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
import re
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import (
|
||||
get_MCInst_var_name,
|
||||
get_text,
|
||||
template_param_list_to_dict,
|
||||
)
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class AddCSDetail(Patch):
|
||||
"""
|
||||
Adds calls to `<ARCH>_add_cs_detail_<n>()` for printOperand functions in <ARCH>InstPrinter.c
|
||||
|
||||
Patch void printThumbLdrLabelOperand(MCInst *MI, unsigned OpNo, SStream *O) {...}
|
||||
to void printThumbLdrLabelOperand(MCInst *MI, unsigned OpNo, SStream *O) {
|
||||
<ARCH>_add_cs_detail_<n>(MI, ARM_OP_GROUP_ThumbLdrLabelOperand, ...);
|
||||
...
|
||||
}
|
||||
"""
|
||||
|
||||
# TODO Simply checking for the passed types would be so much nicer.
|
||||
# Parameter lists of printOperand() functions we need to add `<ARCH>_add_cs_detail_<n>()` to.
|
||||
# Spaces are removed, so we only need to check the letters.
|
||||
valid_param_lists = [
|
||||
b"(MCInst*MI,unsignedOpNum,SStream*O)", # Default printOperand parameters.
|
||||
b"(MCInst*MI,unsignedOpNo,SStream*O)", # ARM - printComplexRotationOp / PPC default
|
||||
b"(MCInst*MI,intopNum,SStream *O)", # Mips - printMemOperandEA and others
|
||||
b"(SStream*O,ARM_AM::ShiftOpcShOpc,unsignedShImm,boolgetUseMarkup())", # ARM - printRegImmShift
|
||||
b"(MCInst*MI,unsignedOpNo,SStream*O,constchar*Modifier)", # PPC - printPredicateOperand
|
||||
b"(MCInst*MI,uint64_tAddress,unsignedOpNo,SStream*O)", # PPC - printBranchOperand
|
||||
b"(MCInst*MI,intOpNum,SStream*O)", # SystemZ
|
||||
b"(MCInst*MI,intOpNum,SStream*O)", # Xtensa printOperand parameters.
|
||||
b"(MCInst*MI,intOpNum,SStream*OS)", # Xtensa printOperand parameters.
|
||||
b"(MCInst*MI,intopNum,SStream*O)", # Sparc printOperand parameters.
|
||||
]
|
||||
|
||||
def __init__(self, priority: int, arch: str):
|
||||
super().__init__(priority)
|
||||
self.arch = arch
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(function_definition"
|
||||
" (_)+"
|
||||
" (function_declarator"
|
||||
' ((identifier) @fcn_id (#match? @fcn_id "print.*"))'
|
||||
" ((parameter_list) @p_list)"
|
||||
" )"
|
||||
" (compound_statement) @comp_stmt"
|
||||
") @print_op"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "print_op"
|
||||
|
||||
def get_patch(
|
||||
self, captures: list[tuple[Node, str]], src: bytes, **kwargs
|
||||
) -> bytes:
|
||||
fcn_def: Node = captures[0][0]
|
||||
params = captures[2][0]
|
||||
params = get_text(src, params.start_byte, params.end_byte)
|
||||
if re.sub(b"[\n \t]", b"", params) not in self.valid_param_lists:
|
||||
return get_text(src, fcn_def.start_byte, fcn_def.end_byte)
|
||||
|
||||
fcn_id = captures[1][0]
|
||||
fcn_id = get_text(src, fcn_id.start_byte, fcn_id.end_byte)
|
||||
|
||||
add_cs_detail = self.get_add_cs_detail(src, fcn_def, fcn_id, params)
|
||||
|
||||
comp = captures[3][0]
|
||||
comp = get_text(src, comp.start_byte, comp.end_byte)
|
||||
return (
|
||||
b"static inline void "
|
||||
+ fcn_id
|
||||
+ params
|
||||
+ b"{ "
|
||||
+ add_cs_detail
|
||||
+ comp.strip(b"{")
|
||||
)
|
||||
|
||||
def get_add_cs_detail(
|
||||
self, src: bytes, fcn_def: Node, fcn_id: bytes, params: bytes
|
||||
) -> bytes:
|
||||
op_group_enum = (
|
||||
self.arch.encode("utf8") + b"_OP_GROUP_" + fcn_id[5:]
|
||||
) # Remove "print" from function id
|
||||
|
||||
is_template = fcn_def.prev_sibling.type == "template_parameter_list"
|
||||
if b"OpNum" in params:
|
||||
op_num_var_name = b"OpNum"
|
||||
elif b"OpNo" in params:
|
||||
op_num_var_name = b"OpNo"
|
||||
elif b"opNum" in params:
|
||||
op_num_var_name = b"opNum"
|
||||
else:
|
||||
raise ValueError("OpNum parameter could not be identified.")
|
||||
|
||||
if not is_template and op_num_var_name in params:
|
||||
# Standard printOperand() parameters
|
||||
mcinst_var = get_MCInst_var_name(src, fcn_def)
|
||||
return (
|
||||
f"{self.arch}_add_cs_detail_0(".encode()
|
||||
+ mcinst_var
|
||||
+ b", "
|
||||
+ op_group_enum
|
||||
+ b", "
|
||||
+ op_num_var_name
|
||||
+ b");"
|
||||
)
|
||||
elif op_group_enum == b"ARM_OP_GROUP_RegImmShift":
|
||||
return (
|
||||
f"{self.arch}_add_cs_detail_1(MI, ".encode()
|
||||
+ op_group_enum
|
||||
+ b", ShOpc, ShImm);"
|
||||
)
|
||||
elif is_template and op_num_var_name in params:
|
||||
mcinst_var = get_MCInst_var_name(src, fcn_def)
|
||||
templ_p = template_param_list_to_dict(fcn_def.prev_sibling)
|
||||
cs_args = b""
|
||||
for tp in templ_p:
|
||||
op_group_enum = (
|
||||
b"CONCAT(" + op_group_enum + b", " + tp["identifier"] + b")"
|
||||
)
|
||||
cs_args += b", " + tp["identifier"]
|
||||
return (
|
||||
f"{self.arch}_add_cs_detail_{len(templ_p)}(".encode()
|
||||
+ mcinst_var
|
||||
+ b", "
|
||||
+ op_group_enum
|
||||
+ b", "
|
||||
+ op_num_var_name
|
||||
+ b" "
|
||||
+ cs_args
|
||||
+ b");"
|
||||
)
|
||||
log.fatal(f"Case {op_group_enum} not handled.")
|
||||
exit(1)
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class AddOperand(Patch):
|
||||
"""
|
||||
Patch MI.addOperand(...)
|
||||
to MCInst_addOperand(MI, ...)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(call_expression "
|
||||
" (field_expression"
|
||||
" ((identifier) @inst_var)"
|
||||
' ((field_identifier) @field_id_op (#eq? @field_id_op "addOperand"))'
|
||||
" )"
|
||||
" ((argument_list) @arg_list)"
|
||||
") @add_operand"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "add_operand"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get instruction variable name (MI, Inst)
|
||||
inst_var: Node = captures[1][0]
|
||||
# Arguments of getOperand(...)
|
||||
get_op_args = captures[3][0]
|
||||
inst = get_text(src, inst_var.start_byte, inst_var.end_byte)
|
||||
args = get_text(src, get_op_args.start_byte, get_op_args.end_byte)
|
||||
return b"MCInst_addOperand2(" + inst + b", " + args + b")"
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
from autosync.cpptranslator.patches.Helper import get_text_from_node
|
||||
|
||||
|
||||
class Assert(Patch):
|
||||
"""
|
||||
Patch replace `assert`|`report_fatal_error` with `CS_ASSERT`
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(expression_statement"
|
||||
" (call_expression"
|
||||
' ((identifier) @id (#match? @id "assert|report_fatal_error"))'
|
||||
" ((argument_list) @arg_list)"
|
||||
" )"
|
||||
") @assert"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "assert"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
args = get_text_from_node(src, captures[2][0])
|
||||
return b"CS_ASSERT" + args + b";"
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
# Copyright © 2024 Dmitry Sibitsev <sibirtsevdl@gmail.com>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class BadConditionCode(Patch):
|
||||
"""
|
||||
Patch return BadConditionCode
|
||||
to CS_ASSERT(0 && "Unknown condition code passed")
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(return_statement "
|
||||
" (call_expression "
|
||||
' (identifier) @fcn_name (#eq? @fcn_name "BadConditionCode")'
|
||||
" (argument_list)"
|
||||
" )"
|
||||
") @bad_condition_code"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "bad_condition_code"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
return b'CS_ASSERT(0 && "Unknown condition code passed");'
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class BitCastStdArray(Patch):
|
||||
"""
|
||||
Patch auto S = bit_cast<std::array<int32_t, 2>>(Imm);
|
||||
to union {
|
||||
typeof(Imm) In;
|
||||
int32_t Out[2];
|
||||
} U_S;
|
||||
U_S.In = Imm;
|
||||
int32_t *S = U_S.Out;
|
||||
|
||||
MSVC doesn't support typeof so it has to be resolved manually.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(declaration"
|
||||
" (placeholder_type_specifier)"
|
||||
" (init_declarator"
|
||||
" (identifier) @arr_name"
|
||||
" (call_expression"
|
||||
" (template_function"
|
||||
' ((identifier) @tfid (#eq @tfid "bit_cast"))'
|
||||
" (template_argument_list"
|
||||
' ((type_descriptor) @td (#match @td "std::array<.*>"))'
|
||||
" )"
|
||||
" )"
|
||||
" (argument_list) @cast_target"
|
||||
" )"
|
||||
" )"
|
||||
") @array_bit_cast"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "array_bit_cast"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
c1 = captures[1][0]
|
||||
c4 = captures[4][0]
|
||||
arr_name: bytes = get_text(src, c1.start_byte, c1.end_byte)
|
||||
array_type: Node = captures[3][0]
|
||||
cast_target: bytes = get_text(src, c4.start_byte, c4.end_byte).strip(b"()")
|
||||
named_child = array_type.named_children[0].named_children[1].named_children[1]
|
||||
array_templ_args: bytes = get_text(
|
||||
src, named_child.start_byte, named_child.end_byte
|
||||
).strip(b"<>")
|
||||
arr_type = array_templ_args.split(b",")[0]
|
||||
arr_len = array_templ_args.split(b",")[1]
|
||||
return (
|
||||
b"union {\n"
|
||||
+ b" typeof("
|
||||
+ cast_target
|
||||
+ b") In;\n"
|
||||
+ b" "
|
||||
+ arr_type
|
||||
+ b" Out["
|
||||
+ arr_len
|
||||
+ b"];\n"
|
||||
+ b"} U_"
|
||||
+ arr_name
|
||||
+ b";\n"
|
||||
+ b"U_"
|
||||
+ arr_name
|
||||
+ b".In = "
|
||||
+ cast_target
|
||||
+ b";\n"
|
||||
+ arr_type
|
||||
+ b" *"
|
||||
+ arr_name
|
||||
+ b" = U_"
|
||||
+ arr_name
|
||||
+ b".Out;"
|
||||
)
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class CheckDecoderStatus(Patch):
|
||||
"""
|
||||
Patch "Check(S, ..."
|
||||
to "Check(&S, ..."
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression"
|
||||
' ((identifier) @fcn_name (#eq? @fcn_name "Check"))'
|
||||
" ((argument_list) @arg_list)"
|
||||
") @check_call"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "check_call"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
call_expr: Node = captures[0][0]
|
||||
first_arg: Node = captures[2][0].named_children[0]
|
||||
|
||||
call_text = get_text(src, call_expr.start_byte, call_expr.end_byte)
|
||||
first_arg_text = get_text(src, first_arg.start_byte, first_arg.end_byte)
|
||||
|
||||
return call_text.replace(first_arg_text + b",", b"&" + first_arg_text + b",")
|
||||
Vendored
+32
@@ -0,0 +1,32 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class ClassConstructorDef(Patch):
|
||||
"""
|
||||
Removes Class constructor definitions with a field initializer list.
|
||||
Removes Class::Class(...) : ... {}
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(function_definition"
|
||||
" (function_declarator)"
|
||||
" (field_initializer_list)"
|
||||
" (compound_statement)"
|
||||
") @class_constructor"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "class_constructor"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
return b""
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
import re
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class ClassesDef(Patch):
|
||||
"""
|
||||
Patch Class definitions
|
||||
to Removes class but extracts method declarations.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return "(class_specifier (_)* ((field_declaration_list) @decl_list)*) @class_specifier"
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "class_specifier"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
if len(captures) < 2:
|
||||
# Forward class definition. Ignore it.
|
||||
return b""
|
||||
field_decl_list = captures[1][0]
|
||||
functions = list()
|
||||
for field_decl in field_decl_list.named_children:
|
||||
if (
|
||||
field_decl.type in "field_declaration"
|
||||
and (
|
||||
"function_declarator" in [t.type for t in field_decl.named_children]
|
||||
)
|
||||
) or field_decl.type == "template_declaration":
|
||||
# Keep comments
|
||||
sibling = field_decl.prev_named_sibling
|
||||
while sibling.type == "comment":
|
||||
functions.append(sibling)
|
||||
sibling = sibling.prev_named_sibling
|
||||
functions.append(field_decl)
|
||||
fcn_decl_text = b""
|
||||
for f in functions:
|
||||
fcn_decl_text += get_text(src, f.start_byte, f.end_byte) + b"\n"
|
||||
return fcn_decl_text
|
||||
Vendored
+36
@@ -0,0 +1,36 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class ConstMCInstParameter(Patch):
|
||||
"""
|
||||
Patch const MCInst *MI
|
||||
to MCInst *MI
|
||||
|
||||
Removes the const qualifier from MCInst parameters because functions like MCInst_getOperand() ignore them anyway.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(parameter_declaration"
|
||||
" ((type_qualifier) @type_qualifier)"
|
||||
' ((type_identifier) @type_id (#eq? @type_id "MCInst"))'
|
||||
" (pointer_declarator) @ptr_decl"
|
||||
") @mcinst_param"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "mcinst_param"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
inst = captures[3][0]
|
||||
inst = get_text(src, inst.start_byte, inst.end_byte)
|
||||
return b"MCInst " + inst
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class ConstMCOperand(Patch):
|
||||
"""
|
||||
Patch const MCOperand ...
|
||||
to MCOperand
|
||||
|
||||
Removes the const qualifier from MCOperand declarations. They are ignored by the following functions.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(declaration"
|
||||
" (type_qualifier)"
|
||||
' ((type_identifier) @tid (#eq? @tid "MCOperand"))'
|
||||
" (init_declarator) @init_decl"
|
||||
") @const_mcoperand"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "const_mcoperand"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
init_decl = captures[2][0]
|
||||
init_decl = get_text(src, init_decl.start_byte, init_decl.end_byte)
|
||||
return b"MCOperand " + init_decl + b";"
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class CppInitCast(Patch):
|
||||
"""
|
||||
Patch int(...)
|
||||
to (int)(...)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression"
|
||||
" (primitive_type) @cast_type"
|
||||
" (argument_list) @cast_target"
|
||||
") @cast"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "cast"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
cast_type: Node = captures[1][0]
|
||||
cast_target: Node = captures[2][0]
|
||||
|
||||
ctype = get_text(src, cast_type.start_byte, cast_type.end_byte)
|
||||
ctarget = get_text(src, cast_target.start_byte, cast_target.end_byte)
|
||||
return b"((" + ctype + b")" + ctarget + b")"
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import re
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class CreateOperand0(Patch):
|
||||
"""
|
||||
Patch Inst.addOperand(MCOperand::createReg(...));
|
||||
to MCOperand_CreateReg0(...)
|
||||
(and equivalent for CreateImm)
|
||||
|
||||
This is the `0` variant of the CS `CreateReg`/`CreateImm` functions. It is used if the
|
||||
operand is added via `addOperand()`.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression "
|
||||
" (field_expression ((identifier) @inst_var"
|
||||
' (field_identifier) @field_id (#eq? @field_id "addOperand")))'
|
||||
" (argument_list (call_expression "
|
||||
" (qualified_identifier ((_) (identifier) @create_fcn))"
|
||||
" (argument_list) @arg_list"
|
||||
" )"
|
||||
" )"
|
||||
") @create_operand0"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "create_operand0"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get name of instruction variable
|
||||
inst_var: Node = captures[1][0]
|
||||
# Get 'create[Reg/Imm]'
|
||||
op_create_fcn: Node = captures[3][0]
|
||||
# Get arg list
|
||||
op_create_args: Node = captures[4][0]
|
||||
|
||||
# Capstone spells the function with capital letter 'C' for whatever reason.
|
||||
fcn = re.sub(
|
||||
b"create",
|
||||
b"Create",
|
||||
get_text(src, op_create_fcn.start_byte, op_create_fcn.end_byte),
|
||||
)
|
||||
inst = get_text(src, inst_var.start_byte, inst_var.end_byte)
|
||||
args = get_text(src, op_create_args.start_byte, op_create_args.end_byte)
|
||||
if args[0] == b"(" and args[-1] == b")":
|
||||
args = args
|
||||
return b"MCOperand_" + fcn + b"0(" + inst + b", " + args + b")"
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import re
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_MCInst_var_name, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class CreateOperand1(Patch):
|
||||
"""
|
||||
Patch MI.insert(..., MCOperand::createReg(...));
|
||||
to MCInst_insert0(..., MCOperand_createReg1(...));
|
||||
(and equivalent for CreateImm)
|
||||
|
||||
This is the `1` variant of the CS `CreateReg`/`CreateImm` functions. It is used if the
|
||||
operand is added via `insert()`.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression "
|
||||
" (field_expression ((identifier) @MC_id"
|
||||
' ((field_identifier) @field_id (#match? @field_id "insert")))'
|
||||
" )"
|
||||
" (argument_list"
|
||||
" ((identifier) @inst_var"
|
||||
" (call_expression"
|
||||
" (qualified_identifier ((_) (identifier) @create_fcn))"
|
||||
" (argument_list) @arg_list)"
|
||||
" )"
|
||||
" )"
|
||||
") @create_operand1"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "create_operand1"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get instruction variable
|
||||
inst_var: Node = captures[1][0]
|
||||
# Get argument of .insert() call
|
||||
insert_arg: Node = captures[3][0]
|
||||
# Get 'create[Reg/Imm]'
|
||||
op_create_fcn: Node = captures[4][0]
|
||||
# CreateReg/Imm args
|
||||
op_create_args: Node = captures[5][0]
|
||||
|
||||
insert_arg_t = get_text(src, insert_arg.start_byte, insert_arg.end_byte)
|
||||
# Capstone spells the function with capital letter 'C' for whatever reason.
|
||||
fcn = re.sub(
|
||||
b"create",
|
||||
b"Create",
|
||||
get_text(src, op_create_fcn.start_byte, op_create_fcn.end_byte),
|
||||
)
|
||||
inst = get_text(src, inst_var.start_byte, inst_var.end_byte)
|
||||
args = get_text(src, op_create_args.start_byte, op_create_args.end_byte)
|
||||
return (
|
||||
b"MCInst_insert0("
|
||||
+ inst
|
||||
+ b", "
|
||||
+ insert_arg_t
|
||||
+ b", "
|
||||
+ b"MCOperand_"
|
||||
+ fcn
|
||||
+ b"1("
|
||||
+ inst
|
||||
+ b", "
|
||||
+ args
|
||||
+ b"))"
|
||||
)
|
||||
@@ -0,0 +1,35 @@
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class Data(Patch):
|
||||
"""
|
||||
Patch Bytes.data()
|
||||
to Bytes
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(call_expression "
|
||||
" (field_expression"
|
||||
" ((identifier) @data_var)"
|
||||
' ((field_identifier) @field_id_op (#eq? @field_id_op "data"))'
|
||||
" )"
|
||||
" ((argument_list) @arg_list)"
|
||||
") @data"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "data"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get operand variable name (Bytes, ArrayRef)
|
||||
op_var: Node = captures[1][0]
|
||||
op = get_text(src, op_var.start_byte, op_var.end_byte)
|
||||
return op
|
||||
external/capstone/suite/auto-sync/src/autosync/cpptranslator/patches/DeclarationInConditionClause.py
Vendored
+50
@@ -0,0 +1,50 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_capture_node, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class DeclarationInConditionalClause(Patch):
|
||||
"""
|
||||
Patch if (DECLARATION) ...
|
||||
to DECLARATION
|
||||
if (VAR) ...
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(if_statement"
|
||||
" (condition_clause"
|
||||
" (declaration"
|
||||
" (_)"
|
||||
" ((identifier) @id)"
|
||||
" (_)"
|
||||
" ) @decl"
|
||||
" )"
|
||||
" (_) @if_body"
|
||||
") @condition_clause"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "condition_clause"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
cond = get_capture_node(captures, "condition_clause")
|
||||
for nc in cond.named_children:
|
||||
if nc.type == "if_statement":
|
||||
# Skip if statements with else if
|
||||
return get_text(src, cond.start_byte, cond.end_byte)
|
||||
declaration = get_capture_node(captures, "decl")
|
||||
identifier = get_capture_node(captures, "id")
|
||||
if_body = get_capture_node(captures, "if_body")
|
||||
identifier = get_text(src, identifier.start_byte, identifier.end_byte)
|
||||
declaration = get_text(src, declaration.start_byte, declaration.end_byte)
|
||||
if_body = get_text(src, if_body.start_byte, if_body.end_byte)
|
||||
res = declaration + b";\nif (" + identifier + b")\n" + if_body
|
||||
return res
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class DecodeInstruction(Patch):
|
||||
"""
|
||||
Patch decodeInstruction(..., this, STI)
|
||||
to decodeInstruction_<instr_width>(..., NULL)
|
||||
|
||||
It also removes the arguments `this, STI`.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression ("
|
||||
' (identifier) @fcn_name (#eq? @fcn_name "decodeInstruction")'
|
||||
" ((argument_list) @arg_list)"
|
||||
")) @decode_instr"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "decode_instr"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
arg_list = captures[2][0]
|
||||
args_text = get_text(src, arg_list.start_byte, arg_list.end_byte).strip(b"()")
|
||||
|
||||
table, mi_inst, opcode_var, address, this, sti = args_text.split(b",")
|
||||
is_32bit = (
|
||||
table[-2:].decode("utf8") == "32" or opcode_var[-2:].decode("utf8") == "32"
|
||||
)
|
||||
is_16bit = (
|
||||
table[-2:].decode("utf8") == "16" or opcode_var[-2:].decode("utf8") == "16"
|
||||
)
|
||||
args = (
|
||||
table + b", " + mi_inst + b", " + opcode_var + b", " + address + b", NULL"
|
||||
)
|
||||
|
||||
if is_16bit and not is_32bit:
|
||||
return b"decodeInstruction_2(" + args + b")"
|
||||
elif is_32bit and not is_16bit:
|
||||
return b"decodeInstruction_4(" + args + b")"
|
||||
else:
|
||||
# Cannot determine instruction width easily. Only update the calls arguments.
|
||||
return b"decodeInstruction(" + args + b")"
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class DecoderCast(Patch):
|
||||
"""
|
||||
Patch Removes casts like `const MCDisassembler *Dis = static_cast<const MCDisassembler*>(Decoder);`
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(declaration"
|
||||
" (type_qualifier)*"
|
||||
' ((type_identifier) @tid (#eq? @tid "MCDisassembler"))'
|
||||
" (init_declarator"
|
||||
" (pointer_declarator)"
|
||||
" (call_expression"
|
||||
" (template_function)" # static_cast<const MCDisassembler>
|
||||
" (argument_list"
|
||||
' ((identifier) @id (#eq? @id "Decoder"))'
|
||||
" )"
|
||||
" )"
|
||||
" )"
|
||||
") @decoder_cast"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "decoder_cast"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
return b""
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class DecoderParameter(Patch):
|
||||
"""
|
||||
Patch const MCDisassembler *Decoder
|
||||
to const void *Decoder
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(parameter_declaration"
|
||||
" ((type_qualifier) @type_qualifier)"
|
||||
' ((type_identifier) @type_id (#eq? @type_id "MCDisassembler"))'
|
||||
" (pointer_declarator) @ptr_decl"
|
||||
") @decoder_param"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "decoder_param"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
return b"const void *Decoder"
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class FallThrough(Patch):
|
||||
"""
|
||||
Patch [[fallthrough]]
|
||||
to // fall through
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return '(attributed_statement) @attr (#match? @attr "fallthrough")'
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "attr"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
return b"// fall through"
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_MCInst_var_name, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class FeatureBits(Patch):
|
||||
"""
|
||||
Patch featureBits[FLAG]
|
||||
to ARCH_getFeatureBits(Inst->csh->mode, FLAG)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int, arch: bytes):
|
||||
self.arch = arch
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
# Search for featureBits usage.
|
||||
return (
|
||||
"(subscript_expression "
|
||||
' ((identifier) @id (#match? @id "[fF]eatureBits"))'
|
||||
" (subscript_argument_list ((qualified_identifier) @qid))"
|
||||
") @feature_bits"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "feature_bits"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get flag name of feature bit.
|
||||
qualified_id: Node = captures[2][0]
|
||||
flag = get_text(src, qualified_id.start_byte, qualified_id.end_byte)
|
||||
mcinst_var_name = get_MCInst_var_name(src, qualified_id)
|
||||
return (
|
||||
self.arch
|
||||
+ b"_getFeatureBits("
|
||||
+ mcinst_var_name
|
||||
+ b"->csh->mode, "
|
||||
+ flag
|
||||
+ b")"
|
||||
)
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class FeatureBitsDecl(Patch):
|
||||
"""
|
||||
Patch ... featureBits = ...
|
||||
to REMOVED
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
# Search for featureBits declarations.
|
||||
return (
|
||||
"(declaration (init_declarator (reference_declarator "
|
||||
'((identifier) @id (#match? @id "[fF]eatureBits"))))) @feature_bits_decl'
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "feature_bits_decl"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Remove declaration
|
||||
return b""
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
import re
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_function_params_of_node, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class FieldFromInstr(Patch):
|
||||
"""
|
||||
Patch fieldFromInstruction(...)
|
||||
to fieldFromInstruction_<instr_width>(...)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
# Search for fieldFromInstruction() calls.
|
||||
return (
|
||||
"(call_expression"
|
||||
' ((identifier) @fcn_name (#eq? @fcn_name "fieldFromInstruction"))'
|
||||
" (argument_list ((identifier) @first_arg) (_) (_))"
|
||||
") @field_from_instr"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "field_from_instr"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
ffi_call: Node = captures[0][0]
|
||||
ffi_first_arg: Node = captures[2][0]
|
||||
param_list_caller = get_function_params_of_node(ffi_call)
|
||||
ffi_first_arg_text = get_text(
|
||||
src, ffi_first_arg.start_byte, ffi_first_arg.end_byte
|
||||
).decode("utf8")
|
||||
|
||||
# Determine width of instruction by the variable name.
|
||||
if ffi_first_arg_text[-2:] == "32":
|
||||
inst_width = b"4"
|
||||
elif ffi_first_arg_text[-2:] == "16":
|
||||
inst_width = b"2"
|
||||
else:
|
||||
# Get the Val/Inst parameter.
|
||||
# Its type determines the instruction width.
|
||||
if len(param_list_caller.named_children) == 1:
|
||||
# If function just return fieldFromInstruction(...)
|
||||
inst_param: Node = param_list_caller.named_children[0]
|
||||
else:
|
||||
inst_param = param_list_caller.named_children[1]
|
||||
inst_param_text = get_text(src, inst_param.start_byte, inst_param.end_byte)
|
||||
|
||||
# Search for the 'Inst' parameter and determine its type
|
||||
# and with it the width of the instruction.
|
||||
inst_type = inst_param_text.split(b" ")[0]
|
||||
if inst_type:
|
||||
if inst_type in [b"uint64_t"]:
|
||||
inst_width = b"8"
|
||||
elif inst_type in [b"unsigned", b"uint32_t"]:
|
||||
inst_width = b"4"
|
||||
elif inst_type in [b"uint16_t"]:
|
||||
inst_width = b"2"
|
||||
elif inst_type in [b"InsnType"]:
|
||||
# Case means the decode function inherits the type from
|
||||
# a template argument InsnType. The InsnType template argument
|
||||
# is the type of integer holding the instruction bytes.
|
||||
# This type is defined in ARCHDisassembler on calling the right macro.
|
||||
# Hence, we do not know at this point of patching which type it might be.
|
||||
# It needs to call fieldOfInstruction_X() which detects dynamically which
|
||||
# integer type might hold the bytes (e.g. a uint32_t or uint16_t).
|
||||
# You can check it manually in ARCHDisassembler.c, but the script can't.
|
||||
#
|
||||
# Here we just create a function with the postfix fieldFromInstruction_w (for width).
|
||||
# This function must be implemented by hand, and check MCInst for the actual bit width.
|
||||
# The bit width must be set in the ARCHDisassembler.c. Just add the code there by hand.
|
||||
# Then call fieldFromInstruction_4, fieldFromInstruction_2 appropriately.
|
||||
log.warning(
|
||||
"Variable fieldFromInstruction width detected.\n"
|
||||
"Please implement fieldFromInstruction_w() and call "
|
||||
"fieldFromInstruction_4, fieldFromInstruction_2 appropriately.\n"
|
||||
"In fieldFromInstruction_w() check MCInst for the actual bit width.\n"
|
||||
"The bit width must be set in the ARCHDisassembler.c. Just add the code there by hand."
|
||||
)
|
||||
inst_width = b"w"
|
||||
else:
|
||||
raise ValueError(f"Type {inst_type} not handled.")
|
||||
else:
|
||||
# Needs manual fix
|
||||
return get_text(src, ffi_call.start_byte, ffi_call.end_byte)
|
||||
return re.sub(
|
||||
rb"fieldFromInstruction",
|
||||
b"fieldFromInstruction_%s" % inst_width,
|
||||
get_text(src, ffi_call.start_byte, ffi_call.end_byte),
|
||||
)
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class GetNumOperands(Patch):
|
||||
"""
|
||||
Patch MI.getNumOperands()
|
||||
to MCInst_getNumOperands(MI)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(call_expression "
|
||||
" (field_expression"
|
||||
" ((identifier) @inst_var)"
|
||||
' ((field_identifier) @field_id_op (#eq? @field_id_op "getNumOperands"))'
|
||||
" )"
|
||||
" ((argument_list) @arg_list)"
|
||||
") @get_num_operands"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "get_num_operands"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get instruction variable name: MI, Inst etc.
|
||||
inst_var: Node = captures[1][0]
|
||||
inst = get_text(src, inst_var.start_byte, inst_var.end_byte)
|
||||
return b"MCInst_getNumOperands(" + inst + b")"
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class GetOpcode(Patch):
|
||||
"""
|
||||
Patch Inst.getOpcode()
|
||||
to MCInst_getOpcode(Inst)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression"
|
||||
" (field_expression ("
|
||||
" ((identifier) @inst_var)"
|
||||
' ((field_identifier) @field_id (#eq? @field_id "getOpcode")))'
|
||||
" )"
|
||||
" (argument_list) @arg_list"
|
||||
") @get_opcode"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "get_opcode"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Instruction variable
|
||||
inst_var: Node = captures[1][0]
|
||||
arg_list: Node = captures[3][0]
|
||||
|
||||
inst = get_text(src, inst_var.start_byte, inst_var.end_byte)
|
||||
args = get_text(src, arg_list.start_byte, arg_list.end_byte)
|
||||
if args != b"()":
|
||||
args = b", " + args
|
||||
else:
|
||||
args = b""
|
||||
return b"MCInst_getOpcode(" + inst + args + b")"
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class GetOperand(Patch):
|
||||
"""
|
||||
Patch MI.getOperand(...)
|
||||
to MCInst_getOperand(MI, ...)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(call_expression "
|
||||
" (field_expression"
|
||||
" ((identifier) @inst_var)"
|
||||
' ((field_identifier) @field_id_op (#eq? @field_id_op "getOperand"))'
|
||||
" )"
|
||||
" ((argument_list) @arg_list)"
|
||||
") @get_operand"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "get_operand"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get instruction variable name (MI, Inst)
|
||||
inst_var: Node = captures[1][0]
|
||||
# Arguments of getOperand(...)
|
||||
get_op_args = captures[3][0]
|
||||
inst = get_text(src, inst_var.start_byte, inst_var.end_byte)
|
||||
args = get_text(src, get_op_args.start_byte, get_op_args.end_byte)
|
||||
return b"MCInst_getOperand(" + inst + b", " + args + b")"
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_capture_node, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class GetOperandRegImm(Patch):
|
||||
"""
|
||||
Patch OPERAND.getReg()
|
||||
to MCOperand_getReg(OPERAND)
|
||||
|
||||
Same for getImm()|getExpr
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(call_expression"
|
||||
" (field_expression"
|
||||
" ((_) @operand)"
|
||||
' ((field_identifier) @field_id (#match? @field_id "get(Reg|Imm|Expr)"))'
|
||||
" )"
|
||||
' ((argument_list) @arg_list (#eq? @arg_list "()"))'
|
||||
") @get_operand"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "get_operand"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# The operand
|
||||
operand: Node = get_capture_node(captures, "operand")
|
||||
# 'getReg()/getImm()\getExpr'
|
||||
get_reg_imm = get_capture_node(captures, "field_id")
|
||||
|
||||
fcn = get_text(src, get_reg_imm.start_byte, get_reg_imm.end_byte)
|
||||
op = get_text(src, operand.start_byte, operand.end_byte)
|
||||
return b"MCOperand_" + fcn + b"(" + op + b")"
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import (
|
||||
get_capture_node,
|
||||
get_MCInst_var_name,
|
||||
get_text,
|
||||
)
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class GetRegClass(Patch):
|
||||
"""
|
||||
Patch MRI.getRegClass(...)
|
||||
to MCRegisterInfo_getRegClass(Inst->MRI, ...)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(call_expression"
|
||||
" (field_expression"
|
||||
" (_)"
|
||||
' ((field_identifier) @field_id (#eq? @field_id "getRegClass"))'
|
||||
" )"
|
||||
" ((argument_list) @arg_list)"
|
||||
") @get_reg_class"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "get_reg_class"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
arg_list: Node = get_capture_node(captures, "arg_list")
|
||||
args = get_text(src, arg_list.start_byte, arg_list.end_byte).strip(b"()")
|
||||
mcinst_var = get_MCInst_var_name(
|
||||
src, get_capture_node(captures, "get_reg_class")
|
||||
)
|
||||
res = b"MCRegisterInfo_getRegClass(" + mcinst_var + b"->MRI, " + args + b")"
|
||||
return res
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_capture_node, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class GetRegFromClass(Patch):
|
||||
"""
|
||||
Patch <ARCH>MCRegisterClasses[<ARCH>::FPR128RegClassID].getRegister(RegNo);
|
||||
to <ARCH>MCRegisterClasses[<ARCH>::FPR128RegClassID].RegsBegin[RegNo];
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(call_expression"
|
||||
" (field_expression"
|
||||
' ((_) @operand (#match? @operand ".+MCRegisterClasses.*"))'
|
||||
' ((field_identifier) @field_id (#eq? @field_id "getRegister"))'
|
||||
" )"
|
||||
" (argument_list) @arg_list"
|
||||
") @get_reg_from_class"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "get_reg_from_class"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Table
|
||||
table: Node = get_capture_node(captures, "operand")
|
||||
# args
|
||||
getter_args = get_capture_node(captures, "arg_list")
|
||||
|
||||
tbl = get_text(src, table.start_byte, table.end_byte)
|
||||
args = get_text(src, getter_args.start_byte, getter_args.end_byte)
|
||||
|
||||
res = tbl + b".RegsBegin" + args.replace(b"(", b"[").replace(b")", b"]")
|
||||
return res
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_MCInst_var_name, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class GetSubReg(Patch):
|
||||
"""
|
||||
Patch MRI.getSubReg(...);
|
||||
to MCRegisterInfo_getSubReg(MI->MRI, ...)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression"
|
||||
" (field_expression ("
|
||||
" (identifier)"
|
||||
' ((field_identifier) @field_id (#eq? @field_id "getSubReg")))'
|
||||
" )"
|
||||
" (argument_list) @arg_list"
|
||||
") @get_sub_reg"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "get_sub_reg"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get arg list
|
||||
op_create_args: Node = captures[2][0]
|
||||
|
||||
args = get_text(src, op_create_args.start_byte, op_create_args.end_byte).strip(
|
||||
b"()"
|
||||
)
|
||||
mcinst_var_name = get_MCInst_var_name(src, op_create_args)
|
||||
return b"MCRegisterInfo_getSubReg(" + mcinst_var_name + b"->MRI, " + args + b")"
|
||||
+234
@@ -0,0 +1,234 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
import re
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.Helper import fail_exit
|
||||
|
||||
|
||||
def get_function_params_of_node(n: Node) -> Node:
|
||||
"""
|
||||
Returns for a given node the parameters of the function this node is a children from.
|
||||
Or None if the node is not part of a function definition.
|
||||
"""
|
||||
fcn_def: Node = n
|
||||
while fcn_def.type != "function_definition":
|
||||
if fcn_def.parent == None:
|
||||
# root node reached
|
||||
return None
|
||||
fcn_def = fcn_def.parent
|
||||
|
||||
# Get parameter list of the function definition
|
||||
param_list: Node = None
|
||||
for child in fcn_def.children:
|
||||
if child.type == "function_declarator":
|
||||
param_list = child.children[1]
|
||||
break
|
||||
if not param_list:
|
||||
log.warning(f"Could not find the functions parameter list for {n.text}")
|
||||
return param_list
|
||||
|
||||
|
||||
def get_MCInst_var_name(src: bytes, n: Node) -> bytes:
|
||||
"""Searches for the name of the parameter of type MCInst and returns it."""
|
||||
params = get_function_params_of_node(n)
|
||||
mcinst_var_name = b""
|
||||
|
||||
if params:
|
||||
for p in params.named_children:
|
||||
p_text = get_text(src, p.start_byte, p.end_byte)
|
||||
if b"MCInst" not in p_text:
|
||||
continue
|
||||
mcinst_var_name = p_text.split((b"&" if b"&" in p_text else b"*"))[1]
|
||||
break
|
||||
if mcinst_var_name == b"":
|
||||
log.debug("Could not find `MCInst` variable name. Defaulting to `Inst`.")
|
||||
mcinst_var_name = b"Inst"
|
||||
return mcinst_var_name
|
||||
|
||||
|
||||
def template_param_list_to_dict(param_list: Node) -> [dict]:
|
||||
if param_list.type != "template_parameter_list":
|
||||
log.fatal(
|
||||
f"Wrong node type '{param_list.type}'. Not 'template_parameter_list'."
|
||||
)
|
||||
exit(1)
|
||||
pl = list()
|
||||
for c in param_list.named_children:
|
||||
if c.type == "type_parameter_declaration":
|
||||
type_decl = {
|
||||
"prim_type": False,
|
||||
"type": "",
|
||||
"identifier": c.children[1].text,
|
||||
}
|
||||
pl.append(type_decl)
|
||||
else:
|
||||
pl.append(parameter_declaration_to_dict(c))
|
||||
return pl
|
||||
|
||||
|
||||
def parameter_declaration_to_dict(param_decl: Node) -> dict:
|
||||
if param_decl.type != "parameter_declaration":
|
||||
log.fatal(
|
||||
f"Wrong node type '{param_decl.type}'. Should be 'parameter_declaration'."
|
||||
)
|
||||
exit(1)
|
||||
return {
|
||||
"prim_type": param_decl.children[0].type == "primitive_type",
|
||||
"type": param_decl.children[0].text,
|
||||
"identifier": param_decl.children[1].text,
|
||||
}
|
||||
|
||||
|
||||
def get_text(src: bytes, start_byte: int, end_byte: int) -> bytes:
|
||||
"""Workaround for https://github.com/tree-sitter/py-tree-sitter/issues/122"""
|
||||
return src[start_byte:end_byte]
|
||||
|
||||
|
||||
def get_text_from_node(src: bytes, node: Node) -> bytes:
|
||||
return src[node.start_byte : node.end_byte]
|
||||
|
||||
|
||||
def namespace_enum(src: bytes, ns_id: bytes, enum: Node) -> bytes:
|
||||
"""
|
||||
Alters an enum in the way that it prepends the namespace id to every enum member.
|
||||
And defines it as a type.
|
||||
Example: naemspace_id = "ARM"
|
||||
enum { X } -> typedef enum { ARM_X } ARM_enum
|
||||
"""
|
||||
enumerator_list: Node = None
|
||||
type_id: Node = None
|
||||
primary_tid_set = False
|
||||
for c in enum.named_children:
|
||||
if c.type == "enumerator_list":
|
||||
enumerator_list = c
|
||||
elif c.type == "type_identifier" and not primary_tid_set:
|
||||
type_id = c
|
||||
primary_tid_set = True
|
||||
|
||||
if not enumerator_list and not type_id:
|
||||
log.fatal("Could not find enumerator_list or enum type_identifier.")
|
||||
exit(1)
|
||||
|
||||
tid = get_text(src, type_id.start_byte, type_id.end_byte) if type_id else None
|
||||
elist = get_text(src, enumerator_list.start_byte, enumerator_list.end_byte)
|
||||
for e in enumerator_list.named_children:
|
||||
if e.type == "enumerator":
|
||||
enum_entry_text = get_text(src, e.start_byte, e.end_byte)
|
||||
elist = elist.replace(enum_entry_text, ns_id + b"_" + enum_entry_text)
|
||||
|
||||
if tid:
|
||||
new_enum = b"typedef enum " + tid + b" " + elist + b"\n " + ns_id + b"_" + tid
|
||||
else:
|
||||
new_enum = b"enum " + b" " + elist + b"\n"
|
||||
return new_enum
|
||||
|
||||
|
||||
def namespace_fcn_def(src: bytes, ns_id: bytes, fcn_def: Node) -> bytes:
|
||||
fcn_id: Node = None
|
||||
for c in fcn_def.named_children:
|
||||
if c.type == "function_declarator":
|
||||
fcn_id = c.named_children[0]
|
||||
break
|
||||
elif c.named_children and c.named_children[0].type == "function_declarator":
|
||||
fcn_id = c.named_children[0].named_children[0]
|
||||
break
|
||||
if not fcn_id:
|
||||
# Not a function declaration
|
||||
return get_text(src, fcn_def.start_byte, fcn_def.end_byte)
|
||||
fcn_id_text = get_text(src, fcn_id.start_byte, fcn_id.end_byte)
|
||||
fcn_def_text = get_text(src, fcn_def.start_byte, fcn_def.end_byte)
|
||||
res = re.sub(fcn_id_text, ns_id + b"_" + fcn_id_text, fcn_def_text)
|
||||
return res
|
||||
|
||||
|
||||
def namespace_struct(src: bytes, ns_id: bytes, struct: Node) -> bytes:
|
||||
"""
|
||||
Defines a struct as a type.
|
||||
Example: naemspace_id = "ARM"
|
||||
struct id { X } -> typedef struct { } ARM_id
|
||||
"""
|
||||
type_id: Node = None
|
||||
field_list: Node = None
|
||||
for c in struct.named_children:
|
||||
if c.type == "type_identifier":
|
||||
type_id = c
|
||||
elif c.type == "base_class_clause":
|
||||
# Inheritances should be fixed manually.
|
||||
return get_text(src, struct.start_byte, struct.end_byte)
|
||||
elif c.type == "field_declaration_list":
|
||||
field_list = c
|
||||
|
||||
if not (type_id and field_list):
|
||||
log.fatal("Could not find struct type_identifier or field declaration list.")
|
||||
exit(1)
|
||||
|
||||
tid = get_text(src, type_id.start_byte, type_id.end_byte)
|
||||
fields = get_text(src, field_list.start_byte, field_list.end_byte)
|
||||
|
||||
typed_struct = (
|
||||
b"typedef struct " + tid + b" " + fields + b"\n " + ns_id + b"_" + tid
|
||||
)
|
||||
return typed_struct
|
||||
|
||||
|
||||
def parse_function_capture(
|
||||
capture: list[tuple[Node, str]], src: bytes
|
||||
) -> tuple[list[bytes], bytes, bytes, bytes, bytes, bytes]:
|
||||
"""
|
||||
Parses the capture of a (template) function definition or declaration and returns the byte strings
|
||||
for each node in the following order:
|
||||
|
||||
list[template_args], storage_class_identifiers, return_type_id, function_name, function_params, compound_stmt
|
||||
|
||||
If any of those is not present it returns an empty byte string for this position.
|
||||
"""
|
||||
temp_args = b""
|
||||
st_class_ids = b""
|
||||
ret_type = b""
|
||||
func_name = b""
|
||||
func_params = b""
|
||||
comp_stmt = b""
|
||||
for node, node_name in capture:
|
||||
t = get_text(src, node.start_byte, node.end_byte)
|
||||
match node.type:
|
||||
case "template_declaration":
|
||||
continue
|
||||
case "template_parameter_list":
|
||||
temp_args += t if not temp_args else b" " + t
|
||||
case "storage_class_specifier":
|
||||
st_class_ids += b" " + t
|
||||
case "type_identifier" | "primitive_type":
|
||||
ret_type += b" " + t
|
||||
case "identifier":
|
||||
func_name += t if not func_name else b" " + t
|
||||
case "parameter_list":
|
||||
func_params += t if not func_params else b" " + t
|
||||
case "compound_statement":
|
||||
comp_stmt += t if not comp_stmt else b" " + t
|
||||
case _:
|
||||
raise NotImplementedError(f"Node type {node.type} not handled.")
|
||||
|
||||
from autosync.cpptranslator.TemplateCollector import TemplateCollector
|
||||
|
||||
return (
|
||||
TemplateCollector.templ_params_to_list(temp_args),
|
||||
st_class_ids,
|
||||
ret_type,
|
||||
func_name,
|
||||
func_params,
|
||||
comp_stmt,
|
||||
)
|
||||
|
||||
|
||||
def get_capture_node(captures: [(Node, str)], name: str) -> Node:
|
||||
"""
|
||||
Returns the captured node with the given name.
|
||||
"""
|
||||
for c in captures:
|
||||
if c[1] == name:
|
||||
return c[0]
|
||||
fail_exit(f'Capture "{name}" is not in captures:\n{captures}')
|
||||
+487
@@ -0,0 +1,487 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class Includes(Patch):
|
||||
"""
|
||||
Patch LLVM includes
|
||||
to Capstone includes
|
||||
"""
|
||||
|
||||
include_count = dict()
|
||||
|
||||
def __init__(self, priority: int, arch: str):
|
||||
self.arch = arch
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return "(preproc_include) @preproc_include"
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "preproc_include"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
filename = kwargs["filename"]
|
||||
if filename not in self.include_count:
|
||||
self.include_count[filename] = 1
|
||||
else:
|
||||
self.include_count[filename] += 1
|
||||
|
||||
include_text = get_text(src, captures[0][0].start_byte, captures[0][0].end_byte)
|
||||
# Special cases, which appear somewhere in the code.
|
||||
if b"GenDisassemblerTables.inc" in include_text:
|
||||
return (
|
||||
b'#include "'
|
||||
+ bytes(self.arch, "utf8")
|
||||
+ b'GenDisassemblerTables.inc"\n\n'
|
||||
)
|
||||
elif b"GenAsmWriter.inc" in include_text:
|
||||
return b'#include "' + bytes(self.arch, "utf8") + b'GenAsmWriter.inc"\n\n'
|
||||
elif b"GenSystemOperands.inc" in include_text:
|
||||
return (
|
||||
b'#include "' + bytes(self.arch, "utf8") + b'GenSystemOperands.inc"\n\n'
|
||||
)
|
||||
|
||||
if self.include_count[filename] > 1:
|
||||
# Only the first include is replaced with all CS includes.
|
||||
return b""
|
||||
|
||||
# All includes which belong to the source files top.
|
||||
res = get_general_inc()
|
||||
match self.arch:
|
||||
case "ARM":
|
||||
return res + get_ARM_includes(filename) + get_general_macros()
|
||||
case "PPC":
|
||||
return res + get_PPC_includes(filename) + get_general_macros()
|
||||
case "AArch64":
|
||||
return res + get_AArch64_includes(filename) + get_general_macros()
|
||||
case "LoongArch":
|
||||
return res + get_LoongArch_includes(filename) + get_general_macros()
|
||||
case "Mips":
|
||||
return res + get_Mips_includes(filename) + get_general_macros()
|
||||
case "SystemZ":
|
||||
return res + get_SystemZ_includes(filename) + get_general_macros()
|
||||
case "Xtensa":
|
||||
return res + get_Xtensa_includes(filename) + get_general_macros()
|
||||
case "ARC":
|
||||
return res + get_ARC_includes(filename) + get_general_macros()
|
||||
case "Sparc":
|
||||
return res + get_sparc_includes(filename) + get_general_macros()
|
||||
case "TEST_ARCH":
|
||||
return res + b"test_output"
|
||||
case _:
|
||||
log.fatal(f"Includes of {self.arch} not handled.")
|
||||
exit(1)
|
||||
|
||||
|
||||
def get_general_inc() -> bytes:
|
||||
return (
|
||||
b"#include <stdio.h>\n"
|
||||
+ b"#include <string.h>\n"
|
||||
+ b"#include <stdlib.h>\n"
|
||||
+ b"#include <capstone/platform.h>\n\n"
|
||||
)
|
||||
|
||||
|
||||
def get_PPC_includes(filename: str) -> bytes:
|
||||
match filename:
|
||||
case "PPCDisassembler.cpp":
|
||||
return (
|
||||
b'#include "../../LEB128.h"\n'
|
||||
+ b'#include "../../MCDisassembler.h"\n'
|
||||
+ b'#include "../../MCFixedLenDisassembler.h"\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCInstrDesc.h"\n'
|
||||
+ b'#include "../../MCInstPrinter.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
+ b'#include "../../SStream.h"\n'
|
||||
+ b'#include "../../utils.h"\n'
|
||||
+ b'#include "PPCLinkage.h"\n'
|
||||
+ b'#include "PPCMapping.h"\n'
|
||||
+ b'#include "PPCMCTargetDesc.h"\n'
|
||||
+ b'#include "PPCPredicates.h"\n\n'
|
||||
)
|
||||
case "PPCInstPrinter.cpp":
|
||||
return (
|
||||
b'#include "../../LEB128.h"\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCInstrDesc.h"\n'
|
||||
+ b'#include "../../MCInstPrinter.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
+ b'#include "PPCInstrInfo.h"\n'
|
||||
+ b'#include "PPCInstPrinter.h"\n'
|
||||
+ b'#include "PPCLinkage.h"\n'
|
||||
+ b'#include "PPCMCTargetDesc.h"\n'
|
||||
+ b'#include "PPCMapping.h"\n'
|
||||
+ b'#include "PPCPredicates.h"\n\n'
|
||||
+ b'#include "PPCRegisterInfo.h"\n\n'
|
||||
)
|
||||
case "PPCInstPrinter.h":
|
||||
return (
|
||||
b'#include "../../LEB128.h"\n'
|
||||
+ b'#include "../../MCDisassembler.h"\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCInstrDesc.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
+ b'#include "../../SStream.h"\n'
|
||||
+ b'#include "PPCMCTargetDesc.h"\n\n'
|
||||
)
|
||||
case "PPCMCTargetDesc.h":
|
||||
return (
|
||||
b'#include "../../LEB128.h"\n'
|
||||
+ b'#include "../../MathExtras.h"\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCInstrDesc.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
)
|
||||
log.fatal(f"No includes given for PPC source file: {filename}")
|
||||
exit(1)
|
||||
|
||||
|
||||
def get_ARM_includes(filename: str) -> bytes:
|
||||
match filename:
|
||||
case "ARMDisassembler.cpp":
|
||||
return (
|
||||
b'#include "../../LEB128.h"\n'
|
||||
+ b'#include "../../MCDisassembler.h"\n'
|
||||
+ b'#include "../../MCFixedLenDisassembler.h"\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCInstrDesc.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
+ b'#include "../../MathExtras.h"\n'
|
||||
+ b'#include "../../cs_priv.h"\n'
|
||||
+ b'#include "../../utils.h"\n'
|
||||
+ b'#include "ARMAddressingModes.h"\n'
|
||||
+ b'#include "ARMBaseInfo.h"\n'
|
||||
+ b'#include "ARMDisassemblerExtension.h"\n'
|
||||
+ b'#include "ARMInstPrinter.h"\n'
|
||||
+ b'#include "ARMLinkage.h"\n'
|
||||
+ b'#include "ARMMapping.h"\n\n'
|
||||
+ b"#define GET_INSTRINFO_MC_DESC\n"
|
||||
+ b'#include "ARMGenInstrInfo.inc"\n\n'
|
||||
)
|
||||
case "ARMInstPrinter.cpp":
|
||||
return (
|
||||
b'#include "../../Mapping.h"\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCInstPrinter.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
+ b'#include "../../SStream.h"\n'
|
||||
+ b'#include "../../utils.h"\n'
|
||||
+ b'#include "ARMAddressingModes.h"\n'
|
||||
+ b'#include "ARMBaseInfo.h"\n'
|
||||
+ b'#include "ARMDisassemblerExtension.h"\n'
|
||||
+ b'#include "ARMInstPrinter.h"\n'
|
||||
+ b'#include "ARMLinkage.h"\n'
|
||||
+ b'#include "ARMMapping.h"\n\n'
|
||||
+ b"#define GET_BANKEDREG_IMPL\n"
|
||||
+ b'#include "ARMGenSystemRegister.inc"\n'
|
||||
)
|
||||
case "ARMInstPrinter.h":
|
||||
return (
|
||||
b'#include "ARMMapping.h"\n\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../SStream.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
+ b'#include "../../MCInstPrinter.h"\n'
|
||||
+ b'#include "../../utils.h"\n\n'
|
||||
)
|
||||
case "ARMBaseInfo.cpp":
|
||||
return b'#include "ARMBaseInfo.h"\n\n'
|
||||
case "ARMAddressingModes.h":
|
||||
return b"#include <assert.h>\n" + b'#include "../../MathExtras.h"\n\n'
|
||||
log.fatal(f"No includes given for ARM source file: {filename}")
|
||||
exit(1)
|
||||
|
||||
|
||||
def get_AArch64_includes(filename: str) -> bytes:
|
||||
match filename:
|
||||
case "AArch64Disassembler.cpp":
|
||||
return (
|
||||
b'#include "../../MCFixedLenDisassembler.h"\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCInstrDesc.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
+ b'#include "../../LEB128.h"\n'
|
||||
+ b'#include "../../MCDisassembler.h"\n'
|
||||
+ b'#include "../../cs_priv.h"\n'
|
||||
+ b'#include "../../utils.h"\n'
|
||||
+ b'#include "AArch64AddressingModes.h"\n'
|
||||
+ b'#include "AArch64BaseInfo.h"\n'
|
||||
+ b'#include "AArch64DisassemblerExtension.h"\n'
|
||||
+ b'#include "AArch64Linkage.h"\n'
|
||||
+ b'#include "AArch64Mapping.h"\n\n'
|
||||
+ b"#define GET_INSTRINFO_MC_DESC\n"
|
||||
+ b'#include "AArch64GenInstrInfo.inc"\n\n'
|
||||
+ b"#define GET_INSTRINFO_ENUM\n"
|
||||
+ b'#include "AArch64GenInstrInfo.inc"\n\n'
|
||||
)
|
||||
case "AArch64InstPrinter.cpp":
|
||||
return (
|
||||
b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCInstPrinter.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
+ b'#include "../../SStream.h"\n'
|
||||
+ b'#include "../../utils.h"\n'
|
||||
+ b'#include "AArch64AddressingModes.h"\n'
|
||||
+ b'#include "AArch64BaseInfo.h"\n'
|
||||
+ b'#include "AArch64DisassemblerExtension.h"\n'
|
||||
+ b'#include "AArch64InstPrinter.h"\n'
|
||||
+ b'#include "AArch64Linkage.h"\n'
|
||||
+ b'#include "AArch64Mapping.h"\n\n'
|
||||
+ b"#define GET_BANKEDREG_IMPL\n"
|
||||
+ b'#include "AArch64GenSystemOperands.inc"\n\n'
|
||||
+ b"#define CONCATs(a, b) CONCATS(a, b)\n"
|
||||
+ b"#define CONCATS(a, b) a##b\n\n"
|
||||
)
|
||||
case "AArch64InstPrinter.h":
|
||||
return (
|
||||
b'#include "AArch64Mapping.h"\n\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
+ b'#include "../../MCInstPrinter.h"\n'
|
||||
+ b'#include "../../SStream.h"\n'
|
||||
+ b'#include "../../utils.h"\n\n'
|
||||
)
|
||||
case "AArch64BaseInfo.cpp":
|
||||
return b'#include "AArch64BaseInfo.h"\n\n'
|
||||
case "AArch64BaseInfo.h":
|
||||
return (
|
||||
b'#include "../../utils.h"\n'
|
||||
+ b"#define GET_REGINFO_ENUM\n"
|
||||
+ b'#include "AArch64GenRegisterInfo.inc"\n\n'
|
||||
+ b"#define GET_INSTRINFO_ENUM\n"
|
||||
+ b'#include "AArch64GenInstrInfo.inc"\n\n'
|
||||
)
|
||||
case "AArch64AddressingModes.h":
|
||||
return b"#include <assert.h>\n" + b'#include "../../MathExtras.h"\n\n'
|
||||
log.fatal(f"No includes given for AArch64 source file: {filename}")
|
||||
exit(1)
|
||||
|
||||
|
||||
def get_LoongArch_includes(filename: str) -> bytes:
|
||||
match filename:
|
||||
case "LoongArchDisassembler.cpp":
|
||||
return (
|
||||
b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MathExtras.h"\n'
|
||||
+ b'#include "../../MCInstPrinter.h"\n'
|
||||
+ b'#include "../../MCDisassembler.h"\n'
|
||||
+ b'#include "../../MCFixedLenDisassembler.h"\n'
|
||||
+ b'#include "../../cs_priv.h"\n'
|
||||
+ b'#include "../../utils.h"\n'
|
||||
+ b'#include "LoongArchDisassemblerExtension.h"\n'
|
||||
+ b"#define GET_SUBTARGETINFO_ENUM\n"
|
||||
+ b'#include "LoongArchGenSubtargetInfo.inc"\n\n'
|
||||
+ b"#define GET_INSTRINFO_ENUM\n"
|
||||
+ b'#include "LoongArchGenInstrInfo.inc"\n\n'
|
||||
+ b"#define GET_REGINFO_ENUM\n"
|
||||
+ b'#include "LoongArchGenRegisterInfo.inc"\n\n'
|
||||
)
|
||||
case "LoongArchInstPrinter.cpp":
|
||||
return (
|
||||
b'#include "LoongArchMapping.h"\n'
|
||||
+ b'#include "LoongArchInstPrinter.h"\n\n'
|
||||
+ b"#define GET_SUBTARGETINFO_ENUM\n"
|
||||
+ b'#include "LoongArchGenSubtargetInfo.inc"\n\n'
|
||||
+ b"#define GET_INSTRINFO_ENUM\n"
|
||||
+ b'#include "LoongArchGenInstrInfo.inc"\n\n'
|
||||
+ b"#define GET_REGINFO_ENUM\n"
|
||||
+ b'#include "LoongArchGenRegisterInfo.inc"\n\n'
|
||||
)
|
||||
case "LoongArchInstPrinter.h":
|
||||
return (
|
||||
b'#include "../../MCInstPrinter.h"\n' + b'#include "../../cs_priv.h"\n'
|
||||
)
|
||||
log.fatal(f"No includes given for LoongArch source file: {filename}")
|
||||
exit(1)
|
||||
|
||||
|
||||
def get_Mips_includes(filename: str) -> bytes:
|
||||
match filename:
|
||||
case "MipsDisassembler.cpp":
|
||||
return (
|
||||
b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MathExtras.h"\n'
|
||||
+ b'#include "../../MCInstPrinter.h"\n'
|
||||
+ b'#include "../../MCDisassembler.h"\n'
|
||||
+ b'#include "../../MCFixedLenDisassembler.h"\n'
|
||||
+ b'#include "../../cs_priv.h"\n'
|
||||
+ b'#include "../../utils.h"\n'
|
||||
+ b"#define GET_SUBTARGETINFO_ENUM\n"
|
||||
+ b'#include "MipsGenSubtargetInfo.inc"\n\n'
|
||||
+ b"#define GET_INSTRINFO_ENUM\n"
|
||||
+ b'#include "MipsGenInstrInfo.inc"\n\n'
|
||||
+ b"#define GET_REGINFO_ENUM\n"
|
||||
+ b'#include "MipsGenRegisterInfo.inc"\n\n'
|
||||
)
|
||||
case "MipsInstPrinter.cpp":
|
||||
return (
|
||||
b'#include "MipsMapping.h"\n'
|
||||
+ b'#include "MipsInstPrinter.h"\n\n'
|
||||
+ b"#define GET_SUBTARGETINFO_ENUM\n"
|
||||
+ b'#include "MipsGenSubtargetInfo.inc"\n\n'
|
||||
+ b"#define GET_INSTRINFO_ENUM\n"
|
||||
+ b'#include "MipsGenInstrInfo.inc"\n\n'
|
||||
+ b"#define GET_REGINFO_ENUM\n"
|
||||
+ b'#include "MipsGenRegisterInfo.inc"\n\n'
|
||||
)
|
||||
case "MipsInstPrinter.h":
|
||||
return (
|
||||
b'#include "../../MCInstPrinter.h"\n' + b'#include "../../cs_priv.h"\n'
|
||||
)
|
||||
log.fatal(f"No includes given for Mips source file: {filename}")
|
||||
exit(1)
|
||||
|
||||
|
||||
def get_SystemZ_includes(filename: str) -> bytes:
|
||||
match filename:
|
||||
case "SystemZDisassembler.cpp":
|
||||
return (
|
||||
b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MathExtras.h"\n'
|
||||
+ b'#include "../../cs_priv.h"\n'
|
||||
+ b'#include "../../utils.h"\n\n'
|
||||
+ b'#include "SystemZMCTargetDesc.h"\n'
|
||||
+ b'#include "SystemZDisassemblerExtension.h"\n\n'
|
||||
+ b"#define GET_SUBTARGETINFO_ENUM\n"
|
||||
+ b'#include "SystemZGenSubtargetInfo.inc"\n\n'
|
||||
+ b"#define GET_INSTRINFO_ENUM\n"
|
||||
+ b'#include "SystemZGenInstrInfo.inc"\n\n'
|
||||
+ b"#define GET_REGINFO_ENUM\n"
|
||||
+ b'#include "SystemZGenRegisterInfo.inc"\n\n'
|
||||
)
|
||||
case "SystemZInstPrinter.cpp":
|
||||
return (
|
||||
b'#include "../../MCAsmInfo.h"\n'
|
||||
+ b'#include "SystemZMapping.h"\n'
|
||||
+ b'#include "SystemZInstPrinter.h"\n\n'
|
||||
+ b"#define GET_SUBTARGETINFO_ENUM\n"
|
||||
+ b'#include "SystemZGenSubtargetInfo.inc"\n\n'
|
||||
+ b"#define GET_INSTRINFO_ENUM\n"
|
||||
+ b'#include "SystemZGenInstrInfo.inc"\n\n'
|
||||
+ b"#define GET_REGINFO_ENUM\n"
|
||||
+ b'#include "SystemZGenRegisterInfo.inc"\n\n'
|
||||
)
|
||||
case "SystemZInstPrinter.h":
|
||||
return b"\n"
|
||||
case "SystemZMCTargetDesc.h":
|
||||
return (
|
||||
b'#include "../../MCInstPrinter.h"\n' + b'#include "../../cs_priv.h"\n'
|
||||
)
|
||||
case "SystemZMCTargetDesc.cpp":
|
||||
return (
|
||||
b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n\n'
|
||||
+ b'#include "SystemZMCTargetDesc.h"\n'
|
||||
+ b'#include "SystemZInstPrinter.h"\n\n'
|
||||
+ b"#define GET_INSTRINFO_MC_DESC\n"
|
||||
+ b"#define ENABLE_INSTR_PREDICATE_VERIFIER\n"
|
||||
+ b'#include "SystemZGenInstrInfo.inc"\n\n'
|
||||
+ b"#define GET_SUBTARGETINFO_MC_DESC\n"
|
||||
+ b'#include "SystemZGenSubtargetInfo.inc"\n\n'
|
||||
+ b"#define GET_REGINFO_MC_DESC\n"
|
||||
+ b'#include "SystemZGenRegisterInfo.inc"\n\n'
|
||||
)
|
||||
log.fatal(f"No includes given for SystemZ source file: {filename}")
|
||||
exit(1)
|
||||
|
||||
|
||||
def get_Xtensa_includes(filename: str) -> bytes:
|
||||
match filename:
|
||||
case "XtensaDisassembler.cpp":
|
||||
return b"""
|
||||
#include "../../MathExtras.h"
|
||||
#include "../../MCDisassembler.h"
|
||||
#include "../../MCFixedLenDisassembler.h"
|
||||
#include "../../SStream.h"
|
||||
#include "../../cs_priv.h"
|
||||
#include "priv.h"
|
||||
|
||||
#define GET_INSTRINFO_MC_DESC
|
||||
#include "XtensaGenInstrInfo.inc"
|
||||
|
||||
"""
|
||||
case "XtensaInstPrinter.cpp":
|
||||
return b"""
|
||||
#include "../../MCInstPrinter.h"
|
||||
#include "../../SStream.h"
|
||||
#include "XtensaMapping.h"
|
||||
#include "priv.h"
|
||||
"""
|
||||
case _:
|
||||
return b""
|
||||
|
||||
|
||||
def get_ARC_includes(filename: str) -> bytes:
|
||||
match filename:
|
||||
case "ARCDisassembler.cpp":
|
||||
return (
|
||||
b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../SStream.h"\n'
|
||||
+ b'#include "../../MCDisassembler.h"\n'
|
||||
+ b'#include "../../MCFixedLenDisassembler.h"\n'
|
||||
+ b'#include "../../MathExtras.h"\n'
|
||||
+ b'#include "../../utils.h"\n'
|
||||
)
|
||||
case "ARCInstPrinter.cpp":
|
||||
return (
|
||||
b'#include "../../SStream.h"\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCInstPrinter.h"\n'
|
||||
+ b'#include "ARCInfo.h"\n'
|
||||
+ b'#include "ARCInstPrinter.h"\n'
|
||||
+ b'#include "ARCLinkage.h"\n'
|
||||
+ b'#include "ARCMapping.h"\n'
|
||||
)
|
||||
case "ARCInstPrinter.h":
|
||||
return b'#include "../../SStream.h"\n' + b'#include "../../MCInst.h"\n'
|
||||
log.fatal(f"No includes given for ARC source file: {filename}")
|
||||
exit(1)
|
||||
|
||||
|
||||
def get_sparc_includes(filename: str) -> bytes:
|
||||
match filename:
|
||||
case "SparcDisassembler.cpp":
|
||||
return (
|
||||
b'#include "../../MCDisassembler.h"\n'
|
||||
+ b'#include "../../MCFixedLenDisassembler.h"\n'
|
||||
+ b'#include "SparcDisassemblerExtension.h"\n'
|
||||
+ b'#include "SparcLinkage.h"\n'
|
||||
+ b'#include "SparcMapping.h"\n'
|
||||
+ b'#include "SparcMCTargetDesc.h"\n'
|
||||
)
|
||||
case "SparcInstPrinter.cpp":
|
||||
return (
|
||||
b'#include "SparcInstrInfo.h"\n'
|
||||
+ b'#include "SparcInstPrinter.h"\n'
|
||||
+ b'#include "SparcLinkage.h"\n'
|
||||
+ b'#include "SparcMCTargetDesc.h"\n'
|
||||
+ b'#include "SparcMapping.h"\n'
|
||||
+ b'#include "SparcRegisterInfo.h"\n\n'
|
||||
)
|
||||
case "SparcInstPrinter.h":
|
||||
return b'#include "SparcMCTargetDesc.h"\n\n'
|
||||
case "SparcMCTargetDesc.h":
|
||||
return (
|
||||
b'#include "../../LEB128.h"\n'
|
||||
+ b'#include "../../MathExtras.h"\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCInstrDesc.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
)
|
||||
log.fatal(f"No includes given for Sparc source file: {filename}")
|
||||
exit(1)
|
||||
|
||||
|
||||
def get_general_macros():
|
||||
return (
|
||||
b"#define CONCAT(a, b) CONCAT_(a, b)\n" b"#define CONCAT_(a, b) a ## _ ## b\n"
|
||||
)
|
||||
Vendored
+37
@@ -0,0 +1,37 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class InlineToStaticInline(Patch):
|
||||
"""
|
||||
Removes the qualified identifier of the class from method definitions.
|
||||
Translating them to functions.
|
||||
|
||||
Patch inline void FUNCTION(...) {...}
|
||||
to static inline void FUNCTION(...) {...}
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(function_definition"
|
||||
' ((storage_class_specifier) @scs (#eq? @scs "inline"))'
|
||||
" (_)+"
|
||||
") @inline_def"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "inline_def"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
inline_def = captures[0][0]
|
||||
inline_def = get_text(src, inline_def.start_byte, inline_def.end_byte)
|
||||
return b"static " + inline_def
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class IsOptionalDef(Patch):
|
||||
"""
|
||||
Patch OpInfo[i].isOptionalDef()
|
||||
to MCOperandInfo_isOptionalDef(&OpInfo[i])
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression"
|
||||
" (field_expression"
|
||||
" (subscript_expression"
|
||||
" ((identifier) @op_info_var)"
|
||||
" ((_) @index)"
|
||||
" )"
|
||||
' ((field_identifier) @fid (#eq? @fid "isOptionalDef"))'
|
||||
" )"
|
||||
") @is_optional_def"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "is_optional_def"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
op_info_var = captures[1][0]
|
||||
index = captures[2][0]
|
||||
op_info_var = get_text(src, op_info_var.start_byte, op_info_var.end_byte)
|
||||
index = get_text(src, index.start_byte, index.end_byte)
|
||||
return b"MCOperandInfo_isOptionalDef(&" + op_info_var + index + b")"
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class IsPredicate(Patch):
|
||||
"""
|
||||
Patch OpInfo[i].isPredicate()
|
||||
to MCOperandInfo_isPredicate(&OpInfo[i])
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression"
|
||||
" (field_expression"
|
||||
" (subscript_expression"
|
||||
" ((identifier) @op_info_var)"
|
||||
" ((_) @index)"
|
||||
" )"
|
||||
' ((field_identifier) @fid (#eq? @fid "isPredicate"))'
|
||||
" )"
|
||||
") @is_predicate"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "is_predicate"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
op_info_var = captures[1][0]
|
||||
index = captures[2][0]
|
||||
op_info_var = get_text(src, op_info_var.start_byte, op_info_var.end_byte)
|
||||
index = get_text(src, index.start_byte, index.end_byte)
|
||||
return b"MCOperandInfo_isPredicate(&" + op_info_var + index + b")"
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class IsOperandRegImm(Patch):
|
||||
"""
|
||||
Patch OPERAND.isReg()
|
||||
to MCOperand_isReg(OPERAND)
|
||||
|
||||
Same for isImm() | isExpr()
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(call_expression"
|
||||
" (field_expression"
|
||||
" ((_) @operand)"
|
||||
' ((field_identifier) @field_id (#match? @field_id "is(Reg|Imm|Expr)"))'
|
||||
" )"
|
||||
" (argument_list)"
|
||||
") @is_operand"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "is_operand"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# The operand
|
||||
operand: Node = captures[1][0]
|
||||
# 'isReg()/isImm()/isExpr'
|
||||
get_reg_imm = captures[2][0]
|
||||
|
||||
fcn = get_text(src, get_reg_imm.start_byte, get_reg_imm.end_byte)
|
||||
op = get_text(src, operand.start_byte, operand.end_byte)
|
||||
return b"MCOperand_" + fcn + b"(" + op + b")"
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class LLVMFallThrough(Patch):
|
||||
"""
|
||||
Patch Remove LLVM_FALLTHROUGH
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(expression_statement"
|
||||
' ((identifier) @id (#eq? @id "LLVM_FALLTHROUGH"))'
|
||||
") @llvm_fall_through"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "llvm_fall_through"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
return b""
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# Copyright © 2024 Billow <billow.fun@gmail.com>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class LLVM_DEBUG(Patch):
|
||||
"""
|
||||
Patch LLVM_DEBUG(dbgs() << "Error msg")
|
||||
to ""
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return """
|
||||
(call_expression (
|
||||
(identifier) @fcn_name (#eq? @fcn_name "LLVM_DEBUG")
|
||||
(argument_list (
|
||||
(binary_expression (
|
||||
(call_expression)
|
||||
(string_literal) @err_msg
|
||||
))
|
||||
))
|
||||
)) @llvm_debug"""
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "llvm_debug"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
return b""
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class LLVMUnreachable(Patch):
|
||||
"""
|
||||
Patch llvm_unreachable("Error msg")
|
||||
to assert(0 && "Error msg")
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression ("
|
||||
' (identifier) @fcn_name (#eq? @fcn_name "llvm_unreachable")'
|
||||
" (argument_list) @err_msg"
|
||||
")) @llvm_unreachable"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "llvm_unreachable"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
err_msg = captures[2][0]
|
||||
err_msg = get_text(src, err_msg.start_byte, err_msg.end_byte).strip(b"()")
|
||||
res = b"CS_ASSERT(0 && " + err_msg + b")"
|
||||
return res
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class MethodToFunction(Patch):
|
||||
"""
|
||||
Removes the qualified identifier of the class from method definitions.
|
||||
Translating them to functions.
|
||||
|
||||
Patch void CLASS::METHOD_NAME(...) {...}
|
||||
to void METHOD_NAME(...) {...}
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(function_declarator"
|
||||
" (qualified_identifier"
|
||||
" (namespace_identifier)"
|
||||
" (identifier) @method_name"
|
||||
" )"
|
||||
" (parameter_list) @param_list"
|
||||
") @method_def"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "method_def"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
name = captures[1][0]
|
||||
parameter_list = captures[2][0]
|
||||
name = get_text(src, name.start_byte, name.end_byte)
|
||||
parameter_list = get_text(
|
||||
src, parameter_list.start_byte, parameter_list.end_byte
|
||||
)
|
||||
res = name + parameter_list
|
||||
return res
|
||||
Vendored
+40
@@ -0,0 +1,40 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class MethodTypeQualifier(Patch):
|
||||
"""
|
||||
Patch Removes type qualifiers like "const" etc. from methods.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(function_declarator"
|
||||
" (["
|
||||
" (qualified_identifier)"
|
||||
" (identifier)"
|
||||
" ]) @id"
|
||||
" (parameter_list) @param_list"
|
||||
" (type_qualifier)"
|
||||
")"
|
||||
"@method_type_qualifier"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "method_type_qualifier"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
identifier = captures[1][0]
|
||||
parameter_list = captures[2][0]
|
||||
identifier = get_text(src, identifier.start_byte, identifier.end_byte)
|
||||
p_list = get_text(src, parameter_list.start_byte, parameter_list.end_byte)
|
||||
res = identifier + p_list
|
||||
return res
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class NamespaceAnon(Patch):
|
||||
"""
|
||||
Patch namespace {CONTENT}
|
||||
to CONTENT
|
||||
|
||||
Only for anonymous or llvm namespaces
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(namespace_definition"
|
||||
" (declaration_list) @decl_list"
|
||||
") @namespace_def"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "namespace_def"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
decl_list = captures[1][0]
|
||||
dl = get_text(src, decl_list.start_byte, decl_list.end_byte).strip(b"{}")
|
||||
return dl
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import (
|
||||
get_text,
|
||||
namespace_enum,
|
||||
namespace_fcn_def,
|
||||
namespace_struct,
|
||||
)
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class NamespaceArch(Patch):
|
||||
"""
|
||||
Patch namespace ArchSpecificNamespace {CONTENT}
|
||||
to CONTENT
|
||||
|
||||
Patches namespaces specific to architecture. This needs to patch enums and functions within this namespace.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(namespace_definition"
|
||||
" (namespace_identifier)"
|
||||
" (declaration_list) @decl_list"
|
||||
") @namespace_def"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "namespace_def"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
namespace = captures[0][0]
|
||||
decl_list = captures[1][0]
|
||||
namespace_id = get_text(
|
||||
src,
|
||||
namespace.named_children[0].start_byte,
|
||||
namespace.named_children[0].end_byte,
|
||||
)
|
||||
|
||||
# We need to prepend the namespace id to all enum members, function declarators and struct types.
|
||||
# Because in the generated files they are accessed via NAMESPACE::X which becomes NAMESPACE_X.
|
||||
res = b""
|
||||
for d in decl_list.named_children:
|
||||
match d.type:
|
||||
case "enum_specifier":
|
||||
res += namespace_enum(src, namespace_id, d) + b";\n\n"
|
||||
case "declaration" | "function_definition":
|
||||
res += namespace_fcn_def(src, namespace_id, d) + b"\n\n"
|
||||
case "struct_specifier":
|
||||
res += namespace_struct(src, namespace_id, d) + b";\n\n"
|
||||
case _:
|
||||
res += get_text(src, d.start_byte, d.end_byte) + b"\n"
|
||||
return (
|
||||
b"// CS namespace begin: "
|
||||
+ namespace_id
|
||||
+ b"\n\n"
|
||||
+ res
|
||||
+ b"// CS namespace end: "
|
||||
+ namespace_id
|
||||
+ b"\n\n"
|
||||
)
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class NamespaceLLVM(Patch):
|
||||
"""
|
||||
Patch namespace llvm {CONTENT}
|
||||
to CONTENT
|
||||
|
||||
Only for anonymous or llvm namespaces
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(namespace_definition"
|
||||
' (namespace_identifier) @id (#eq? @id "llvm")'
|
||||
" (declaration_list) @decl_list"
|
||||
") @namespace_def"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "namespace_def"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
decl_list = captures[2][0]
|
||||
dl = get_text(src, decl_list.start_byte, decl_list.end_byte).strip(b"{}")
|
||||
return dl
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class OutStreamParam(Patch):
|
||||
"""
|
||||
Patches the parameter list only:
|
||||
|
||||
Patch void function(int a, raw_ostream &OS)
|
||||
to void function(int a, SStream *OS)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(parameter_list"
|
||||
" (_)*"
|
||||
" (parameter_declaration"
|
||||
' ((type_identifier) @tid (#eq? @tid "raw_ostream"))'
|
||||
" (_)"
|
||||
" )"
|
||||
" (_)*"
|
||||
") @ostream_param"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "ostream_param"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
param_list = list()
|
||||
for param in captures[0][0].named_children:
|
||||
p_text = get_text(src, param.start_byte, param.end_byte)
|
||||
if b"raw_ostream" in p_text:
|
||||
p_text = p_text.replace(b"raw_ostream", b"SStream").replace(b"&", b"*")
|
||||
param_list.append(p_text)
|
||||
res = b"(" + b", ".join(param_list) + b")"
|
||||
return res
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class Override(Patch):
|
||||
"""
|
||||
Patch function(args) override
|
||||
to function(args)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(function_declarator "
|
||||
" ((field_identifier) @declarator)"
|
||||
" ((parameter_list) @parameter_list)"
|
||||
' ((virtual_specifier) @specifier (#eq? @specifier "override"))'
|
||||
") @override"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "override"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get function name
|
||||
declarator: Node = captures[1][0]
|
||||
# Get parameter list
|
||||
parameter_list: Node = captures[2][0]
|
||||
decl = get_text(src, declarator.start_byte, declarator.end_byte)
|
||||
params = get_text(src, parameter_list.start_byte, parameter_list.end_byte)
|
||||
return decl + params
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
|
||||
class Patch:
|
||||
priority: int = None
|
||||
|
||||
def __init__(self, priority: int = 0):
|
||||
self.priority = priority
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
"""
|
||||
Returns a search pattern for the syntax tree of the C++ file.
|
||||
The search pattern must be formed according to:
|
||||
https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries
|
||||
|
||||
Also, each pattern needs to be assigned a name in order to work.
|
||||
See: https://github.com/tree-sitter/py-tree-sitter/issues/77
|
||||
|
||||
:return: The search pattern which matches a part in the syntax tree which will be patched.
|
||||
"""
|
||||
log.fatal("Method must be overloaded.")
|
||||
exit(1)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
"""
|
||||
:return: The name of the capture which matches the complete syntax to be patched.
|
||||
"""
|
||||
log.fatal("Method must be overloaded.")
|
||||
exit(1)
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
"""
|
||||
Patches the given subtree accordingly and returns the patch as string.
|
||||
|
||||
:param src: The source code currently patched.
|
||||
:param captures: The subtree and its name which needs to be patched.
|
||||
:param **kwargs: Additional arguments the Patch might need.
|
||||
:return: The patched version of the code.
|
||||
"""
|
||||
log.fatal("Method must be overloaded.")
|
||||
exit(1)
|
||||
Vendored
+48
@@ -0,0 +1,48 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_MCInst_var_name, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class PredicateBlockFunctions(Patch):
|
||||
"""
|
||||
Patch VPTBlock.instrInVPTBlock()
|
||||
to VPTBlock_instrInVPTBlock(&(MI->csh->VPTBlock))
|
||||
|
||||
And other functions of VPTBlock and ITBlock
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression "
|
||||
" (field_expression"
|
||||
' ((identifier) @block_var (#match? @block_var "[VI][PT]T?Block"))'
|
||||
" ((field_identifier) @field_id)"
|
||||
" )"
|
||||
" ((argument_list) @arg_list)"
|
||||
") @block_fcns"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "block_fcns"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
block_var = captures[1][0]
|
||||
fcn_id = captures[2][0]
|
||||
args = captures[3][0]
|
||||
block_var_text = get_text(src, block_var.start_byte, block_var.end_byte)
|
||||
fcn_id_text = get_text(src, fcn_id.start_byte, fcn_id.end_byte)
|
||||
args_text = get_text(src, args.start_byte, args.end_byte)
|
||||
mcinst_var: bytes = get_MCInst_var_name(src, block_var)
|
||||
|
||||
a = b"&(" + mcinst_var + b"->csh->" + block_var_text + b")"
|
||||
args_text = args_text.strip(b"()")
|
||||
if args_text:
|
||||
a += b"," + args_text
|
||||
return block_var_text + b"_" + fcn_id_text + b"(" + a + b")"
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class PrintAnnotation(Patch):
|
||||
"""
|
||||
Removes printAnnotation(...) calls.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression ("
|
||||
' (identifier) @fcn_name (#eq? @fcn_name "printAnnotation")'
|
||||
" (argument_list)"
|
||||
")) @print_annotation"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "print_annotation"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
return b""
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_MCInst_var_name, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class PrintRegImmShift(Patch):
|
||||
"""
|
||||
Patch printRegImmShift(...)
|
||||
to printRegImmShift(MI, ...)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
self.apply_only_to = {"files": ["ARMInstPrinter.cpp"], "archs": list()}
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression ("
|
||||
' (identifier) @fcn_name (#eq? @fcn_name "printRegImmShift")'
|
||||
" ((argument_list) @arg_list)"
|
||||
")) @print_call"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "print_call"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
call: Node = captures[0][0]
|
||||
mcinst_var = get_MCInst_var_name(src, call)
|
||||
params = captures[2][0]
|
||||
params = get_text(src, params.start_byte, params.end_byte)
|
||||
return b"printRegImmShift(" + mcinst_var + b", " + params.strip(b"(")
|
||||
Vendored
+40
@@ -0,0 +1,40 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class QualifiedIdentifier(Patch):
|
||||
"""
|
||||
Patch NAMESPACE::ID
|
||||
to NAMESPACE_ID
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return "(qualified_identifier) @qualified_id"
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "qualified_id"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
if len(captures[0][0].named_children) > 1:
|
||||
identifier = captures[0][0].named_children[1]
|
||||
identifier = get_text(src, identifier.start_byte, identifier.end_byte)
|
||||
namespace = captures[0][0].named_children[0]
|
||||
namespace = get_text(src, namespace.start_byte, namespace.end_byte)
|
||||
else:
|
||||
# The namespace can be omitted. E.g. std::transform(..., ::tolower)
|
||||
namespace = b""
|
||||
identifier = captures[0][0].named_children[0]
|
||||
identifier = get_text(src, identifier.start_byte, identifier.end_byte)
|
||||
match (namespace, identifier):
|
||||
case (b"std", b"size"):
|
||||
return b"sizeof"
|
||||
case _:
|
||||
return namespace + b"_" + identifier
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import re
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class ReferencesDecl(Patch):
|
||||
"""
|
||||
Patch TYPE &Param
|
||||
to TYPE *Param
|
||||
|
||||
Param is optional
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"["
|
||||
"(reference_declarator)"
|
||||
"(type_identifier) (abstract_reference_declarator)"
|
||||
"] @reference_decl"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "reference_decl"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
ref_decl: Node = captures[0][0]
|
||||
ref_decl_text = get_text(src, ref_decl.start_byte, ref_decl.end_byte)
|
||||
|
||||
res = re.sub(rb"&", b"*", ref_decl_text)
|
||||
return res
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_capture_node, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class RegClassContains(Patch):
|
||||
"""
|
||||
Patch ...getRegClass(...).contains(Reg)
|
||||
to MCRegisterClass_contains(...getRegClass(...), Reg)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(call_expression"
|
||||
" (field_expression"
|
||||
' ((_) @reg_class (#match? @reg_class ".+getRegClass.+"))'
|
||||
' ((field_identifier) @field_id (#eq? @field_id "contains"))'
|
||||
" )"
|
||||
" ((argument_list) @arg_list)"
|
||||
") @reg_class_contains"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "reg_class_contains"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
reg_class_getter: Node = get_capture_node(captures, "reg_class")
|
||||
arg_list: Node = get_capture_node(captures, "arg_list")
|
||||
args = get_text(src, arg_list.start_byte, arg_list.end_byte).strip(b"()")
|
||||
reg_class = get_text(
|
||||
src, reg_class_getter.start_byte, reg_class_getter.end_byte
|
||||
)
|
||||
res = b"MCRegisterClass_contains(" + reg_class + b", " + args + b")"
|
||||
return res
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class STIArgument(Patch):
|
||||
"""
|
||||
Patch printSomeOperand(MI, NUM, STI, NUM)
|
||||
to printSomeOperand(MI, NUM, NUM)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return '(argument_list (_) (_) (_)? ((identifier) @id (#eq? @id "STI")) (_)) @sti_arg'
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "sti_arg"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
param_list = list()
|
||||
for param in captures[0][0].named_children:
|
||||
p_text = get_text(src, param.start_byte, param.end_byte)
|
||||
if b"STI" in p_text:
|
||||
continue
|
||||
param_list.append(p_text)
|
||||
res = b"(" + b", ".join(param_list) + b")"
|
||||
return res
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class STIFeatureBits(Patch):
|
||||
"""
|
||||
Patch STI.getFeatureBits()[ARCH::FLAG]
|
||||
to ARCH_getFeatureBits(Inst->csh->mode, ARCH::FLAG)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int, arch: bytes):
|
||||
self.arch = arch
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
# Search for featureBits usage.
|
||||
return (
|
||||
"(subscript_expression "
|
||||
" (call_expression"
|
||||
" (field_expression"
|
||||
" (identifier)"
|
||||
' ((field_identifier) @fid (#eq? @fid "getFeatureBits"))'
|
||||
" )"
|
||||
" (argument_list)"
|
||||
" )"
|
||||
" (subscript_argument_list ((qualified_identifier) @flag))"
|
||||
") @sti_feature_bits"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "sti_feature_bits"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get flag name of feature bit.
|
||||
qualified_id: Node = captures[2][0]
|
||||
flag = get_text(src, qualified_id.start_byte, qualified_id.end_byte)
|
||||
return self.arch + b"_getFeatureBits(Inst->csh->mode, " + flag + b")"
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class SubtargetInfoParam(Patch):
|
||||
"""
|
||||
Patch Removes MCSubtargetInfo &STI parameter
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(parameter_list"
|
||||
" (_)*"
|
||||
" (parameter_declaration"
|
||||
' ((type_identifier) @tid (#eq? @tid "MCSubtargetInfo"))'
|
||||
" (_)"
|
||||
" )"
|
||||
" (_)*"
|
||||
") @subtarget_info_param"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "subtarget_info_param"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
param_list = list()
|
||||
for param in captures[0][0].named_children:
|
||||
p_text = get_text(src, param.start_byte, param.end_byte)
|
||||
if b"MCSubtargetInfo" in p_text:
|
||||
continue
|
||||
param_list.append(p_text)
|
||||
res = b"(" + b", ".join(param_list) + b")"
|
||||
return res
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class SetOpcode(Patch):
|
||||
"""
|
||||
Patch Inst.setOpcode(...)
|
||||
to MCInst_setOpcode(Inst, ...)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression"
|
||||
" (field_expression ("
|
||||
" ((identifier) @inst_var)"
|
||||
' ((field_identifier) @field_id (#eq? @field_id "setOpcode")))'
|
||||
" )"
|
||||
" (argument_list) @arg_list"
|
||||
") @set_opcode"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "set_opcode"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Instruction variable
|
||||
inst_var: Node = captures[1][0]
|
||||
arg_list: Node = captures[3][0]
|
||||
|
||||
inst = get_text(src, inst_var.start_byte, inst_var.end_byte)
|
||||
args = get_text(src, arg_list.start_byte, arg_list.end_byte)
|
||||
if args != b"()":
|
||||
args = b", " + args
|
||||
else:
|
||||
args = b""
|
||||
return b"MCInst_setOpcode(" + inst + args + b")"
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
from autosync.cpptranslator.TemplateCollector import TemplateCollector
|
||||
|
||||
|
||||
class SignExtend(Patch):
|
||||
"""
|
||||
Patch SignExtend32<A>(...)
|
||||
to SignExtend32(..., A)
|
||||
|
||||
Same for SignExtend64
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression"
|
||||
" (template_function"
|
||||
' ((identifier) @name (#match? @name "SignExtend(32|64)"))'
|
||||
" ((template_argument_list) @templ_args)"
|
||||
" )"
|
||||
" ((argument_list) @fcn_args)"
|
||||
") @sign_extend"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "sign_extend"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
sign_extend: Node = captures[1][0]
|
||||
templ_args: Node = captures[2][0]
|
||||
fcn_args: Node = captures[3][0]
|
||||
|
||||
name = get_text(src, sign_extend.start_byte, sign_extend.end_byte)
|
||||
t_args = get_text(src, templ_args.start_byte, templ_args.end_byte)
|
||||
t_args = b", ".join(TemplateCollector.templ_params_to_list(t_args))
|
||||
f_args = get_text(src, fcn_args.start_byte, fcn_args.end_byte)
|
||||
return name + b"(" + f_args + b", " + t_args + b")"
|
||||
@@ -0,0 +1,35 @@
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class Size(Patch):
|
||||
"""
|
||||
Patch Bytes.size()
|
||||
to BytesLen
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(call_expression "
|
||||
" (field_expression"
|
||||
" ((identifier) @inst_var)"
|
||||
' ((field_identifier) @field_id_op (#eq? @field_id_op "size"))'
|
||||
" )"
|
||||
" ((argument_list) @arg_list)"
|
||||
") @size"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "size"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get operand variable name (Bytes, ArrayRef)
|
||||
op_var: Node = captures[1][0]
|
||||
op = get_text(src, op_var.start_byte, op_var.end_byte)
|
||||
return op + b"Len"
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import re
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_function_params_of_node, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class SizeAssignment(Patch):
|
||||
"""
|
||||
Patch Size = <num>
|
||||
to *Size = <num>
|
||||
|
||||
if Size is a reference.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(assignment_expression"
|
||||
' ((identifier) @id (#eq? @id "Size"))'
|
||||
") @assign"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "assign"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
assign = captures[0][0]
|
||||
assign_text = get_text(src, assign.start_byte, assign.end_byte)
|
||||
|
||||
param_list = get_function_params_of_node(assign)
|
||||
if not param_list:
|
||||
return assign_text
|
||||
|
||||
for p in param_list.named_children:
|
||||
p_text = get_text(src, p.start_byte, p.end_byte)
|
||||
if b"&Size" in p_text:
|
||||
return re.sub(b"Size", b"*Size", assign_text)
|
||||
|
||||
return assign_text
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text, get_text_from_node
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class StreamOperations(Patch):
|
||||
"""
|
||||
Patch OS << ...
|
||||
to SStream_concat(OS, ...)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(expression_statement"
|
||||
" (binary_expression"
|
||||
" ((binary_expression)"
|
||||
' "<<"'
|
||||
" (_))*"
|
||||
" ) @bin_expr"
|
||||
") @stream"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "stream"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
bin_expr = captures[1][0]
|
||||
# Extract operands passed to the stream into a list.
|
||||
ops = list()
|
||||
while bin_expr.type == "binary_expression":
|
||||
ops.append(bin_expr.named_children[1])
|
||||
bin_expr = bin_expr.named_children[0]
|
||||
s_name = get_text(src, bin_expr.start_byte, bin_expr.end_byte)
|
||||
# We added the operands from right to left.
|
||||
# We reversing it so the left most operand comes first.
|
||||
ops.reverse()
|
||||
|
||||
res = b""
|
||||
# Capstone uses the following functions to copy the strings to a buffer:
|
||||
# SStream_concat - Copies multiple strings.
|
||||
# SStream_concat1 - Copies a char.
|
||||
# SStream_concat0 - Copies a string and null terminates the buffer.
|
||||
last_op: Node = ops[-1]
|
||||
op: Node = ops[0]
|
||||
string_ops = list()
|
||||
i = 0
|
||||
while op != last_op:
|
||||
if op.type == "char_literal":
|
||||
if len(string_ops) != 0:
|
||||
# Make a SStream_concat call with all string literals collected before.
|
||||
res += (
|
||||
b"SStream_concat("
|
||||
+ s_name
|
||||
+ b', "'
|
||||
+ b"%s" * len(string_ops)
|
||||
+ b'", '
|
||||
+ b", ".join(
|
||||
[
|
||||
get_text(src, o.start_byte, o.end_byte)
|
||||
for o in string_ops
|
||||
]
|
||||
)
|
||||
+ b");\n"
|
||||
)
|
||||
string_ops.clear()
|
||||
res += (
|
||||
b"SStream_concat1("
|
||||
+ s_name
|
||||
+ b", "
|
||||
+ get_text(src, op.start_byte, op.end_byte)
|
||||
+ b");\n"
|
||||
)
|
||||
else:
|
||||
string_ops.append(op)
|
||||
i += 1
|
||||
op = ops[i]
|
||||
|
||||
if len(string_ops) != 0:
|
||||
res += (
|
||||
b"SStream_concat("
|
||||
+ s_name
|
||||
+ b', "'
|
||||
+ b"%s" * len(string_ops)
|
||||
+ b'", '
|
||||
+ b", ".join(
|
||||
[get_text(src, o.start_byte, o.end_byte) for o in string_ops]
|
||||
)
|
||||
+ b");\n"
|
||||
)
|
||||
string_ops.clear()
|
||||
|
||||
last_op_text = get_text(src, last_op.start_byte, last_op.end_byte)
|
||||
if last_op.type == "char_literal":
|
||||
res += (
|
||||
b"SStream_concat0("
|
||||
+ s_name
|
||||
+ b", "
|
||||
+ last_op_text.replace(b"'", b'"')
|
||||
+ b");\n"
|
||||
)
|
||||
elif last_op.type == "identifier":
|
||||
queue_str = f"""
|
||||
(declaration (
|
||||
(primitive_type) @typ
|
||||
(init_declarator
|
||||
(identifier) @ident (#eq? @ident "{last_op_text.decode("utf8")}")
|
||||
)
|
||||
)) @decl
|
||||
"""
|
||||
query = kwargs["ts_cpp_lang"].query(queue_str)
|
||||
root_node = kwargs["tree"].root_node
|
||||
query_result = list(
|
||||
filter(
|
||||
lambda x: "typ" in x[1],
|
||||
query.matches(root_node),
|
||||
)
|
||||
)
|
||||
if len(query_result) == 0:
|
||||
res += b"SStream_concat0(" + s_name + b", " + last_op_text + b");"
|
||||
else:
|
||||
typ = get_text_from_node(src, query_result[0][1]["typ"][-1])
|
||||
match typ:
|
||||
case b"int":
|
||||
res += b"printInt32(" + s_name + b", " + last_op_text + b");"
|
||||
case b"int64_t":
|
||||
res += b"printInt64(" + s_name + b", " + last_op_text + b");"
|
||||
case _:
|
||||
res += (
|
||||
b"SStream_concat0(" + s_name + b", " + last_op_text + b");"
|
||||
)
|
||||
else:
|
||||
res += b"SStream_concat0(" + s_name + b", " + last_op_text + b");"
|
||||
stream = captures[0][0]
|
||||
if len(ops) > 1 and stream.parent.type in ["if_statement"]:
|
||||
# If statements without {} brackets might execute a single line `OS << ...;` statement.
|
||||
# Which we then translate into multiple lines. For this case we need to add the brackets.
|
||||
res = b"{ " + res + b" }"
|
||||
return res
|
||||
Vendored
+84
@@ -0,0 +1,84 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import parse_function_capture
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
from autosync.cpptranslator.TemplateCollector import (
|
||||
TemplateCollector,
|
||||
TemplateRefInstance,
|
||||
)
|
||||
|
||||
|
||||
class TemplateDeclaration(Patch):
|
||||
"""
|
||||
Patch template<A, B>
|
||||
RET_TYPE TemplateFunction(...);
|
||||
|
||||
to #define DECLARE_TemplateFunction_A_B \
|
||||
RET_TYPE CONCAT(TemplateFunction, CONCAT(A, B))(...);
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int, template_collector: TemplateCollector):
|
||||
self.collector: TemplateCollector = template_collector
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(template_declaration"
|
||||
" ((template_parameter_list) @templ_params)"
|
||||
" (declaration"
|
||||
" ((storage_class_specifier)* @storage_class_id)"
|
||||
" ([(type_identifier)(primitive_type)] @type_id)"
|
||||
" (function_declarator"
|
||||
" ((identifier) @fcn_name)"
|
||||
" ((parameter_list) @fcn_params)"
|
||||
" )"
|
||||
" )"
|
||||
") @template_decl"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "template_decl"
|
||||
|
||||
def get_patch(
|
||||
self, captures: list[tuple[Node, str]], src: bytes, **kwargs
|
||||
) -> bytes:
|
||||
t_params, sc, tid, f_name, f_params, _ = parse_function_capture(captures, src)
|
||||
if f_name in self.collector.templates_with_arg_deduction:
|
||||
return sc + tid + b" " + f_name + f_params + b";"
|
||||
|
||||
declaration = (
|
||||
b"#define DECLARE_" + f_name + b"(" + b", ".join(t_params) + b")\n"
|
||||
)
|
||||
declaration += (
|
||||
sc
|
||||
+ b" "
|
||||
+ tid
|
||||
+ b" "
|
||||
+ TemplateCollector.get_macro_c_call(f_name, t_params, f_params)
|
||||
+ b";"
|
||||
)
|
||||
declaration = declaration.replace(b"\n", b" \\\n") + b"\n"
|
||||
|
||||
template_instance: TemplateRefInstance
|
||||
declared_implementations = list()
|
||||
if f_name not in self.collector.template_refs:
|
||||
self.collector.log_missing_ref_and_exit(f_name)
|
||||
|
||||
for template_instance in self.collector.template_refs[f_name]:
|
||||
d = (
|
||||
b"DECLARE_"
|
||||
+ f_name
|
||||
+ b"("
|
||||
+ b", ".join(template_instance.get_args_for_decl())
|
||||
+ b");\n"
|
||||
)
|
||||
if d in declared_implementations:
|
||||
continue
|
||||
declared_implementations.append(d)
|
||||
declaration += d
|
||||
return declaration
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
import re
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import parse_function_capture
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
from autosync.cpptranslator.TemplateCollector import (
|
||||
TemplateCollector,
|
||||
TemplateRefInstance,
|
||||
)
|
||||
|
||||
|
||||
class TemplateDefinition(Patch):
|
||||
"""
|
||||
Patch template<A, B>
|
||||
RET_TYPE TemplateFunction(...) {...}
|
||||
|
||||
to #define DEFINE_TemplateFunction_A_B \
|
||||
RET_TYPE CONCAT(TemplateFunction, CONCAT(A, B))(...) {...}
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int, template_collector: TemplateCollector):
|
||||
self.collector: TemplateCollector = template_collector
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(template_declaration"
|
||||
" ((template_parameter_list) @templ_params)"
|
||||
" (function_definition"
|
||||
" ((storage_class_specifier)* @storage_class_id)"
|
||||
" ([(type_identifier)(primitive_type)] @type_id)"
|
||||
" (function_declarator"
|
||||
" ((identifier) @fcn_name)"
|
||||
" ((parameter_list) @fcn_params)"
|
||||
" )"
|
||||
" ((compound_statement) @compound)"
|
||||
" )"
|
||||
") @template_def"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "template_def"
|
||||
|
||||
def get_patch(
|
||||
self, captures: list[tuple[Node, str]], src: bytes, **kwargs
|
||||
) -> bytes:
|
||||
t_params, sc, tid, f_name, f_params, f_compound = parse_function_capture(
|
||||
captures, src
|
||||
)
|
||||
if f_name in self.collector.templates_with_arg_deduction:
|
||||
return sc + tid + b" " + f_name + f_params + f_compound
|
||||
|
||||
definition = b"#define DEFINE_" + f_name + b"(" + b", ".join(t_params) + b")\n"
|
||||
definition += (
|
||||
sc
|
||||
+ b" "
|
||||
+ tid
|
||||
+ b" "
|
||||
+ TemplateCollector.get_macro_c_call(f_name, t_params, f_params)
|
||||
+ f_compound
|
||||
)
|
||||
# Remove // comments
|
||||
definition = re.sub(b" *//.*", b"", definition)
|
||||
definition = definition.replace(b"\n", b" \\\n") + b"\n"
|
||||
|
||||
template_instance: TemplateRefInstance
|
||||
declared_implementations = list()
|
||||
if f_name not in self.collector.template_refs:
|
||||
self.collector.log_missing_ref_and_exit(f_name)
|
||||
|
||||
for template_instance in self.collector.template_refs[f_name]:
|
||||
d = (
|
||||
b"DEFINE_"
|
||||
+ f_name
|
||||
+ b"("
|
||||
+ b", ".join(template_instance.get_args_for_decl())
|
||||
+ b");\n"
|
||||
)
|
||||
if d in declared_implementations:
|
||||
continue
|
||||
declared_implementations.append(d)
|
||||
definition += d
|
||||
return definition
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class TemplateParamDecl(Patch):
|
||||
"""
|
||||
Example:
|
||||
|
||||
Patch ArrayRef<uint8_t> x
|
||||
to const uint8_t *x, size_t xLen
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(parameter_declaration"
|
||||
" (template_type"
|
||||
" (type_identifier) @templ_type"
|
||||
" (template_argument_list) @arg_list"
|
||||
" )"
|
||||
" (identifier) @param_id"
|
||||
") @template_param_decl"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "template_param_decl"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
template_type = captures[1][0]
|
||||
arg_list = captures[2][0]
|
||||
param_id = captures[3][0]
|
||||
templ_type = get_text(src, template_type.start_byte, template_type.end_byte)
|
||||
args = get_text(src, arg_list.start_byte, arg_list.end_byte)
|
||||
p_id = get_text(src, param_id.start_byte, param_id.end_byte)
|
||||
|
||||
if templ_type == b"ArrayRef":
|
||||
res = (
|
||||
b"const "
|
||||
+ args.strip(b"<>")
|
||||
+ b" *"
|
||||
+ p_id
|
||||
+ b", size_t "
|
||||
+ p_id
|
||||
+ b"Len"
|
||||
)
|
||||
return res
|
||||
log.fatal(f"Template type {templ_type} not handled as parameter")
|
||||
exit(1)
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
from autosync.cpptranslator.TemplateCollector import TemplateCollector
|
||||
|
||||
|
||||
class TemplateRefs(Patch):
|
||||
"""
|
||||
Patch TemplateFunction<A, B>
|
||||
to CONCAT(TemplateFunction, CONCAT(A, B))
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(template_function"
|
||||
" ((identifier) @name)"
|
||||
" ((template_argument_list) @templ_args)"
|
||||
") @template_refs"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "template_refs"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
tc: Node = captures[1][0]
|
||||
templ_args: Node = captures[2][0]
|
||||
|
||||
name = get_text(src, tc.start_byte, tc.end_byte)
|
||||
t_params = get_text(src, templ_args.start_byte, templ_args.end_byte)
|
||||
if name == b"static_cast" or name == b"dyn_cast":
|
||||
return t_params.replace(b"<", b"(").replace(b">", b")")
|
||||
t_params_list = TemplateCollector.templ_params_to_list(t_params)
|
||||
res = TemplateCollector.get_macro_c_call(name, t_params_list)
|
||||
return res
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class UseMarkup(Patch):
|
||||
"""
|
||||
Patch UseMarkup
|
||||
to getUseMarkup()
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return '((identifier) @use_markup (#eq? @use_markup "UseMarkup"))'
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "use_markup"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
return b"getUseMarkup()"
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class UsingDeclaration(Patch):
|
||||
"""
|
||||
Patch Removes declarations with the keyword "using"
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return "([(using_declaration) (alias_declaration)]) @using_declaration"
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "using_declaration"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
return b""
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
from autosync.cpptranslator.TemplateCollector import TemplateCollector
|
||||
|
||||
|
||||
class IsUInt(Patch):
|
||||
"""
|
||||
Patch isUInt|isInt<N>(...)
|
||||
to isUInt|isInt(..., N)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression"
|
||||
" (template_function"
|
||||
' ((identifier) @id (#match? @id "isUInt|isInt"))'
|
||||
" ((template_argument_list) @templ_args)"
|
||||
" )"
|
||||
" ((argument_list) @arg_list)"
|
||||
") @is_u_int"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "is_u_int"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
identifier: Node = captures[1][0]
|
||||
templ_args: Node = captures[2][0]
|
||||
args_list: Node = captures[3][0]
|
||||
|
||||
name = get_text(src, identifier.start_byte, identifier.end_byte)
|
||||
targs = get_text(src, templ_args.start_byte, templ_args.end_byte).strip(b"<>")
|
||||
args = get_text(src, args_list.start_byte, args_list.end_byte).strip(b"()")
|
||||
|
||||
res = name + b"N(" + targs + b", " + args + b")"
|
||||
|
||||
return res
|
||||
+4544
File diff suppressed because it is too large
Load Diff
+20
@@ -0,0 +1,20 @@
|
||||
from tree_sitter import Node, Query
|
||||
|
||||
|
||||
# Queries for the given pattern and converts the query back to the tree-siter v22.3 format.
|
||||
# Which is: A list of tuples where the first element is the
|
||||
# Node of the capture and the second one is the name.
|
||||
def query_captures_22_3(query: Query, node: Node) -> list[tuple[Node, str]]:
|
||||
result = list()
|
||||
captures = query.captures(node)
|
||||
# Captures are no longer sorted by start point.
|
||||
captures_sorted = dict()
|
||||
nodes: list[Node]
|
||||
for name, nodes in captures.items():
|
||||
captures_sorted[name] = sorted(nodes, key=lambda n: n.start_point)
|
||||
while len(captures_sorted) != 0:
|
||||
for name, nodes in captures_sorted.items():
|
||||
node = nodes.pop(0)
|
||||
result.append((node, name))
|
||||
captures_sorted = {k: l for k, l in captures_sorted.items() if len(l) != 0}
|
||||
return result
|
||||
Reference in New Issue
Block a user