mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
7a1b11a83d
Before this commit, we assumed integer-to-pointer casts were only widening, never narrowing. Turns out this is not true. For instance, narrowing casts happen when decompiling s390x code. With this commit, the decompiler can handle that case gracefully.
152 lines
4.6 KiB
C++
152 lines
4.6 KiB
C++
//
|
|
// Copyright rev.ng Srls. See LICENSE.md for details.
|
|
//
|
|
|
|
#include "llvm/ADT/SmallSet.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/GlobalVariable.h"
|
|
#include "llvm/IR/Module.h"
|
|
|
|
#include "clang/AST/ASTContext.h"
|
|
#include "clang/AST/Expr.h"
|
|
#include "clang/AST/Stmt.h"
|
|
|
|
#include "revng/Support/IRHelpers.h"
|
|
|
|
#include "DecompilationHelpers.h"
|
|
|
|
using namespace llvm;
|
|
|
|
static bool isUsedInFunction(const ConstantExpr *CE, const Function &F) {
|
|
SmallSet<const Constant *, 16> UnexploredCEUsers;
|
|
UnexploredCEUsers.insert(CE);
|
|
SmallSet<const Constant *, 16> NextUnexploredCEUsers;
|
|
do {
|
|
NextUnexploredCEUsers.clear();
|
|
for (const Constant *CEUser : UnexploredCEUsers) {
|
|
for (const User *U : CEUser->users()) {
|
|
|
|
if (auto *I = dyn_cast<Instruction>(U)) {
|
|
if (I->getFunction() == &F)
|
|
return true;
|
|
|
|
} else if (auto *CExpr = dyn_cast<Constant>(U)) {
|
|
NextUnexploredCEUsers.insert(CExpr);
|
|
|
|
} else {
|
|
revng_abort();
|
|
}
|
|
}
|
|
}
|
|
std::swap(UnexploredCEUsers, NextUnexploredCEUsers);
|
|
} while (not UnexploredCEUsers.empty());
|
|
|
|
return false;
|
|
}
|
|
|
|
std::set<const GlobalVariable *> getDirectlyUsedGlobals(const Function &F) {
|
|
std::set<const GlobalVariable *> Results;
|
|
const llvm::Module *M = F.getParent();
|
|
for (const GlobalVariable &G : M->globals()) {
|
|
for (const User *U : G.users()) {
|
|
if (auto *I = dyn_cast<Instruction>(U)) {
|
|
if (I->getFunction() == &F) {
|
|
Results.insert(&G);
|
|
break;
|
|
}
|
|
} else if (auto *CE = dyn_cast<ConstantExpr>(U)) {
|
|
if (isUsedInFunction(CE, F)) {
|
|
Results.insert(&G);
|
|
break;
|
|
}
|
|
} else {
|
|
revng_abort();
|
|
}
|
|
}
|
|
}
|
|
return Results;
|
|
}
|
|
|
|
std::set<const Function *> getDirectlyCalledFunctions(const Function &F) {
|
|
std::set<const Function *> Results;
|
|
for (auto &BB : F) {
|
|
for (auto &I : BB) {
|
|
if (auto *Call = dyn_cast<CallInst>(&I)) {
|
|
if (auto *Callee = getCallee(Call))
|
|
Results.insert(Callee);
|
|
} else if (isa<UnreachableInst>(&I)) {
|
|
// UnreachableInst are decompiled as calls to abort, so if F has an
|
|
// unreachable instruction we need to add "abort" to the called
|
|
// functions.
|
|
auto *Abort = F.getParent()->getFunction("abort");
|
|
revng_assert(nullptr != Abort);
|
|
if (Abort)
|
|
Results.insert(Abort);
|
|
}
|
|
}
|
|
}
|
|
return Results;
|
|
}
|
|
|
|
clang::CastExpr *createCast(clang::QualType LHSQualTy,
|
|
clang::Expr *RHS,
|
|
clang::ASTContext &ASTCtx) {
|
|
using namespace clang;
|
|
QualType RHSQualTy = RHS->getType();
|
|
const clang::Type *LHSTy = LHSQualTy.getTypePtr();
|
|
const clang::Type *RHSTy = RHSQualTy.getTypePtr();
|
|
|
|
CastKind CK;
|
|
if (LHSTy->isBooleanType() and RHSTy->isIntegerType()) {
|
|
// casting integer to boolean
|
|
return ImplicitCastExpr::Create(ASTCtx,
|
|
LHSQualTy,
|
|
CastKind::CK_IntegralToBoolean,
|
|
RHS,
|
|
nullptr,
|
|
VK_RValue);
|
|
}
|
|
if (RHSTy->isBooleanType() and LHSTy->isIntegerType()) {
|
|
// casting boolean to inteeger
|
|
return ImplicitCastExpr::Create(ASTCtx,
|
|
LHSQualTy,
|
|
CastKind::CK_IntegralCast,
|
|
RHS,
|
|
nullptr,
|
|
VK_RValue);
|
|
}
|
|
if (LHSTy->isIntegerType()) {
|
|
if (RHSTy->isIntegerType()) {
|
|
CK = CastKind::CK_IntegralCast;
|
|
} else if (RHSTy->isPointerType()) {
|
|
CK = CastKind::CK_PointerToIntegral;
|
|
} else {
|
|
revng_abort();
|
|
}
|
|
} else if (LHSTy->isPointerType()) {
|
|
if (RHSTy->isIntegerType()) {
|
|
|
|
uint64_t PtrSize = ASTCtx.getTypeSize(LHSQualTy);
|
|
uint64_t IntegerSize = ASTCtx.getTypeSize(RHSQualTy);
|
|
revng_assert((PtrSize >= IntegerSize) or (IntegerSize == 128));
|
|
CK = CastKind::CK_IntegralToPointer;
|
|
} else if (RHSTy->isPointerType()) {
|
|
CK = CastKind::CK_BitCast;
|
|
} else {
|
|
revng_abort();
|
|
}
|
|
} else {
|
|
revng_abort();
|
|
}
|
|
TypeSourceInfo *TI = ASTCtx.CreateTypeSourceInfo(LHSQualTy);
|
|
return CStyleCastExpr::Create(ASTCtx,
|
|
LHSQualTy,
|
|
VK_RValue,
|
|
CK,
|
|
RHS,
|
|
nullptr,
|
|
TI,
|
|
{},
|
|
{});
|
|
}
|