Add a tool to generate wrapping library (#803)

This tool will automatically generate part of the wrapping library, certainly to avoid a lot of manual writing
hoping to bring some help.
This commit is contained in:
wannacu 2023-03-30 15:57:06 +08:00 committed by GitHub
parent 13bbf105ad
commit 94f451c4b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 1505 additions and 0 deletions

View File

@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.10)
project("helper")
find_package(Clang REQUIRED CONFIG)
add_executable(helper main.cpp gen.cpp)
#target_include_directories(helper SYSTEM PUBLIC ${CLANG_INCLUDE_DIRS})
target_link_libraries(helper PUBLIC clang-cpp LLVM)

41
wrapperhelper/README.md Normal file
View File

@ -0,0 +1,41 @@
This tool is based on liblcangtooling, by parsing the AST of the library header files, generating the required structures of the wrapping library, including structure definitions, export function signatures, callback function wrapping, etc. Of course, this cannot completely automate, only as a reference. At the same time, this tool is also quite rough, and may even have errors.
Usage:
helper <filename> <libname> [guest_triple] [host_triple] -- <clang_flags>
<filename> : set the header file to be parsed
<libname> : set libname required for wrapping func
[guest_triple]: set guest triple arm32/arm64/x86/x64, default is x86
[host_triple]: set host tripe arm32/arm64/x86/x64, default is arm32
-- : is necessary
Usage example:
./helper /usr/include/jpeglib.h libjpeg x86 arm32 --
You will see output similar to wrappedlibjpeg.c file and libjpeg_private.h file. If there are multiple header files to process, write them into a custom header file as input.
The output may like this:
```c
// libjpeg_private.h
GOM(jpeg_read_coefficients, pFEp)
GOM(jpeg_write_coefficients, vFEpp)
GOM(jpeg_copy_critical_parameters, vFEpp)
GOM(jpeg_read_icc_profile, uFEppp)
...
// wrappedlibjpeg.c
typedef void (*vFp_t)(struct jpeg_common_struct * a0);
typedef void (*vFpu_t)(struct jpeg_common_struct * a0, int a1);
...
typedef struct jpeg_error_mgr {
vFp_t error_exit;
vFpu_t emit_message;
vFp_t output_messag
...
EXPORT void my_jpeg_set_marker_processor(void* emu, struct jpeg_decompress_struct * cinfo, int marker_code, void * routine) {
// WARN: This function's arg has structure ptr which is special, may be need wrap it for host
libjpeg62_my_tmy = (libjpeg62_my_t)my_lib->priv.w.p2;
my->jpeg_set_marker_processor(cinfo, marker_code, findjpeg_marker_parser_methodFct(routine))
}
...
```

165
wrapperhelper/ast.h Normal file
View File

@ -0,0 +1,165 @@
#pragma once
#include <clang/AST/ASTConsumer.h>
#include <clang/AST/Attr.h>
#include <clang/AST/Decl.h>
#include <clang/AST/Type.h>
#include <clang/Tooling/Tooling.h>
#include <clang/Tooling/CompilationDatabase.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Frontend/FrontendAction.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Tooling/CommonOptionsParser.h>
#include <ios>
#include <llvm/Support/Casting.h>
#include <cstddef>
#include <fstream>
#include <memory>
#include <string>
#include <iostream>
#include <vector>
#include <cstring>
#include <map>
#include "gen.h"
#include "utils.h"
using namespace clang;
using namespace clang::tooling;
static void ParseParameter(ASTContext* AST, WrapperGenerator* Gen, ParmVarDecl* Decl, FuncInfo* Func) {
auto ParmType = Decl->getType();
if (ParmType->isPointerType()) {
auto PointeeType = ParmType->getPointeeType();
if (PointeeType->isRecordType()) {
if (Gen->records.find(StripTypedef(PointeeType)) == Gen->records.end()) {
auto Record = &Gen->records[StripTypedef(PointeeType)];
if (PointeeType->isUnionType()) {
Record->is_union = true;
}
Record->type = StripTypedef(PointeeType);
Record->decl = PointeeType->getAs<RecordType>()->getDecl();
Record->type_name = Record->decl->getIdentifier()->getName().str();
}
} else if (PointeeType->isPointerType()) {
PointeeType = PointeeType->getPointeeType();
if (PointeeType->isRecordType()) {
if (Gen->records.find(StripTypedef(PointeeType)) == Gen->records.end()) {
auto Record = &Gen->records[StripTypedef(PointeeType)];
if (PointeeType->isUnionType()) {
Record->is_union = true;
}
Record->type = StripTypedef(PointeeType);
Record->decl = PointeeType->getAs<RecordType>()->getDecl();
Record->type_name = Record->decl->getIdentifier()->getName().str();
}
}
}
} else if (ParmType->isRecordType()) {
if (Gen->records.find(StripTypedef(ParmType)) == Gen->records.end()) {
auto Record = &Gen->records[StripTypedef(ParmType)];
if (ParmType->isUnionType()) {
Record->is_union = true;
}
Record->type = StripTypedef(ParmType);
Record->decl = ParmType->getAs<RecordType>()->getDecl();
Record->type_name = Record->decl->getIdentifier()->getName().str();
}
}
}
static void ParseFunction(ASTContext* AST, WrapperGenerator* Gen, FunctionDecl* Decl) {
auto Type = Decl->getType().getTypePtr();
auto FuncInfo = &Gen->funcs[Type];
FuncInfo->type = Type;
FuncInfo->func_name = Decl->getNameAsString();
FuncInfo->decl = Decl;
FuncInfo->callback_args.resize(Decl->getNumParams());
if (Decl->getAttr<clang::WeakRefAttr>()) {
FuncInfo->is_weak = true;
}
if (Decl->isVariadic()) {
FuncInfo->is_variadaic = true;
}
for (int i = 0; i < Decl->getNumParams(); i++) {
auto ParmDecl = Decl->getParamDecl(i);
if (ParmDecl->getType()->isFunctionPointerType()) {
FuncInfo->callback_args[i] = ParmDecl->getType().getTypePtr();
FuncInfo->has_callback_arg = true;
} else {
FuncInfo->callback_args[i] = nullptr;
}
ParseParameter(AST, Gen, ParmDecl, FuncInfo);
}
}
class MyASTVisitor : public clang::RecursiveASTVisitor<MyASTVisitor> {
public:
MyASTVisitor(ASTContext* ctx) : Ctx(ctx) {}
MyASTVisitor(ASTContext* ctx, WrapperGenerator* gen) : Ctx(ctx), Gen(gen) {}
bool VisitFunctionDecl(FunctionDecl* Decl) {
ParseFunction(Ctx, Gen, Decl);
return true;
}
private:
ASTContext* Ctx;
WrapperGenerator* Gen;
};
class MyASTConsumer : public clang::ASTConsumer {
public:
MyASTConsumer(ASTContext* Context, const std::string& libname, const std::string& host_triple, const std::string& guest_triple)
: Visitor(Context, &Generator) {
Generator.Init(libname, host_triple, guest_triple);
}
void HandleTranslationUnit(clang::ASTContext &Ctx) override {
Visitor.TraverseDecl(Ctx.getTranslationUnitDecl());
std::cout << "--------------- Libclangtooling parse complete -----------------\n";
Generator.Prepare(&Ctx);
std::cout << "--------------- Generator prepare complete -----------------\n";
std::ofstream FuncDeclFile(Generator.libname + "_private.h", std::ios::out);
FuncDeclFile << Generator.GenFuncDeclare(&Ctx) << std::endl;
FuncDeclFile.close();
std::ofstream FuncDefinelFile("wrapped" + Generator.libname + ".c", std::ios::out);
FuncDefinelFile << Generator.GenCallbackTypeDefs(&Ctx) << std::endl;
FuncDefinelFile << Generator.GenRecordDeclare(&Ctx) << std::endl;
FuncDefinelFile << Generator.GenRecordConvert(&Ctx) << std::endl;
FuncDefinelFile << Generator.GenCallbackWrap(&Ctx) << std::endl;
FuncDefinelFile << Generator.GenFuncDefine(&Ctx) << std::endl;
FuncDefinelFile.close();
std::cout << "--------------- Generator gen complete -----------------\n";
}
private:
MyASTVisitor Visitor;
WrapperGenerator Generator;
};
class MyGenAction : public clang::ASTFrontendAction {
public:
MyGenAction(const std::string& libname, const std::string& host_triple, const std::string& guest_triple) :
libname(libname), host_triple(host_triple), guest_triple(guest_triple) {}
std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance& Compiler, clang::StringRef file) override {
return std::make_unique<MyASTConsumer>(&Compiler.getASTContext(), libname, host_triple, guest_triple);
}
private:
std::string libname;
std::string host_triple;
std::string guest_triple;
};
class MyFrontendActionFactory : public clang::tooling::FrontendActionFactory {
public:
MyFrontendActionFactory(const std::string& libname, const std::string& host_triple, const std::string& guest_triple) :
libname(libname), host_triple(host_triple), guest_triple(guest_triple) {}
private:
std::unique_ptr<clang::FrontendAction> create() override {
return std::make_unique<MyGenAction>(libname, host_triple, guest_triple);
}
private:
std::string libname;
std::string host_triple;
std::string guest_triple;
};

913
wrapperhelper/gen.cpp Normal file
View File

@ -0,0 +1,913 @@
#include "gen.h"
#include "utils.h"
#include <clang/AST/ASTContext.h>
#include <clang/AST/Decl.h>
#include <clang/AST/Type.h>
#include <clang/Basic/LLVM.h>
// Prepare for generation, collect the structures and functions that need to be prcessed
void WrapperGenerator::Prepare(clang::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<clang::TypedefType>()->getDecl()->getNameAsString();
} else if (Type) {
callbacks[StripTypedef(Type->getPointeeType())] =
GetFuncSig(Ctx, Type->getPointeeType().getTypePtr()) + "_t";
}
}
}
std::vector<const clang::Type *> Types;
for (const auto &record_pair : records) {
auto Record = &record_pair.second;
Types.push_back(record_pair.first);
}
for (auto Type : Types) {
std::set<const clang::Type *> 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 Type : it->second.callback_fields) {
if (Type->isTypedefNameType()) {
callbacks[StripTypedef(Type->getPointeeType())] =
Type->getAs<clang::TypedefType>()->getDecl()->getNameAsString();
} else {
callbacks[StripTypedef(Type->getPointeeType())] =
GetFuncSig(Ctx, Type->getPointeeType().getTypePtr()) + "_t";
}
}
++it;
}
}
for (auto &func_pair : funcs) {
for (int 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(clang::ASTContext *Ctx) {
std::string res{};
for (auto callback : callbacks) {
auto Type = callback.first;
auto Definiton = GetFuncDefinition(Type);
res += "typedef " + Definiton.ret_str + "(*" + callback.second + ")(";
for (int i = 0; i < Definiton.arg_size - 1; i++) {
res += Definiton.arg_types_str[i];
res += " ";
res += Definiton.arg_names[i];
res += ", ";
}
if (Definiton.arg_size) {
res += Definiton.arg_types_str[Definiton.arg_size - 1];
res += " ";
res += Definiton.arg_names[Definiton.arg_size - 1];
}
res += ");";
res += "\n";
}
return res;
}
// Gen function declare
std::string WrapperGenerator::GenDeclare(clang::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(clang::ASTContext *Ctx,
const RecordInfo &Record) {
std::string RecordStr{};
RecordStr += "typedef ";
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 += TypeStrify(StripTypedef(Type), Field, nullptr);
}
} else {
RecordStr += TypeStrify(StripTypedef(Type), Field, nullptr);
}
RecordStr += ";\n";
}
RecordStr += "}";
RecordStr += Record.type_name + ", *" + Record.type_name + "_ptr;\n";
return RecordStr;
}
std::string WrapperGenerator::GenCallbackWrap(clang::ASTContext *Ctx,
const FuncInfo &Func) {
std::string res{};
for (int 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 =
std::string("my_") + Func.decl->getParamDecl(i)->getNameAsString();
res += "#define GO(A) \\\n";
res +=
std::string("static uintptr_t ") + my_funcname + "_fct_##A = 0; \\\n";
res += 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];
res += " ";
res += Definition.arg_names[i];
res += ", ";
}
res += Definition.arg_types_str[arg_size - 1];
res += " ";
res += Definition.arg_names[arg_size - 1];
}
res += ") {\\\n";
res += " ";
res +=
"return RunFunction(my_context, " + my_funcname + "_fct_##A" + ", ",
std::to_string(arg_size);
if (arg_size) {
for (int i = 0; i < arg_size; i++) {
res += ", " + Definition.arg_names[i];
}
}
res += ");\\\n";
res += "}\n";
res += "#undef GO\n";
res += "static void* find" + funcname + "Fct(void* fct) {\n";
res += " if(!fct) return fct;\n";
res += " if(GetNativeFnc((uintptr_t)fct)) return "
"GetNativeFnc((uintptr_t)fct);\n";
res += " #define GO(A) if(" + my_funcname +
"_fct_##A == (uintptr_t)fct) return " + my_funcname + "_##A;}\n";
res += " SUPER()\n";
res += " #undef GO\n";
res += " #define GO(A) if(" + my_funcname + "_fct_##A == 0) {" +
my_funcname + "_fct_##A = (uintptr_t)fct;" + "return " +
my_funcname + "_##A;}\n";
res += " SUPER()\n";
res += " #undef GO\n";
res += " return NULL;\n";
res += "}\n";
}
}
return res;
}
std::string WrapperGenerator::GenCallbackWrap(clang::ASTContext *Ctx,
const RecordInfo &Struct) {
std::string res{};
auto Type = Struct.type;
auto RecordType = Type->getAs<clang::RecordType>();
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 += "#define GO(A) \\\n";
res +=
std::string("static uintptr_t ") + my_funcname + "_fct_##A = 0;\\\n";
res += 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];
res += " ";
res += Definition.arg_names[i];
res += ", ";
}
res += Definition.arg_types_str[arg_size - 1];
res += " ";
res += Definition.arg_names[arg_size - 1];
}
res += ") {\\\n";
res += " ";
res += "return RunFunction(my_context, " + my_funcname + "_fct_##A" +
", " + std::to_string(arg_size);
if (arg_size) {
for (int i = 0; i < arg_size; i++) {
res += ", " + Definition.arg_names[i];
}
}
res += ");\\\n";
res += "}\n";
res += "#undef GO\n";
res += "static void* find" + funcname + "Fct(void* fct) {\n";
res += " if(!fct) return fct;\n";
res += " if(GetNativeFnc((uintptr_t)fct)) return "
"GetNativeFnc((uintptr_t)fct);\n";
res += " #define GO(A) if(" + my_funcname +
"_fct_##A == (uintptr_t)fct) return " + my_funcname + "_##A;}\n";
res += " SUPER()\n";
res += " #undef GO\n";
res += " #define GO(A) if(" + my_funcname + "_fct_##A == 0) {" +
my_funcname + "_fct_##A = (uintptr_t)fct;" + "return " +
my_funcname + "_##A;}\n";
res += " SUPER()\n";
res += " #undef GO\n";
res += " return NULL;\n";
res += "}\n";
}
}
return res;
}
std::string WrapperGenerator::GenDefine(clang::ASTContext *Ctx,
const FuncInfo &Func) {
std::string Res{};
auto Definition = GetFuncDefinition(Func.decl);
std::string Sig = GetFuncSig(Ctx, Func.type);
Res += "EXPORT ";
Res += Definition.ret_str;
Res += "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(
Definition.arg_types[i]->getPointeeType().getTypePtr())) {
Res +=
Definition.arg_types[i]->getCanonicalTypeInternal().getAsString();
} else {
Res += Definition.arg_types_str[i];
}
} else {
Res += Definition.arg_types_str[i];
}
Res += " ";
Res += Definition.arg_names[i];
Res += ", ";
}
if (Definition.arg_types[arg_size - 1]->isPointerType()) {
auto PointeeType = Definition.arg_types[arg_size - 1]->getPointeeType();
if (records.count(Definition.arg_types[arg_size - 1]
->getPointeeType()
.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";
std::string FuncBodyStr{};
if (Func.has_special_arg) {
FuncBodyStr += " // WARN: This function's arg has structure ptr which is "
"special, may be need wrap it for host\n";
} else if (Func.has_special_ret) {
FuncBodyStr += " // WARN: This function's ret structure ptr which is "
"special, may be need wrap it for guest\n";
}
if (Func.has_callback_arg) {
FuncBodyStr += " " + my_lib_type + "my = " + "(" + my_lib_type + ")" +
my_lib + "->priv.w.p2;\n";
FuncBodyStr += " 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()) {
FuncBodyStr +=
"find" + Func.func_name + "_arg" + std::to_string(i) + "Fct";
} else {
FuncBodyStr += "find" +
Func.callback_args[i]
->getAs<clang::TypedefType>()
->getDecl()
->getNameAsString() +
"Fct";
}
FuncBodyStr += "(" + Definition.arg_names[i] + ")";
} else {
FuncBodyStr += Definition.arg_names[i];
}
FuncBodyStr += ", ";
}
if (Func.callback_args[arg_size - 1]) {
if (!Func.callback_args[arg_size - 1]->isTypedefNameType()) {
FuncBodyStr += "find" + Func.func_name + "_arg" +
std::to_string(arg_size - 1) + "Fct";
} else {
FuncBodyStr += "find" +
Func.callback_args[arg_size - 1]
->getAs<clang::TypedefType>()
->getDecl()
->getNameAsString() +
"Fct";
}
FuncBodyStr += "(" + Definition.arg_names[arg_size - 1] + ")";
} else {
FuncBodyStr += Definition.arg_names[arg_size - 1];
}
FuncBodyStr += ")\n";
}
} else {
FuncBodyStr += " " + my_lib_type + "my = " + "(" + my_lib_type + ")" +
my_lib + "->priv.w.p2;\n";
FuncBodyStr += " my->" + Func.func_name + "(";
if (arg_size) {
for (int i = 0; i < arg_size - 1; i++) {
FuncBodyStr += Definition.arg_names[i];
FuncBodyStr += ", ";
}
FuncBodyStr += Definition.arg_names[arg_size - 1];
FuncBodyStr += ");\n";
}
}
Res += FuncBodyStr;
Res += "}\n";
return Res;
}
std::string WrapperGenerator::GenDeclareDiffTriple(
clang::ASTContext *Ctx, const RecordInfo &Record,
const std::string &GuestTriple, const std::string &HostTriple) {
std::string GuestRecord{};
std::string HostRecord{};
std::vector<int> GuestFieldOff;
std::vector<int> 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);
int GuestRecordSize = GetRecordSize(Record.type, GuestTriple);
int HostRecordSize = GetRecordSize(Record.type, HostTriple);
int SizeDiff = GuestRecordSize - HostRecordSize;
int FieldIndex = 0;
std::set<clang::FieldDecl *> AlignDiffFields;
for (const auto &Field : Record.decl->fields()) {
if (OffDiff[FieldIndex] == 0) {
FieldIndex++;
continue;
}
auto Type = Field->getType();
std::string Name = Field->getNameAsString();
if (OffDiff[FieldIndex] != SizeDiff) {
auto Diff = OffDiff[FieldIndex];
AlignDiffFields.insert(Field);
for (int 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()) {
switch (GetTypeSize(StripTypedef(Field->getType()), guest_triple)) {
// FIXME: should test more case in different triple
case 4:
GuestRecord += "int " + Name;
case 8:
GuestRecord += "int " + Name + "[2]";
default:
break;
}
HostRecord += TypeStrify(StripTypedef(Type), Field, nullptr);
} 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\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;
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 += " ";
FieldStr += Name;
GuestRecord += FieldStr;
HostRecord += "host_" + FieldStr;
} else {
GuestRecord += TypeStrify(StripTypedef(Type), Field, nullptr);
HostRecord += TypeStrify(StripTypedef(Type), Field, nullptr);
}
} else {
HostRecord += TypeStrify(StripTypedef(Type), Field, nullptr);
GuestRecord += TypeStrify(StripTypedef(Type), Field, nullptr);
}
GuestRecord += ";\n";
HostRecord += ";\n";
}
GuestRecord += "}";
GuestRecord += Record.type_name + ", *" + Record.type_name + "_ptr;\n";
HostRecord += "}";
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<int> GuestFieldOff;
std::vector<int> HostFieldOff;
auto OffDiff = GetRecordFieldOffDiff(Record.type, guest_triple, host_triple,
GuestFieldOff, HostFieldOff);
int FieldIndex = 0;
std::vector<clang::FieldDecl *> AlignDiffFields;
int SizeDiff = Record.guest_size - Record.host_size;
for (const auto &Field : RecordDecl->fields()) {
if (OffDiff[FieldIndex] == 0) {
FieldIndex++;
continue;
}
auto Type = Field->getType();
std::string Name = Field->getNameAsString();
if (OffDiff[FieldIndex] != SizeDiff) {
auto Diff = OffDiff[FieldIndex];
AlignDiffFields.push_back(Field);
for (int 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 (int i = 1; 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;
res += "}\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(
clang::ASTContext *Ctx, const clang::Type *Type, bool &Special,
std::set<const clang::Type *> &Visited) {
auto RecordType = Type->getAs<clang::RecordType>();
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;
}
}
int GuestSize = GetRecordSize(Type, guest_triple);
int 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::TypeStrify(const clang::Type *Type,
clang::FieldDecl *FieldDecl,
clang::ParmVarDecl *ParmDecl,
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 {\n" : "struct ";
res += records[StripTypedef(PointeeType)].type_name;
} else {
res += "void";
}
} else {
res += "void";
}
res += " * " + name;
} else if (Type->isEnumeralType()) {
res += "int ";
res += name;
} else if (Type->isRecordType()) {
if (records.find(StripTypedef(Type->getCanonicalTypeInternal())) !=
records.end() &&
records[StripTypedef(Type->getCanonicalTypeInternal())].is_special) {
res += Type->isUnionType() ? "union {\n" : "struct ";
res += records[StripTypedef(Type->getCanonicalTypeInternal())].type_name;
res += " ";
} else {
res += AnonRecordDecl(Type->getAs<clang::RecordType>());
}
res += name;
} else if (Type->isConstantArrayType()) {
auto ArrayType =
clang::dyn_cast<clang::ConstantArrayType>(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 res;
}
// Type to String, less detail
std::string WrapperGenerator::SimpleTypeStrify(const clang::Type *Type,
clang::FieldDecl *FieldDecl,
clang::ParmVarDecl *ParmDecl,
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 {\n" : "struct ";
res += records[StripTypedef(Type->getCanonicalTypeInternal())].type_name;
res += " ";
} else {
res += SimpleAnonRecordDecl(Type->getAs<clang::RecordType>());
}
res += name;
} else if (Type->isConstantArrayType()) {
auto ArrayType =
clang::dyn_cast<clang::ConstantArrayType>(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 res;
}
std::string WrapperGenerator::AnonRecordDecl(const clang::RecordType *Type) {
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 += " ";
res += TypeStrify(StripTypedef(FieldType), field, nullptr);
res += ";\n";
}
res += " } ";
return res;
}
std::string
WrapperGenerator::SimpleAnonRecordDecl(const clang::RecordType *Type) {
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 += " ";
res += SimpleTypeStrify(StripTypedef(FieldType), field, nullptr);
res += ";\n";
}
res += " } ";
return res;
}
// Get func info from FunctionType
FuncDefinition WrapperGenerator::GetFuncDefinition(const clang::Type *Type) {
FuncDefinition res;
auto ProtoType = Type->getAs<clang::FunctionProtoType>();
res.ret = StripTypedef(ProtoType->getReturnType());
res.ret_str =
TypeStrify(StripTypedef(ProtoType->getReturnType()), nullptr, nullptr);
for (int i = 0; i < ProtoType->getNumParams(); i++) {
auto ParamType = ProtoType->getParamType(i);
res.arg_types.push_back(StripTypedef(ParamType));
res.arg_types_str.push_back(
TypeStrify(StripTypedef(ParamType), nullptr, nullptr));
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(clang::FunctionDecl *Decl) {
FuncDefinition res;
auto RetType = Decl->getReturnType();
res.ret = RetType.getTypePtr();
res.ret_str = TypeStrify(StripTypedef(RetType), nullptr, nullptr, "");
for (int 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(
TypeStrify(StripTypedef(ParamType), nullptr, nullptr, ""));
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<int> WrapperGenerator::GetRecordFieldOffDiff(
const clang::Type *Type, const std::string &GuestTriple,
const std::string &HostTriple, std::vector<int> &GuestFieldOff,
std::vector<int> &HostFieldOff) {
std::string Code = TypeStrify(Type, nullptr, nullptr, "dummy;");
return ::GetRecordFieldOffDiff(Code, GuestTriple, HostTriple, GuestFieldOff,
HostFieldOff);
}
// Get the size under a specific triple
int WrapperGenerator::GetRecordSize(const clang::Type *Type,
const std::string &Triple) {
std::string Code = TypeStrify(Type, nullptr, nullptr, "dummy;");
return ::GetRecordSize(Code, Triple);
}
// Get the align under a specific triple
int WrapperGenerator::GetRecordAlign(const clang::Type *Type,
const std::string &Triple) {
std::string Code = TypeStrify(Type, nullptr, nullptr, "dummy;");
return ::GetRecordAlign(Code, Triple);
}
// Generate the func sig by type, used for export func
std::string WrapperGenerator::GetFuncSig(clang::ASTContext *CTX,
const FuncInfo &Func) {
std::string sig{};
auto Decl = Func.decl;
auto Type = Decl->getType().getTypePtr();
auto ProtoType = Type->getAs<clang::FunctionProtoType>();
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 (int 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(clang::ASTContext *CTX,
const clang::Type *Type) {
std::string sig{};
auto ProtoType = Type->getAs<clang::FunctionProtoType>();
auto RetType = ProtoType->getReturnType();
sig += TypeToSig(CTX, RetType.getTypePtr());
sig += "F";
if (ProtoType->getNumParams()) {
for (int i = 0; i < ProtoType->getNumParams(); i++) {
sig += TypeToSig(CTX, ProtoType->getParamType(i).getTypePtr());
}
} else {
sig += "v";
}
return sig;
}

143
wrapperhelper/gen.h Normal file
View File

@ -0,0 +1,143 @@
#pragma once
#include <clang/AST/ASTContext.h>
#include <clang/AST/Type.h>
#include <cstdint>
#include <string>
#include <vector>
#include <set>
struct FuncDefinition {
std::vector<const clang::Type*> arg_types;
std::vector<std::string> arg_types_str;
std::vector<std::string> arg_names;
const clang::Type* ret;
std::string ret_str;
int arg_size;
bool is_variadaic;
};
struct FuncInfo {
const clang::Type* type;
clang::FunctionDecl* decl;
std::string func_name;
bool is_weak;
bool is_variadaic;
bool has_special_arg;
bool has_special_ret;
bool has_callback_arg;
std::vector<const clang::Type*> callback_args;
};
struct RecordInfo {
const clang::Type* type;
clang::RecordDecl* decl;
std::string type_name;
bool is_union;
bool is_special;
int guest_size;
int host_size;
std::vector<const clang::Type*> callback_fields;
};
struct ObjectInfo {
const clang::Type* type;
std::string object_name;
};
struct WrapperGenerator {
void Init(const std::string& libname, const std::string& host_triple, const std::string& guest_triple) {
this->host_triple = host_triple;
this->guest_triple = guest_triple;
this->libname = libname;
this->my_lib_type = libname + "_my_t";
this->my_lib = "my_lib";
}
void Prepare(clang::ASTContext* Ctx);
std::string GenCallbackTypeDefs(clang::ASTContext* Ctx);
std::string GenFuncDeclare(clang::ASTContext* Ctx) {
std::string res{};
for (const auto& func : funcs) {
res += GenDeclare(Ctx, func.second);
}
return res;
}
std::string GenRecordDeclare(clang::ASTContext* Ctx) {
std::string res{};
for (const auto& st : records) {
if (st.second.host_size == st.second.guest_size)
res += GenDeclare(Ctx, st.second);
else {
res += GenDeclareDiffTriple(Ctx, st.second, guest_triple, host_triple);
}
}
return res;
}
std::string GenFuncDefine(clang::ASTContext* Ctx) {
std::string res{};
for (const auto& func : funcs) {
res += GenDefine(Ctx, func.second);
}
return res;
}
std::string GenCallbackWrap(clang::ASTContext* Ctx) {
std::string res{};
for (const auto& func : funcs) {
res += GenCallbackWrap(Ctx, func.second);
}
for (const auto& st : records) {
res += GenCallbackWrap(Ctx, st.second);
}
return res;
}
std::string GenRecordConvert(clang::ASTContext* Ctx) {
std::string res{};
for (const auto& record : records) {
if (record.second.host_size != record.second.guest_size) {
res += GenRecordConvert(record.second);
}
}
return res;
}
std::map<const clang::Type*, FuncInfo> funcs;
std::map<const clang::Type*, RecordInfo> records;
std::map<const clang::Type*, ObjectInfo> objects;
std::map<const clang::Type*, std::string> callbacks;
std::string host_triple;
std::string guest_triple;
std::string libname;
std::string my_lib_type;
std::string my_lib;
private:
std::string GenRecordConvert(const RecordInfo& Record);
std::string GenDeclare(clang::ASTContext* Ctx, const FuncInfo& Func);
std::string GenDefine(clang::ASTContext* Ctx, const FuncInfo& Func);
std::string GenCallbackWrap(clang::ASTContext* Ctx, const FuncInfo& Func);
std::string GenDeclareDiffTriple(clang::ASTContext* Ctx, const RecordInfo& Record, const std::string& GuestTriple, const std::string& HostTriple);
std::string GenDeclare(clang::ASTContext* Ctx, const RecordInfo& Struct);
std::string GenCallbackWrap(clang::ASTContext* Ctx, const RecordInfo& Struct);
void ParseRecordRecursive(clang::ASTContext* Ctx, const clang::Type* ReocrdType, bool& Special, std::set<const clang::Type*>& Visited);
std::string TypeStrify(const clang::Type* Type, clang::FieldDecl* FieldDecl, clang::ParmVarDecl* ParmDecl, std::string Name = "");
std::string SimpleTypeStrify(const clang::Type* Type, clang::FieldDecl* FieldDecl, clang::ParmVarDecl* ParmDecl, std::string Name = "");
std::string AnonRecordDecl(const clang::RecordType* Type);
std::string SimpleAnonRecordDecl(const clang::RecordType* Type);
FuncDefinition GetFuncDefinition(const clang::Type* Type);
FuncDefinition GetFuncDefinition(clang::FunctionDecl* Decl);
int GetRecordSize(const clang::Type* Type, const std::string& Triple);
std::vector<int> GetRecordFieldOffDiff(const clang::Type* Type, const std::string& GuestTriple, const std::string& HostTriple, std::vector<int>& GuestFieldOff, std::vector<int>& HostFieldOff);
int GetRecordAlign(const clang::Type* Type, const std::string& Triple);
std::string GetFuncSig(clang::ASTContext* CTX, const FuncInfo& Decl);
std::string GetFuncSig(clang::ASTContext* CTX, const clang::Type* Type);
};

61
wrapperhelper/main.cpp Normal file
View File

@ -0,0 +1,61 @@
#include "ast.h"
#include "utils.h"
void dump_usage() {
std::string Usage = R"usage(
usage: command <filename> <libname> [guest_triple] [host_triple] -- <clang_flags>
<filename> : set the header file to be parsed
<libname> : set libname required for wrapping func
[guest_triple]: set guest triple arm32/arm64/x86/x64, default is x86
[host_triple]: set host tripe arm32/arm64/x86/x64, default is arm32
-- : is necessary
)usage";
std::cerr << Usage << std::endl;
}
std::string parse_triple(const char* arg) {
if (strcmp(arg, "arm32") == 0) {
return TripleName[ARM32];
} else if (strcmp(arg, "arm64") == 0) {
return TripleName[ARM64];
} else if (strcmp(arg, "x86") == 0) {
return TripleName[X86];
} else if (strcmp(arg, "x64") == 0) {
return TripleName[X64];
} else {
return "";
}
}
using namespace clang::tooling;
int main(int argc, const char* argv[]) {
if (argc < 4) {
dump_usage();
return 0;
}
std::string libname = argv[2];
std::string guest_triple = TripleName[X86];
std::string host_triple = TripleName[ARM32];
if (argc >= 5) {
guest_triple = parse_triple(argv[3]);
}
if (argc >= 6) {
host_triple = parse_triple(argv[4]);
}
bool has_nessary_tag = false;
for (int i = 0; i < argc; i++) {
if (strcmp(argv[i], "--") == 0) {
has_nessary_tag = true;
break;
}
}
if (!has_nessary_tag) {
std::cerr << "Please add '--' after triple arg" << std::endl;
return 0;
}
std::string err;
auto compile_db = FixedCompilationDatabase::loadFromCommandLine(argc, argv, err);
ClangTool Tool(*compile_db, {argv[1]});
return Tool.run(std::make_unique<MyFrontendActionFactory>(libname, host_triple, guest_triple).get());
}

175
wrapperhelper/utils.h Normal file
View File

@ -0,0 +1,175 @@
#pragma once
#include <clang/AST/Decl.h>
#include <clang/AST/Type.h>
#include <clang/Tooling/Tooling.h>
#include <clang/AST/RecordLayout.h>
#include <clang/AST/Decl.h>
#include <llvm/ADT/Triple.h>
#include <llvm/Support/Casting.h>
#include <cstddef>
#include <cstring>
#include <iostream>
enum Triple {
X86,
X64,
ARM32,
ARM64,
RISCV64,
TripleCnt,
};
static const char* TripleName[TripleCnt] = {
"i386-pc-linux-gnu",
"x86_64-pc-linux-gnu",
"armv7-unknown-linux-gnueabihf",
"aarch64-unknown-linux-gnu",
"riscv64-unknown-linux-gnu"
};
static const clang::Type* StripTypedef(clang::QualType type) {
if (type->isTypedefNameType()) {
return StripTypedef(type->getAs<clang::TypedefType>()->getDecl()->getUnderlyingType());
} else {
return type.getTypePtr();
}
}
static int GetRecordSize(const std::string& Code, const std::string& Triple) {
std::vector<std::string> Args = {"-target", Triple};
std::unique_ptr<clang::ASTUnit> 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<clang::RecordDecl>(Decl)) {
return Ctx.getTypeSize(RecordDecl->getTypeForDecl()) / 8;
}
}
return 0;
}
static std::vector<int> GetRecordFieldOff(const std::string& Code, const std::string& Triple) {
std::vector<int> FieldOff;
std::vector<std::string> Args = {"-target", Triple};
std::unique_ptr<clang::ASTUnit> 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<clang::RecordDecl>(Decl)) {
auto& RecordLayout = Ctx.getASTRecordLayout(RecordDecl);
for (int i = 0; i < RecordLayout.getFieldCount(); i++) {
FieldOff.push_back(RecordLayout.getFieldOffset(i) / 8);
}
break;
}
}
return FieldOff;
}
static int GetRecordAlign(const std::string& Code, const std::string& Triple) {
std::vector<std::string> Args = {"-target", Triple};
std::unique_ptr<clang::ASTUnit> 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<clang::RecordDecl>(Decl)) {
auto& RecordLayout = Ctx.getASTRecordLayout(RecordDecl);
for (int i = 0; i < RecordLayout.getFieldCount(); i++) {
return RecordLayout.getAlignment().getQuantity() / 8;
}
break;
}
}
return 0;
}
static std::vector<int> GetRecordFieldOffDiff(const std::string& Code, const std::string& GuestTriple, const std::string& HostTriple, std::vector<int>& GuestFieldOff, std::vector<int>& HostFieldOff) {
std::vector<int> OffsetDiff;
GuestFieldOff = GetRecordFieldOff(Code, GuestTriple);
HostFieldOff = GetRecordFieldOff(Code, HostTriple);
if (GuestFieldOff.size() != HostFieldOff.size()) {
return OffsetDiff;
}
for (int i = 0; i < GuestFieldOff.size(); i++) {
OffsetDiff.push_back(GuestFieldOff[i] - HostFieldOff[i]);
}
return OffsetDiff;
}
static int GetTypeSize(const clang::Type* Type, const std::string& Triple) {
std::string Code = Type->getCanonicalTypeInternal().getAsString() + " dummy;";
std::vector<std::string> Args = {"-target", Triple};
std::unique_ptr<clang::ASTUnit> AST = clang::tooling::buildASTFromCodeWithArgs(Code, Args);
auto& Ctx = AST->getASTContext();
auto TranslateDecl = Ctx.getTranslationUnitDecl();
for (const auto& Decl : TranslateDecl->decls()) {
if (const auto VarDecl = clang::dyn_cast<clang::VarDecl>(Decl)) {
return Ctx.getTypeSize(VarDecl->getType()) / 8;
}
}
return 0;
}
static int GetTypeAlign(const clang::Type* Type, const std::string& Triple) {
std::string Code = Type->getCanonicalTypeInternal().getAsString() + " dummy;";
std::vector<std::string> Args = {"-target", Triple};
std::unique_ptr<clang::ASTUnit> AST = clang::tooling::buildASTFromCodeWithArgs(Code, Args);
auto& Ctx = AST->getASTContext();
auto TranslateDecl = Ctx.getTranslationUnitDecl();
for (const auto& Decl : TranslateDecl->decls()) {
if (const auto VarDecl = clang::dyn_cast<clang::VarDecl>(Decl)) {
return Ctx.getTypeAlign(VarDecl->getType());;
}
}
return 0;
}
static std::string TypeToSig(clang::ASTContext* Ctx, const clang::Type* Type) {
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 "i";
case 8:
return "I";
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 "u";
case 8:
return "U";
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";
default:
std::cout << "Unsupported Floating Type: " << Type->getCanonicalTypeInternal().getAsString() << std::endl;
}
} else {
std::cout << "Unsupported Type: " << Type->getCanonicalTypeInternal().getAsString() << std::endl;
}
return "?";
}