mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
229 lines
8.5 KiB
C++
229 lines
8.5 KiB
C++
//
|
|
// Copyright rev.ng Srls. See LICENSE.md for details.
|
|
//
|
|
|
|
#include "llvm/IR/Constants.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
|
|
#include "clang/AST/ASTContext.h"
|
|
#include "clang/AST/Type.h"
|
|
|
|
#include "revng/Support/Assert.h"
|
|
|
|
#include "revng-c/Decompiler/DLALayouts.h"
|
|
|
|
#include "DecompilationHelpers.h"
|
|
#include "IRASTTypeTranslation.h"
|
|
#include "Mangling.h"
|
|
|
|
namespace clang {
|
|
class TranslationUnitDecl;
|
|
} // end namespace clang
|
|
|
|
using clang::QualType;
|
|
|
|
// TODO: this should be a RecursiveCoroutine
|
|
DeclCreator::TypeDeclOrQualType
|
|
DeclCreator::createTypeFromLayout(const dla::Layout *L,
|
|
clang::ASTContext &ClangCtx,
|
|
llvm::LLVMContext &LLVMCtx) {
|
|
TypeDeclOrQualType Result = ClangCtx.VoidTy;
|
|
|
|
using LayoutKind = dla::Layout::LayoutKind;
|
|
revng_assert(L->size());
|
|
|
|
// Build the type decl for the C type associated to layout.
|
|
switch (L->getKind()) {
|
|
|
|
case LayoutKind::Padding: {
|
|
QualType CharTy = ClangCtx.CharTy;
|
|
|
|
if (L->size() > 1) {
|
|
|
|
auto ByteSize = L->size();
|
|
llvm::APInt ArraySize(64 /* bits */, ByteSize);
|
|
auto ArraySizeKind = clang::ArrayType::ArraySizeModifier::Normal;
|
|
|
|
Result = ClangCtx.getConstantArrayType(CharTy,
|
|
ArraySize,
|
|
nullptr,
|
|
ArraySizeKind,
|
|
0);
|
|
|
|
} else {
|
|
Result = CharTy;
|
|
}
|
|
|
|
} break;
|
|
|
|
case LayoutKind::Base: {
|
|
auto *Base = llvm::cast<dla::BaseLayout>(L);
|
|
auto ByteSize = Base->size();
|
|
revng_assert(ByteSize);
|
|
bool IsPowerOf2 = (ByteSize & (ByteSize - 1)) == 0;
|
|
revng_assert(IsPowerOf2);
|
|
revng_assert(ByteSize <= 16);
|
|
auto *IntTy = llvm::IntegerType::get(LLVMCtx, ByteSize * 8);
|
|
Result = getOrCreateType(IntTy,
|
|
nullptr,
|
|
ClangCtx,
|
|
*ClangCtx.getTranslationUnitDecl());
|
|
} break;
|
|
|
|
case LayoutKind::Array: {
|
|
|
|
auto *Array = llvm::cast<dla::ArrayLayout>(L);
|
|
dla::Layout *ElementLayout = Array->getElem();
|
|
|
|
TypeDeclOrQualType EQTy = getOrCreateTypeFromLayout(ElementLayout,
|
|
ClangCtx,
|
|
LLVMCtx);
|
|
QualType ElemQualTy = DeclCreator::getQualType(EQTy);
|
|
|
|
auto ArraySizeKind = clang::ArrayType::ArraySizeModifier::Normal;
|
|
if (Array->hasKnownLength()) {
|
|
llvm::APInt ArraySize(64 /* bits */, Array->length());
|
|
Result = ClangCtx.getConstantArrayType(ElemQualTy,
|
|
ArraySize,
|
|
nullptr,
|
|
ArraySizeKind,
|
|
0);
|
|
} else {
|
|
Result = ClangCtx.getIncompleteArrayType(ElemQualTy, ArraySizeKind, 0);
|
|
}
|
|
|
|
} break;
|
|
|
|
case LayoutKind::Struct: {
|
|
auto *Struct = llvm::cast<dla::StructLayout>(L);
|
|
|
|
std::string TypeName = getUniqueTypeNameForDecl(nullptr);
|
|
clang::IdentifierInfo &TypeId = ClangCtx.Idents.get(TypeName);
|
|
clang::TranslationUnitDecl &TUDecl = *ClangCtx.getTranslationUnitDecl();
|
|
auto *StructDecl = clang::RecordDecl::Create(ClangCtx,
|
|
clang::TTK_Struct,
|
|
&TUDecl,
|
|
clang::SourceLocation{},
|
|
clang::SourceLocation{},
|
|
&TypeId,
|
|
nullptr);
|
|
|
|
StructDecl->startDefinition();
|
|
|
|
for (const auto &Group : llvm::enumerate(Struct->fields())) {
|
|
// Create the type decl for the PointerLayout.
|
|
const dla::Layout *PointedLayout = Group.value();
|
|
TypeDeclOrQualType FTy = getOrCreateTypeFromLayout(PointedLayout,
|
|
ClangCtx,
|
|
LLVMCtx);
|
|
QualType FieldTy = DeclCreator::getQualType(FTy);
|
|
clang::TypeSourceInfo *TI = ClangCtx.CreateTypeSourceInfo(FieldTy);
|
|
const std::string FieldName = std::string("field_")
|
|
+ std::to_string(Group.index());
|
|
clang::IdentifierInfo &FieldId = ClangCtx.Idents.get(FieldName);
|
|
auto *Field = clang::FieldDecl::Create(ClangCtx,
|
|
StructDecl,
|
|
clang::SourceLocation{},
|
|
clang::SourceLocation{},
|
|
&FieldId,
|
|
FieldTy,
|
|
TI,
|
|
nullptr,
|
|
/*Mutable*/ false,
|
|
clang::ICIS_NoInit);
|
|
StructDecl->addDecl(Field);
|
|
}
|
|
|
|
StructDecl->completeDefinition();
|
|
|
|
Result = DeclCreator::getQualType(StructDecl);
|
|
|
|
} break;
|
|
|
|
case LayoutKind::Union: {
|
|
auto *Union = llvm::cast<dla::UnionLayout>(L);
|
|
|
|
std::string TypeName = getUniqueTypeNameForDecl(nullptr);
|
|
clang::IdentifierInfo &TypeId = ClangCtx.Idents.get(TypeName);
|
|
clang::TranslationUnitDecl &TUDecl = *ClangCtx.getTranslationUnitDecl();
|
|
auto *UnionDecl = clang::RecordDecl::Create(ClangCtx,
|
|
clang::TTK_Union,
|
|
&TUDecl,
|
|
clang::SourceLocation{},
|
|
clang::SourceLocation{},
|
|
&TypeId,
|
|
nullptr);
|
|
|
|
UnionDecl->startDefinition();
|
|
|
|
for (const auto &Group : llvm::enumerate(Union->elements())) {
|
|
// Create the type decl for the PointerLayout.
|
|
const dla::Layout *PointedLayout = Group.value();
|
|
TypeDeclOrQualType FTy = getOrCreateTypeFromLayout(PointedLayout,
|
|
ClangCtx,
|
|
LLVMCtx);
|
|
QualType FieldTy = DeclCreator::getQualType(FTy);
|
|
clang::TypeSourceInfo *TI = ClangCtx.CreateTypeSourceInfo(FieldTy);
|
|
const std::string FieldName = std::string("field_")
|
|
+ std::to_string(Group.index());
|
|
clang::IdentifierInfo &FieldId = ClangCtx.Idents.get(FieldName);
|
|
auto *Field = clang::FieldDecl::Create(ClangCtx,
|
|
UnionDecl,
|
|
clang::SourceLocation{},
|
|
clang::SourceLocation{},
|
|
&FieldId,
|
|
FieldTy,
|
|
TI,
|
|
nullptr,
|
|
/*Mutable*/ false,
|
|
clang::ICIS_NoInit);
|
|
UnionDecl->addDecl(Field);
|
|
}
|
|
|
|
UnionDecl->completeDefinition();
|
|
|
|
Result = DeclCreator::getQualType(UnionDecl);
|
|
|
|
} break;
|
|
|
|
default:
|
|
revng_unreachable();
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
// TODO: this should be a RecursiveCoroutine
|
|
DeclCreator::TypeDeclOrQualType
|
|
DeclCreator::getOrCreateTypeFromLayout(const dla::Layout *L,
|
|
clang::ASTContext &ClangCtx,
|
|
llvm::LLVMContext &LLVMCtx) {
|
|
revng_assert(L);
|
|
|
|
// First, look it up, to see if we've already computed it.
|
|
llvm::Optional<TypeDeclOrQualType> CachedQTy = lookupType(L);
|
|
if (CachedQTy.hasValue())
|
|
return CachedQTy.getValue();
|
|
|
|
// If we havent found it, create it, along with all the other types that might
|
|
// be necessary to complete its declaration.
|
|
TypeDeclOrQualType Result = createTypeFromLayout(L, ClangCtx, LLVMCtx);
|
|
|
|
// Insert it into the mapping.
|
|
insertTypeMapping(L, Result);
|
|
return Result;
|
|
}
|
|
|
|
void DeclCreator::createTypeDeclsForFunctionPrototype(clang::ASTContext &Ctx,
|
|
const llvm::Function *F) {
|
|
clang::TranslationUnitDecl &TUDecl = *Ctx.getTranslationUnitDecl();
|
|
|
|
// Create return type
|
|
getOrCreateType(F, Ctx, TUDecl);
|
|
|
|
// Create argument types
|
|
for (const llvm::Argument &A : F->args())
|
|
getOrCreateType(&A, Ctx, TUDecl);
|
|
}
|