diff --git a/include/revng/Support/DecompilationHelpers.h b/include/revng/Support/DecompilationHelpers.h index 0b1c914dd..ffe8b553c 100644 --- a/include/revng/Support/DecompilationHelpers.h +++ b/include/revng/Support/DecompilationHelpers.h @@ -55,7 +55,7 @@ inline bool areMemOpCompatible(const model::Type &ModelType, const model::Binary &Model) { // loads/stores from/to void pointers are not allowed - if (ModelType.isVoidPrimitive()) + if (ModelType.isVoidPrimitive() or ModelType.isPrototype()) return false; // We don't load or store entire structs in a single mem operation diff --git a/lib/Backend/DecompileFunction.cpp b/lib/Backend/DecompileFunction.cpp index f4601d830..1cd145e2e 100644 --- a/lib/Backend/DecompileFunction.cpp +++ b/lib/Backend/DecompileFunction.cpp @@ -373,6 +373,8 @@ private: RecursiveCoroutine getModelGEPToken(const llvm::CallInst *C); + std::string getIsolatedFunctionToken(const llvm::Function *F); + RecursiveCoroutine getIsolatedCallToken(const llvm::CallInst *C); RecursiveCoroutine @@ -507,6 +509,10 @@ CCodeGenerator::getConstantToken(const llvm::Value *C) { rc_return get128BitIntegerHexConstant(Value, B, Model); } + if (auto *Function = dyn_cast(C)) { + rc_return getIsolatedFunctionToken(Function); + } + if (auto *Global = dyn_cast(C)) { using namespace llvm; // Check if initializer is a CString @@ -556,6 +562,15 @@ CCodeGenerator::getConstantToken(const llvm::Value *C) { DstType); } + case Instruction::PtrToInt: { + const auto *Operand = cast(ConstExpr->getOperand(0)); + const model::Type &SrcType = *TypeMap.at(Operand); + const model::Type &DstType = *TypeMap.at(ConstExpr); + rc_return buildCastExpr(rc_recur getConstantToken(Operand), + SrcType, + DstType); + } + default: revng_abort(dumpToString(ConstExpr).c_str()); } @@ -594,9 +609,13 @@ CCodeGenerator::getModelGEPToken(const llvm::CallInst *Call) { if (IsRef) { // In ModelGEPRefs, the base value is a reference, and the base type is // its type - revng_assert(*TypeMap.at(BaseValue) == *CurType, - "The ModelGEP base type is not coherent with the " - "propagated type."); + if (*TypeMap.at(BaseValue) != *CurType) { + BaseValue->dump(); + TypeMap.at(BaseValue)->dump(); + CurType->dump(); + revng_abort("The ModelGEP base type is not coherent with the " + "propagated type."); + } // If there are no further arguments we're just dereferencing the base value if (std::next(CurArg) == Call->arg_end()) { // But dereferencing a reference does not produce any code so we're done @@ -886,6 +905,19 @@ CCodeGenerator::getCustomOpcodeToken(const llvm::CallInst *Call) { rc_return ""; } +std::string +CCodeGenerator::getIsolatedFunctionToken(const llvm::Function *CalledFunc) { + revng_assert(CalledFunc); + const model::Function *ModelFunc = llvmToModelFunction(Model, *CalledFunc); + revng_assert(ModelFunc); + std::string Location = locationString(ranks::Function, ModelFunc->key()); + return B.getTag(ptml::tags::Span, B.NameBuilder.name(*ModelFunc).str()) + .addAttribute(attributes::Token, tokens::Function) + .addAttribute(attributes::ActionContextLocation, Location) + .addAttribute(attributes::LocationReferences, Location) + .toString(); +} + RecursiveCoroutine CCodeGenerator::getIsolatedCallToken(const llvm::CallInst *Call) { @@ -916,16 +948,7 @@ CCodeGenerator::getIsolatedCallToken(const llvm::CallInst *Call) { // Isolated function llvm::Function *CalledFunc = getCalledFunction(Call); revng_assert(CalledFunc); - const model::Function *ModelFunc = llvmToModelFunction(Model, - *CalledFunc); - revng_assert(ModelFunc); - std::string Location = locationString(ranks::Function, ModelFunc->key()); - CalleeToken = B.getTag(ptml::tags::Span, - B.NameBuilder.name(*ModelFunc).str()) - .addAttribute(attributes::Token, tokens::Function) - .addAttribute(attributes::ActionContextLocation, Location) - .addAttribute(attributes::LocationReferences, Location) - .toString(); + CalleeToken = getIsolatedFunctionToken(CalledFunc); } } diff --git a/lib/Canonicalize/MakeModelGEPPass.cpp b/lib/Canonicalize/MakeModelGEPPass.cpp index e8a6dc888..2d4889ef0 100644 --- a/lib/Canonicalize/MakeModelGEPPass.cpp +++ b/lib/Canonicalize/MakeModelGEPPass.cpp @@ -528,20 +528,20 @@ getIRArithmetic(Use &AddressUse, const ModelTypesMap &PointerTypes) { rc_return IRArithmetic::constant(ConstantValue); } - auto *AddrArithmeticInst = dyn_cast(AddressArith); - auto *ConstExprAddrArith = dyn_cast(AddressArith); - if (ConstExprAddrArith) - AddrArithmeticInst = ConstExprAddrArith->getAsInstruction(); + unsigned int Opcode = 0; + auto *AddrArithmeticUser = dyn_cast(AddressArith); + if (auto *I = dyn_cast(AddressArith)) + Opcode = I->getOpcode(); + else if (auto *CE = dyn_cast(AddressArith)) + Opcode = CE->getOpcode(); - switch (AddrArithmeticInst->getOpcode()) { + switch (Opcode) { case Instruction::Add: { - auto *Add = cast(AddrArithmeticInst); - - Use &LHSUse = Add->getOperandUse(0); + Use &LHSUse = AddrArithmeticUser->getOperandUse(0); auto LHSOrNone = rc_recur getIRArithmetic(LHSUse, PointerTypes); - Use &RHSUse = Add->getOperandUse(1); + Use &RHSUse = AddrArithmeticUser->getOperandUse(1); auto RHSOrNone = rc_recur getIRArithmetic(RHSUse, PointerTypes); if (not RHSOrNone.has_value() or not LHSOrNone.has_value()) @@ -576,9 +576,9 @@ getIRArithmetic(Use &AddressUse, const ModelTypesMap &PointerTypes) { // shrink if we go backwards. We have to detect this case, because if // something is the result of zero extension of boolean value it cannot be // an address for sure. - auto *Operand = AddrArithmeticInst->getOperand(0); + auto *Operand = AddrArithmeticUser->getOperand(0); if (Operand->getType()->getIntegerBitWidth() == 1) - rc_return IRArithmetic::unknown(AddrArithmeticInst); + rc_return IRArithmetic::unknown(AddrArithmeticUser); } break; case Instruction::IntToPtr: @@ -587,15 +587,15 @@ getIRArithmetic(Use &AddressUse, const ModelTypesMap &PointerTypes) { case Instruction::Freeze: { // casts are traversed revng_log(ModelGEPLog, "Traverse cast!"); - rc_return rc_recur getIRArithmetic(AddrArithmeticInst->getOperandUse(0), + rc_return rc_recur getIRArithmetic(AddrArithmeticUser->getOperandUse(0), PointerTypes); } case Instruction::Mul: { - auto *Op0 = AddrArithmeticInst->getOperand(0); + auto *Op0 = AddrArithmeticUser->getOperand(0); auto *Op0Const = dyn_cast(Op0); - auto *Op1 = AddrArithmeticInst->getOperand(1); + auto *Op1 = AddrArithmeticUser->getOperand(1); auto *Op1Const = dyn_cast(Op1); auto *ConstOp = Op1Const ? Op1Const : Op0Const; auto *OtherOp = Op1Const ? Op0 : Op1; @@ -609,24 +609,24 @@ getIRArithmetic(Use &AddressUse, const ModelTypesMap &PointerTypes) { } else { // In all the other cases, fall back to treating this as a // non-address and non-strided instruction, just like e.g. division. - rc_return IRArithmetic::unknown(AddrArithmeticInst); + rc_return IRArithmetic::unknown(AddrArithmeticUser); } } case Instruction::Shl: { - auto *ShiftedBits = AddrArithmeticInst->getOperand(1); + auto *ShiftedBits = AddrArithmeticUser->getOperand(1); if (auto *ConstShift = dyn_cast(ShiftedBits)) { if (ConstShift->getValue().isNonNegative()) { // Build the stride - auto *AddrType = AddrArithmeticInst->getType(); + auto *AddrType = AddrArithmeticUser->getType(); auto *ArithTy = cast(AddrType); auto *Stride = ConstantInt::get(ArithTy, 1ULL << ConstShift->getZExtValue()); if (not Stride->isNegative()) { // The first operand of the shift is the index - auto *IndexForStridedAccess = AddrArithmeticInst->getOperand(0); + auto *IndexForStridedAccess = AddrArithmeticUser->getOperand(0); rc_return IRArithmetic::index(Stride, IndexForStridedAccess); } @@ -636,7 +636,7 @@ getIRArithmetic(Use &AddressUse, const ModelTypesMap &PointerTypes) { // In all the other cases, fall back to treating this as a non-address // and non-strided instruction, just like e.g. division. - rc_return IRArithmetic::unknown(AddrArithmeticInst); + rc_return IRArithmetic::unknown(AddrArithmeticUser); } case Instruction::Alloca: { @@ -667,7 +667,7 @@ getIRArithmetic(Use &AddressUse, const ModelTypesMap &PointerTypes) { // If we reach one of these instructions, it definitely cannot be an // address, but it's just considered as regular offset arithmetic of // an unknown offset. - rc_return IRArithmetic::unknown(AddrArithmeticInst); + rc_return IRArithmetic::unknown(AddrArithmeticUser); } default: { @@ -675,9 +675,6 @@ getIRArithmetic(Use &AddressUse, const ModelTypesMap &PointerTypes) { } break; } - if (ConstExprAddrArith) - AddrArithmeticInst->deleteValue(); - } else if (auto *Const = dyn_cast(AddressArith)) { // If we reach this point the constant int does not represent a pointer @@ -693,7 +690,8 @@ getIRArithmetic(Use &AddressUse, const ModelTypesMap &PointerTypes) { } else if (isa(AddressArith) or isa(AddressArith) - or isa(AddressArith)) { + or isa(AddressArith) + or isa(AddressArith)) { rc_return std::nullopt; diff --git a/lib/DataLayoutAnalysis/Frontend/SCEVBaseAddressExplorer.cpp b/lib/DataLayoutAnalysis/Frontend/SCEVBaseAddressExplorer.cpp index 8f8ffe879..3ed872ab7 100644 --- a/lib/DataLayoutAnalysis/Frontend/SCEVBaseAddressExplorer.cpp +++ b/lib/DataLayoutAnalysis/Frontend/SCEVBaseAddressExplorer.cpp @@ -133,7 +133,8 @@ SCEVBaseAddressExplorer::checkAddressOrTraverse(llvm::ScalarEvolution *SE, using namespace llvm; revng_assert(isa(UVal) or isa(UVal) or isa(UVal) or isa(UVal) - or isa(UVal) or isa(UVal)); + or isa(UVal) or isa(UVal) + or isa(UVal)); } break; case llvm::scZeroExtend: { diff --git a/lib/InitModelTypes/InitModelTypes.cpp b/lib/InitModelTypes/InitModelTypes.cpp index 4b02254e3..bbe8a0390 100644 --- a/lib/InitModelTypes/InitModelTypes.cpp +++ b/lib/InitModelTypes/InitModelTypes.cpp @@ -22,8 +22,11 @@ #include "revng/ADT/RecursiveCoroutine.h" #include "revng/InitModelTypes/InitModelTypes.h" #include "revng/Model/Architecture.h" +#include "revng/Model/ArrayType.h" #include "revng/Model/Binary.h" #include "revng/Model/CABIFunctionDefinition.h" +#include "revng/Model/CommonTypeMethods.h" +#include "revng/Model/DefinedType.h" #include "revng/Model/IRHelpers.h" #include "revng/Model/RawFunctionDefinition.h" #include "revng/Model/TypedefDefinition.h" @@ -80,14 +83,14 @@ static RecursiveCoroutine addOperandType(const llvm::Value *Operand, const model::Binary &Model, ModelTypesMap &TypeMap, bool PointersOnly) { - // For ConstExprs, check their OpCode if (auto *Expr = dyn_cast(Operand)) { // A constant expression might have its own uninitialized constant operands for (const llvm::Value *Op : Expr->operand_values()) rc_recur addOperandType(Op, Model, TypeMap, PointersOnly); - if (Expr->getOpcode() == Instruction::IntToPtr) { + unsigned Opcode = Expr->getOpcode(); + if (Opcode == Instruction::IntToPtr or Opcode == Instruction::PtrToInt) { auto It = TypeMap.find(Expr->getOperand(0)); if (It != TypeMap.end()) { const model::UpcastableType &OperandType = It->second; @@ -95,7 +98,6 @@ static RecursiveCoroutine addOperandType(const llvm::Value *Operand, if (OperandType->isPointer()) { // If the operand is already a pointer, just forward it TypeMap.insert({ Operand, OperandType.copy() }); - } else if (not PointersOnly) { auto PS = model::Architecture::getPointerSize(Model.Architecture()); TypeMap.insert({ Operand, model::PrimitiveType::makeGeneric(PS) }); @@ -140,6 +142,23 @@ static RecursiveCoroutine addOperandType(const llvm::Value *Operand, auto PtrSize = model::Architecture::getPointerSize(Model.Architecture()); TypeMap.insert({ Operand, model::PrimitiveType::makeGeneric(PtrSize) }); rc_return true; + } else if (auto *ReferencedFunction = dyn_cast(Operand)) { + if (FunctionTags::Isolated.isTagOf(ReferencedFunction)) { + // Given a function, obtain a function pointer + // TODO: introduce helpers, this is terrible + using namespace model; + auto EntryAddress = getMetaAddressOfIsolatedFunction(*ReferencedFunction); + const model::Function &Function = Model.Functions().at(EntryAddress); + const auto &Prototype = Model.prototypeOrDefault(Function.prototype()); + const auto &Key = Prototype->getPrototype()->key(); + auto PrototypeReference = Model.getDefinitionReference(Key); + auto PrototypeType = DefinedType::make(PrototypeReference); + auto PointerSize = Architecture::getPointerSize(Model.Architecture()); + auto Pointer = PointerType::make(std::move(PrototypeType), PointerSize); + TypeMap.insert({ Operand, Pointer }); + + rc_return true; + } } rc_return false; diff --git a/lib/RemoveLiftingArtifacts/MakeSegmentRefPass.cpp b/lib/RemoveLiftingArtifacts/MakeSegmentRefPass.cpp index c3718c12a..e60709ca2 100644 --- a/lib/RemoveLiftingArtifacts/MakeSegmentRefPass.cpp +++ b/lib/RemoveLiftingArtifacts/MakeSegmentRefPass.cpp @@ -127,8 +127,13 @@ getStringLiteral(RawBinaryView &BinaryView, bool MakeSegmentRefPassImpl::runOnFunction(const model::Function &ModelFunction, llvm::Function &F) { + model::NameBuilder NameBuilder(Binary); RawBinaryView &BinaryView = getAnalysis().get(); + std::map FunctionEntries; + for (const model::Function &Function : Binary.Functions()) + FunctionEntries[Function.Entry().toGeneric()] = Function.Entry(); + bool Changed = false; IRBuilder<> IRB(Context); llvm::Type *PtrSizedInteger = getPointerSizedInteger(Context, Binary); @@ -162,8 +167,10 @@ bool MakeSegmentRefPassImpl::runOnFunction(const model::Function &ModelFunction, if (auto Segment = findLiteralInSegments(Binary, ConstantAddress); Segment) { + const auto &[StartAddress, VirtualSize] = *Segment; auto OffsetInSegment = ConstantAddress - StartAddress.address(); + MetaAddress Address = StartAddress + OffsetInSegment; if (isa(&I)) { auto *BB = cast(&I)->getIncomingBlock(Op); @@ -172,12 +179,25 @@ bool MakeSegmentRefPassImpl::runOnFunction(const model::Function &ModelFunction, IRB.SetInsertPoint(&I); } + auto It = FunctionEntries.find(Address); + if (It != FunctionEntries.end()) { + auto Name = NameBuilder.llvmName(Binary.Functions().at(It->second)); + + auto *ReferencedFunction = M.getFunction(Name); + revng_assert(ReferencedFunction != nullptr); + I.setOperand(Op.getOperandNo(), + IRB.CreatePtrToInt(ReferencedFunction, Op->getType())); + Changed = true; + continue; + } + IntegerType *OperandType = ConstOp->getType(); // Check if the use of this constant is a icmp. If it is we cannot // replace it with a string literal, because comparisons between // string literals are undefined behavior in C. bool UseIsComparison = llvm::isa(Op.getUser()); + // Check if the Op is large as a pointer. If it isn't it can't be a // string literal. // See if we can find a string literal there.