Files
revng-revng/lib/Decompiler/IRASTTypeTranslation.cpp
T
Pietro Fezzardi 2ff7044bb9 Decompiler: forward-declare types coming from DLA
This commits enable the emission of rich types associated with function
signatures. This types are forward-declared in the decompiled C code
before the definition of each decompiled function that uses them.

The types we emit for now are the types that the DLA is able to compute
(if any) for the return values and the arguments of the function.

Such types are not yet used in the body of the function, nor in the
function declaration. These are the next steps to come.
2021-02-02 11:23:53 +01:00

245 lines
10 KiB
C++

//
// Copyright rev.ng Srls. See LICENSE.md for details.
//
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/Casting.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "revng/Support/Assert.h"
#include "IRASTTypeTranslation.h"
#include "Mangling.h"
clang::QualType DeclCreator::getOrCreateBoolQualType(clang::ASTContext &ASTCtx,
const llvm::Type *Ty) {
clang::QualType Result;
clang::TranslationUnitDecl *TUDecl = ASTCtx.getTranslationUnitDecl();
const std::string BoolName = "bool";
clang::IdentifierInfo &BoolId = ASTCtx.Idents.get(BoolName);
clang::DeclarationName TypeName(&BoolId);
bool Found = false;
for (clang::Decl *D : TUDecl->lookup(TypeName)) {
if (auto *Typedef = llvm::dyn_cast<clang::TypedefDecl>(D)) {
const std::string Name = Typedef->getNameAsString();
if (Name == "bool") {
revng_assert(not Found);
insertTypeMapping(Ty, Typedef);
Result = ASTCtx.getTypedefType(Typedef);
Found = true;
}
}
}
if (not Found) {
// C99 actually defines '_Bool', while 'bool' is a MACRO, which expands
// to '_Bool'. We cheat by injecting a 'typedef _Bool bool;' in the
// translation unit we're handling, that has already been preprocessed
clang::CanQualType BoolQType = ASTCtx.BoolTy;
using TSInfo = clang::TypeSourceInfo;
TSInfo *BoolTypeInfo = ASTCtx.getTrivialTypeSourceInfo(BoolQType);
auto *BoolTypedefDecl = clang::TypedefDecl::Create(ASTCtx,
TUDecl,
{},
{},
&BoolId,
BoolTypeInfo);
insertTypeMapping(Ty, BoolTypedefDecl);
TUDecl->addDecl(BoolTypedefDecl);
Result = ASTCtx.getTypedefType(BoolTypedefDecl);
return Result;
revng_abort("'_Bool' type not found!\n"
"This should not happen since we compile as c99\n");
}
return Result;
}
clang::QualType DeclCreator::getOrCreateQualType(const llvm::Type *Ty,
const llvm::Value *NamingValue,
clang::ASTContext &ASTCtx,
clang::DeclContext &DeclCtx) {
clang::QualType Result;
switch (Ty->getTypeID()) {
case llvm::Type::TypeID::IntegerTyID: {
auto *LLVMIntType = llvm::cast<llvm::IntegerType>(Ty);
unsigned BitWidth = LLVMIntType->getBitWidth();
revng_assert(BitWidth == 1 or BitWidth == 8 or BitWidth == 16
or BitWidth == 32 or BitWidth == 64 or BitWidth == 128);
clang::TranslationUnitDecl *TUDecl = ASTCtx.getTranslationUnitDecl();
revng_assert(TUDecl->isLookupContext());
switch (BitWidth) {
case 1: {
Result = getOrCreateBoolQualType(ASTCtx, Ty);
} break;
case 16: {
const std::string UInt16Name = "uint16_t";
clang::IdentifierInfo &Id = ASTCtx.Idents.get(UInt16Name);
clang::DeclarationName TypeName(&Id);
for (clang::Decl *D : TUDecl->lookup(TypeName))
if (auto *Typedef = llvm::dyn_cast<clang::TypedefDecl>(D))
return ASTCtx.getTypedefType(Typedef);
revng_abort("'uint16_t' type not found!\n"
"This should not happen since we '#include <stdint.h>'\n"
"Please make sure you have installed the header\n");
} break;
case 32: {
const std::string UInt32Name = "uint32_t";
clang::IdentifierInfo &Id = ASTCtx.Idents.get(UInt32Name);
clang::DeclarationName TypeName(&Id);
for (clang::Decl *D : TUDecl->lookup(TypeName))
if (auto *Typedef = llvm::dyn_cast<clang::TypedefDecl>(D))
return ASTCtx.getTypedefType(Typedef);
revng_abort("'uint32_t' type not found!\n"
"This should not happen since we '#include <stdint.h>'\n"
"Please make sure you have installed the header\n");
} break;
case 64: {
const std::string UInt64Name = "uint64_t";
clang::IdentifierInfo &Id = ASTCtx.Idents.get(UInt64Name);
clang::DeclarationName TypeName(&Id);
for (clang::Decl *D : TUDecl->lookup(TypeName))
if (auto *Typedef = llvm::dyn_cast<clang::TypedefDecl>(D))
return ASTCtx.getTypedefType(Typedef);
revng_abort("'uint64_t' type not found!\n"
"This should not happen since we '#include <stdint.h>'\n"
"Please make sure you have installed the header\n");
} break;
case 8:
// use char for strict aliasing reasons
case 128:
// use builtin clang types (__int128_t and __uint128_t), because C99 does
// not require to have 128 bit integer types
Result = ASTCtx.getIntTypeForBitwidth(BitWidth, /* Signed */ false);
break;
default:
revng_abort("unexpected integer size");
}
} break;
case llvm::Type::TypeID::PointerTyID: {
const llvm::PointerType *PtrTy = llvm::cast<llvm::PointerType>(Ty);
const llvm::Type *PointeeTy = PtrTy->getElementType();
clang::QualType PointeeType = getOrCreateQualType(PointeeTy,
nullptr,
ASTCtx,
DeclCtx);
Result = ASTCtx.getPointerType(PointeeType);
} break;
case llvm::Type::TypeID::VoidTyID:
case llvm::Type::TypeID::MetadataTyID: {
Result = ASTCtx.VoidTy;
} break;
case llvm::Type::TypeID::StructTyID: {
if (auto *TDecl = getTypeDeclOrNull(Ty)) {
Result = clang::QualType(TDecl->getTypeForDecl(), 0);
break;
}
const llvm::StructType *StructTy = llvm::cast<llvm::StructType>(Ty);
std::string TypeName;
if (StructTy->hasName()) {
TypeName = makeCIdentifier(StructTy->getName());
} else if (NamingValue and NamingValue->hasName()) {
if (auto *F = llvm::dyn_cast<llvm::Function>(NamingValue)) {
TypeName = makeCIdentifier(F->getName().str())
+ std::string("_ret_type");
} else if (auto *Arg = llvm::dyn_cast<llvm::Argument>(NamingValue)) {
const llvm::Function *F = Arg->getParent();
TypeName = makeCIdentifier(F->getName().str()) + "_arg_"
+ makeCIdentifier(NamingValue->getName().str())
+ std::string("_type");
} else {
TypeName = getUniqueTypeNameForDecl();
}
} else {
TypeName = getUniqueTypeNameForDecl();
}
clang::IdentifierInfo &TypeId = ASTCtx.Idents.get(TypeName);
auto *Struct = clang::RecordDecl::Create(ASTCtx,
clang::TTK_Struct,
&DeclCtx,
clang::SourceLocation{},
clang::SourceLocation{},
&TypeId,
nullptr);
insertTypeMapping(Ty, Struct);
unsigned N = 0;
FieldDecls[Struct].resize(StructTy->getNumElements(), nullptr);
Struct->startDefinition();
for (llvm::Type *FieldTy : StructTy->elements()) {
// HACK: Handle the type of the `@env` global variable, which we simply
// cast to a `void` `nullptr` type.
if (FieldTy->getTypeID() == llvm::Type::TypeID::ArrayTyID) {
Result = ASTCtx.VoidTy;
break;
}
clang::QualType QFieldTy = getOrCreateQualType(FieldTy,
nullptr,
ASTCtx,
DeclCtx);
clang::TypeSourceInfo *TI = ASTCtx.CreateTypeSourceInfo(QFieldTy);
const std::string FieldName = std::string("field_") + std::to_string(N);
clang::IdentifierInfo &FieldId = ASTCtx.Idents.get(FieldName);
auto *Field = clang::FieldDecl::Create(ASTCtx,
Struct,
clang::SourceLocation{},
clang::SourceLocation{},
&FieldId,
QFieldTy,
TI,
nullptr,
/*Mutable*/ false,
clang::ICIS_NoInit);
FieldDecls[Struct][N] = Field;
Struct->addDecl(Field);
N++;
}
Struct->completeDefinition();
Result = clang::QualType(Struct->getTypeForDecl(), 0);
} break;
case llvm::Type::TypeID::ArrayTyID:
case llvm::Type::TypeID::FunctionTyID:
case llvm::Type::TypeID::VectorTyID:
case llvm::Type::TypeID::LabelTyID:
case llvm::Type::TypeID::X86_MMXTyID:
case llvm::Type::TypeID::TokenTyID:
case llvm::Type::TypeID::HalfTyID:
case llvm::Type::TypeID::FloatTyID:
case llvm::Type::TypeID::DoubleTyID:
case llvm::Type::TypeID::X86_FP80TyID:
case llvm::Type::TypeID::FP128TyID:
case llvm::Type::TypeID::PPC_FP128TyID:
revng_abort("unsupported type");
}
revng_assert(not Result.isNull());
return Result;
}
clang::QualType DeclCreator::getOrCreateQualType(const llvm::GlobalVariable *G,
clang::ASTContext &ASTCtx,
clang::DeclContext &DeclCtx) {
llvm::PointerType *GlobalPtrTy = llvm::cast<llvm::PointerType>(G->getType());
llvm::Type *Ty = GlobalPtrTy->getElementType();
return getOrCreateQualType(Ty, G, ASTCtx, DeclCtx);
}
clang::QualType DeclCreator::getOrCreateQualType(const llvm::Value *I,
clang::ASTContext &ASTCtx,
clang::DeclContext &DeclCtx) {
llvm::Type *Ty = I->getType();
return getOrCreateQualType(Ty, I, ASTCtx, DeclCtx);
}