#include "gen.h" #include "utils.h" #include #include #include #include using namespace clang; using namespace clang::tooling; static std::vector GetRecordFieldOff(const std::string& Code, const std::string& Triple) { std::vector FieldOff; std::vector Args = {"-target", Triple}; std::unique_ptr AST = clang::tooling::buildASTFromCodeWithArgs(Code, Args); auto& Ctx = AST->getASTContext(); auto TranslateDecl = Ctx.getTranslationUnitDecl(); for (const auto& Decl : TranslateDecl->decls()) { if (const auto RecordDecl = clang::dyn_cast(Decl)) { auto& RecordLayout = Ctx.getASTRecordLayout(RecordDecl); for (unsigned i = 0; i < RecordLayout.getFieldCount(); i++) { FieldOff.push_back(RecordLayout.getFieldOffset(i) / 8); } break; } } return FieldOff; } static uint64_t GetRecordSize(const std::string& Code, const std::string& Triple) { std::vector Args = {"-target", Triple}; std::unique_ptr AST = buildASTFromCodeWithArgs(Code, Args); auto& Ctx = AST->getASTContext(); auto TranslateDecl = Ctx.getTranslationUnitDecl(); for (const auto& Decl : TranslateDecl->decls()) { if (const auto recordDecl = dyn_cast(Decl)) { return Ctx.getTypeSize(recordDecl->getTypeForDecl()) / 8; } } return 0; } static CharUnits::QuantityType GetRecordAlign(const std::string& Code, const std::string& Triple) { std::vector Args = {"-target", Triple}; std::unique_ptr AST = buildASTFromCodeWithArgs(Code, Args); auto& Ctx = AST->getASTContext(); auto TranslateDecl = Ctx.getTranslationUnitDecl(); for (const auto& Decl : TranslateDecl->decls()) { if (const auto recordDecl = dyn_cast(Decl)) { auto& RecordLayout = Ctx.getASTRecordLayout(recordDecl); for (unsigned i = 0; i < RecordLayout.getFieldCount(); i++) { return RecordLayout.getAlignment().getQuantity() / 8; } break; } } return 0; } static uint64_t GetTypeSize(const Type* Type, const std::string& Triple) { std::string Code = Type->getCanonicalTypeInternal().getAsString() + " dummy;"; std::vector Args = {"-target", Triple}; std::unique_ptr AST = buildASTFromCodeWithArgs(Code, Args); auto& Ctx = AST->getASTContext(); auto TranslateDecl = Ctx.getTranslationUnitDecl(); for (const auto& Decl : TranslateDecl->decls()) { if (const auto varDecl = dyn_cast(Decl)) { return Ctx.getTypeSize(varDecl->getType()) / 8; } } return 0; } static std::string TypeToSig(ASTContext* Ctx, const Type* Type) { if (Type->isBuiltinType()) { switch (Type->getAs()->getKind()) { case clang::BuiltinType::Kind::Void: return "v"; case clang::BuiltinType::Kind::Bool: return "i"; case clang::BuiltinType::Kind::Char_U: return "C"; case clang::BuiltinType::Kind::Char_S: return "c"; case clang::BuiltinType::Kind::Char8: return "c"; case clang::BuiltinType::Kind::UChar: return "C"; case clang::BuiltinType::Kind::SChar: return "c"; case clang::BuiltinType::Kind::WChar_U: return "W"; case clang::BuiltinType::Kind::UShort: return "W"; case clang::BuiltinType::Kind::WChar_S: return "w"; case clang::BuiltinType::Kind::Char16: return "w"; case clang::BuiltinType::Kind::Short: return "w"; case clang::BuiltinType::Kind::UInt: return "u"; case clang::BuiltinType::Kind::Char32: return "i"; case clang::BuiltinType::Kind::Int: return "i"; case clang::BuiltinType::Kind::ULong: return "L"; case clang::BuiltinType::Kind::Long: return "l"; case clang::BuiltinType::Kind::ULongLong: return "U"; case clang::BuiltinType::Kind::LongLong: return "I"; case clang::BuiltinType::Kind::UInt128: return "H"; case clang::BuiltinType::Kind::Int128: return "H"; case clang::BuiltinType::Kind::Float: return "f"; case clang::BuiltinType::Kind::Double: return "d"; case clang::BuiltinType::Kind::LongDouble: return "D"; case clang::BuiltinType::Kind::NullPtr: return "p"; // nullptr_t default: std::cout << "Unsupported BuiltinType: " << Type->getCanonicalTypeInternal().getAsString() << std::endl; } } else { if (Type->isPointerType()) { return "p"; } else if (Type->isVoidType()) { return "v"; } else if (Type->isUnsignedIntegerOrEnumerationType()) { switch(Ctx->getTypeSizeInChars(Type).getQuantity()) { case 1: return "C"; case 2: return "W"; case 4: return "u"; case 8: return "U"; default: std::cout << "Unsupported UnsignedInteger Type: " << Type->getCanonicalTypeInternal().getAsString() << std::endl; } } else if (Type->isSignedIntegerOrEnumerationType()) { switch(Ctx->getTypeSizeInChars(Type).getQuantity()) { case 1: return "c"; case 2: return "w"; case 4: return "i"; case 8: return "I"; default: std::cout << "Unsupported SignedInteger Type: " << Type->getCanonicalTypeInternal().getAsString() << std::endl; } } else if (Type->isCharType()) { return "c"; } else if (Type->isFloatingType()) { switch(Ctx->getTypeSizeInChars(Type).getQuantity()) { case 4: return "f"; case 8: return "d"; case 16: return "D"; default: std::cout << "Unsupported Floating Type: " << Type->getCanonicalTypeInternal().getAsString() << " (quantity = " << Ctx->getTypeSizeInChars(Type).getQuantity() << ")" << std::endl; } } else { std::cout << "Unsupported Type: " << Type->getCanonicalTypeInternal().getAsString() << std::endl; } } return "?"; } // Prepare for generation, collect the structures and functions that need to be prcessed void WrapperGenerator::Prepare(ASTContext *Ctx) { for (const auto &func_pair : funcs) { for (auto Type : func_pair.second.callback_args) { if (Type && Type->isTypedefNameType()) { callbacks[StripTypedef(Type->getPointeeType())] = Type->getAs()->getDecl()->getNameAsString(); } else if (Type) { callbacks[StripTypedef(Type->getPointeeType())] = GetFuncSig(Ctx, Type->getPointeeType().getTypePtr()) + "_t"; } } } std::vector Types; for (const auto &record_pair : records) { Types.push_back(record_pair.first); } for (auto type : Types) { std::set Visited{type}; bool Special = false; ParseRecordRecursive(Ctx, type, Special, Visited); } for (auto it = records.begin(); it != records.end();) { if (!it->second.is_special) { it = records.erase(it); } else { for (auto field : it->second.callback_fields) { if (field->isTypedefNameType()) { callbacks[StripTypedef(field->getPointeeType())] = field->getAs()->getDecl()->getNameAsString(); } else { callbacks[StripTypedef(field->getPointeeType())] = GetFuncSig(Ctx, field->getPointeeType().getTypePtr()) + "_t"; } } ++it; } } for (auto &func_pair : funcs) { for (unsigned i = 0; i < func_pair.second.decl->getNumParams(); i++) { auto ParamDecl = func_pair.second.decl->getParamDecl(i); auto ParamType = ParamDecl->getType(); if (ParamType->isPointerType() && ParamType->getPointeeType()->isRecordType()) { if (records.find(StripTypedef(ParamType->getPointeeType())) != records.end()) { func_pair.second.has_special_arg = true; break; } } else if (ParamType->isRecordType()) { if (records.find(StripTypedef(ParamType)) != records.end()) { func_pair.second.has_special_arg = true; break; } } } auto RetType = func_pair.second.decl->getReturnType(); if (RetType->isPointerType() && RetType->getPointeeType()->isRecordType()) { if (records.find(StripTypedef(RetType->getPointeeType())) != records.end()) { func_pair.second.has_special_ret = true; } } else if (RetType->isRecordType()) { if (records.find(StripTypedef(RetType)) != records.end()) { func_pair.second.has_special_ret = true; } } } } // Gen callback typedef std::string WrapperGenerator::GenCallbackTypeDefs(ASTContext *Ctx) { (void)Ctx; std::string res; for (auto callback : callbacks) { auto Type = callback.first; auto Definition = GetFuncDefinition(Type); res += "typedef " + Definition.ret_str + "(*" + callback.second + ")("; for (int i = 0; i < Definition.arg_size - 1; i++) { res += Definition.arg_types_str[i] + Definition.arg_names[i] + ", "; } if (Definition.arg_size) { res += Definition.arg_types_str[Definition.arg_size - 1] + Definition.arg_names[Definition.arg_size - 1]; } res += ");\n"; } return res; } // Gen function declare std::string WrapperGenerator::GenDeclare(ASTContext *Ctx, const FuncInfo &Func) { std::string res; std::string sig = GetFuncSig(Ctx, Func); res += "GO"; if (Func.is_weak) { res += "W"; } if (sig.find('E') != std::string::npos) { res += "M"; } res += "(" + Func.func_name + ", " + sig + ")\n"; ; return res; } // Gen structure declare std::string WrapperGenerator::GenDeclare(ASTContext *Ctx, const RecordInfo &Record) { (void)Ctx; std::string RecordStr; std::string PreDecl; RecordStr += "\ntypedef "; RecordStr += (Record.is_union ? "union " : "struct ") + Record.type_name + " {\n"; for (const auto &Field : Record.decl->fields()) { auto Type = Field->getType(); std::string Name = Field->getNameAsString(); RecordStr += " "; if (Type->isFunctionPointerType()) { auto FuncType = StripTypedef(Type->getPointeeType()); if (callbacks.count(FuncType)) { std::string FieldStr = callbacks[FuncType]; FieldStr += " "; FieldStr += Name; RecordStr += FieldStr; } else { std::cout << "Err: FuncPtr(" << Record.type_name << "." << Name << ") is not supported\n"; } } else if (Type->isPointerType()) { auto PointeeType = Type->getPointeeType(); if (PointeeType->isRecordType()) { if (records.count(PointeeType.getTypePtr())) { std::string FieldStr = records[PointeeType.getTypePtr()].type_name; FieldStr += "_ptr "; FieldStr += Name; RecordStr += FieldStr; } else { RecordStr += "void *" + Name; } } else { RecordStr += "void *" + Name; } } else if (Type->isRecordType()) { if (records.count(Type.getTypePtr())) { std::string FieldStr = records[Type.getTypePtr()].type_name; FieldStr += " "; FieldStr += Name; RecordStr += FieldStr; } else { RecordStr += TypeStringify(StripTypedef(Type), Field, nullptr, PreDecl); } } else { RecordStr += TypeStringify(StripTypedef(Type), Field, nullptr, PreDecl); } RecordStr += ";\n"; } RecordStr += "} "; RecordStr += Record.type_name + ", *" + Record.type_name + "_ptr;\n"; return RecordStr; } std::string WrapperGenerator::GenCallbackWrap(ASTContext *Ctx, const FuncInfo &Func) { (void)Ctx; std::string res; for (unsigned i = 0; i < Func.decl->getNumParams(); i++) { auto ParamType = Func.decl->getParamDecl(i)->getType(); if (ParamType->isFunctionPointerType()) { auto PointeeType = ParamType->getPointeeType(); auto Definition = GetFuncDefinition(PointeeType.getTypePtr()); std::string my_funcname = std::string("my_") + Func.decl->getParamDecl(i)->getNameAsString(); std::string funcname = Func.decl->getParamDecl(i)->getNameAsString(); res += "\n#define GO(A) \\\n" "static uintptr_t " + my_funcname + "_fct_##A = 0; \\\n" + Definition.ret_str + " " + my_funcname + "("; int arg_size = Definition.arg_names.size(); if (arg_size) { for (int i = 0; i < arg_size - 1; i++) { res += Definition.arg_types_str[i] + " " + Definition.arg_names[i] + ", "; } res += Definition.arg_types_str[arg_size - 1] + " " + Definition.arg_names[arg_size - 1]; } res += ") { \\\n" " return RunFunction(my_context, " + my_funcname + "_fct_##A" + ", " + std::to_string(arg_size); for (int i = 0; i < arg_size; i++) { res += ", " + Definition.arg_names[i]; } res += "); \\\n" "}\n" "SUPER()\n" "#undef GO\n" "static void* find" + funcname + "Fct(void* fct) {\n" " if (!fct) return fct;\n" " if (GetNativeFnc((uintptr_t)fct)) return GetNativeFnc((uintptr_t)fct);\n" " #define GO(A) if (" + my_funcname + "_fct_##A == (uintptr_t)fct) return " + my_funcname + "_##A;\n" " SUPER()\n" " #undef GO\n" " #define GO(A) if (" + my_funcname + "_fct_##A == 0) { " + my_funcname + "_fct_##A = (uintptr_t)fct; return " + my_funcname + "_##A; }\n" " SUPER()\n" " #undef GO\n" " return NULL;\n" "}\n"; } } return res; } std::string WrapperGenerator::GenCallbackWrap(ASTContext *Ctx, const RecordInfo &Struct) { (void)Ctx; std::string res; for (const auto &field : Struct.decl->fields()) { auto FieldType = field->getType(); if (FieldType->isFunctionPointerType()) { auto PointeeType = FieldType->getPointeeType(); auto Definition = GetFuncDefinition(PointeeType.getTypePtr()); std::string my_funcname = std::string("my_") + field->getNameAsString(); std::string funcname = field->getNameAsString(); res += "\n#define GO(A) \\\n" "static uintptr_t " + my_funcname + "_fct_##A = 0; \\\n" + Definition.ret_str + " " + my_funcname + "_##A("; int arg_size = Definition.arg_names.size(); if (arg_size) { for (int i = 0; i < arg_size - 1; i++) { res += Definition.arg_types_str[i] + " " + Definition.arg_names[i] + ", "; } res += Definition.arg_types_str[arg_size - 1] + " " + Definition.arg_names[arg_size - 1]; } res += ") { \\\n" " return RunFunction(my_context, " + my_funcname + "_fct_##A" + ", " + std::to_string(arg_size); for (int i = 0; i < arg_size; i++) { res += ", " + Definition.arg_names[i]; } res += "); \\\n" "}\n" "SUPER()\n" "#undef GO\n" "static void* find" + funcname + "Fct(void* fct) {\n" " if(!fct) return fct;\n" " if(GetNativeFnc((uintptr_t)fct)) return GetNativeFnc((uintptr_t)fct);\n" " #define GO(A) if(" + my_funcname + "_fct_##A == (uintptr_t)fct) return " + my_funcname + "_##A;}\n" " SUPER()\n" " #undef GO\n" " #define GO(A) if(" + my_funcname + "_fct_##A == 0) {" + my_funcname + "_fct_##A = (uintptr_t)fct;" + "return " + my_funcname + "_##A;}\n" " SUPER()\n" " #undef GO\n" " return NULL;\n" "}\n"; } } return res; } std::string WrapperGenerator::GenDefine(ASTContext *Ctx, const FuncInfo &Func) { std::string res; auto Definition = GetFuncDefinition(Func.decl); std::string Sig = GetFuncSig(Ctx, Func.type); res += "\nEXPORT " + Definition.ret_str + "my_" + Func.func_name + "("; if (Sig.find('E')) { res += "void *emu, "; } int arg_size = Definition.arg_names.size(); if (arg_size) { for (int i = 0; i < arg_size - 1; i++) { if (Definition.arg_types[i]->isPointerType()) { auto PointeeType = Definition.arg_types[i]->getPointeeType(); if (records.count(PointeeType.getTypePtr())) { res += Definition.arg_types[i]->getCanonicalTypeInternal().getAsString(); } else { res += Definition.arg_types_str[i]; } } else { res += Definition.arg_types_str[i]; } res += " " + Definition.arg_names[i] + ", "; } if (Definition.arg_types[arg_size - 1]->isPointerType()) { auto PointeeType = Definition.arg_types[arg_size - 1]->getPointeeType(); if (records.count(PointeeType.getTypePtr())) { res += Definition.arg_types[arg_size - 1] ->getCanonicalTypeInternal() .getAsString(); } else { res += Definition.arg_types_str[arg_size - 1]; } } else { res += Definition.arg_types_str[arg_size - 1]; } res += " "; res += Definition.arg_names[arg_size - 1]; } res += ") {\n"; if (Func.has_special_arg) { res += " // WARN: This function's arg has a structure ptr which is " "special, may need to wrap it for the host\n"; } else if (Func.has_special_ret) { res += " // WARN: This function's ret is a structure ptr which is " "special, may need to wrap it for the guest\n"; } if (Func.has_callback_arg) { res += " " + my_lib_type + " *my = " + "(" + my_lib_type + "*)" + my_lib + "->priv.w.p2;\n" " my->" + Func.func_name + "("; if (arg_size) { for (int i = 0; i < arg_size - 1; i++) { if (Func.callback_args[i]) { if (!Func.callback_args[i]->isTypedefNameType()) { res += "find" + Func.func_name + "_arg" + std::to_string(i) + "Fct"; } else { res += "find" + Func.callback_args[i] ->getAs() ->getDecl() ->getNameAsString() + "Fct"; } res += "(" + Definition.arg_names[i] + ")"; } else { res += Definition.arg_names[i]; } res += ", "; } if (Func.callback_args[arg_size - 1]) { if (!Func.callback_args[arg_size - 1]->isTypedefNameType()) { res += "find" + Func.func_name + "_arg" + std::to_string(arg_size - 1) + "Fct"; } else { res += "find" + Func.callback_args[arg_size - 1] ->getAs() ->getDecl() ->getNameAsString() + "Fct"; } res += "(" + Definition.arg_names[arg_size - 1] + ")"; } else { res += Definition.arg_names[arg_size - 1]; } res += ")\n"; } } else { res += " " + my_lib_type + " *my = (" + my_lib_type + "*)" + my_lib + "->priv.w.p2;\n" " my->" + Func.func_name + "("; if (arg_size) { for (int i = 0; i < arg_size - 1; i++) { res += Definition.arg_names[i] + ", "; } res += Definition.arg_names[arg_size - 1]; } res += ");\n"; } res += "}\n"; return res; } std::string WrapperGenerator::GenDeclareDiffTriple( ASTContext *Ctx, const RecordInfo &Record, const std::string &GuestTriple, const std::string &HostTriple) { (void)Ctx; std::string GuestRecord; std::string HostRecord; std::string PreDecl; std::vector GuestFieldOff; std::vector HostFieldOff; GuestRecord += "typedef "; HostRecord += "typedef "; GuestRecord += (Record.is_union ? "union " : "struct ") + Record.type_name + " {\n"; HostRecord += (Record.is_union ? "union " : "struct ") + std::string("host_") + Record.type_name + " {\n"; auto OffDiff = GetRecordFieldOffDiff(Record.type, GuestTriple, HostTriple, GuestFieldOff, HostFieldOff); uint64_t GuestRecordSize = GetRecordSize(Record.type, GuestTriple); uint64_t HostRecordSize = GetRecordSize(Record.type, HostTriple); uint64_t SizeDiff = GuestRecordSize - HostRecordSize; int FieldIndex = 0; std::set AlignDiffFields; for (const auto &Field : Record.decl->fields()) { if (OffDiff[FieldIndex] == 0) { FieldIndex++; continue; } std::string Name = Field->getNameAsString(); if (OffDiff[FieldIndex] != SizeDiff) { auto Diff = OffDiff[FieldIndex]; AlignDiffFields.insert(Field); for (size_t i = FieldIndex; i < OffDiff.size(); i++) { if (OffDiff[i] == Diff) { OffDiff[i] = 0; } else { break; } } } else { AlignDiffFields.insert(Field); break; } FieldIndex++; } for (const auto &Field : Record.decl->fields()) { auto Type = Field->getType(); std::string Name = Field->getNameAsString(); GuestRecord += " "; HostRecord += " "; if (AlignDiffFields.find(Field) != AlignDiffFields.end()) { auto typeSize = GetTypeSize(StripTypedef(Field->getType()), guest_triple); switch (typeSize) { // FIXME: should test more case in different triple case 4: GuestRecord += "int " + Name ; break; case 8: GuestRecord += "int " + Name + "[2]"; break; default: std::cout << "Err: unknown type size " << typeSize << std::endl; break; } HostRecord += TypeStringify(StripTypedef(Type), Field, nullptr, PreDecl); } else if (Type->isFunctionPointerType()) { auto FuncType = StripTypedef(Type->getPointeeType()); if (callbacks.count(FuncType)) { std::string FieldStr = callbacks[FuncType]; FieldStr += " "; FieldStr += Name; GuestRecord += FieldStr; HostRecord += FieldStr; } else { std::cout << "Err: FuncPtr(" << Record.type_name << "." << Name << ") is not supported" << std::endl; } } else if (Type->isPointerType()) { auto PointeeType = Type->getPointeeType(); if (PointeeType->isRecordType()) { if (records.count(PointeeType.getTypePtr())) { std::string FieldStr = records[PointeeType.getTypePtr()].type_name; FieldStr += "_ptr " + Name; GuestRecord += FieldStr; HostRecord += "host_" + FieldStr; } else { GuestRecord += "void *" + Name; HostRecord += "void *" + Name; } } else { GuestRecord += "void *" + Name; HostRecord += "void *" + Name; } } else if (Type->isRecordType()) { if (records.count(Type.getTypePtr())) { std::string FieldStr = records[Type.getTypePtr()].type_name; FieldStr += " " + Name; GuestRecord += FieldStr; HostRecord += "host_" + FieldStr; } else { GuestRecord += TypeStringify(StripTypedef(Type), Field, nullptr, PreDecl); HostRecord += TypeStringify(StripTypedef(Type), Field, nullptr, PreDecl); } } else { HostRecord += TypeStringify(StripTypedef(Type), Field, nullptr, PreDecl); GuestRecord += TypeStringify(StripTypedef(Type), Field, nullptr, PreDecl); } GuestRecord += ";\n"; HostRecord += ";\n"; } GuestRecord += "} " + Record.type_name + ", *" + Record.type_name + "_ptr;\n"; HostRecord += "} host_" + Record.type_name + ", *host_" + Record.type_name + "_ptr;\n"; return GuestRecord + HostRecord; } // Gen record convert function between host and guest std::string WrapperGenerator::GenRecordConvert(const RecordInfo &Record) { std::string res; if (Record.guest_size != Record.host_size) { auto RecordDecl = Record.decl; std::vector GuestFieldOff; std::vector HostFieldOff; auto OffDiff = GetRecordFieldOffDiff(Record.type, guest_triple, host_triple, GuestFieldOff, HostFieldOff); int FieldIndex = 0; std::vector AlignDiffFields; uint64_t SizeDiff = Record.guest_size - Record.host_size; for (const auto &Field : RecordDecl->fields()) { if (OffDiff[FieldIndex] == 0) { FieldIndex++; continue; } if (OffDiff[FieldIndex] != SizeDiff) { auto Diff = OffDiff[FieldIndex]; AlignDiffFields.push_back(Field); for (size_t i = FieldIndex; i < OffDiff.size(); i++) { if (OffDiff[i] == Diff) { OffDiff[i] = 0; } else { break; } } } else { AlignDiffFields.push_back(Field); break; } FieldIndex++; } if (!AlignDiffFields.size()) { return res; } res += "void g2h_" + Record.type_name + "(" + "struct host_" + Record.type_name + " *d, struct " + Record.type_name + " *s) {\n"; std::string body = " memcpy(d, s, offsetof(struct " + Record.type_name + ", " + AlignDiffFields[0]->getNameAsString() + "));\n"; std::string offstr = "offsetof(struct " + Record.type_name + ", " + AlignDiffFields[0]->getNameAsString() + ")"; for (size_t i = 0; i < AlignDiffFields.size() - 1; i++) { body += " memcpy(d->" + AlignDiffFields[i]->getNameAsString() + ", " + "s->" + AlignDiffFields[i]->getNameAsString() + ", " + "offsetof(struct " + Record.type_name + ", " + AlignDiffFields[i + 1]->getNameAsString() + ") - " + offstr + ");\n"; offstr = "offsetof(struct " + Record.type_name + ", " + AlignDiffFields[i + 1]->getNameAsString() + ")"; } body += " memcpy(d->" + AlignDiffFields[AlignDiffFields.size() - 1]->getNameAsString() + ", " + "s->" + AlignDiffFields[AlignDiffFields.size() - 1]->getNameAsString() + ", " + std::to_string(GetRecordSize(Record.type, guest_triple)) + " - " + offstr + ");\n"; res += body + "}\n"; res += "void h2g_" + Record.type_name + "(struct " + Record.type_name + " *d, " + "struct host_" + Record.type_name + " *s) {\n"; res += body; res += "}\n"; } return res; } void WrapperGenerator::ParseRecordRecursive( ASTContext *Ctx, const Type *type, bool &Special, std::set &Visited) { auto recordType = type->getAs(); auto RecordDecl = recordType->getDecl(); for (const auto &field : RecordDecl->fields()) { auto FieldType = field->getType(); if (FieldType->isFunctionPointerType()) { auto Record = &records[type]; Record->callback_fields.push_back(field->getType().getTypePtr()); // Record->type_name = Special = true; } else if (FieldType->isPointerType() && FieldType->getPointeeType()->isRecordType()) { auto FieldRecordType = StripTypedef(FieldType->getPointeeType()); if (Visited.find(FieldRecordType) != Visited.end()) continue; Visited.insert(FieldRecordType); bool _Special = false; ParseRecordRecursive(Ctx, FieldRecordType, _Special, Visited); if (_Special) Special = true; } else if (FieldType->isRecordType()) { auto FieldRecordType = StripTypedef(FieldType); if (Visited.find(FieldRecordType) != Visited.end()) continue; Visited.insert(FieldRecordType); bool _Special = false; ParseRecordRecursive(Ctx, FieldRecordType, _Special, Visited); if (_Special) Special = true; } } uint64_t GuestSize = GetRecordSize(type, guest_triple); uint64_t HostSize = GetRecordSize(type, host_triple); auto Record = &records[type]; if (GuestSize != HostSize) { Special = 1; } if (type->isUnionType()) { Record->is_union = true; } if (!Record->decl) { Record->type = type; Record->decl = RecordDecl; if (RecordDecl->getIdentifier()) Record->type_name = RecordDecl->getIdentifier()->getName().str(); } Record->guest_size = GuestSize; Record->host_size = HostSize; if (Record->type_name.empty()) { Record->is_special = false; } else Record->is_special = Special; } // Type to String std::string WrapperGenerator::TypeStringify(const Type *Type, FieldDecl *FieldDecl, ParmVarDecl *ParmDecl, std::string& PreDecl, std::string indent, std::string Name) { std::string res; std::string name = FieldDecl ? FieldDecl->getNameAsString() : (ParmDecl ? ParmDecl->getNameAsString() : Name); if (Type->isPointerType()) { auto PointeeType = Type->getPointeeType(); if (PointeeType->isBuiltinType()) { res += StripTypedef(PointeeType)->getCanonicalTypeInternal().getAsString(); } else if (PointeeType->isRecordType()) { if (records.find(StripTypedef(PointeeType)) != records.end() && records[StripTypedef(PointeeType)].is_special) { res += (PointeeType->isUnionType() ? "union " : "struct ") + records[StripTypedef(PointeeType)].type_name; } else { res += "void"; } } else { res += "void"; } res += " *" + name; } else if (Type->isEnumeralType()) { res += "int " + name; } else if (Type->isRecordType()) { if (records.find(StripTypedef(Type->getCanonicalTypeInternal())) != records.end() && records[StripTypedef(Type->getCanonicalTypeInternal())].is_special) { res += Type->isUnionType() ? "union " : "struct "; res += records[StripTypedef(Type->getCanonicalTypeInternal())].type_name; res += " "; } else { res += AnonRecordDecl(Type->getAs(), PreDecl, indent + " "); } res += name; } else if (Type->isConstantArrayType()) { auto ArrayType = dyn_cast(Type->getAsArrayTypeUnsafe()); int EleSize = ArrayType->getSize().getZExtValue(); if (ArrayType->getElementType()->isPointerType()) { res += "void *"; } else if (ArrayType->getElementType()->isEnumeralType()) { res += "int "; } else if (ArrayType->getElementType()->isRecordType()) { auto RecordType = ArrayType->getElementType()->getAs(); auto RecordDecl = RecordType->getDecl(); if (RecordDecl->isCompleteDefinition()) { auto& Ctx = RecordDecl->getDeclContext()->getParentASTContext(); PreDecl += "#include \""; PreDecl += GetDeclHeaderFile(Ctx, RecordDecl); PreDecl += "\""; PreDecl += "\n"; } res += StripTypedef(ArrayType->getElementType()) ->getCanonicalTypeInternal() .getAsString(); } else { res += StripTypedef(ArrayType->getElementType()) ->getCanonicalTypeInternal() .getAsString(); } res += " "; res += name; res += "["; res += std::to_string(EleSize); res += "]"; } else { res += StripTypedef(Type->getCanonicalTypeInternal()) ->getCanonicalTypeInternal() .getAsString(); res += " "; res += name; } return indent + res; } // Type to String, less detail std::string WrapperGenerator::SimpleTypeStringify(const Type *Type, FieldDecl *FieldDecl, ParmVarDecl *ParmDecl, std::string indent, std::string Name) { std::string res; std::string name = FieldDecl ? FieldDecl->getNameAsString() : (ParmDecl ? ParmDecl->getNameAsString() : Name); if (Type->isPointerType()) { res += "void *" + name; } else if (Type->isEnumeralType()) { res += "int "; res += name; } else if (Type->isRecordType()) { if (records.find(StripTypedef(Type->getCanonicalTypeInternal())) != records.end()) { res += Type->isUnionType() ? "union " : "struct "; res += records[StripTypedef(Type->getCanonicalTypeInternal())].type_name; res += " "; } else { res += SimpleAnonRecordDecl(Type->getAs(), indent); } res += name; } else if (Type->isConstantArrayType()) { auto ArrayType = dyn_cast(Type->getAsArrayTypeUnsafe()); int EleSize = ArrayType->getSize().getZExtValue(); if (ArrayType->getElementType()->isPointerType()) { res += "void *"; } else { res += StripTypedef(ArrayType->getElementType()) ->getCanonicalTypeInternal() .getAsString(); } res += " "; res += name; res += "["; res += std::to_string(EleSize); res += "]"; } else { res += StripTypedef(Type->getCanonicalTypeInternal()) ->getCanonicalTypeInternal() .getAsString(); res += " "; res += name; } return indent + res; } std::string WrapperGenerator::AnonRecordDecl(const RecordType *Type, std::string& PreDecl, std::string indent) { auto RecordDecl = Type->getDecl(); std::string res; res += Type->isUnionType() ? "union {\n" : "struct {\n"; for (const auto &field : RecordDecl->fields()) { auto FieldType = field->getType(); res += TypeStringify(StripTypedef(FieldType), field, nullptr, PreDecl, indent + " "); res += ";\n"; } res += indent + "} "; return res; } std::string WrapperGenerator::SimpleAnonRecordDecl(const RecordType *Type, std::string indent) { auto RecordDecl = Type->getDecl(); std::string res; res += Type->isUnionType() ? "union {\n" : "struct {\n"; for (const auto &field : RecordDecl->fields()) { auto FieldType = field->getType(); res += SimpleTypeStringify(StripTypedef(FieldType), field, nullptr, indent + " "); res += ";\n"; } res += indent + "} "; return res; } // Get func info from FunctionType FuncDefinition WrapperGenerator::GetFuncDefinition(const Type *Type) { FuncDefinition res; std::string PreDecl; auto ProtoType = Type->getAs(); res.ret = StripTypedef(ProtoType->getReturnType()); res.ret_str = TypeStringify(StripTypedef(ProtoType->getReturnType()), nullptr, nullptr, PreDecl); for (unsigned i = 0; i < ProtoType->getNumParams(); i++) { auto ParamType = ProtoType->getParamType(i); res.arg_types.push_back(StripTypedef(ParamType)); res.arg_types_str.push_back( TypeStringify(StripTypedef(ParamType), nullptr, nullptr, PreDecl)); res.arg_names.push_back(std::string("a") + std::to_string(i)); } if (ProtoType->isVariadic()) { res.is_variadaic = true; } res.arg_size = ProtoType->getNumParams(); return res; } // Get funcdecl info from FunctionDecl FuncDefinition WrapperGenerator::GetFuncDefinition(FunctionDecl *Decl) { FuncDefinition res; std::string PreDecl; auto RetType = Decl->getReturnType(); res.ret = RetType.getTypePtr(); res.ret_str = TypeStringify(StripTypedef(RetType), nullptr, nullptr, PreDecl); for (unsigned i = 0; i < Decl->getNumParams(); i++) { auto ParamDecl = Decl->getParamDecl(i); auto ParamType = ParamDecl->getType(); res.arg_types.push_back(ParamType.getTypePtr()); res.arg_types_str.push_back( TypeStringify(StripTypedef(ParamType), nullptr, nullptr, PreDecl)); res.arg_names.push_back(ParamDecl->getNameAsString()); } if (Decl->isVariadic()) { res.is_variadaic = true; } return res; } // Get the offset diff between two different triple std::vector WrapperGenerator::GetRecordFieldOffDiff( const Type *Type, const std::string &GuestTriple, const std::string &HostTriple, std::vector &GuestFieldOff, std::vector &HostFieldOff) { std::string PreDecl; std::string Code = TypeStringify(Type, nullptr, nullptr, PreDecl, "", "dummy;"); std::vector OffsetDiff; GuestFieldOff = GetRecordFieldOff(Code, GuestTriple); HostFieldOff = GetRecordFieldOff(Code, HostTriple); if (GuestFieldOff.size() != HostFieldOff.size()) { // Should not happen std::cout << "Greater field offsets in guest than in host" << std::endl; return OffsetDiff; } for (size_t i = 0; i < GuestFieldOff.size(); i++) { OffsetDiff.push_back(GuestFieldOff[i] - HostFieldOff[i]); } return OffsetDiff; } // Get the size under a specific triple uint64_t WrapperGenerator::GetRecordSize(const Type *Type, const std::string &Triple) { std::string PreDecl; std::string Code = TypeStringify(Type, nullptr, nullptr, PreDecl, "", "dummy;"); auto Size = ::GetRecordSize(PreDecl + Code, Triple); return Size; } // Get the align under a specific triple CharUnits::QuantityType WrapperGenerator::GetRecordAlign(const Type *Type, const std::string &Triple) { std::string PreDecl{}; std::string Code = TypeStringify(Type, nullptr, nullptr, PreDecl, "", "dummy;"); return ::GetRecordAlign(PreDecl + Code, Triple); } // Generate the func sig by type, used for export func std::string WrapperGenerator::GetFuncSig(ASTContext *CTX, const FuncInfo &Func) { std::string sig; auto Decl = Func.decl; auto Type = Decl->getType().getTypePtr(); auto ProtoType = Type->getAs(); auto RetType = ProtoType->getReturnType(); sig += TypeToSig(CTX, RetType.getTypePtr()); sig += "F"; if (Func.has_special_arg || Func.has_special_ret || Func.has_callback_arg) { sig += "E"; } if (ProtoType->getNumParams()) { for (unsigned i = 0; i < ProtoType->getNumParams(); i++) { sig += TypeToSig(CTX, ProtoType->getParamType(i).getTypePtr()); } } else { sig += "v"; } if (Decl->isVariadic()) { sig += "VV"; } return sig; } // Generate the func sig by type, used for callbacks std::string WrapperGenerator::GetFuncSig(ASTContext *CTX, const Type *Type) { std::string sig; auto ProtoType = Type->getAs(); auto RetType = ProtoType->getReturnType(); sig += TypeToSig(CTX, RetType.getTypePtr()); sig += "F"; if (ProtoType->getNumParams()) { for (unsigned i = 0; i < ProtoType->getNumParams(); i++) { sig += TypeToSig(CTX, ProtoType->getParamType(i).getTypePtr()); } } else { sig += "v"; } return sig; }