mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 18:00:17 +02:00
- Do compiler/architecture checks EARLY, don't waste time doing random configuration stuff if the user can't even compile in the first place - MSVC is unsupported, I assume? So add a check to disallow. There's literally no MSVC or MSC_VER checks anywhere, so... - Rather than using the MSVC architecture definitions, use our own `ARCHITECTURE_arm64` et al. Hijacking existing "standard" definitions is a very bad idea. Also makes it more readable in CMake - Change the x86 host check to `x86|amd64`. Some systems still refer to themselves as x86 despite being 64-bit for... reasons, and I saw one a very long time ago that referred to it as amd64. This should basically never come up, nor is it really relevant given that FEX is for arm64... but it kinda annoyed me so whatever. TODOs: - Should we check `CMAKE_SIZEOF_VOID_P (equal) 64`? I don't think anyone is even trying to compile this thing on armv7 or older, but might as well? maybe? - What's the status of *BSD, Solaris, macOS? Technically macOS does support Wine, not sure about the others. Signed-off-by: crueter <crueter@eden-emu.dev>
779 lines
26 KiB
Python
Executable File
779 lines
26 KiB
Python
Executable File
#!/usr/bin/python3
|
|
import clang.cindex
|
|
from clang.cindex import CursorKind
|
|
from clang.cindex import TypeKind
|
|
from clang.cindex import TranslationUnit
|
|
import sys
|
|
from dataclasses import dataclass
|
|
import subprocess
|
|
import logging
|
|
logger = logging.getLogger()
|
|
logger.setLevel(logging.WARNING)
|
|
|
|
# These defines are temporarily defined since python3-clang doesn't yet support these.
|
|
# Once this tool gets switched over to C++ then this won't be an issue.
|
|
# Type definitions redeclared from `clang/include/clang-c/Index.h`
|
|
|
|
# Expression that references a C++20 concept.
|
|
CursorKind.CONCEPTSPECIALIZATIONEXPR = CursorKind(153),
|
|
|
|
# Expression that references a C++20 concept.
|
|
CursorKind.REQUIRESEXPR = CursorKind(154),
|
|
|
|
# C++2a std::bit_cast expression.
|
|
CursorKind.BUILTINBITCASTEXPR = CursorKind(280)
|
|
|
|
try:
|
|
# a concept declaration.
|
|
CursorKind.CONCEPTDECL = CursorKind(604),
|
|
except:
|
|
pass
|
|
|
|
@dataclass
|
|
class TypeDefinition:
|
|
TYPE_UNKNOWN = 0
|
|
TYPE_STRUCT = 1
|
|
TYPE_UNION = 2
|
|
TYPE_FIELD = 3
|
|
TYPE_VARDECL = 4
|
|
|
|
name: str
|
|
type: int
|
|
def __init__(self, Name, Type):
|
|
self.name = Name
|
|
self.type = Type
|
|
|
|
@property
|
|
def Name(self):
|
|
return self.name
|
|
@property
|
|
def Type(self):
|
|
return self.type
|
|
|
|
@dataclass
|
|
class AliasType:
|
|
ALIAS_X86_32 = 0
|
|
ALIAS_X86_64 = 1
|
|
ALIAS_AARCH64 = 2
|
|
ALIAS_WIN32 = 3
|
|
ALIAS_WIN64 = 4
|
|
Name: str
|
|
AliasType: int
|
|
def __init__(self, Name, Type):
|
|
self.Name = Name
|
|
self.AliasType = Type
|
|
|
|
@dataclass
|
|
class StructDefinition(TypeDefinition):
|
|
Size: int
|
|
Aliases: list
|
|
Members: list
|
|
ExpectFEXMatch: bool
|
|
|
|
def __init__(self, Name, Size):
|
|
super(StructDefinition, self).__init__(Name, TypeDefinition.TYPE_STRUCT)
|
|
self.Size = Size
|
|
self.Aliases = []
|
|
self.Members = []
|
|
self.ExpectFEXMatch = False
|
|
|
|
@dataclass
|
|
class UnionDefinition(TypeDefinition):
|
|
Size: int
|
|
Aliases: list
|
|
Members: list
|
|
ExpectFEXMatch: bool
|
|
|
|
def __init__(self, Name, Size):
|
|
super(UnionDefinition, self).__init__(Name, TypeDefinition.TYPE_UNION)
|
|
self.Size = Size
|
|
self.Aliases = []
|
|
self.Members = []
|
|
self.ExpectFEXMatch = False
|
|
|
|
@dataclass
|
|
class FieldDefinition(TypeDefinition):
|
|
Size: int
|
|
OffsetOf: int
|
|
Alignment: int
|
|
def __init__(self, Name, Size, OffsetOf, Alignment):
|
|
super(FieldDefinition, self).__init__(Name, TypeDefinition.TYPE_FIELD)
|
|
self.Size = Size
|
|
self.OffsetOf = OffsetOf
|
|
self.Alignment = Alignment
|
|
|
|
@dataclass
|
|
class VarDeclDefinition(TypeDefinition):
|
|
Size: int
|
|
Aliases: list
|
|
ExpectFEXMatch: bool
|
|
Value: str
|
|
|
|
def __init__(self, Name, Size):
|
|
super(VarDeclDefinition, self).__init__(Name, TypeDefinition.TYPE_VARDECL)
|
|
self.Size = Size
|
|
self.Aliases = []
|
|
self.ExpectFEXMatch = False
|
|
|
|
@dataclass
|
|
class ArchDB:
|
|
Parsed: bool
|
|
ArchName: str
|
|
NamespaceScope: list
|
|
CurrentNamespace: str
|
|
TU: TranslationUnit
|
|
Structs: dict
|
|
Unions: dict
|
|
VarDecls: dict
|
|
FieldDecls: list
|
|
def __init__(self, ArchName):
|
|
self.Parsed = True
|
|
self.ArchName = ArchName
|
|
self.NamespaceScope = []
|
|
self.CurrentNamespace = ""
|
|
self.TU = None
|
|
self.Structs = {}
|
|
self.Unions = {}
|
|
self.VarDecls = {}
|
|
self.FieldDecls = []
|
|
|
|
class DBList:
|
|
DBs: list
|
|
def __init__(self, DB32, DB64, DBAArch64, DBWin32, DBWin64):
|
|
self.DBs = [DB32, DB64, DBAArch64, DBWin32, DBWin64]
|
|
|
|
def FindClangArguments(OriginalArguments):
|
|
AddedArguments = ["clang"]
|
|
AddedArguments.extend(OriginalArguments)
|
|
AddedArguments.extend(["-v", "-x", "c++", "-S", "-"])
|
|
Proc = subprocess.Popen(AddedArguments, stderr = subprocess.PIPE, stdin = subprocess.DEVNULL)
|
|
NewIncludes = []
|
|
BeginSearch = False
|
|
while True:
|
|
Line = Proc.stderr.readline().strip()
|
|
|
|
if not Line:
|
|
Proc.terminate()
|
|
break
|
|
|
|
if (Line == b"End of search list."):
|
|
BeginSearch = False
|
|
Proc.terminate()
|
|
break
|
|
|
|
if (BeginSearch == True):
|
|
NewIncludes.append("-I" + Line.decode('ascii'))
|
|
|
|
if (Line == b"#include <...> search starts here:"):
|
|
BeginSearch = True
|
|
|
|
# Add back original arguments
|
|
NewIncludes.extend(OriginalArguments)
|
|
return NewIncludes
|
|
|
|
def SetNamespace(Arch):
|
|
Arch.CurrentNamespace = ""
|
|
for Namespace in Arch.NamespaceScope:
|
|
Arch.CurrentNamespace = Arch.CurrentNamespace + Namespace + "::"
|
|
|
|
def HandleStructDeclCursor(Arch, Cursor, NameOverride = ""):
|
|
# Append namespace
|
|
CursorName = ""
|
|
StructType = Cursor.type
|
|
if (len(StructType.spelling) == 0):
|
|
CursorName = NameOverride
|
|
else:
|
|
CursorName = StructType.spelling
|
|
|
|
if (len(CursorName) != 0):
|
|
Arch.NamespaceScope.append(CursorName)
|
|
SetNamespace(Arch)
|
|
|
|
Struct = StructDefinition(
|
|
Name = CursorName,
|
|
Size = StructType.get_size())
|
|
|
|
# Handle children
|
|
Arch.Structs[Struct.Name] = HandleStructElements(Arch, Struct, Cursor)
|
|
|
|
# Pop namespace off
|
|
if (len(CursorName) != 0):
|
|
Arch.NamespaceScope.pop()
|
|
SetNamespace(Arch)
|
|
|
|
return Arch
|
|
|
|
def HandleUnionDeclCursor(Arch, Cursor, NameOverride = ""):
|
|
# Append namespace
|
|
CursorName = ""
|
|
|
|
if (len(Cursor.spelling) == 0):
|
|
CursorName = NameOverride
|
|
else:
|
|
CursorName = Cursor.spelling
|
|
|
|
if (len(CursorName) != 0):
|
|
Arch.NamespaceScope.append(CursorName)
|
|
SetNamespace(Arch)
|
|
|
|
UnionType = Cursor.type
|
|
Union = UnionDefinition(
|
|
Name = CursorName,
|
|
Size = UnionType.get_size())
|
|
Arch.Unions[Union.Name] = Union
|
|
|
|
# Handle children
|
|
Arch.Unions[Union.Name] = HandleStructElements(Arch, Union, Cursor)
|
|
|
|
# Pop namespace off
|
|
if (len(CursorName) != 0):
|
|
Arch.NamespaceScope.pop()
|
|
SetNamespace(Arch)
|
|
|
|
return Arch
|
|
|
|
def HandleVarDeclCursor(Arch, Cursor):
|
|
CursorName = Cursor.spelling
|
|
DeclType = Cursor.type
|
|
Def = Cursor.get_definition()
|
|
|
|
VarDecl = VarDeclDefinition(
|
|
Name = CursorName,
|
|
Size = DeclType.get_size())
|
|
Arch.VarDecls[VarDecl.Name] = HandleVarDeclElements(Arch, VarDecl, Cursor)
|
|
return Arch
|
|
|
|
def HandleVarDeclElements(Arch, VarDecl, Cursor):
|
|
for Child in Cursor.get_children():
|
|
|
|
if (Child.kind == CursorKind.ANNOTATE_ATTR):
|
|
if (Child.spelling.startswith("ioctl-alias-")):
|
|
Sections = Child.spelling.split("-")
|
|
if (Sections[2] == "x86_32"):
|
|
VarDecl.Aliases.append(AliasType(Sections[3], AliasType.ALIAS_X86_32))
|
|
elif (Sections[2] == "x86_64"):
|
|
VarDecl.Aliases.append(AliasType(Sections[3], AliasType.ALIAS_X86_64))
|
|
elif (Sections[2] == "aarch64"):
|
|
VarDecl.Aliases.append(AliasType(Sections[3], AliasType.ALIAS_AARCH64))
|
|
elif (Sections[2] == "win32"):
|
|
VarDecl.Aliases.append(AliasType(Sections[3], AliasType.ALIAS_WIN32))
|
|
elif (Sections[2] == "win64"):
|
|
VarDecl.Aliases.append(AliasType(Sections[3], AliasType.ALIAS_WIN64))
|
|
else:
|
|
logging.critical ("Can't handle alias type '{0}'".format(Child.spelling))
|
|
Arch.Parsed = False
|
|
elif (Child.spelling == "fex-match"):
|
|
VarDecl.ExpectFEXMatch = True
|
|
else:
|
|
# Unknown annotation
|
|
pass
|
|
elif (Child.kind == CursorKind.TYPE_REF or
|
|
Child.kind == CursorKind.UNEXPOSED_EXPR or
|
|
Child.kind == CursorKind.PAREN_EXPR or
|
|
Child.kind == CursorKind.BINARY_OPERATOR
|
|
):
|
|
pass
|
|
|
|
return VarDecl
|
|
|
|
|
|
def HandleTypeDefDeclCursor(Arch, Cursor):
|
|
TypeDefType = Cursor.underlying_typedef_type
|
|
CanonicalType = TypeDefType.get_canonical()
|
|
|
|
TypeDefName = Cursor.type.get_typedef_name()
|
|
|
|
if (TypeDefType.kind == TypeKind.ELABORATED and CanonicalType.kind == TypeKind.RECORD):
|
|
if (len(TypeDefName) != 0):
|
|
HandleTypeDefDecl(Arch, Cursor, TypeDefName)
|
|
|
|
# Append namespace
|
|
Arch.NamespaceScope.append(TypeDefName)
|
|
SetNamespace(Arch)
|
|
|
|
Arch = HandleCursor(Arch, Cursor)
|
|
#StructType = Cursor.type
|
|
#Struct = StructDefinition(
|
|
# Name = TypeDefName,
|
|
# Size = CanonicalType.get_size())
|
|
#Arch.Structs[TypeDefName] = Struct
|
|
|
|
## Handle children
|
|
#Arch.Structs[TypeDefName] = HandleStructElements(Arch, Struct, Cursor)
|
|
|
|
# Pop namespace off
|
|
Arch.NamespaceScope.pop()
|
|
SetNamespace(Arch)
|
|
else:
|
|
if (len(TypeDefName) != 0):
|
|
Def = Cursor.get_definition()
|
|
|
|
VarDecl = VarDeclDefinition(
|
|
Name = TypeDefName,
|
|
Size = CanonicalType.get_size())
|
|
Arch.VarDecls[VarDecl.Name] = HandleVarDeclElements(Arch, VarDecl, Cursor)
|
|
|
|
return Arch
|
|
|
|
def HandleStructElements(Arch, Struct, Cursor):
|
|
for Child in Cursor.get_children():
|
|
# logging.info ("\t\tStruct/Union Children: Cursor \"{0}{1}\" of kind {2}".format(Arch.CurrentNamespace, Child.spelling, Child.kind))
|
|
if (Child.kind == CursorKind.ANNOTATE_ATTR):
|
|
if (Child.spelling.startswith("alias-")):
|
|
Sections = Child.spelling.split("-")
|
|
if (Sections[1] == "x86_32"):
|
|
Struct.Aliases.append(AliasType(Sections[2], AliasType.ALIAS_X86_32))
|
|
elif (Sections[1] == "x86_64"):
|
|
Struct.Aliases.append(AliasType(Sections[2], AliasType.ALIAS_X86_64))
|
|
elif (Sections[1] == "aarch64"):
|
|
Struct.Aliases.append(AliasType(Sections[2], AliasType.ALIAS_AARCH64))
|
|
elif (Sections[1] == "win32"):
|
|
Struct.Aliases.append(AliasType(Sections[2], AliasType.ALIAS_WIN32))
|
|
elif (Sections[1] == "win64"):
|
|
Struct.Aliases.append(AliasType(Sections[2], AliasType.ALIAS_WIN64))
|
|
else:
|
|
logging.critical ("Can't handle alias type '{0}'".format(Child.spelling))
|
|
Arch.Parsed = False
|
|
|
|
elif (Child.spelling == "fex-match"):
|
|
Struct.ExpectFEXMatch = True
|
|
else:
|
|
# Unknown annotation
|
|
pass
|
|
elif (Child.kind == CursorKind.FIELD_DECL):
|
|
ParentType = Cursor.type
|
|
FieldType = Child.type
|
|
Field = FieldDefinition(
|
|
Name = Child.spelling,
|
|
Size = FieldType.get_size(),
|
|
OffsetOf = ParentType.get_offset(Child.spelling),
|
|
Alignment = FieldType.get_align())
|
|
|
|
#logging.info ("\t{0}".format(Child.spelling))
|
|
#logging.info ("\t\tSize of type: {0}".format(FieldType.get_size()));
|
|
#logging.info ("\t\tAlignment of type: {0}".format(FieldType.get_align()));
|
|
#logging.info ("\t\tOffsetof of type: {0}".format(ParentType.get_offset(Child.spelling)));
|
|
Struct.Members.append(Field)
|
|
Arch.FieldDecls.append(Field)
|
|
elif (Child.kind == CursorKind.STRUCT_DECL):
|
|
ParentType = Cursor.type
|
|
FieldType = Child.type
|
|
Field = FieldDefinition(
|
|
Name = Child.spelling,
|
|
Size = FieldType.get_size(),
|
|
OffsetOf = ParentType.get_offset(Child.spelling),
|
|
Alignment = FieldType.get_align())
|
|
|
|
#logging.info ("\t{0}".format(Child.spelling))
|
|
#logging.info ("\t\tSize of type: {0}".format(FieldType.get_size()));
|
|
#logging.info ("\t\tAlignment of type: {0}".format(FieldType.get_align()));
|
|
#logging.info ("\t\tOffsetof of type: {0}".format(ParentType.get_offset(Child.spelling)));
|
|
Struct.Members.append(Field)
|
|
Arch.FieldDecls.append(Field)
|
|
Arch = HandleStructDeclCursor(Arch, Child)
|
|
elif (Child.kind == CursorKind.UNION_DECL):
|
|
Struct = HandleStructElements(Arch, Struct, Child)
|
|
#ParentType = Cursor.type
|
|
#FieldType = Child.type
|
|
#Field = FieldDefinition(
|
|
# Name = Child.spelling,
|
|
# Size = FieldType.get_size(),
|
|
# OffsetOf = ParentType.get_offset(Child.spelling),
|
|
# Alignment = FieldType.get_align())
|
|
|
|
#logging.info ("\t{0}".format(Child.spelling))
|
|
#logging.info ("\t\tSize of type: {0}".format(FieldType.get_size()));
|
|
#logging.info ("\t\tAlignment of type: {0}".format(FieldType.get_align()));
|
|
#logging.info ("\t\tOffsetof of type: {0}".format(ParentType.get_offset(Child.spelling)));
|
|
#Struct.Members.append(Field)
|
|
#Arch.FieldDecls.append(Field)
|
|
#Arch = HandleUnionDeclCursor(Arch, Child)
|
|
elif (Child.kind == CursorKind.TYPEDEF_DECL):
|
|
Arch = HandleTypeDefDeclCursor(Arch, Child)
|
|
else:
|
|
Arch = HandleCursor(Arch, Child)
|
|
|
|
return Struct
|
|
|
|
def HandleTypeDefDecl(Arch, Cursor, Name):
|
|
for Child in Cursor.get_children():
|
|
if (Child.kind == CursorKind.UNION_DECL):
|
|
pass
|
|
elif (Child.kind == CursorKind.STRUCT_DECL):
|
|
Arch = HandleStructDeclCursor(Arch, Child, Name)
|
|
elif (Child.kind == CursorKind.UNION_DECL):
|
|
Arch = HandleUnionDeclCursor(Arch, Child, Name)
|
|
elif (Child.kind == CursorKind.TYPEDEF_DECL):
|
|
Arch = HandleTypeDefDeclCursor(Arch, Child)
|
|
elif (Child.kind == CursorKind.TYPE_REF or
|
|
Child.kind == CursorKind.NAMESPACE_REF or
|
|
Child.kind == CursorKind.TEMPLATE_REF or
|
|
Child.kind == CursorKind.ALIGNED_ATTR):
|
|
# Safe to pass on
|
|
pass
|
|
else:
|
|
logging.critical ("Unhandled TypedefDecl {0}-{1}-{2}".format(Child.kind, Child.type.spelling, Child.spelling))
|
|
|
|
def HandleCursor(Arch, Cursor):
|
|
if (Cursor.kind.is_invalid()):
|
|
Diags = TU.diagnostics
|
|
for Diag in Diags:
|
|
logging.warning (Diag.format())
|
|
|
|
Arch.Parsed = False
|
|
return
|
|
|
|
for Child in Cursor.get_children():
|
|
kind = Child.kind
|
|
if (kind == CursorKind.TRANSLATION_UNIT):
|
|
Arch = HandleCursor(Arch, Child)
|
|
elif (kind == CursorKind.FIELD_DECL):
|
|
pass
|
|
elif (kind == CursorKind.UNION_DECL):
|
|
Arch = HandleUnionDeclCursor(Arch, Child)
|
|
elif (kind == CursorKind.STRUCT_DECL):
|
|
Arch = HandleStructDeclCursor(Arch, Child)
|
|
elif (kind == CursorKind.TYPEDEF_DECL):
|
|
Arch = HandleTypeDefDeclCursor(Arch, Child)
|
|
elif (kind == CursorKind.VAR_DECL):
|
|
Arch = HandleVarDeclCursor(Arch, Child)
|
|
elif (kind == CursorKind.NAMESPACE):
|
|
# Append namespace
|
|
Arch.NamespaceScope.append(Child.spelling)
|
|
SetNamespace(Arch)
|
|
|
|
# Handle children
|
|
Arch = HandleCursor(Arch, Child)
|
|
|
|
# Pop namespace off
|
|
Arch.NamespaceScope.pop()
|
|
SetNamespace(Arch)
|
|
elif (kind == CursorKind.TYPE_REF):
|
|
# Safe to pass on
|
|
pass
|
|
else:
|
|
Arch = HandleCursor(Arch, Child)
|
|
|
|
return Arch
|
|
|
|
def GetDB(Arch, filename, args):
|
|
Index = clang.cindex.Index.create()
|
|
try:
|
|
TU = Index.parse(filename, args=args, options=TranslationUnit.PARSE_INCOMPLETE)
|
|
except TranslationUnitLoadError:
|
|
Arch.Parsed = False
|
|
Diags = TU.diagnostics
|
|
for Diag in Diags:
|
|
logging.warning (Diag.format())
|
|
|
|
return
|
|
|
|
Arch.TU = TU
|
|
HandleCursor(Arch, TU.cursor)
|
|
|
|
# Get diagnostics
|
|
Diags = TU.diagnostics
|
|
if (len(Diags) != 0):
|
|
logging.warning ("Diagnostics from Arch: {0}".format(Arch.ArchName))
|
|
|
|
for Diag in Diags:
|
|
logging.warning (Diag.format())
|
|
|
|
return Arch
|
|
|
|
def GetCompar(ComparisonName, DBs):
|
|
if (ComparisonName.lower() == "x86_32"):
|
|
return DBs.DBs[AliasType.ALIAS_X86_32]
|
|
elif (ComparisonName.lower() == "x86_64"):
|
|
return DBs.DBs[AliasType.ALIAS_X86_64]
|
|
elif (ComparisonName.lower() == "win32"):
|
|
return DBs.DBs[AliasType.ALIAS_WIN32]
|
|
elif (ComparisonName.lower() == "win64"):
|
|
return DBs.DBs[AliasType.ALIAS_WIN64]
|
|
elif (ComparisonName.lower() == "aarch64"):
|
|
return DBs.DBs[AliasType.ALIAS_AARCH64]
|
|
|
|
def PrintMissingMembers(Struct1, Struct2):
|
|
for Member1 in Struct1.Members:
|
|
WasMissing = True
|
|
for Member2 in Struct2.Members:
|
|
if (Member1.Name == Member2.Name):
|
|
WasMissing = False
|
|
break
|
|
if (WasMissing):
|
|
logging.error ("\t'{0}' member '{1}' Doesn't exist in '{2}'".format(Struct1.Name, Member1.Name, Struct2.Name));
|
|
|
|
def CompareStructs(Struct1, Struct2):
|
|
HadWarning = False
|
|
HadError = False
|
|
|
|
# Check if the struct size is a mismatch
|
|
if (Struct1.Size != Struct2.Size):
|
|
logging.warning ("\t#### Warning: Struct size mismatch. {0} != {1}".format(Struct1.Size, Struct2.Size))
|
|
logging.warning ("\t\tMight not be a problem if struct isn't in used inside another struct, or end of object")
|
|
HadWarning = True
|
|
|
|
# Check if the number of members differ
|
|
if (len(Struct1.Members) != len(Struct2.Members)):
|
|
logging.error ("@@@@ ERROR: Struct fields mismatch! Number of fields don't match! {0} != {1}".format(len(Struct1.Members), len(Struct2.Members)));
|
|
PrintMissingMembers(Struct1, Struct2)
|
|
PrintMissingMembers(Struct2, Struct1)
|
|
HadError = True
|
|
else:
|
|
# Compare the members themselves
|
|
for StructMemberIndex in range(0, len(Struct1.Members)):
|
|
Member1 = Struct1.Members[StructMemberIndex]
|
|
Member2 = Struct2.Members[StructMemberIndex]
|
|
if (Member1.Type == TypeDefinition.TYPE_FIELD):
|
|
if (Member1.Size != Member2.Size):
|
|
logging.error ("\t@@@@ ERROR: Member '{0}' mismatch Size! {1} != {2}".format(Member1.Name, Member1.Size, Member2.Size));
|
|
HadError = True
|
|
if (Member1.OffsetOf != Member2.OffsetOf):
|
|
logging.error ("\t@@@@ ERROR: Member '{0}' mismatch OffsetOf! {1} != {2}".format(Member1.Name, Member1.OffsetOf, Member2.OffsetOf));
|
|
HadError = True
|
|
if (Member1.Alignment != Member2.Alignment):
|
|
logging.error ("\t@@@@ ERROR: Member '{0}' mismatch Alignment! {1} != {2}".format(Member1.Name, Member1.Alignment, Member2.Alignment));
|
|
logging.error ("\t\tProbably not a problem if offset and size matches");
|
|
HadWarning = True
|
|
else:
|
|
logging.critical ("Oops, didn't handle member type {0}".format(Member1.Type))
|
|
pass
|
|
|
|
return not (HadWarning or HadError)
|
|
|
|
def CompareAliases(DB, DBs):
|
|
Passed = True
|
|
for StructKey, StructDef in DB.Structs.items():
|
|
if (len(StructKey) == 0):
|
|
# XXX: Oops, shouldn't have anonymous structs
|
|
continue
|
|
|
|
if (len(StructDef.Aliases) != 0):
|
|
logging.info ("Comparing Aliases {0}".format(StructDef.Name))
|
|
|
|
for Alias in StructDef.Aliases:
|
|
OtherDB = DBs.DBs[Alias.AliasType]
|
|
OtherStruct = OtherDB.Structs.get(Alias.Name)
|
|
if (OtherStruct == None):
|
|
logging.critical ("Couldn't find alias {0} in {1} DB".format(Alias.Name, OtherDB.ArchName))
|
|
Passed = False
|
|
continue
|
|
|
|
ThisAlias = CompareStructs(StructDef, OtherStruct)
|
|
if not (ThisAlias):
|
|
logging.error ("Couldn't Alias to Arch {0} successfully".format(OtherDB.ArchName))
|
|
Passed &= ThisAlias
|
|
|
|
for VarDeclKey, VarDecl in DB.VarDecls.items():
|
|
if (len(VarDeclKey) == 0):
|
|
# XXX: Oops, shouldn't have anonymous vardecls
|
|
continue
|
|
|
|
|
|
for Alias in VarDecl.Aliases:
|
|
OtherDB = DBs.DBs[Alias.AliasType]
|
|
OtherAlias = OtherDB.VarDecls.get(Alias.Name)
|
|
if (OtherAlias == None):
|
|
logging.critical ("Couldn't find alias {0} in {1} DB".format(Alias.Name, OtherDB.ArchName))
|
|
Passed = False
|
|
continue
|
|
|
|
if (VarDecl.Size != OtherAlias.Size):
|
|
logging.critical("VarDecl: {0}/{1} didn't match {2}/{3}: {4:08X} != {5:08X}".format(VarDeclKey, DB.ArchName, Alias.Name,
|
|
OtherDB.ArchName,
|
|
VarDecl.Size, OtherAlias.Size))
|
|
Passed = False
|
|
continue
|
|
|
|
|
|
return Passed
|
|
|
|
def CompareCrossArch(DB1, DB2):
|
|
Passed = True
|
|
for StructKey, StructDef in DB1.Structs.items():
|
|
if (len(StructKey) == 0):
|
|
# XXX: Oops, shouldn't have anonymous structs
|
|
continue
|
|
|
|
logging.info ("Comparing crossArch {0}".format(StructDef.Name))
|
|
if (StructDef.ExpectFEXMatch):
|
|
Struct2 = DB2.Structs.get(StructDef.Name)
|
|
if (Struct2 == None):
|
|
logging.critical ("Couldn't find Struct {0} in {1} DB".format(StructDef.Name, DB2.ArchName))
|
|
Passed = False
|
|
continue
|
|
|
|
Passed &= CompareStructs(StructDef, Struct2)
|
|
|
|
return Passed
|
|
|
|
def main():
|
|
if sys.version_info[0] < 3:
|
|
logging.critical ("Python 3 or a more recent version is required.")
|
|
|
|
if (len(sys.argv) < 2):
|
|
print ("usage: %s <options> <Header.hpp> <clang arguments...>" % (sys.argv[0]))
|
|
print ("\t-c1 <Type1>: Base Comparison Type");
|
|
print ("\t-c2 <Type2>: Second Comparison Type");
|
|
print ("\t-win: Parse Windows");
|
|
sys.exit ("\t-no-linux: Do not parse Linux");
|
|
|
|
ParseLinux = True
|
|
ParseWindows = False
|
|
|
|
Header = ""
|
|
Comparison1 = ""
|
|
Comparison2 = ""
|
|
BaseArgs = []
|
|
|
|
StartOfArgs = 0
|
|
|
|
# Parse our arguments
|
|
ArgIndex = 1
|
|
while ArgIndex < len(sys.argv):
|
|
Arg = sys.argv[ArgIndex]
|
|
if (Arg == "--"):
|
|
StartOfArgs = ArgIndex + 1
|
|
break;
|
|
|
|
if (Arg == "-c1"):
|
|
ArgIndex += 1
|
|
Comparison1 = sys.argv[ArgIndex]
|
|
elif (Arg == "-c2"):
|
|
ArgIndex += 1
|
|
Comparison2 = sys.argv[ArgIndex]
|
|
elif (Arg == "-win"):
|
|
ParseWindows = True
|
|
elif (Arg == "-no-linux"):
|
|
ParseLinux = False
|
|
else:
|
|
Header = Arg
|
|
StartOfArgs = ArgIndex + 1
|
|
break
|
|
|
|
# Increment
|
|
ArgIndex += 1
|
|
|
|
# Add arguments for clang
|
|
for ArgIndex in range(StartOfArgs, len(sys.argv)):
|
|
BaseArgs.append(sys.argv[ArgIndex])
|
|
|
|
args_x86_32 = [
|
|
"-isystem", "/usr/i686-linux-gnu/include",
|
|
"-O2",
|
|
"-m32",
|
|
"--target=i686-linux-unknown",
|
|
]
|
|
|
|
args_x86_64 = [
|
|
"-isystem", "/usr/x86_64-linux-gnu/include",
|
|
"-O2",
|
|
"--target=x86_64-linux-unknown",
|
|
"-DARCHITECTURE_x86_64",
|
|
]
|
|
|
|
args_aarch64 = [
|
|
"-isystem", "/usr/aarch64-linux-gnu/include",
|
|
"-O2",
|
|
"--target=aarch64-linux-unknown",
|
|
"-DARCHITECTURE_arm64",
|
|
]
|
|
|
|
args_x86_win32 = [
|
|
"-I/usr/lib/gcc/i686-w64-mingw32/10-win32/include/c++/",
|
|
"-I/usr/lib/gcc/i686-w64-mingw32/10-win32/include/c++/i686-w64-mingw32/",
|
|
"-O2",
|
|
"-m32",
|
|
"--target=i686-pc-win32",
|
|
]
|
|
|
|
args_x86_win64 = [
|
|
"-I/usr/lib/gcc/x86_64-w64-mingw32/10-win32/include/c++/",
|
|
"-I/usr/lib/gcc/x86_64-w64-mingw32/10-win32/include/c++/x86_64-w64-mingw32/",
|
|
"-O2",
|
|
"--target=x86_64-pc-win32",
|
|
]
|
|
|
|
# Add all the arguments to the different lists
|
|
args_x86_32.extend(BaseArgs)
|
|
args_x86_64.extend(BaseArgs)
|
|
args_aarch64.extend(BaseArgs)
|
|
args_x86_win32.extend(BaseArgs)
|
|
args_x86_win64.extend(BaseArgs)
|
|
|
|
# We need to find the default arguments through clang invocations
|
|
args_x86_32 = FindClangArguments(args_x86_32)
|
|
args_x86_64 = FindClangArguments(args_x86_64)
|
|
args_aarch64 = FindClangArguments(args_aarch64)
|
|
|
|
args_x86_win32 = FindClangArguments(args_x86_win32)
|
|
args_x86_win64 = FindClangArguments(args_x86_win64)
|
|
|
|
Arch_x86_32 = ArchDB("x86_32")
|
|
Arch_x86_64 = ArchDB("x86_64")
|
|
|
|
Arch_aarch64 = ArchDB("aarch64")
|
|
Arch_x86_win32 = ArchDB("win32")
|
|
Arch_x86_win64 = ArchDB("win64")
|
|
|
|
if (ParseLinux):
|
|
Arch_x86_32 = GetDB(Arch_x86_32, Header, args_x86_32)
|
|
Arch_x86_64 = GetDB(Arch_x86_64, Header, args_x86_64)
|
|
Arch_aarch64 = GetDB(Arch_aarch64, Header, args_aarch64)
|
|
|
|
if not (Arch_x86_32.Parsed):
|
|
logging.critical ("Couldn't parse:{0}".format(Arch_x86_32.ArchName))
|
|
|
|
if not (Arch_x86_64.Parsed):
|
|
logging.critical ("Couldn't parse:{0}".format(Arch_x86_64.ArchName))
|
|
|
|
if not (Arch_aarch64.Parsed):
|
|
logging.critical ("Couldn't parse:{0}".format(Arch_aarch64.ArchName))
|
|
|
|
if (ParseWindows):
|
|
Arch_x86_win32 = GetDB(Arch_x86_win32, Header, args_x86_win32)
|
|
Arch_x86_win64 = GetDB(Arch_x86_win64, Header, args_x86_win64)
|
|
|
|
if not (Arch_x86_win32.Parsed):
|
|
logging.critical ("Couldn't parse:{0}".format(Arch_x86_win32.ArchName))
|
|
|
|
if not (Arch_x86_win64.Parsed):
|
|
logging.critical ("Couldn't parse:{0}".format(Arch_x86_win64.ArchName))
|
|
|
|
DBs = DBList(Arch_x86_32,
|
|
Arch_x86_64,
|
|
Arch_aarch64,
|
|
Arch_x86_win32,
|
|
Arch_x86_win64)
|
|
|
|
Result = 0
|
|
if (len(Comparison1) != 0 and len(Comparison2) != 0):
|
|
CompDB1 = GetCompar(Comparison1, DBs)
|
|
CompDB2 = GetCompar(Comparison2, DBs)
|
|
|
|
# Now compare across the two compared architectures
|
|
Result = 0 if CompareCrossArch(CompDB1, CompDB2) else 1
|
|
elif (len(Comparison1) != 0):
|
|
CompDB1 = GetCompar(Comparison1, DBs)
|
|
|
|
# First compare the aliases to make sure we are matching
|
|
Result = 0 if CompareAliases(CompDB1, DBs) else 1
|
|
|
|
if (Result == 1):
|
|
logging.error("Execution environment")
|
|
Args = "[ "
|
|
for Arg in sys.argv:
|
|
Args += Arg + ", "
|
|
Args += " ]"
|
|
logging.error(Args)
|
|
Args = ""
|
|
for Arg in sys.argv:
|
|
Args += "\"" + Arg + "\" "
|
|
|
|
logging.error(Args)
|
|
return Result
|
|
|
|
if __name__ == "__main__":
|
|
# execute only if run as a script
|
|
sys.exit(main())
|