diff --git a/include/revng/Model/Binary.h b/include/revng/Model/Binary.h index 5898f74c6..3d7618358 100644 --- a/include/revng/Model/Binary.h +++ b/include/revng/Model/Binary.h @@ -22,10 +22,12 @@ namespace model { class VerifyHelper; class Function; +class DynamicFunction; class Binary; class FunctionEdge; class CallEdge; class BasicBlock; +class Segment; } // namespace model // TODO: Prevent changing the keys. Currently we need them to be public and @@ -72,29 +74,6 @@ enum Values { Count }; -inline bool hasDestination(Values V) { - switch (V) { - case Invalid: - case Count: - revng_abort(); - break; - case DirectBranch: - case FakeFunctionCall: - case FakeFunctionReturn: - case FunctionCall: - return true; - - case IndirectCall: - case Return: - case BrokenReturn: - case IndirectTailCall: - case LongJmp: - case Killer: - case Unreachable: - return false; - } -} - inline bool isCall(Values V) { switch (V) { case Count: @@ -252,6 +231,9 @@ public: /// In case of a direct function call, it has to be the same as the callee. TypePath Prototype; + /// Name of the dynamic function being called, or empty if not a dynamic call + std::string DynamicFunction; + public: CallEdge() : FunctionEdge(MetaAddress::invalid(), FunctionEdgeType::FunctionCall) {} @@ -271,7 +253,12 @@ public: bool verify(bool Assert) const debug_function; bool verify(VerifyHelper &VH) const; }; -INTROSPECTION_NS(model, CallEdge, Destination, Type, Prototype); +INTROSPECTION_NS(model, + CallEdge, + Destination, + Type, + Prototype, + DynamicFunction); template<> struct concrete_types_traits { @@ -288,7 +275,8 @@ struct llvm::yaml::MappingTraits template<> struct llvm::yaml::MappingTraits - : public TupleLikeMappingTraits {}; + : public TupleLikeMappingTraits::DynamicFunction> {}; template<> struct llvm::yaml::ScalarTraits @@ -466,12 +454,137 @@ struct KeyedObjectTraits { }; }; +/// Function defined in a dynamic library +class model::DynamicFunction { +public: + /// The name of the symbol for this dynamic function + std::string SymbolName; + + /// An optional custom name + Identifier CustomName; + + /// The prototype of the function + TypePath Prototype; + + // TODO: DefiningLibrary + +public: + DynamicFunction() {} + DynamicFunction(const std::string &SymbolName) : SymbolName(SymbolName) {} + bool operator==(const model::DynamicFunction &Other) const = default; + +public: + Identifier name() const; + +public: + bool verify() const debug_function; + bool verify(bool Assert) const debug_function; + bool verify(VerifyHelper &VH) const; +}; + +INTROSPECTION_NS(model, DynamicFunction, SymbolName, CustomName, Prototype) + +template<> +struct llvm::yaml::MappingTraits + : public TupleLikeMappingTraits::CustomName> { +}; + +template<> +struct KeyedObjectTraits { + + static auto key(const model::DynamicFunction &F) { return F.SymbolName; } + + static model::DynamicFunction fromKey(const std::string &Key) { + return model::DynamicFunction(Key); + } +}; + +static_assert(validateTupleTree(IsYamlizable)); + +class model::Segment { +public: + using Key = std::pair; + +public: + MetaAddress StartAddress; + MetaAddress EndAddress; + + uint64_t StartOffset = 0; + uint64_t EndOffset = 0; + + bool IsReadable = false; + bool IsWriteable = false; + bool IsExecutable = false; + + Identifier CustomName; + +public: + Segment() {} + Segment(const Key &K) : StartAddress(K.first), EndAddress(K.second) {} + bool operator==(const model::Segment &Other) const = default; + +public: + Identifier name() const; + +public: + bool verify() const debug_function; + bool verify(bool Assert) const debug_function; + bool verify(VerifyHelper &VH) const; +}; + +INTROSPECTION_NS(model, + Segment, + StartAddress, + EndAddress, + StartOffset, + EndOffset, + IsReadable, + IsWriteable, + IsExecutable, + CustomName) + +template<> +struct llvm::yaml::MappingTraits + : public TupleLikeMappingTraits::CustomName> {}; + +template<> +struct KeyedObjectTraits { + + static model::Segment::Key key(const model::Segment &F) { + return { F.StartAddress, F.EndAddress }; + } + + static model::Segment fromKey(const model::Segment::Key &K) { + return model::Segment(K); + } +}; + +template<> +struct llvm::yaml::ScalarTraits + : public CompositeScalar {}; + +static_assert(validateTupleTree(IsYamlizable)); + /// Data structure representing the whole binary class model::Binary { public: /// List of the functions within the binary SortedVector Functions; + /// List of the functions within the binary + SortedVector ImportedDynamicFunctions; + + /// Binary architecture + model::Architecture::Values Architecture = model::Architecture::Invalid; + + /// List of segments in the original binary + SortedVector Segments; + + /// Program entry point + MetaAddress EntryPoint; + /// The type system SortedVector> Types; @@ -495,7 +608,13 @@ public: bool verify(bool Assert) const debug_function; bool verify(VerifyHelper &VH) const; }; -INTROSPECTION_NS(model, Binary, Functions, Types) +INTROSPECTION_NS(model, + Binary, + Functions, + ImportedDynamicFunctions, + Types, + Architecture, + Segments) template<> struct llvm::yaml::MappingTraits diff --git a/include/revng/Support/FunctionTags.h b/include/revng/Support/FunctionTags.h index dbda9f6bf..b272379c4 100644 --- a/include/revng/Support/FunctionTags.h +++ b/include/revng/Support/FunctionTags.h @@ -91,5 +91,6 @@ extern Tag FunctionDispatcher; extern Tag Root; extern Tag CSVsAsArgumentsWrapper; extern Tag Marker; +extern Tag DynamicFunction; } // namespace FunctionTags diff --git a/include/revng/Support/IRHelpers.h b/include/revng/Support/IRHelpers.h index 44c85fbec..a121ee617 100644 --- a/include/revng/Support/IRHelpers.h +++ b/include/revng/Support/IRHelpers.h @@ -930,6 +930,8 @@ llvm::Constant *getUniqueString(llvm::Module *M, llvm::StringRef String, const llvm::Twine &Name = llvm::Twine()); +llvm::StringRef extractFromConstantStringPtr(llvm::Value *V); + inline llvm::User *getUniqueUser(llvm::Value *V) { llvm::User *Result = nullptr; diff --git a/lib/FunctionCallIdentification/FunctionCallIdentification.cpp b/lib/FunctionCallIdentification/FunctionCallIdentification.cpp index 7ab324406..42b105307 100644 --- a/lib/FunctionCallIdentification/FunctionCallIdentification.cpp +++ b/lib/FunctionCallIdentification/FunctionCallIdentification.cpp @@ -36,7 +36,7 @@ bool FunctionCallIdentification::runOnModule(llvm::Module &M) { auto *Int8NullPtr = ConstantPointerNull::get(Int8PtrTy); auto *PCPtrTy = cast(GCBI.pcReg()->getType()); std::initializer_list FunctionArgsTy = { - Int8PtrTy, Int8PtrTy, MetaAddress::getStruct(&M), PCPtrTy, Int8PtrTy + Int8PtrTy, Int8PtrTy, MetaAddress::getStruct(&M), PCPtrTy }; using FT = FunctionType; auto *Ty = FT::get(Type::getVoidTy(C), FunctionArgsTy, false); @@ -266,8 +266,7 @@ bool FunctionCallIdentification::runOnModule(llvm::Module &M) { const std::initializer_list Args{ Callee, BlockAddress::get(ReturnBB), GCBI.toConstant(ReturnPC), - V.LinkRegister, - Int8NullPtr }; + V.LinkRegister }; FallthroughAddresses.insert(ReturnPC); diff --git a/lib/FunctionIsolation/EnforceABI.cpp b/lib/FunctionIsolation/EnforceABI.cpp index 3a638f92f..d7b8c1004 100644 --- a/lib/FunctionIsolation/EnforceABI.cpp +++ b/lib/FunctionIsolation/EnforceABI.cpp @@ -11,6 +11,8 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Metadata.h" +#include "llvm/IR/Module.h" #include "llvm/IR/Verifier.h" #include "llvm/Support/raw_os_ostream.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" @@ -19,8 +21,12 @@ #include "revng/ADT/SmallMap.h" #include "revng/FunctionIsolation/EnforceABI.h" #include "revng/FunctionIsolation/StructInitializers.h" +#include "revng/Model/Register.h" +#include "revng/Model/Type.h" +#include "revng/StackAnalysis/ABI.h" #include "revng/Support/FunctionTags.h" #include "revng/Support/IRHelpers.h" +#include "revng/Support/MetaAddress.h" #include "revng/Support/OpaqueFunctionsPool.h" using namespace llvm; @@ -48,23 +54,29 @@ class EnforceABIImpl { public: EnforceABIImpl(Module &M, GeneratedCodeBasicInfo &GCBI, - const model::Binary &Binary) : + model::Binary &Binary) : M(M), GCBI(GCBI), FunctionDispatcher(M.getFunction("function_dispatcher")), Context(M.getContext()), Initializers(&M), - IndirectPlaceholderPool(&M, false), - Binary(Binary) {} + Binary(Binary), + MetaAddressStruct(MetaAddress::getStruct(&M)) {} void run(); private: - Function *handleFunction(Function &F, const model::Function &FunctionModel); + Function * + handleFunction(Function &OldFunction, const model::Function &FunctionModel); + Function *recreateFunction(Function &OldFunction, + const model::RawFunctionType &Prototype); + void + createPrologue(Function *NewFunction, const model::Function &FunctionModel); void handleRegularFunctionCall(CallInst *Call); void generateCall(IRBuilder<> &Builder, - Function *Callee, + FunctionCallee Callee, + const model::BasicBlock &CallSiteBlock, const model::CallEdge &CallSite); private: @@ -76,14 +88,16 @@ private: Function *OpaquePC; LLVMContext &Context; StructInitializers Initializers; - OpaqueFunctionsPool IndirectPlaceholderPool; - const model::Binary &Binary; + model::Binary &Binary; + StructType *MetaAddressStruct; }; bool EnforceABI::runOnModule(Module &M) { auto &GCBI = getAnalysis().getGCBI(); - const auto &ModelWrapper = getAnalysis().get(); - const model::Binary &Binary = ModelWrapper.getReadOnlyModel(); + auto &ModelWrapper = getAnalysis().get(); + // TODO: prepopulate type system with basic types of the ABI, so this can be + // const + model::Binary &Binary = *ModelWrapper.getWriteableModel().get(); EnforceABIImpl Impl(M, GCBI, Binary); Impl.run(); @@ -105,15 +119,44 @@ void EnforceABIImpl::run() { FunctionTags::OpaqueCSVValue.addTo(OpaquePC); std::vector OldFunctions; + if (FunctionDispatcher != nullptr) + OldFunctions.push_back(FunctionDispatcher); + + // Recreate dynamic functions with arguments + for (const model::DynamicFunction &FunctionModel : + Binary.ImportedDynamicFunctions) { + // TODO: have an API to go from model to llvm::Function + auto OldFunctionName = (Twine("dynamic_") + FunctionModel.name()).str(); + Function *OldFunction = M.getFunction(OldFunctionName); + revng_assert(OldFunction != nullptr); + OldFunctions.push_back(OldFunction); + + const auto *Type = FunctionModel.Prototype.get(); + revng_assert(Type != nullptr); + + auto Prototype = abi::getRawFunctionTypeOrDefault(Binary, Type); + Function *NewFunction = recreateFunction(*OldFunction, Prototype); + FunctionTags::DynamicFunction.addTo(NewFunction); + + // EnforceABI currently does not support execution + NewFunction->deleteBody(); + + OldToNew[OldFunction] = NewFunction; + } + + // Recreate isolated functions with arguments for (const model::Function &FunctionModel : Binary.Functions) { if (FunctionModel.Type == model::FunctionType::Fake) continue; revng_assert(not FunctionModel.name().empty()); - Function *OldFunction = M.getFunction(FunctionModel.name()); + auto OldFunctionName = (Twine("local_") + FunctionModel.name()).str(); + Function *OldFunction = M.getFunction(OldFunctionName); revng_assert(OldFunction != nullptr); OldFunctions.push_back(OldFunction); + Function *NewFunction = handleFunction(*OldFunction, FunctionModel); + FunctionsMap[NewFunction] = &FunctionModel; OldToNew[OldFunction] = NewFunction; } @@ -133,19 +176,9 @@ void EnforceABIImpl::run() { for (CallInst *Call : RegularCalls) handleRegularFunctionCall(Call); - // Drop function_dispatcher - if (FunctionDispatcher != nullptr) { - FunctionDispatcher->deleteBody(); - ReturnInst::Create(Context, - BasicBlock::Create(Context, "", FunctionDispatcher)); - } - // Drop all the old functions, after we stole all of its blocks - for (Function *OldFunction : OldFunctions) { - for (User *U : OldFunction->users()) - cast(U)->getParent()->dump(); + for (Function *OldFunction : OldFunctions) OldFunction->eraseFromParent(); - } // Quick and dirty DCE for (auto [F, _] : FunctionsMap) @@ -157,6 +190,11 @@ void EnforceABIImpl::run() { } } +static Type *getLLVMTypeForRegister(Module *M, model::Register::Values V) { + LLVMContext &C = M->getContext(); + return IntegerType::getIntNTy(C, 8 * model::Register::getSize(V)); +} + static FunctionType * toLLVMType(llvm::Module *M, const model::RawFunctionType &Prototype) { using model::NamedTypedRegister; @@ -168,17 +206,11 @@ toLLVMType(llvm::Module *M, const model::RawFunctionType &Prototype) { SmallVector ArgumentsTypes; SmallVector ReturnTypes; - for (const NamedTypedRegister &TR : Prototype.Arguments) { - auto Name = ABIRegister::toCSVName(TR.Location); - auto *CSV = cast(M->getGlobalVariable(Name, true)); - ArgumentsTypes.push_back(CSV->getType()->getPointerElementType()); - } + for (const NamedTypedRegister &TR : Prototype.Arguments) + ArgumentsTypes.push_back(getLLVMTypeForRegister(M, TR.Location)); - for (const TypedRegister &TR : Prototype.ReturnValues) { - auto Name = ABIRegister::toCSVName(TR.Location); - auto *CSV = cast(M->getGlobalVariable(Name, true)); - ReturnTypes.push_back(CSV->getType()->getPointerElementType()); - } + for (const TypedRegister &TR : Prototype.ReturnValues) + ReturnTypes.push_back(getLLVMTypeForRegister(M, TR.Location)); // Create the return type Type *ReturnType = Type::getVoidTy(Context); @@ -195,27 +227,17 @@ toLLVMType(llvm::Module *M, const model::RawFunctionType &Prototype) { Function *EnforceABIImpl::handleFunction(Function &OldFunction, const model::Function &FunctionModel) { - using model::NamedTypedRegister; - using model::RawFunctionType; - using model::TypedRegister; - - SmallVector ArgumentCSVs; - SmallVector ReturnCSVs; - - const auto &Prototype = *cast(FunctionModel.Prototype.get()); - // We sort arguments by their CSV name - for (const NamedTypedRegister &TR : Prototype.Arguments) { - auto Name = ABIRegister::toCSVName(TR.Location); - auto *CSV = cast(M.getGlobalVariable(Name, true)); - ArgumentCSVs.push_back(CSV); - } - - for (const TypedRegister &TR : Prototype.ReturnValues) { - auto Name = ABIRegister::toCSVName(TR.Location); - auto *CSV = cast(M.getGlobalVariable(Name, true)); - ReturnCSVs.push_back(CSV); - } + const model::Type *PrototypeType = FunctionModel.Prototype.get(); + const auto &Prototype = *cast(PrototypeType); + Function *NewFunction = recreateFunction(OldFunction, Prototype); + FunctionTags::Lifted.addTo(NewFunction); + createPrologue(NewFunction, FunctionModel); + return NewFunction; +} +Function * +EnforceABIImpl::recreateFunction(Function &OldFunction, + const model::RawFunctionType &Prototype) { // Create new function auto *NewType = toLLVMType(&M, Prototype); auto *NewFunction = Function::Create(NewType, @@ -224,7 +246,6 @@ Function *EnforceABIImpl::handleFunction(Function &OldFunction, OldFunction.getParent()); NewFunction->takeName(&OldFunction); NewFunction->copyAttributesFrom(&OldFunction); - FunctionTags::Lifted.addTo(NewFunction); // Set argument names for (const auto &[LLVMArgument, ModelArgument] : @@ -243,6 +264,33 @@ Function *EnforceABIImpl::handleFunction(Function &OldFunction, revng_assert(BB->getParent() == NewFunction); } + return NewFunction; +} + +void EnforceABIImpl::createPrologue(Function *NewFunction, + const model::Function &FunctionModel) { + using model::NamedTypedRegister; + using model::RawFunctionType; + using model::TypedRegister; + + const auto &Prototype = *cast(FunctionModel.Prototype.get()); + + SmallVector ArgumentCSVs; + SmallVector ReturnCSVs; + + // We sort arguments by their CSV name + for (const NamedTypedRegister &TR : Prototype.Arguments) { + auto Name = ABIRegister::toCSVName(TR.Location); + auto *CSV = cast(M.getGlobalVariable(Name, true)); + ArgumentCSVs.push_back(CSV); + } + + for (const TypedRegister &TR : Prototype.ReturnValues) { + auto Name = ABIRegister::toCSVName(TR.Location); + auto *CSV = cast(M.getGlobalVariable(Name, true)); + ReturnCSVs.push_back(CSV); + } + // Store arguments to CSVs BasicBlock &Entry = NewFunction->getEntryBlock(); IRBuilder<> StoreBuilder(Entry.getTerminator()); @@ -267,8 +315,6 @@ Function *EnforceABIImpl::handleFunction(Function &OldFunction, } } } - - return NewFunction; } void EnforceABIImpl::handleRegularFunctionCall(CallInst *Call) { @@ -276,7 +322,6 @@ void EnforceABIImpl::handleRegularFunctionCall(CallInst *Call) { const model::Function &FunctionModel = *FunctionsMap.at(Caller); Function *CallerFunction = Call->getParent()->getParent(); - revng_assert(CallerFunction->getName() == FunctionModel.name()); Function *Callee = cast(skipCasts(Call->getCalledOperand())); bool IsDirect = (Callee != FunctionDispatcher); @@ -316,7 +361,7 @@ void EnforceABIImpl::handleRegularFunctionCall(CallInst *Call) { // Generate the call IRBuilder<> Builder(Call); - generateCall(Builder, Callee, *CallSite); + generateCall(Builder, Callee, Block, *CallSite); // Create an additional store to the local %pc, so that the optimizer cannot // do stuff with llvm.assume. @@ -327,32 +372,43 @@ void EnforceABIImpl::handleRegularFunctionCall(CallInst *Call) { Call->eraseFromParent(); } +static FunctionCallee +toFunctionPointer(IRBuilder<> &B, Value *V, FunctionType *FT) { + Module *M = getModule(B.GetInsertBlock()); + const auto &DL = M->getDataLayout(); + IntegerType *IntPtrTy = DL.getIntPtrType(M->getContext()); + Value *Callee = B.CreateIntToPtr(V, FT->getPointerTo()); + return FunctionCallee(FT, Callee); +} + void EnforceABIImpl::generateCall(IRBuilder<> &Builder, - Function *Callee, + FunctionCallee Callee, + const model::BasicBlock &CallSiteBlock, const model::CallEdge &CallSite) { using model::NamedTypedRegister; using model::RawFunctionType; using model::TypedRegister; - revng_assert(Callee != nullptr); + revng_assert(Callee.getCallee() != nullptr); llvm::SmallVector Arguments; llvm::SmallVector ReturnCSVs; - const auto &Prototype = *cast(CallSite.Prototype.get()); + const auto &Prototype = abi::getRawFunctionTypeOrDefault(Binary, + CallSite.Prototype + .get()); - bool IsIndirect = (Callee != FunctionDispatcher); + bool IsIndirect = (Callee.getCallee() == FunctionDispatcher); if (IsIndirect) { // Create a new `indirect_placeholder` function with the specific function // type we need + Value *PC = GCBI.programCounterHandler()->loadJumpablePC(Builder); auto *NewType = toLLVMType(&M, Prototype); - Callee = IndirectPlaceholderPool.get(NewType, - NewType, - "indirect_placeholder"); + Callee = toFunctionPointer(Builder, PC, NewType); } else { BasicBlock *InsertBlock = Builder.GetInsertPoint()->getParent(); revng_log(EnforceABILog, - "Emitting call to " << getName(Callee) << " from " + "Emitting call to " << getName(Callee.getCallee()) << " from " << getName(InsertBlock)); } diff --git a/lib/FunctionIsolation/InvokeIsolatedFunctions.cpp b/lib/FunctionIsolation/InvokeIsolatedFunctions.cpp index 8fd09ef29..0723c88fc 100644 --- a/lib/FunctionIsolation/InvokeIsolatedFunctions.cpp +++ b/lib/FunctionIsolation/InvokeIsolatedFunctions.cpp @@ -46,9 +46,10 @@ public: continue; // TODO: this temporary - Map[Function.Entry] = { &Function, - nullptr, - M->getFunction(Function.name()) }; + auto Name = (Twine("local_") + Function.name()).str(); + llvm::Function *F = M->getFunction(Name); + revng_assert(F != nullptr); + Map[Function.Entry] = { &Function, nullptr, F }; } for (BasicBlock &BB : *RootFunction) { diff --git a/lib/FunctionIsolation/IsolateFunctions.cpp b/lib/FunctionIsolation/IsolateFunctions.cpp index 44b6e6cf6..537f4f1ae 100644 --- a/lib/FunctionIsolation/IsolateFunctions.cpp +++ b/lib/FunctionIsolation/IsolateFunctions.cpp @@ -7,6 +7,8 @@ // #include "llvm/ADT/PostOrderIterator.h" +#include "llvm/IR/DIBuilder.h" +#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Verifier.h" #include "llvm/Support/raw_os_ostream.h" @@ -124,8 +126,6 @@ public: class IsolateFunctionsImpl { private: - using BlockToFunctionsMap = std::map>; using SuccessorsContainer = std::map; private: @@ -136,8 +136,8 @@ private: const model::Binary &Binary; Function *RaiseException = nullptr; Function *FunctionDispatcher = nullptr; - Function *CallMarker = nullptr; - BlockToFunctionsMap IsolatedFunctionsMap; + std::map IsolatedFunctionsMap; + std::map DynamicFunctionsMap; ConstantStringsPool Strings; GlobalVariable *ExceptionSourcePC; GlobalVariable *ExceptionDestinationPC; @@ -157,9 +157,7 @@ public: private: /// Isolate the function described by \p Function - /// - /// \return a pair of the entry block in root and the newly create Function - std::pair isolate(const model::Function &Function); + void isolate(const model::Function &Function); /// Process a basic block from the model void handleBasicBlock(const model::BasicBlock &Block, @@ -170,7 +168,7 @@ private: /// /// \return a vector of boundary basic blocks std::vector - cloneAndIdentifyBoundaries(MetaAddress Entry, + cloneAndIdentifyBoundaries(const model::BasicBlock &Block, ValueToValueMapTy &OldToNew, FunctionBlocks &ClonedBlocks); @@ -187,17 +185,26 @@ private: FunctionBlocks &ClonedBlocks); /// Emit a function call marker and a branch to the return address + void createFunctionCall(IRBuilder<> &Builder, + Function *Callee, + const Boundary &TheBoundary); + void createFunctionCall(IRBuilder<> &Builder, MetaAddress ExpectedCallee, - const Boundary &TheBoundary, - FunctionBlocks &ClonedBlocks); + const Boundary &TheBoundary); + + void createFunctionCall(BasicBlock *BB, + Function *Callee, + const Boundary &TheBoundary) { + IRBuilder<> Builder(BB); + createFunctionCall(Builder, Callee, TheBoundary); + } void createFunctionCall(BasicBlock *BB, MetaAddress Callee, - const Boundary &TheBoundary, - FunctionBlocks &ClonedBlocks) { + const Boundary &TheBoundary) { IRBuilder<> Builder(BB); - createFunctionCall(Builder, Callee, TheBoundary, ClonedBlocks); + createFunctionCall(Builder, Callee, TheBoundary); } /// Post process all the call markers, replacing them with actual calls @@ -208,11 +215,11 @@ private: /// Create code to throw of an exception void throwException(IRBuilder<> &Builder, - StringRef Reason, + const Twine &Reason, const DebugLoc &DbgLocation); void throwException(BasicBlock *BB, - StringRef Reason, + const Twine &Reason, const DebugLoc &DbgLocation) { IRBuilder<> Builder(BB); throwException(Builder, Reason, DbgLocation); @@ -220,10 +227,10 @@ private: }; void IFI::throwException(IRBuilder<> &Builder, - StringRef Reason, + const Twine &Reason, const DebugLoc &DbgLocation) { revng_assert(RaiseException != nullptr); - revng_assert(DbgLocation); + // revng_assert(DbgLocation); // Create the message string Constant *ReasonString = Strings.get(Reason.str()); @@ -269,14 +276,12 @@ void IFI::populateFunctionDispatcher() { // Create all the entries of the dispatcher ProgramCounterHandler::DispatcherTargets Targets; - for (auto &[Block, P] : IsolatedFunctionsMap) { - auto &[_, F] = P; - + for (auto &[Address, F] : IsolatedFunctionsMap) { BasicBlock *Trampoline = BasicBlock::Create(Context, F->getName() + "_trampoline", FunctionDispatcher, nullptr); - Targets.emplace_back(GCBI.getPCFromNewPC(&*Block->begin()), Trampoline); + Targets.emplace_back(Address, Trampoline); Builder.SetInsertPoint(Trampoline); Builder.CreateCall(F); @@ -492,10 +497,7 @@ bool IFI::handleIndirectBoundary(const std::vector &Boundaries, switch (IndirectType) { case IndirectCall: case IndirectTailCall: - createFunctionCall(Builder, - MetaAddress::invalid(), - *IndirectBoundary, - ClonedBlocks); + createFunctionCall(Builder, MetaAddress::invalid(), *IndirectBoundary); break; case Return: @@ -601,7 +603,7 @@ bool IFI::handleDirectBoundary(const Boundary &TheBoundary, if (Edge.Type == model::FunctionEdgeType::FunctionCall) { eraseBranch(BB->getTerminator(), TheBoundary.CalleeBlock); - createFunctionCall(BB, Edge.Destination, TheBoundary, ClonedBlocks); + createFunctionCall(BB, Edge.Destination, TheBoundary); } } } @@ -612,9 +614,10 @@ bool IFI::handleDirectBoundary(const Boundary &TheBoundary, } std::vector -IFI::cloneAndIdentifyBoundaries(MetaAddress Entry, +IFI::cloneAndIdentifyBoundaries(const model::BasicBlock &Block, ValueToValueMapTy &OldToNew, FunctionBlocks &ClonedBlocks) { + MetaAddress Entry = Block.Start; std::set Blocks; for (BasicBlock *Block : GCBI.getBlocksGeneratedByPC(Entry)) Blocks.insert(Block); @@ -643,34 +646,6 @@ IFI::cloneAndIdentifyBoundaries(MetaAddress Entry, } } - return Boundaries; -} - -void IFI::handleBasicBlock(const model::BasicBlock &Block, - ValueToValueMapTy &OldToNew, - FunctionBlocks &ClonedBlocks) { - // Sentinel to ensure we don't have more than a call within a basic block - SetAtMostOnce CallConsumed; - - // Identify boundary blocks - std::vector Boundaries = cloneAndIdentifyBoundaries(Block.Start, - OldToNew, - ClonedBlocks); - - // At this point, we first need to handle all the boundary blocks that - // represent direct jumps, then we'll take care of the (only) indirect jump, - // if any - - SuccessorsContainer ExpectedSuccessors; - for (const auto &E : Block.Successors) { - // Ignore self-loops - if (E->Destination != Block.Start) { - ExpectedSuccessors[*E] = 0; - } - } - - int IndirectCount = 0; - if (TheLogger.isEnabled()) { TheLogger << "Boundaries: \n"; for (const Boundary &B : Boundaries) { @@ -690,6 +665,63 @@ void IFI::handleBasicBlock(const model::BasicBlock &Block, TheLogger << Buffer << DoLog; } + return Boundaries; +} + +void IFI::handleBasicBlock(const model::BasicBlock &Block, + ValueToValueMapTy &OldToNew, + FunctionBlocks &ClonedBlocks) { + if (TheLogger.isEnabled()) { + TheLogger << "Isolating "; + Block.Start.dump(TheLogger); + TheLogger << "-"; + Block.End.dump(TheLogger); + TheLogger << DoLog; + } + + LoggerIndent<> Indent(TheLogger); + + // Sentinel to ensure we don't have more than a call within a basic block + SetAtMostOnce CallConsumed; + + // Identify boundary blocks + std::vector Boundaries = cloneAndIdentifyBoundaries(Block.Start, + OldToNew, + ClonedBlocks); + + // Handle call to dynamic functions + StringRef DynamicFunction; + for (const auto &Edge : Block.Successors) + if (auto *Call = dyn_cast(Edge.get())) + if (not Call->DynamicFunction.empty()) + DynamicFunction = Call->DynamicFunction; + + if (not DynamicFunction.empty()) { + revng_assert(Boundaries.size() == 1); + const auto &TheBoundary = Boundaries[0]; + auto *BB = TheBoundary.Block; + + eraseBranch(BB->getTerminator(), TheBoundary.CalleeBlock); + + createFunctionCall(BB, + DynamicFunctionsMap.at(DynamicFunction), + TheBoundary); + + return; + } + + // At this point, we first need to handle all the boundary blocks that + // represent direct jumps, then we'll take care of the (only) indirect jump, + // if any + + SuccessorsContainer ExpectedSuccessors; + for (const auto &E : Block.Successors) { + // Ignore self-loops + if (E->Destination != Block.Start) { + ExpectedSuccessors[*E] = 0; + } + } + // Consume direct jumps calls for (const auto &Boundary : Boundaries) { if (not(Boundary.Successors.AnyPC or Boundary.Successors.UnexpectedPC)) { @@ -710,8 +742,7 @@ void IFI::handleBasicBlock(const model::BasicBlock &Block, revng_assert(not(HasIndirectBoundary and CallConsumed)); } -std::pair -IFI::isolate(const model::Function &Function) { +void IFI::isolate(const model::Function &Function) { // Map from origina values to new ones ValueToValueMapTy OldToNew; @@ -741,21 +772,9 @@ IFI::isolate(const model::Function &Function) { TheLogger << DoLog; LoggerIndent<> Indent(TheLogger); - for (const model::BasicBlock &Block : Function.CFG) { - - if (TheLogger.isEnabled()) { - TheLogger << "Isolating "; - Block.Start.dump(TheLogger); - TheLogger << "-"; - Block.End.dump(TheLogger); - TheLogger << DoLog; - } - - LoggerIndent<> Indent2(TheLogger); - - // Process the basic block + // Process each basic block + for (const model::BasicBlock &Block : Function.CFG) handleBasicBlock(Block, OldToNew, ClonedBlocks); - } // Create a dummy entry branching to real entry revng_assert(ClonedBlocks.dummyEntryBlock() == nullptr); @@ -788,27 +807,46 @@ IFI::isolate(const model::Function &Function) { true, ""); llvm::Function *NewFunction = CE.extractCodeRegion(CEAC); - FunctionTags::Lifted.addTo(NewFunction); - revng_assert(NewFunction != nullptr); - NewFunction->setName(Function.name()); FunctionType *FT = NewFunction->getFunctionType(); revng_assert(FT->getReturnType()->isVoidTy()); revng_assert(FT->getNumParams() == 0); - return { OriginalEntry, NewFunction }; + auto *TargetFunction = IsolatedFunctionsMap.at(Function.Entry); + + // Record all the blocks + SmallVector Blocks; + for (BasicBlock &BB : *NewFunction) + Blocks.push_back(&BB); + + // Move the blocks + for (BasicBlock *BB : Blocks) { + BB->removeFromParent(); + TargetFunction->getBasicBlockList().push_back(BB); + } + + // Drop the temporary isolated functions and its call + auto UserIt = NewFunction->user_begin(); + revng_assert(UserIt != NewFunction->user_end()); + auto *Call = cast(*UserIt); + ++UserIt; + revng_assert(UserIt == NewFunction->user_end()); + Call->eraseFromParent(); + + revng_assert(NewFunction->use_empty()); + revng_assert(NewFunction->getBasicBlockList().empty()); + NewFunction->eraseFromParent(); } void IFI::createFunctionCall(IRBuilder<> &Builder, MetaAddress ExpectedCallee, - const Boundary &TheBoundary, - FunctionBlocks &ClonedBlocks) { + const Boundary &TheBoundary) { + Function *Callee = nullptr; BasicBlock *ExpectedCalleeBB = nullptr; - unsigned CalleeIndex = 0; if (ExpectedCallee.isValid()) { + Callee = IsolatedFunctionsMap.at(ExpectedCallee); ExpectedCalleeBB = GCBI.getBlockAt(ExpectedCallee); - CalleeIndex = IsolatedFunctionsMap.at(ExpectedCalleeBB).first; } if (TheBoundary.CalleeBlock != nullptr @@ -820,12 +858,22 @@ void IFI::createFunctionCall(IRBuilder<> &Builder, << getName(ExpectedCalleeBB) << ")"); } + createFunctionCall(Builder, Callee, TheBoundary); +} + +void IFI::createFunctionCall(IRBuilder<> &Builder, + Function *Callee, + const Boundary &TheBoundary) { + + if (Callee == nullptr) + Callee = FunctionDispatcher; + BasicBlock::iterator InsertPoint = Builder.GetInsertPoint(); revng_assert(not Builder.GetInsertBlock()->empty()); - Instruction *Old = InsertPoint == Builder.GetInsertBlock()->end() ? - &*Builder.GetInsertBlock()->rbegin() : - &*InsertPoint; - auto *NewCall = Builder.CreateCall(CallMarker, Builder.getInt32(CalleeIndex)); + bool AtEnd = InsertPoint == Builder.GetInsertBlock()->end(); + Instruction *Old = AtEnd ? &*Builder.GetInsertBlock()->rbegin() : + &*InsertPoint; + auto *NewCall = Builder.CreateCall(Callee); NewCall->setDebugLoc(Old->getDebugLoc()); if (TheBoundary.ReturnBlock != nullptr) { @@ -833,9 +881,8 @@ void IFI::createFunctionCall(IRBuilder<> &Builder, Builder.CreateBr(TheBoundary.ReturnBlock); } else { if (TheLogger.isEnabled()) { - TheLogger << "Call to "; - ExpectedCallee.dump(TheLogger); - TheLogger << " in " << getName(TheBoundary.Block) + TheLogger << "Call to " << Callee->getName() << " in " + << getName(TheBoundary.Block) << " has not been detected as a function call in the binary." << DoLog; } @@ -847,32 +894,6 @@ void IFI::createFunctionCall(IRBuilder<> &Builder, } } -void IFI::replaceCallMarker() const { - std::vector Functions; - Functions.resize(IsolatedFunctionsMap.size() + 1); - - Functions[0] = FunctionDispatcher; - for (auto [_, P] : IsolatedFunctionsMap) { - auto [Index, Function] = P; - revng_assert(Index != 0); - revng_assert(Function != nullptr); - Functions[Index] = Function; - } - - for (auto It = CallMarker->user_begin(); It != CallMarker->user_end();) { - User *U = *It; - ++It; - - auto *Call = cast(U); - Value *CallMarkerArgument = Call->getArgOperand(0); - unsigned Index = cast(CallMarkerArgument)->getLimitedValue(); - Function *Callee = Functions[Index]; - auto *NewCall = CallInst::Create(FunctionCallee{ Callee }, "", Call); - NewCall->setDebugLoc(Call->getDebugLoc()); - Call->eraseFromParent(); - } -} - void IFI::run() { ExceptionSourcePC = MetaAddress::createStructVariable(TheModule, "exception_source_pc"); @@ -899,18 +920,53 @@ void IFI::run() { TheModule); FunctionTags::FunctionDispatcher.addTo(FunctionDispatcher); - auto *CallMarkerFTy = createFunctionType(Context); - CallMarker = Function::Create(CallMarkerFTy, - GlobalValue::ExternalLinkage, - "call_marker", - TheModule); + auto *IsolatedFunctionType = createFunctionType(Context); - unsigned I = 1; + // Create all the dynamic functions + for (const model::DynamicFunction &Function : + Binary.ImportedDynamicFunctions) { + StringRef Name = Function.SymbolName; + auto *NewFunction = Function::Create(IsolatedFunctionType, + GlobalValue::ExternalLinkage, + "dynamic_" + Function.name(), + TheModule); + FunctionTags::DynamicFunction.addTo(NewFunction); + auto *EntryBB = BasicBlock::Create(Context, "", NewFunction); + throwException(EntryBB, Twine("Dynamic call ") + Name, DebugLoc()); + + // TODO: implement more efficient version. + // if (setjmp(...) == 0) { + // // First return + // serialize_cpu_state(); + // dynamic_function(); + // // If we get here, it means that the external function return properly + // deserialize_cpu_state(); + // simulate_ret(); + // // If the caller tail-called us, it must return immediately, without + // // checking if the pc is the fallthrough of the call (which was not a + // // call!) + // } else { + // // If we get here, it means that the external function either invoked a + // // callback or something else weird i going on. + // deserialize_cpu_state(); + // throw_exception(); + // } + + DynamicFunctionsMap[Name] = NewFunction; + } + + // Precreate all the isolated functions for (const model::Function &Function : Binary.Functions) { if (Function.Type == model::FunctionType::Fake) continue; - IsolatedFunctionsMap[GCBI.getBlockAt(Function.Entry)].first = I; - ++I; + + auto *NewFunction = Function::Create(IsolatedFunctionType, + GlobalValue::ExternalLinkage, + "local_" + Function.name(), + TheModule); + IsolatedFunctionsMap[Function.Entry] = NewFunction; + FunctionTags::Lifted.addTo(NewFunction); + revng_assert(NewFunction != nullptr); } std::set IsolatedFunctions; @@ -920,19 +976,9 @@ void IFI::run() { continue; // Perform isolation - auto [EntryBlock, IsolatedFunction] = isolate(Function); - - // Record new isolated function - BasicBlock *OriginalEntry = GCBI.getBlockAt(Function.Entry); - IsolatedFunctions.insert(IsolatedFunction); - IsolatedFunctionsMap.at(OriginalEntry).second = IsolatedFunction; + isolate(Function); } - replaceCallMarker(); - - this->CallMarker->eraseFromParent(); - this->CallMarker = nullptr; - revng_check(not verifyModule(*TheModule, &dbgs())); // Create the functions and basic blocks needed for the correct execution of diff --git a/lib/FunctionIsolation/PromoteCSVs.cpp b/lib/FunctionIsolation/PromoteCSVs.cpp index bc5cba582..55ab955ce 100644 --- a/lib/FunctionIsolation/PromoteCSVs.cpp +++ b/lib/FunctionIsolation/PromoteCSVs.cpp @@ -535,10 +535,9 @@ void PromoteCSVs::wrapCallsToHelpers(Function *F) { for (Instruction &I : BB) { if (auto *Call = dyn_cast(&I)) { Function *Callee = getCallee(Call); - revng_assert(Callee != nullptr); // Ignore calls to isolated functions - if (not needsWrapper(Callee)) + if (Callee == nullptr or not needsWrapper(Callee)) continue; ToWrap.emplace_back(Call); diff --git a/lib/Model/Binary.cpp b/lib/Model/Binary.cpp index 66b2ca539..c022edf82 100644 --- a/lib/Model/Binary.cpp +++ b/lib/Model/Binary.cpp @@ -140,21 +140,49 @@ bool Binary::verify(VerifyHelper &VH) const { if (Edge->Type == model::FunctionEdgeType::FunctionCall) { // We're in a direct call, get the callee const auto *Call = dyn_cast(Edge.get()); - auto It = Functions.find(Call->Destination); - // If missing, fail - if (It == Functions.end()) - return VH.fail(); + model::TypePath CalleePrototype; + if (not Call->DynamicFunction.empty()) { + // It's a dynamic call + + if (Call->Destination.isValid()) { + return VH.fail("Destination must be invalid for dynamic function " + "calls"); + } + + auto It = ImportedDynamicFunctions.find(Call->DynamicFunction); + + // If missing, fail + if (It == ImportedDynamicFunctions.end()) + return VH.fail("Can't find callee \"" + Call->DynamicFunction + + "\""); + CalleePrototype = It->Prototype; + } else { + // Regular call + auto It = Functions.find(Call->Destination); + + // If missing, fail + if (It == Functions.end()) + return VH.fail("Can't find callee"); + + CalleePrototype = It->Prototype; + } // If call and callee prototypes differ, fail - const Function &Callee = *It; - if (Call->Prototype != Callee.Prototype) - return VH.fail(); + if (Call->Prototype != CalleePrototype) + return VH.fail("In direct calls, function prototype of call and " + "callee must be the same"); } } } } + // Verify DynamicFunctions + for (const DynamicFunction &DF : ImportedDynamicFunctions) { + if (not DF.verify(VH)) + return VH.fail(); + } + // // Verify the type system // @@ -212,6 +240,14 @@ Identifier Function::name() const { } } +Identifier DynamicFunction::name() const { + using llvm::Twine; + if (not CustomName.empty()) + return CustomName; + else + return Identifier(SymbolName); +} + void Function::dumpCFG() const { FunctionCFG CFG = getGraph(*this); raw_os_ostream Stream(dbg); @@ -276,6 +312,36 @@ bool Function::verify(VerifyHelper &VH) const { return true; } +bool DynamicFunction::verify() const { + return verify(false); +} + +bool DynamicFunction::verify(bool Assert) const { + VerifyHelper VH(Assert); + return verify(VH); +} + +bool DynamicFunction::verify(VerifyHelper &VH) const { + // Ensure we have a name + if (SymbolName.size() == 0) + return VH.fail("Dynamic functions must have a SymbolName"); + + // Prototype is present + if (not Prototype.isValid()) + return VH.fail(); + + // Prototype is valid + if (not Prototype.get()->verify(VH)) + return VH.fail(); + + const model::Type *FunctionType = Prototype.get(); + if (not(isa(FunctionType) + or isa(FunctionType))) + return VH.fail(); + + return true; +} + bool FunctionEdge::verify() const { return verify(false); } @@ -287,8 +353,37 @@ bool FunctionEdge::verify(bool Assert) const { static bool verifyFunctionEdge(VerifyHelper &VH, const FunctionEdge &E) { using namespace model::FunctionEdgeType; - return VH.maybeFail(E.Type != FunctionEdgeType::Invalid - and E.Destination.isValid() == hasDestination(E.Type)); + + switch (E.Type) { + case Invalid: + case Count: + return VH.fail(); + + case DirectBranch: + case FakeFunctionCall: + case FakeFunctionReturn: + if (E.Destination.isInvalid()) + return VH.fail(); + break; + case FunctionCall: { + const auto &Call = cast(E); + if (not(E.Destination.isValid() == Call.DynamicFunction.empty())) + return VH.fail(); + } break; + + case IndirectCall: + case Return: + case BrokenReturn: + case IndirectTailCall: + case LongJmp: + case Killer: + case Unreachable: + if (E.Destination.isValid()) + return VH.fail(); + break; + } + + return true; } bool FunctionEdge::verify(VerifyHelper &VH) const { @@ -308,6 +403,13 @@ bool CallEdge::verify(bool Assert) const { } bool CallEdge::verify(VerifyHelper &VH) const { + if (Type == model::FunctionEdgeType::FunctionCall) { + if (Destination.isInvalid() and DynamicFunction.empty()) + return VH.fail("Direct call is missing Destination"); + else if (Destination.isValid() and not DynamicFunction.empty()) + return VH.fail("Dynamic function calls cannot have a valid Destination"); + } + return VH.maybeFail(verifyFunctionEdge(VH, *this) and Prototype.isValid() and Prototype.get()->verify(VH)); } diff --git a/lib/StackAnalysis/StackAnalysis.cpp b/lib/StackAnalysis/StackAnalysis.cpp index 599ce785f..c89703e38 100644 --- a/lib/StackAnalysis/StackAnalysis.cpp +++ b/lib/StackAnalysis/StackAnalysis.cpp @@ -227,7 +227,53 @@ void commitToModel(GeneratedCodeBasicInfo &GCBI, break; case BranchType::InstructionLocalCFG: - EdgeType = FET::Invalid; + continue; + + default: + break; + } + + // Identify Source address + auto [Source, Size] = getPC(BB->getTerminator()); + Source += Size; + revng_assert(Source.isValid()); + + // Identify Destination address + llvm::BasicBlock *JumpTargetBB = GCBI.getJumpTargetBlock(BB); + MetaAddress JumpTargetAddress = GCBI.getPCFromNewPC(JumpTargetBB); + model::BasicBlock &CurrentBlock = Function.CFG[JumpTargetAddress]; + CurrentBlock.End = Source; + auto SuccessorsInserter = CurrentBlock.Successors.batch_insert(); + + llvm::BasicBlock *Successor = BB->getSingleSuccessor(); + llvm::StringRef SymbolName; + + MetaAddress Destination = MetaAddress::invalid(); + if (Successor != nullptr) + Destination = getBasicBlockPC(Successor); + + if (Destination.isValid()) { + revng_assert(not JumpTargetBB->empty()); + auto *NewPCCall = getCallTo(&*Successor->begin(), "newpc"); + revng_assert(NewPCCall != nullptr); + + // Extract symbol name if any + auto *SymbolNameValue = NewPCCall->getArgOperand(4); + if (not isa(SymbolNameValue)) { + llvm::Value *SymbolNameString = NewPCCall->getArgOperand(4); + SymbolName = extractFromConstantStringPtr(SymbolNameString); + revng_assert(SymbolName.size() != 0); + } + } + + switch (Branch) { + case BranchType::Invalid: + case BranchType::FakeFunction: + case BranchType::RegularFunction: + case BranchType::NoReturnFunction: + case BranchType::UnhandledCall: + case BranchType::InstructionLocalCFG: + revng_abort(); break; case BranchType::FunctionLocalCFG: @@ -243,7 +289,10 @@ void commitToModel(GeneratedCodeBasicInfo &GCBI, break; case BranchType::HandledCall: - EdgeType = FET::FunctionCall; + if (SymbolName.size() > 0) + EdgeType = FET::IndirectCall; + else + EdgeType = FET::FunctionCall; break; case BranchType::IndirectCall: @@ -275,21 +324,6 @@ void commitToModel(GeneratedCodeBasicInfo &GCBI, break; } - if (EdgeType == FET::Invalid) - continue; - - // Identify Source address - auto [Source, Size] = getPC(BB->getTerminator()); - Source += Size; - revng_assert(Source.isValid()); - - // Identify Destination address - llvm::BasicBlock *JumpTargetBB = GCBI.getJumpTargetBlock(BB); - MetaAddress JumpTargetAddress = GCBI.getPCFromNewPC(JumpTargetBB); - model::BasicBlock &CurrentBlock = Function.CFG[JumpTargetAddress]; - CurrentBlock.End = Source; - auto SuccessorsInserter = CurrentBlock.Successors.batch_insert(); - if (EdgeType == FET::DirectBranch) { // Handle direct branch auto Successors = GCBI.getSuccessors(BB); @@ -304,21 +338,31 @@ void commitToModel(GeneratedCodeBasicInfo &GCBI, SuccessorsInserter.insert(MakeEdge(Destination, EdgeType)); } else if (FunctionEdgeType::isCall(EdgeType)) { - // Handle call - llvm::BasicBlock *Successor = BB->getSingleSuccessor(); - MetaAddress Destination = MetaAddress::invalid(); - if (Successor != nullptr) - Destination = getBasicBlockPC(Successor); - // Record the edge in the CFG auto TempEdge = MakeEdge(Destination, EdgeType); const auto &Result = SuccessorsInserter.insert(TempEdge); auto *Edge = llvm::cast(Result.get()); if (Destination.isValid()) { - // If it's a direct call, inherit the prototype from the callee - model::Function &Callee = TheBinary.Functions.at(Destination); - Edge->Prototype = Callee.Prototype; + const auto IDF = TheBinary.ImportedDynamicFunctions; + bool IsDynamicCall = (not SymbolName.empty() + and IDF.count(SymbolName.str()) != 0); + if (IsDynamicCall) { + revng_assert(EdgeType == model::FunctionEdgeType::IndirectCall); + Edge->Destination = MetaAddress::invalid(); + Edge->DynamicFunction = SymbolName.str(); + Edge->Prototype = TheBinary.ImportedDynamicFunctions + .at(Edge->DynamicFunction) + .Prototype; + } else { + revng_assert(EdgeType == model::FunctionEdgeType::FunctionCall); + // If it's a direct call, inherit the prototype from the callee + model::Function &Callee = TheBinary.Functions.at(Destination); + Edge->Prototype = Callee.Prototype; + } + + revng_assert(Edge->Prototype.isValid()); + } else { // It's an indirect call: forge a new prototype auto NewType = makeType(); @@ -370,9 +414,6 @@ void commitToModel(GeneratedCodeBasicInfo &GCBI, } else { // Handle other successors llvm::BasicBlock *Successor = BB->getSingleSuccessor(); - MetaAddress Destination = MetaAddress::invalid(); - if (Successor != nullptr) - Destination = getBasicBlockPC(Successor); // Record the edge in the CFG SuccessorsInserter.insert(MakeEdge(Destination, EdgeType)); diff --git a/lib/Support/FunctionTags.cpp b/lib/Support/FunctionTags.cpp index 0d32cc77c..cf665656a 100644 --- a/lib/Support/FunctionTags.cpp +++ b/lib/Support/FunctionTags.cpp @@ -31,6 +31,7 @@ Tag FunctionDispatcher("FunctionDispatcher"); Tag Root("Root"); Tag CSVsAsArgumentsWrapper("CSVsAsArgumentsWrapper"); Tag Marker("Marker"); +Tag DynamicFunction("DynamicFunction"); static const char *TagsMetadataName = "revng.tags"; diff --git a/lib/Support/IRHelpers.cpp b/lib/Support/IRHelpers.cpp index 8ebce6369..c95ed63b9 100644 --- a/lib/Support/IRHelpers.cpp +++ b/lib/Support/IRHelpers.cpp @@ -43,6 +43,23 @@ Constant *buildStringPtr(Module *M, StringRef String, const Twine &Name) { return ConstantExpr::getBitCast(NewVariable, getStringPtrType(C)); } +StringRef extractFromConstantStringPtr(Value *V) { + auto *ConstantGEP = dyn_cast(V); + if (ConstantGEP == nullptr) + return {}; + + auto *NoCasts = ConstantGEP->stripPointerCasts(); + auto *GV = dyn_cast_or_null(NoCasts); + if (GV == nullptr) + return {}; + + auto *Initializer = dyn_cast_or_null(GV->getInitializer()); + if (Initializer == nullptr or not Initializer->isCString()) + return {}; + + return Initializer->getAsCString(); +} + Constant *getUniqueString(Module *M, StringRef Namespace, StringRef String, diff --git a/tests/unit/Model.cpp b/tests/unit/Model.cpp index 89294cff7..201ce13e3 100644 --- a/tests/unit/Model.cpp +++ b/tests/unit/Model.cpp @@ -60,10 +60,6 @@ BOOST_AUTO_TEST_CASE(TestPathAccess) { revng_check(getByPath("/Functions/:Invalid", TheBinary) == &F); } -template<> -struct llvm::yaml::ScalarTraits> - : CompositeScalar, '-'> {}; - BOOST_AUTO_TEST_CASE(TestCompositeScalar) { // MetaAddress pair { diff --git a/tools/revng-lift/AdvancedValueInfoPass.h b/tools/revng-lift/AdvancedValueInfoPass.h index da09d4ca5..e45ea9c46 100644 --- a/tools/revng-lift/AdvancedValueInfoPass.h +++ b/tools/revng-lift/AdvancedValueInfoPass.h @@ -147,9 +147,12 @@ AdvancedValueInfoPass::run(llvm::Function &F, ValuesMD.reserve(Values.size()); for (const MaterializedValue &V : Values) { // TODO: we are we ignoring those with symbols - if (not V.hasSymbol()) { - ValuesMD.push_back(QMD.get(V.value())); - } + auto Offset = V.value(); + StringRef SymbolName; + if (V.hasSymbol()) + SymbolName = V.symbolName(); + + ValuesMD.push_back(QMD.tuple({ QMD.get(SymbolName), QMD.get(Offset) })); } Call->setMetadata("revng.avi", QMD.tuple(ValuesMD)); diff --git a/tools/revng-lift/BinaryFile.cpp b/tools/revng-lift/BinaryFile.cpp index e0dcaa252..66b9b423f 100644 --- a/tools/revng-lift/BinaryFile.cpp +++ b/tools/revng-lift/BinaryFile.cpp @@ -1984,7 +1984,7 @@ std::string BinaryFile::nameForAddress(MetaAddress Address, uint64_t Size) const { using interval = boost::icl::interval; std::stringstream Result; - const auto &SymbolMap = labels(); + const auto &SymbolMap = labelsMap(); auto End = Address.toGeneric() + Size; revng_assert(Address.isValid() and End.isValid()); diff --git a/tools/revng-lift/BinaryFile.h b/tools/revng-lift/BinaryFile.h index d9ce2b14c..8c9ad9090 100644 --- a/tools/revng-lift/BinaryFile.h +++ b/tools/revng-lift/BinaryFile.h @@ -281,6 +281,8 @@ public: bool hasValue() const { return isAbsoluteValue() or isBaseRelativeValue(); } + LabelOrigin::Values origin() const { return Origin; } + MetaAddress address() const { return Address; } uint64_t size() const { return Size; } @@ -485,7 +487,8 @@ public: const Architecture &architecture() const { return TheArchitecture; } std::vector &segments() { return Segments; } const std::vector &segments() const { return Segments; } - const LabelIntervalMap &labels() const { return LabelsMap; } + const LabelIntervalMap &labelsMap() const { return LabelsMap; } + llvm::ArrayRef