diff --git a/include/revng/DebugHelper/DebugHelper.h b/include/revng/DebugHelper/DebugHelper.h index 230ea8994..abb5105c0 100644 --- a/include/revng/DebugHelper/DebugHelper.h +++ b/include/revng/DebugHelper/DebugHelper.h @@ -63,8 +63,9 @@ public: /// metadata refering to the produce IR itself or not. DebugAnnotationWriter(llvm::LLVMContext &Context, bool DebugInfo); - virtual void emitInstructionAnnot(const llvm::Instruction *TheInstruction, - llvm::formatted_raw_ostream &Output); + virtual void + emitInstructionAnnot(const llvm::Instruction *TheInstruction, + llvm::formatted_raw_ostream &Output) override; private: llvm::LLVMContext &Context; diff --git a/include/revng/Support/IRHelpers.h b/include/revng/Support/IRHelpers.h index f918f68cf..0339547ae 100644 --- a/include/revng/Support/IRHelpers.h +++ b/include/revng/Support/IRHelpers.h @@ -11,6 +11,7 @@ #include // LLVM includes +#include "llvm/ADT/iterator_range.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/Interval.h" @@ -60,7 +61,7 @@ inline void purgeBranch(llvm::BasicBlock::iterator I) { inline llvm::ConstantInt * getConstValue(llvm::Constant *C, const llvm::DataLayout &DL) { while (auto *Expr = llvm::dyn_cast(C)) { - C = ConstantFoldConstantExpression(Expr, DL); + C = ConstantFoldConstant(Expr, DL); if (Expr->getOpcode() == llvm::Instruction::IntToPtr || Expr->getOpcode() == llvm::Instruction::PtrToInt) @@ -159,13 +160,6 @@ inline I *isa_with_op(llvm::Instruction *Inst) { return nullptr; } -/// \brief Return an range iterating backward from the given instruction -inline llvm::iterator_range -backward_range(llvm::Instruction *I) { - return llvm::make_range(llvm::make_reverse_iterator(I->getIterator()), - I->getParent()->rend()); -} - template struct BlackListTraitBase { BlackListTraitBase(C Obj) : Obj(Obj) {} @@ -290,7 +284,7 @@ inline void visitPredecessors(llvm::Instruction *I, BlackListTrait BL) { std::set Visited; - llvm::BasicBlock::reverse_iterator It(make_reverse_iterator(I)); + llvm::BasicBlock::reverse_iterator It(++I->getReverseIterator()); if (It == I->getParent()->rend()) return; @@ -498,7 +492,7 @@ QuickMetadata::extract(const llvm::Metadata *MD) { /// \brief Return the instruction coming before \p I, or nullptr if it's the /// first. inline llvm::Instruction *getPrevious(llvm::Instruction *I) { - llvm::BasicBlock::reverse_iterator It(make_reverse_iterator(I)); + llvm::BasicBlock::reverse_iterator It(++I->getReverseIterator()); if (It == I->getParent()->rend()) return nullptr; @@ -626,7 +620,7 @@ inline void erase_if(Container &C, UnaryPredicate P) { C.erase(std::remove_if(C.begin(), C.end(), P), C.end()); } -inline std::string dumpToString(llvm::Value *V) { +inline std::string dumpToString(const llvm::Value *V) { std::string Result; llvm::raw_string_ostream Stream(Result); V->print(Stream, true); @@ -634,7 +628,7 @@ inline std::string dumpToString(llvm::Value *V) { return Result; } -inline std::string dumpToString(llvm::Module *M) { +inline std::string dumpToString(const llvm::Module *M) { std::string Result; llvm::raw_string_ostream Stream(Result); M->print(Stream, nullptr, false, true); diff --git a/include/revng/Support/revng.h b/include/revng/Support/revng.h index 4c926794a..fe75abbca 100644 --- a/include/revng/Support/revng.h +++ b/include/revng/Support/revng.h @@ -15,7 +15,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" -#include "llvm/Support/ELF.h" +#include "llvm/BinaryFormat/ELF.h" // Local libraries includes #include "revng/Support/IRHelpers.h" @@ -261,7 +261,9 @@ public: llvm::SmallVector abiRegisters() const { return ABIRegisters; } - const char *name() const { return llvm::Triple::getArchTypeName(Type); } + const char *name() const { + return llvm::Triple::getArchTypeName(Type).data(); + } unsigned pcMContextIndex() const { return PCMContextIndex; } llvm::StringRef writeRegisterAsm() const { return WriteRegisterAsm; } diff --git a/lib/BasicAnalyses/GeneratedCodeBasicInfo.cpp b/lib/BasicAnalyses/GeneratedCodeBasicInfo.cpp index 3dabbc2bc..8ef30f1a5 100644 --- a/lib/BasicAnalyses/GeneratedCodeBasicInfo.cpp +++ b/lib/BasicAnalyses/GeneratedCodeBasicInfo.cpp @@ -89,7 +89,7 @@ GeneratedCodeBasicInfo::getPC(Instruction *TheInstruction) const { if (TheInstruction->getIterator() == TheInstruction->getParent()->begin()) WorkList.push(--TheInstruction->getParent()->rend()); else - WorkList.push(make_reverse_iterator(TheInstruction)); + WorkList.push(++TheInstruction->getReverseIterator()); while (!WorkList.empty()) { auto I = WorkList.front(); diff --git a/lib/DebugHelper/DebugHelper.cpp b/lib/DebugHelper/DebugHelper.cpp index 4ac1aaa01..2ee776f10 100644 --- a/lib/DebugHelper/DebugHelper.cpp +++ b/lib/DebugHelper/DebugHelper.cpp @@ -11,6 +11,7 @@ // LLVM includes #include "llvm/IR/AssemblyAnnotationWriter.h" +#include "llvm/IR/DIBuilder.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" @@ -62,7 +63,7 @@ static void writeMetadataIfNew(const Instruction *TheInstruction, MDString *PrevMD = nullptr; do { - if (TheInstruction == TheInstruction->getParent()->begin()) + if (TheInstruction->getIterator() == TheInstruction->getParent()->begin()) TheInstruction = nullptr; else { TheInstruction = TheInstruction->getPrevNode(); @@ -149,9 +150,9 @@ DebugHelper::DebugHelper(std::string Output, } if (DebugInfo != DebugInfoType::None) { + auto File = Builder.createFile(this->DebugPath, ""); CompileUnit = Builder.createCompileUnit(dwarf::DW_LANG_C, - this->DebugPath, - "", + File, "revamb", false, "", diff --git a/lib/StackAnalysis/ABIIR.h b/lib/StackAnalysis/ABIIR.h index 2ddf8dba2..9cee6b584 100644 --- a/lib/StackAnalysis/ABIIR.h +++ b/lib/StackAnalysis/ABIIR.h @@ -451,10 +451,10 @@ namespace llvm { template<> struct GraphTraits { - using NodeType = StackAnalysis::ABIIRBasicBlock; + using NodeRef = StackAnalysis::ABIIRBasicBlock *; using ChildIteratorType = StackAnalysis::ABIIRBasicBlock::links_iterator; - static NodeType *getEntryNode(StackAnalysis::ABIIRBasicBlock *BB) { + static NodeRef getEntryNode(StackAnalysis::ABIIRBasicBlock *BB) { return BB; } diff --git a/lib/StackAnalysis/InterproceduralAnalysis.cpp b/lib/StackAnalysis/InterproceduralAnalysis.cpp index e616c09cb..531cd7017 100644 --- a/lib/StackAnalysis/InterproceduralAnalysis.cpp +++ b/lib/StackAnalysis/InterproceduralAnalysis.cpp @@ -673,7 +673,6 @@ FunctionsSummary ResultsPool::finalize(const Module *M) { for (auto &P : FunctionCallSlots) { CallSite Call = P.first; revng_assert(CallSites.count(Call) != 0); - Optional StackFrameSize = CallSites[Call]; Instruction *I = Call.callInstruction(); BasicBlock *Callee = getFunctionCallCallee(I->getParent()); bool UnknownCallee = (Callee == nullptr); diff --git a/scripts/translate b/scripts/translate index 0c653f352..848b7471f 100755 --- a/scripts/translate +++ b/scripts/translate @@ -166,7 +166,7 @@ fi OBJ="$LL.o" "$CC" \ "$OBJ" \ - -lz -lm -lrt $("$TOOPT" "$CSV" "$LIBSCSV") -L ./ \ + -lz -lm -lrt -lpthread $("$TOOPT" "$CSV" "$LIBSCSV") -L ./ \ -o "$OUTPUT" \ $DISABLE_PIE diff --git a/tests/Unit/ReachingDefinitionsPass.cpp b/tests/Unit/ReachingDefinitionsPass.cpp index cc1bb83aa..74b1f0aea 100644 --- a/tests/Unit/ReachingDefinitionsPass.cpp +++ b/tests/Unit/ReachingDefinitionsPass.cpp @@ -167,92 +167,82 @@ struct ColorsProviderTraits { } // namespace RDA -class Test { -public: - enum Type { Regular, Conditional, Both }; +enum TestType { Regular, Conditional, Both }; -private: - LLVMContext &Context; +static void +runTest(const char *Body, + std::vector>> Checks, + std::vector BlackList = {}, + TestType T = Both) { -public: - Test() : Context(getGlobalContext()) {} + LLVMContext TestContext; + std::unique_ptr M = loadModule(TestContext, Body); + Function *F = M->getFunction("main"); - void - test(const char *Body, - std::vector>> Checks, - std::vector BlackList = {}, - Type T = Both) { + std::set BasicBlockBlackList; + for (const char *Name : BlackList) + BasicBlockBlackList.insert(basicBlockByName(F, Name)); - std::unique_ptr M = loadModule(Context, Body); - Function *F = M->getFunction("main"); + if (T == Regular || T == Both) { + using Analysis = RDA::Analysis>; + Analysis A(F, RDA::NullColorsProvider(), BasicBlockBlackList); + A.registerExtremal(&F->getEntryBlock()); + A.initialize(); + A.run(); - std::set BasicBlockBlackList; - for (const char *Name : BlackList) - BasicBlockBlackList.insert(basicBlockByName(F, Name)); - - if (T == Regular || T == Both) { - using Analysis = RDA::Analysis>; - Analysis A(F, RDA::NullColorsProvider(), BasicBlockBlackList); - A.registerExtremal(&F->getEntryBlock()); - A.initialize(); - A.run(); - - for (auto &P : Checks) - assertReachers(F, A, P.first, P.second); - } - - if (T == Conditional || T == Both) { - - highlightConditionEdges(*F); - - // Compute the dominator tree - // TODO: in more recent LLVM versions we don't need to recompute the - // dominator tree but we'll be able to update it - DominatorTree DT(*F); - - ColorMap Colors; - - // Perform a light version of the ConditionNumberingPass - std::map ConditionsMap; - for (BasicBlock &BB : *F) { - auto *T = dyn_cast(BB.getTerminator()); - if (T == nullptr or T->isUnconditional()) - continue; - - int32_t ConditionIndex = reinterpret_cast(T->getCondition()); - - // ConditionIndex at the first iteration will be positive, at the second - // negative - std::array Successors{ T->getSuccessor(0), - T->getSuccessor(1) }; - for (BasicBlock *Successor : Successors) { - revng_assert(Successor->getSinglePredecessor() == &BB); - - SmallVector Descendants; - DT.getDescendants(Successor, Descendants); - for (BasicBlock *Descendant : Descendants) - Colors[Descendant].push_back(ConditionIndex); - - ConditionIndex = -ConditionIndex; - } - } - - using Analysis = RDA::Analysis>; - Analysis CA(F, Colors, BasicBlockBlackList); - CA.registerExtremal(&F->getEntryBlock()); - CA.initialize(); - CA.run(); - - for (auto &P : Checks) - assertReachers(F, CA, P.first, P.second); - } + for (auto &P : Checks) + assertReachers(F, A, P.first, P.second); } -}; + + if (T == Conditional || T == Both) { + + highlightConditionEdges(*F); + + // Compute the dominator tree + // TODO: in more recent LLVM versions we don't need to recompute the + // dominator tree but we'll be able to update it + DominatorTree DT(*F); + + ColorMap Colors; + + // Perform a light version of the ConditionNumberingPass + std::map ConditionsMap; + for (BasicBlock &BB : *F) { + auto *T = dyn_cast(BB.getTerminator()); + if (T == nullptr or T->isUnconditional()) + continue; + + int32_t ConditionIndex = reinterpret_cast(T->getCondition()); + + // ConditionIndex at the first iteration will be positive, at the second + // negative + std::array Successors{ T->getSuccessor(0), + T->getSuccessor(1) }; + for (BasicBlock *Successor : Successors) { + revng_assert(Successor->getSinglePredecessor() == &BB); + + SmallVector Descendants; + DT.getDescendants(Successor, Descendants); + for (BasicBlock *Descendant : Descendants) + Colors[Descendant].push_back(ConditionIndex); + + ConditionIndex = -ConditionIndex; + } + } + + using Analysis = RDA::Analysis>; + Analysis CA(F, Colors, BasicBlockBlackList); + CA.registerExtremal(&F->getEntryBlock()); + CA.initialize(); + CA.run(); + + for (auto &P : Checks) + assertReachers(F, CA, P.first, P.second); + } +} BOOST_AUTO_TEST_CASE(OneStoreOneLoad) { - Test X; - // // One store, one load // @@ -263,12 +253,10 @@ BOOST_AUTO_TEST_CASE(OneStoreOneLoad) { ret void )LLVM"; - X.test(Body, { { "load_rax", { "s:zero" } } }); + runTest(Body, { { "load_rax", { "s:zero" } } }); } BOOST_AUTO_TEST_CASE(StoreToDifferentCSV) { - Test X; - // // Store to a different CSV // @@ -281,12 +269,10 @@ BOOST_AUTO_TEST_CASE(StoreToDifferentCSV) { ret void )LLVM"; - X.test(Body, { { "load_rax", { "s:zero" } } }); + runTest(Body, { { "load_rax", { "s:zero" } } }); } BOOST_AUTO_TEST_CASE(ClobberingStore) { - Test X; - // // Store clobbering a previous store // @@ -299,12 +285,10 @@ BOOST_AUTO_TEST_CASE(ClobberingStore) { ret void )LLVM"; - X.test(Body, { { "load_rax", { "s:one" } } }); + runTest(Body, { { "load_rax", { "s:one" } } }); } BOOST_AUTO_TEST_CASE(LoadReachingAnotherLoad) { - Test X; - // // Load reaching another load // @@ -314,12 +298,10 @@ BOOST_AUTO_TEST_CASE(LoadReachingAnotherLoad) { ret void )LLVM"; - X.test(Body, { { "load_rax2", { "load_rax1" } } }); + runTest(Body, { { "load_rax2", { "load_rax1" } } }); } BOOST_AUTO_TEST_CASE(MultipleLoadsReachingAnotherLoad) { - Test X; - // // Multiple loads reaching another load // @@ -330,12 +312,10 @@ BOOST_AUTO_TEST_CASE(MultipleLoadsReachingAnotherLoad) { ret void )LLVM"; - X.test(Body, { { "load_rax3", { "load_rax1" } } }); + runTest(Body, { { "load_rax3", { "load_rax1" } } }); } BOOST_AUTO_TEST_CASE(IfStatement) { - Test X; - // // If statement // @@ -359,15 +339,13 @@ end: ret void )LLVM"; - X.test(If, { { "load_rax", { "s:storeone", "s:storetwo" } } }); + runTest(If, { { "load_rax", { "s:storeone", "s:storetwo" } } }); // Now try again but inhibiting propgation to the end basic block - X.test(If, { { "load_rax", {} } }, { "end" }); + runTest(If, { { "load_rax", {} } }, { "end" }); } BOOST_AUTO_TEST_CASE(Loop) { - Test X; - // // Loop // @@ -386,12 +364,10 @@ end: ret void )LLVM"; - X.test(Body, { { "load_rax", { "s:storeone", "s:storetwo" } } }); + runTest(Body, { { "load_rax", { "s:storeone", "s:storetwo" } } }); } BOOST_AUTO_TEST_CASE(SelfReachingLoad) { - Test X; - // // Self-reaching load // @@ -406,12 +382,10 @@ end: ret void )LLVM"; - X.test(Body, { { "load_rax", {} } }); + runTest(Body, { { "load_rax", {} } }); } BOOST_AUTO_TEST_CASE(RepeatedIfStatement) { - Test X; - // // Repeated if statement // @@ -445,22 +419,20 @@ end: ret void )LLVM"; - X.test(RepeatedIf, + runTest(RepeatedIf, { { "load_three", { "s:storeone", "s:storetwo" } }, { "load_four", { "s:storeone", "s:storetwo" } } }, {}, - Test::Regular); + Regular); - X.test(RepeatedIf, + runTest(RepeatedIf, { { "load_three", { "s:storeone" } }, { "load_four", { "s:storetwo" } } }, {}, - Test::Conditional); + Conditional); } BOOST_AUTO_TEST_CASE(ConditionalDefinition) { - Test X; - // // Conditional definition // @@ -489,16 +461,14 @@ end: ret void )LLVM"; - X.test(ConditionalDefinition, + runTest(ConditionalDefinition, { { "load_one", { "s:storeone" } }, { "load_two", { "s:storezero" } } }, {}, - Test::Conditional); + Conditional); } BOOST_AUTO_TEST_CASE(LoopClobbering) { - Test X; - // // Conditional definition // @@ -523,8 +493,8 @@ end: ret void )LLVM"; - X.test(ConditionalDefinition, + runTest(ConditionalDefinition, { { "load_one", { "s:storezero" } } }, {}, - Test::Conditional); + Conditional); } diff --git a/tools/revamb-dump/IsolateFunctions.cpp b/tools/revamb-dump/IsolateFunctions.cpp index 7d6544102..07d495cd0 100644 --- a/tools/revamb-dump/IsolateFunctions.cpp +++ b/tools/revamb-dump/IsolateFunctions.cpp @@ -493,11 +493,9 @@ void IFI::run() { // variables and functions). We'll initialize the LocalVMaps of the single // functions with these mappings. ValueToValueMap GlobalVMap; - for (auto Iter : ModuleCloningVMap) { - if (isa(Iter.first)) { + for (auto Iter : ModuleCloningVMap) + if (isa(Iter.first) or isa(Iter.first)) GlobalVMap[Iter.first] = Iter.second; - } - } // 2. Create the needed structure to handle the throw of an exception @@ -920,13 +918,9 @@ void IFI::run() { StringRef FunctionNameString = getFunctionNameString(Node); Function *TargetFunc = NewModule->getFunction(FunctionNameString); - // Remove the old instruction that compose the entry block (note that we - // do not increment the iterator since the removal of the instruction - // seems to automatically do that) - auto It = BB.rbegin(); - while (It != BB.rend()) { - It->eraseFromParent(); - } + // Remove the old instruction that compose the entry block + BB.dropAllReferences(); + BB.getInstList().clear(); // Emit the invoke instruction InvokeInst::Create(TargetFunc, @@ -954,7 +948,7 @@ bool IF::runOnFunction(Function &F) { // functions. We additionaly store all the mappings created in the // ModuleCloningVMap. ValueToValueMapTy ModuleCloningVMap; - NewModule = CloneModule(F.getParent(), ModuleCloningVMap); + NewModule = CloneModule(*F.getParent(), ModuleCloningVMap); // Create an object of type IsolateFunctionsImpl and run the pass IFI Impl(F, NewModule.get(), GCBI, ModuleCloningVMap); diff --git a/tools/revamb-dump/Main.cpp b/tools/revamb-dump/Main.cpp index c93c16108..5091ad64f 100644 --- a/tools/revamb-dump/Main.cpp +++ b/tools/revamb-dump/Main.cpp @@ -197,12 +197,12 @@ int main(int argc, const char *argv[]) { Loggers->activateArguments(); installStatistics(); - LLVMContext &Context = getGlobalContext(); + LLVMContext RevambDumpContext; SMDiagnostic Err; std::unique_ptr TheModule; { Callgrind DisableCallgrind(false); - TheModule = parseIRFile(InputPath, Err, Context); + TheModule = parseIRFile(InputPath, Err, RevambDumpContext); } if (!TheModule) { diff --git a/tools/revamb/BinaryFile.cpp b/tools/revamb/BinaryFile.cpp index 7592ab1b0..76e942748 100644 --- a/tools/revamb/BinaryFile.cpp +++ b/tools/revamb/BinaryFile.cpp @@ -15,11 +15,11 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/ELF.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Casting.h" -#include "llvm/Support/Dwarf.h" -#include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/LEB128.h" @@ -353,34 +353,44 @@ struct RelocationHelper { template void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { // Parse the ELF file - std::error_code EC; - object::ELFFile TheELF(TheBinary->getData(), EC); - revng_assert(!EC, "Error while loading the ELF file"); + auto TheELFOrErr = object::ELFFile::create(TheBinary->getData()); + if (not TheELFOrErr) { + logAllUnhandledErrors(std::move(TheELFOrErr.takeError()), errs(), ""); + revng_abort(); + } + object::ELFFile TheELF = *TheELFOrErr; // BaseAddress makes sense only for shared (relocatable, PIC) objects if (TheELF.getHeader()->e_type == ELF::ET_DYN) this->BaseAddress = BaseAddress; // Look for static or dynamic symbols and relocations - using Elf_ShdrPtr = decltype(&(*TheELF.sections().begin())); - using Elf_PhdrPtr = decltype(&(*TheELF.program_headers().begin())); - Elf_ShdrPtr SymtabShdr = nullptr; + using ConstElf_ShdrPtr = const typename object::ELFFile::Elf_Shdr *; + using Elf_PhdrPtr = const typename object::ELFFile::Elf_Phdr *; + ConstElf_ShdrPtr SymtabShdr = nullptr; Elf_PhdrPtr DynamicPhdr = nullptr; Optional DynamicAddress; Optional EHFrameAddress; Optional EHFrameSize; Optional EHFrameHdrAddress; - for (auto &Section : TheELF.sections()) { - if (ErrorOr Name = TheELF.getSectionName(&Section)) { - if (*Name == ".symtab") { + auto Sections = TheELF.sections(); + if (not Sections) { + logAllUnhandledErrors(std::move(Sections.takeError()), errs(), ""); + revng_abort(); + } + for (auto &Section : *Sections) { + auto NameOrErr = TheELF.getSectionName(&Section); + if (NameOrErr) { + auto &Name = *NameOrErr; + if (Name == ".symtab") { revng_assert(SymtabShdr == nullptr, "Duplicate .symtab"); SymtabShdr = &Section; - } else if (*Name == ".eh_frame") { + } else if (Name == ".eh_frame") { revng_assert(not EHFrameAddress, "Duplicate .eh_frame"); EHFrameAddress = relocate(static_cast(Section.sh_addr)); EHFrameSize = static_cast(Section.sh_size); - } else if (*Name == ".dynamic") { + } else if (Name == ".dynamic") { revng_assert(not DynamicAddress, "Duplicate .dynamic"); DynamicAddress = relocate(static_cast(Section.sh_addr)); } @@ -390,14 +400,33 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { // If we found a symbol table if (SymtabShdr != nullptr && SymtabShdr->sh_link != 0) { // Obtain a reference to the string table - const Elf_ShdrPtr Strtab = TheELF.getSection(SymtabShdr->sh_link).get(); - ArrayRef StrtabArray = TheELF.getSectionContents(Strtab).get(); - StringRef StrtabContent(reinterpret_cast(StrtabArray.data()), - StrtabArray.size()); + auto Strtab = TheELF.getSection(SymtabShdr->sh_link); + if (not Strtab) { + logAllUnhandledErrors(std::move(Strtab.takeError()), errs(), ""); + revng_abort(); + } + auto StrtabArray = TheELF.getSectionContents(*Strtab); + if (not StrtabArray) { + logAllUnhandledErrors(std::move(StrtabArray.takeError()), errs(), ""); + revng_abort(); + } + StringRef StrtabContent(reinterpret_cast(StrtabArray->data()), + StrtabArray->size()); // Collect symbol names - for (auto &Symbol : TheELF.symbols(SymtabShdr)) { - Symbols.push_back({ Symbol.getName(StrtabContent).get(), + auto ELFSymbols = TheELF.symbols(SymtabShdr); + if (not ELFSymbols) { + logAllUnhandledErrors(std::move(ELFSymbols.takeError()), errs(), ""); + revng_abort(); + } + for (auto &Symbol : *ELFSymbols) { + auto Name = Symbol.getName(StrtabContent); + if (not Name) { + logAllUnhandledErrors(std::move(Name.takeError()), errs(), ""); + revng_abort(); + } + + Symbols.push_back({ *Name, Symbol.st_value, Symbol.st_size, Symbol.getType() == ELF::STT_FUNC }); @@ -415,7 +444,13 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { // CSV using Elf_Phdr = const typename object::ELFFile::Elf_Phdr; using Elf_Dyn = const typename object::ELFFile::Elf_Dyn; - for (Elf_Phdr &ProgramHeader : TheELF.program_headers()) { + + auto ProgHeaders = TheELF.program_headers(); + if (not ProgHeaders) { + logAllUnhandledErrors(std::move(ProgHeaders.takeError()), errs(), ""); + revng_abort(); + } + for (Elf_Phdr &ProgramHeader : *ProgHeaders) { switch (ProgramHeader.p_type) { case ELF::PT_LOAD: { SegmentInfo Segment; @@ -434,7 +469,7 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { if (UseDebugSymbols && Segment.IsExecutable) { using Elf_Shdr = const typename object::ELFFile::Elf_Shdr; auto Inserter = std::back_inserter(Segment.ExecutableSections); - for (Elf_Shdr &SectionHeader : TheELF.sections()) { + for (Elf_Shdr &SectionHeader : *Sections) { if (SectionHeader.sh_flags & ELF::SHF_EXECINSTR) { auto SectionStart = relocate(SectionHeader.sh_addr); auto SectionEnd = SectionStart + SectionHeader.sh_size; @@ -497,7 +532,12 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { FilePortion ReldynPortion; FilePortion RelpltPortion; - for (Elf_Dyn &DynamicTag : *TheELF.dynamic_table(DynamicPhdr)) { + auto DynamicEntries = TheELF.dynamicEntries(); + if (not DynamicEntries) { + logAllUnhandledErrors(std::move(DynamicEntries.takeError()), errs(), ""); + revng_abort(); + } + for (Elf_Dyn &DynamicTag : *DynamicEntries) { auto TheTag = DynamicTag.getTag(); switch (TheTag) { diff --git a/tools/revamb/CPUStateAccessAnalysisPass.cpp b/tools/revamb/CPUStateAccessAnalysisPass.cpp index d4499773c..ae6c68962 100644 --- a/tools/revamb/CPUStateAccessAnalysisPass.cpp +++ b/tools/revamb/CPUStateAccessAnalysisPass.cpp @@ -20,6 +20,7 @@ #include "llvm/IR/Value.h" #include "llvm/IR/Verifier.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/raw_ostream.h" // Local libraries includes #include "revng/Support/Debug.h" @@ -224,6 +225,12 @@ forwardTaintAnalysis(GlobalVariable *CPUStatePtr, ArgNo(N) {} }; + Module *M = CPUStatePtr->getParent(); + if (TaintLog.isEnabled()) { + TaintLog << "MODULE:" << DoLog; + TaintLog << dumpToString(M) << DoLog; + } + // 1. Iterate on the users of `CPUStatePtr` for (const User *U : CPUStatePtr->users()) { @@ -244,9 +251,12 @@ forwardTaintAnalysis(GlobalVariable *CPUStatePtr, const Function *F = Load->getParent()->getParent(); if (Load->getNumUses() != 0 and ReachableFunctions.find(F) != ReachableFunctions.end()) { - TaintLog << "Tainted origin: " << Load << DoLog; + if (TaintLog.isEnabled()) { + TaintLog << "Tainted origin: " << Load << DoLog; + TaintLog << dumpToString(Load) << DoLog; + TaintLog.indent(); + } ToTaintWorkList.push(&*Load->use_begin()); - TaintLog.indent(); } // 2. For each user of `CPUStatePtr`, consider its next user, @@ -258,7 +268,7 @@ forwardTaintAnalysis(GlobalVariable *CPUStatePtr, const auto OpCode = TheUser->getOpcode(); if (TaintLog.isEnabled()) { TaintLog << "Inst: " << TheUser << DoLog; - TheUser->dump(); + TaintLog << dumpToString(TheUser) << DoLog; } const size_t Size = ToTaintWorkList.size(); @@ -279,7 +289,7 @@ forwardTaintAnalysis(GlobalVariable *CPUStatePtr, if (TheUse->get() == L->getPointerOperand()) { if (TaintLog.isEnabled()) { TaintLog << "TAINT: " << TheUser << DoLog; - TheUser->dump(); + TaintLog << dumpToString(TheUser) << DoLog; } Results.TaintedLoads.insert(TheUser); } @@ -291,7 +301,7 @@ forwardTaintAnalysis(GlobalVariable *CPUStatePtr, if (TheUse->get() == S->getPointerOperand()) { if (TaintLog.isEnabled()) { TaintLog << "TAINT: " << TheUser << DoLog; - TheUser->dump(); + TaintLog << dumpToString(TheUser) << DoLog; } Results.TaintedStores.insert(TheUser); } @@ -315,7 +325,7 @@ forwardTaintAnalysis(GlobalVariable *CPUStatePtr, bool JustTainted = Results.TaintedValues.insert(TheUser).second; if (TaintLog.isEnabled()) { TaintLog << "TAINT: " << TheUser << DoLog; - TheUser->dump(); + TaintLog << dumpToString(TheUser) << DoLog; } if (JustTainted) { TaintLog << "Just Tainted" << DoLog; @@ -354,14 +364,14 @@ forwardTaintAnalysis(GlobalVariable *CPUStatePtr, if (OpNo == 0) { if (TaintLog.isEnabled()) { TaintLog << "TAINT: " << TheUser << DoLog; - TheUser->dump(); + TaintLog << dumpToString(TheUser) << DoLog; } Results.TaintedStores.insert(TheUser); } if (OpNo == 1) { if (TaintLog.isEnabled()) { TaintLog << "TAINT: " << TheUser << DoLog; - TheUser->dump(); + TaintLog << dumpToString(TheUser) << DoLog; } Results.TaintedLoads.insert(TheUser); } @@ -394,10 +404,7 @@ forwardTaintAnalysis(GlobalVariable *CPUStatePtr, // also push on the ToTaintWorkList its first use that is not tainted. if (TaintLog.isEnabled()) { TaintLog << "Argument: " << FormalArgument << DoLog; - std::string ArgLog; - raw_string_ostream OStream(ArgLog); - FormalArgument->print(OStream); - CSVAccessLog << ArgLog << DoLog; + TaintLog << dumpToString(FormalArgument) << DoLog; } bool JustTainted = Results.TaintedValues.insert(FormalArgument).second; if (JustTainted) { @@ -405,10 +412,7 @@ forwardTaintAnalysis(GlobalVariable *CPUStatePtr, for (const Use &U : FormalArgument->uses()) { if (TaintLog.isEnabled()) { TaintLog << "User: " << U.getUser() << DoLog; - std::string UserLog; - raw_string_ostream OStream(UserLog); - U.getUser()->print(OStream); - CSVAccessLog << UserLog << DoLog; + TaintLog << dumpToString(U.getUser()) << DoLog; } if (Results.TaintedValues.count(U.getUser()) == 0) { TaintLog << "PUSH" << DoLog; @@ -430,7 +434,7 @@ forwardTaintAnalysis(GlobalVariable *CPUStatePtr, bool JustTainted = Results.TaintedValues.insert(TheUser).second; if (TaintLog.isEnabled()) { TaintLog << "TAINT: " << TheUser << DoLog; - TheUser->dump(); + TaintLog << dumpToString(TheUser) << DoLog; } if (JustTainted) { TaintLog << "Just Tainted" << DoLog; @@ -459,7 +463,7 @@ forwardTaintAnalysis(GlobalVariable *CPUStatePtr, // taint analysis to its uses. if (TaintLog.isEnabled()) { TaintLog << "TAINT: " << TheUser << DoLog; - TheUser->dump(); + TaintLog << dumpToString(TheUser) << DoLog; } bool JustTainted = Results.TaintedValues.insert(TheUser).second; if (JustTainted) { @@ -472,7 +476,7 @@ forwardTaintAnalysis(GlobalVariable *CPUStatePtr, if (TaintLog.isEnabled()) { TaintLog << "TAINT: " << CSInfo.CallSite << DoLog; - CallSiteInfos.top().CallSite->dump(); + TaintLog << dumpToString(CallSiteInfos.top().CallSite) << DoLog; std::string Name = getCallee(CSInfo.CallSite)->getName(); TaintLog << "pair: < " << Name << ", " << CSInfo.ArgNo << " > " << DoLog; @@ -519,11 +523,11 @@ forwardTaintAnalysis(GlobalVariable *CPUStatePtr, const Use *PoppedTopUse = ToTaintWorkList.top(); if (TaintLog.isEnabled()) { TaintLog << "POP : " << PoppedTopUse->get() << DoLog; - PoppedTopUse->get()->dump(); + TaintLog << dumpToString(PoppedTopUse->get()) << DoLog; } if (TaintLog.isEnabled()) { TaintLog << "PoppedUser : " << PoppedTopUse->getUser() << DoLog; - PoppedTopUse->getUser()->dump(); + TaintLog << dumpToString(PoppedTopUse->getUser()) << DoLog; } ToTaintWorkList.pop(); TaintLog.unindent(); @@ -548,7 +552,7 @@ forwardTaintAnalysis(GlobalVariable *CPUStatePtr, if (TaintLog.isEnabled()) { TaintLog << "CallSite: " << CallSite << DoLog; - CallSite->dump(); + TaintLog << dumpToString(CallSite) << DoLog; } // If the CallSite was tainted it means that the taint analysis @@ -588,7 +592,6 @@ forwardTaintAnalysis(GlobalVariable *CPUStatePtr, } } - Module *M = CPUStatePtr->getParent(); QuickMetadata QMD(M->getContext()); for (CallInst *Call : Results.IllegalCalls) { CallInst *Abort = CallInst::Create(M->getFunction("abort"), {}, Call); @@ -1030,7 +1033,7 @@ public: private: CSVOffsets foldOffsets(CSVOffsets::Kind ResKind, WorkItem::size_type NumSrcs, - const Instruction *I, + Instruction *I, const SmallVector &OffsetsIt) { return static_cast(this)->foldOffsets(ResKind, NumSrcs, I, OffsetsIt); } @@ -1086,20 +1089,20 @@ private: CSVOffsets foldOffsets(CSVOffsets::Kind ResultKind, WorkItem::size_type NumSrcs, - const Instruction *I, + Instruction *I, const SmallVector &OffsetsIt) { auto OpCode = I->getOpcode(); revng_assert(OpCode == Instruction::Add or OpCode == Instruction::Sub); SmallVector Operands(NumSrcs, nullptr); // Setup operands for (WorkItem::size_type SI = 0; SI < NumSrcs; ++SI) { - const int64_t o = *OffsetsIt[SI]; - Operands[SI] = ConstantInt::get(Int64Ty, APInt(64, o, true)); + const int64_t O = *OffsetsIt[SI]; + Operands[SI] = ConstantInt::get(Int64Ty, APInt(64, O, true)); } // Constant fold the operation with the selected operands ArrayRef TmpOp(Operands); - Constant *Res = ConstantFoldInstOperands(OpCode, Int64Ty, TmpOp, DL); - const ConstantInt *R = cast(Res); + Constant *Res = ConstantFoldInstOperands(I, TmpOp, DL); + ConstantInt *R = cast(Res); const int64_t ResO = R->getSExtValue(); return CSVOffsets(ResultKind, ResO); } @@ -1237,41 +1240,23 @@ private: CSVOffsets foldOffsets(CSVOffsets::Kind ResultKind, WorkItem::size_type NumSrcs, - const Instruction *I, + Instruction *I, const SmallVector &OffsetsIt) { const auto *GEP = cast(I); - const auto OpResTy = GEP->getType(); const auto PtrOpTy = GEP->getPointerOperand()->getType(); SmallVector Operands(NumSrcs, nullptr); // Setup operands - int64_t ptr_o = *OffsetsIt[0]; - Constant *int_c = ConstantInt::get(Int64Ty, APInt(64, ptr_o, true)); - Constant *ptr_c = ConstantExpr::getIntToPtr(int_c, PtrOpTy); - Operands[0] = ptr_c; + int64_t PtrOp = *OffsetsIt[0]; + Operands[0] = Constant::getIntegerValue(PtrOpTy, APInt(64, PtrOp, true)); for (WorkItem::size_type SI = 1; SI < NumSrcs; ++SI) { - const int64_t o = *OffsetsIt[SI]; - Operands[SI] = ConstantInt::get(Int32Ty, APInt(32, o, true)); + const int64_t O = *OffsetsIt[SI]; + Operands[SI] = ConstantInt::get(Int32Ty, APInt(32, O, true)); } // Constant fold the operation with the selected operands ArrayRef TmpOp(Operands); - auto OpCode = I->getOpcode(); - Constant *Res = ConstantFoldInstOperands(OpCode, OpResTy, TmpOp, DL); - const ConstantInt *R = nullptr; - if (Res->getType()->isPointerTy()) { - if (isa(Res)) { - auto Const = ConstantInt::get(Int32Ty, APInt(32, 0, true)); - R = cast(Const); - } else if (auto *PtrCast = dyn_cast(Res)) { - auto OpCode = PtrCast->getAsInstruction()->getOpcode(); - revng_assert(OpCode == Instruction::IntToPtr); - R = cast(PtrCast->getOperand(0)); - } else { - revng_abort(); - } - } else { - R = cast(Res); - } - const int64_t ResO = R->getSExtValue(); + Constant *Res = ConstantFoldInstOperands(I, TmpOp, DL); + ConstantInt *R = getConstValue(Res, DL); + const int64_t ResO = getSExtValue(R, DL); return CSVOffsets(ResultKind, ResO); } }; @@ -1712,20 +1697,15 @@ void CPUSAOA::computeOffsetsFromSources(const WorkItem &Item, bool IsLoad) { ValueCallSiteOffsets.at(AddressValue)); bool New = LoadCallSiteOffsets.insert(LoadCSOff).second; if (CSVAccessLog.isEnabled()) { - CSVAccessLog << "Load "; - std::string InstrLog; - raw_string_ostream OStream(InstrLog); - Instr->print(OStream); - CSVAccessLog << InstrLog << DoLog; + CSVAccessLog << "Load " << dumpToString(Instr) << DoLog; + for (const auto &CS2O : LoadCSOff.second) { CSVAccessLog << "CallSite: "; - std::string CallLog; - raw_string_ostream CallOStream(CallLog); if (CS2O.first) - Instr->print(CallOStream); + CSVAccessLog << dumpToString(Instr); else - CallOStream << "nullptr"; - CSVAccessLog << CallLog << DoLog; + CSVAccessLog << "nullptr"; + CSVAccessLog << DoLog; CSVAccessLog << CS2O.second << DoLog; } } @@ -1737,27 +1717,21 @@ void CPUSAOA::computeOffsetsFromSources(const WorkItem &Item, bool IsLoad) { ValueCallSiteOffsets.at(AddressValue)); bool New = StoreCallSiteOffsets.insert(StoreCSOff).second; if (CSVAccessLog.isEnabled()) { - CSVAccessLog << "Store "; - std::string InstrLog; - raw_string_ostream OStream(InstrLog); - Instr->print(OStream); - CSVAccessLog << InstrLog << DoLog; + CSVAccessLog << "Store " << dumpToString(Instr) << DoLog; for (const auto &CS2O : StoreCSOff.second) { CSVAccessLog << "CallSite: "; - std::string CallLog; - raw_string_ostream CallOStream(CallLog); if (CS2O.first) - Instr->print(CallOStream); + CSVAccessLog << dumpToString(Instr); else - CallOStream << "nullptr"; - CSVAccessLog << CallLog << DoLog; + CSVAccessLog << "nullptr"; + CSVAccessLog << DoLog; CSVAccessLog << CS2O.second << DoLog; } } revng_assert(New); } break; default: - revng_abort(); + revng_abort(dumpToString(Instr).data()); } } else { revng_abort(); @@ -1798,7 +1772,7 @@ CPUSAOA::getOffsetsOrExploreSrc(Value *V, WorkItem &Item, bool IsLoad) const { if (auto *Call = dyn_cast(V)) { if (CSVAccessLog.isEnabled()) { CSVAccessLog << "CALL" << DoLog; - Call->dump(); + CSVAccessLog << dumpToString(Call) << DoLog; } Item = WorkItem(Call, IsLoad); } else if (auto *Arg = dyn_cast(V)) { @@ -2102,13 +2076,12 @@ bool CPUSAOA::run() { TaintLog << "== Loads ==\n"; for (Instruction *LoadOrStore : TaintedAccesses.TaintedLoads) { TaintLog << "INSTRUCTION: " << LoadOrStore << DoLog; - LoadOrStore->dump(); - TaintLog << DoLog; + TaintLog << dumpToString(LoadOrStore) << DoLog; TaintLog.indent(4); for (const auto &CSO : LoadCallSiteOffsets.at(LoadOrStore)) { TaintLog << "CallSite: " << CSO.first << '\n'; if (CSO.first != nullptr) - CSO.first->dump(); + TaintLog << dumpToString(CSO.first); TaintLog << DoLog; TaintLog << CSO.second << '\n'; } @@ -2118,13 +2091,12 @@ bool CPUSAOA::run() { TaintLog << "== Stores ==\n"; for (Instruction *LoadOrStore : TaintedAccesses.TaintedStores) { TaintLog << "INSTRUCTION: " << LoadOrStore << DoLog; - LoadOrStore->dump(); - TaintLog << DoLog; + TaintLog << dumpToString(LoadOrStore) << DoLog; TaintLog.indent(4); for (const auto &CSO : StoreCallSiteOffsets.at(LoadOrStore)) { TaintLog << "CallSite: " << CSO.first << '\n'; if (CSO.first != nullptr) - CSO.first->dump(); + TaintLog << dumpToString(CSO.first); TaintLog << DoLog; TaintLog << CSO.second << '\n'; } @@ -2347,15 +2319,17 @@ static void fixEnv2EnvMemCopies(const Module &M, Builder.SetInsertPoint(Instr); CallInst *MemcpyLoad = Builder.CreateMemCpy(TmpBuffer, + TmpBuffer->getAlignment(), MemcpySrc, - MemcpySize, - TmpBuffer->getAlignment()); + 1, + MemcpySize); NewLoadCSOffsets.insert({ MemcpyLoad, InstCSOffset.second }); CallInst *MemcpyStore = Builder.CreateMemCpy(MemcpyDst, + 1, TmpBuffer, - MemcpySize, - TmpBuffer->getAlignment()); + TmpBuffer->getAlignment(), + MemcpySize); NewStoreCSOffsets.insert({ MemcpyStore, It->second }); AccessToRemove.insert(Instr); @@ -2594,11 +2568,7 @@ void CPUStateAccessAnalysis::correctCPUStateAccesses() { case CSVOffsets::Kind::OutAndUnknownInPtr: case CSVOffsets::Kind::KnownInPtr: { - if (FixAccessLog.isEnabled()) { - FixAccessLog << "Before: " << DoLog; - F->dump(); - FixAccessLog << DoLog; - } + revng_log(FixAccessLog, "Before: " << dumpToString(F)); // This is necessary to get the correct debug info. // Setting the insert point to an Instruction also updates the Builder @@ -2760,10 +2730,7 @@ void CPUStateAccessAnalysis::correctCPUStateAccesses() { if (FixAccessLog.isEnabled()) { ++NumUnknown; FunToNumUnknown[F->getName()]++; - std::string InstrLog; - raw_string_ostream OStream(InstrLog); - AccessToFix->print(OStream); - FunToUnknowns[F->getName()].insert(InstrLog); + FunToUnknowns[F->getName()].insert(dumpToString(AccessToFix)); } SwitchInst *SwitchOffset = Builder.CreateSwitch(OffsetValue, @@ -2808,21 +2775,17 @@ void CPUStateAccessAnalysis::correctCPUStateAccesses() { } // Verify the transformation and cleanup the access to fix - if (FixAccessLog.isEnabled()) { - FixAccessLog << "After: " << DoLog; - F->dump(); - FixAccessLog << DoLog; - } + revng_log(FixAccessLog, "After: " << dumpToString(F)); if (I != AccessToFix) { if (FixAccessLog.isEnabled()) { FixAccessLog << "Erasing AccessToFix: " << AccessToFix << DoLog; - AccessToFix->dump(); + FixAccessLog << dumpToString(AccessToFix) << DoLog; } AccessToFix->eraseFromParent(); } if (FixAccessLog.isEnabled()) { FixAccessLog << "Erasing I: " << I << DoLog; - I->dump(); + FixAccessLog << dumpToString(I) << DoLog; } I->eraseFromParent(); } @@ -2852,21 +2815,21 @@ bool CPUStateAccessAnalysis::run() { TaintLog << "==== Tainted Loads =====\n"; for (const Instruction *I : TaintResults.TaintedLoads) { TaintLog << I << DoLog; - I->dump(); + TaintLog << dumpToString(I) << DoLog; std::string Name = I->getParent()->getParent()->getName(); TaintLog << "In Function: " << Name << DoLog; } TaintLog << "==== Tainted Stores ====\n"; for (const Instruction *I : TaintResults.TaintedStores) { TaintLog << I << DoLog; - I->dump(); + TaintLog << dumpToString(I) << DoLog; std::string Name = I->getParent()->getParent()->getName(); TaintLog << "In Function: " << Name << DoLog; } TaintLog << "==== Illegal Calls =====\n"; for (const Instruction *I : TaintResults.IllegalCalls) { TaintLog << I << DoLog; - I->dump(); + TaintLog << dumpToString(I) << DoLog; std::string Name = I->getParent()->getParent()->getName(); TaintLog << "In Function: " << Name << DoLog; } diff --git a/tools/revamb/CodeGenerator.cpp b/tools/revamb/CodeGenerator.cpp index 391d90e06..070bd96d2 100644 --- a/tools/revamb/CodeGenerator.cpp +++ b/tools/revamb/CodeGenerator.cpp @@ -31,13 +31,16 @@ #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" #include "llvm/Linker/Linker.h" #include "llvm/Support/Casting.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_os_ostream.h" #include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Utils.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/Cloning.h" // Local libraries includes #include "revng/DebugHelper/DebugHelper.h" @@ -129,8 +132,7 @@ auto X = cl::values(clEnumValN(DebugInfoType::None, "Tiny Code"), clEnumValN(DebugInfoType::LLVMIR, "ll", - "debug information referred to the LLVM IR"), - clEnumValEnd); + "debug information referred to the LLVM IR")); static cl::opt DebugInfo("debug-info", cl::desc("emit debug " "information"), @@ -175,20 +177,31 @@ static std::unique_ptr parseIR(StringRef Path, LLVMContext &Context) { CodeGenerator::CodeGenerator(BinaryFile &Binary, Architecture &Target, + llvm::LLVMContext &TheContext, std::string Output, std::string Helpers, std::string EarlyLinked) : TargetArchitecture(Target), - Context(getGlobalContext()), + Context(TheContext), TheModule((new Module("top", Context))), OutputPath(Output), Debug(new DebugHelper(Output, TheModule.get(), DebugInfo, DebugPath)), Binary(Binary) { OriginalInstrMDKind = Context.getMDKindID("oi"); PTCInstrMDKind = Context.getMDKindID("pi"); - DbgMDKind = Context.getMDKindID("dbg"); HelpersModule = parseIR(Helpers, Context); + for (auto &F : HelpersModule->functions()) { + // Remove 'optnone' Function attribute from QEMU helpers. + // QEMU helpers are compiled with -O0 in libtinycode because the LLVM IR + // generated in this way it much more readable, but we need to optimize + // them when we link them with the decompiled code. + // In particular we desperately need SROA to get rid of allocas, to + // enable the CPUStateAccessAnalysisPass. + // If we don't remove this attribute future optimizations are blocked. + F.removeFnAttr(Attribute::OptimizeNone); + F.setDSOLocal(false); + } EarlyLinkedModule = parseIR(EarlyLinked, Context); if (CoveragePath.size() == 0) @@ -285,10 +298,14 @@ CodeGenerator::CodeGenerator(BinaryFile &Binary, NeededLibsStream << Library << "\n"; } -Function *CodeGenerator::importHelperFunctionDefinition(StringRef Name) { - Function *HelperFunction = HelpersModule->getFunction(Name); - FunctionType *HelperType = HelperFunction->getFunctionType(); - return cast(TheModule->getOrInsertFunction(Name, HelperType)); +Function *CodeGenerator::importHelperFunctionDeclaration(StringRef Name) { + // Don't copy the FunctionType from the HelpersModule. Simply add the function + // declaration with the correct name, and this will trigger the Linker. + // The Linker will then overwrite the stub declaration with the real imported + // definition, fixing it up with the correct FunctionType. + FunctionType *StubType = FunctionType::get(Type::getVoidTy(Context), false); + Constant *Inserted = TheModule->getOrInsertFunction(Name, StubType); + return cast(Inserted); } std::string SegmentInfo::generateName() { @@ -347,7 +364,7 @@ char CpuLoopFunctionPass::ID = 0; using RegisterCLF = RegisterPass; static RegisterCLF Y("cpu-loop", "cpu_loop FunctionPass", false, false); -void CpuLoopFunctionPass::getAnalysisUsage(AnalysisUsage &AU) const { +void CpuLoopFunctionPass::getAnalysisUsage(llvm::AnalysisUsage &AU) const { AU.addRequired(); } @@ -461,7 +478,7 @@ static void purgeNoReturn(Function *F) { if (Call->hasFnAttr(Attribute::NoReturn)) { auto OldAttr = Call->getAttributes(); auto NewAttr = OldAttr.removeAttribute(Context, - AttributeSet::FunctionIndex, + AttributeList::FunctionIndex, Attribute::NoReturn); Call->setAttributes(NewAttr); } @@ -530,7 +547,14 @@ bool CpuLoopExitPass::runOnModule(llvm::Module &M) { // Call cpu_loop auto *EnvType = CpuLoop->getFunctionType()->getParamType(0); auto *AddressComputation = VM->computeEnvAddress(EnvType, Call); - CallInst::Create(CpuLoop, { AddressComputation }, "", Call); + auto *CallCpuLoop = CallInst::Create(CpuLoop, + { AddressComputation }, + "", + Call); + // In recent versions of LLVM you can no longer inject a CallInst in a + // Function with debug location if the call itself has not a debug location + // as well, otherwise verifyModule() will fail. + CallCpuLoop->setDebugLoc(Call->getDebugLoc()); // Set cpu_loop_exiting to true new StoreInst(ConstantInt::getTrue(BoolType), CpuLoopExitingVariable, Call); @@ -643,7 +667,7 @@ void CodeGenerator::translate(uint64_t VirtualAddress) { auto *AbortTy = FunctionType::get(Type::getVoidTy(Context), false); auto *AbortFunction = TheModule->getOrInsertFunction("abort", AbortTy); - importHelperFunctionDefinition("target_set_brk"); + importHelperFunctionDeclaration("target_set_brk"); TheModule->getOrInsertFunction("syscall_init", FT::get(Type::getVoidTy(Context), {}, false)); @@ -907,7 +931,7 @@ void CodeGenerator::translate(uint64_t VirtualAddress) { std::tie(VirtualAddress, Entry) = JumpTargets.peek(); } // End translations loop - importHelperFunctionDefinition("cpu_loop"); + importHelperFunctionDeclaration("cpu_loop"); Function *CpuLoop = HelpersModule->getFunction("cpu_loop"); revng_assert(CpuLoop != nullptr); @@ -920,9 +944,10 @@ void CodeGenerator::translate(uint64_t VirtualAddress) { Variables.getByEnvOffset(ptc.exception_index, "exception_index"); // Handle some specific QEMU functions as no-ops or abort - auto NoOpFunctionNames = make_array("qemu_log_mask", + auto NoOpFunctionNames = make_array("cpu_dump_state", + "cpu_exit", + "end_exclusive" "fprintf", - "cpu_dump_state", "mmap_lock", "mmap_unlock", "pthread_cond_broadcast", @@ -930,35 +955,30 @@ void CodeGenerator::translate(uint64_t VirtualAddress) { "pthread_mutex_lock", "pthread_cond_wait", "pthread_cond_signal", - "cpu_exit", - "start_exclusive", "process_pending_signals", - "end_exclusive"); + "qemu_log_mask", + "qemu_thread_atexit_init", + "start_exclusive"); auto AbortFunctionNames = make_array("cpu_restore_state", + "cpu_mips_exec", "gdb_handlesig", "queue_signal", - "cpu_mips_exec", // syscall.c + "do_ioctl_dm", "print_syscall", "print_syscall_ret", - "do_ioctl_dm", // ARM cpu_loop - "EmulateAll", "cpu_abort", - "do_arm_semihosting"); + "do_arm_semihosting", + "EmulateAll"); - // EmulateAll: requires access to the opcode // do_arm_semihosting: we don't care about semihosting + // EmulateAll: requires access to the opcode - // Initializes the CPUState which is important on x86 architecture. - if (HelpersModule->getFunction("initialize_env") != nullptr) { - Function *InitEnv = importHelperFunctionDefinition("initialize_env"); - auto *CPUStateType = InitEnv->getFunctionType()->getParamType(0); - Instruction *InsertBefore = InitEnvInsertPoint; - auto *AddressComputation = Variables.computeEnvAddress(CPUStateType, - InsertBefore); - CallInst::Create(InitEnv, { AddressComputation }, "", InsertBefore); - } + // Import the function to initialize the CPUState, if present. + // This is important on x86 architecture. + if (HelpersModule->getFunction("initialize_env") != nullptr) + importHelperFunctionDeclaration("initialize_env"); // From syscall.c new GlobalVariable(*TheModule, @@ -990,24 +1010,23 @@ void CodeGenerator::translate(uint64_t VirtualAddress) { // non-static symbols not directly imported as static. { std::set Declarations; - for (auto &GV : TheModule->functions()) - if (GV.isDeclaration()) - Declarations.insert(GV.getName()); + for (auto &F : TheModule->functions()) + if (F.isDeclaration()) + Declarations.insert(F.getName()); + for (auto &F : HelpersModule->functions()) + if (not F.isDeclaration() and Declarations.count(F.getName()) == 0 + and F.hasExternalLinkage()) + F.setLinkage(GlobalValue::InternalLinkage); + + Declarations.clear(); for (auto &GV : TheModule->globals()) if (GV.isDeclaration()) Declarations.insert(GV.getName()); - for (auto &GV : HelpersModule->functions()) - if (!GV.isDeclaration() - && Declarations.find(GV.getName()) == Declarations.end() - && GV.hasExternalLinkage()) - GV.setLinkage(GlobalValue::InternalLinkage); - for (auto &GV : HelpersModule->globals()) - if (!GV.isDeclaration() - && Declarations.find(GV.getName()) == Declarations.end() - && GV.hasExternalLinkage()) + if (not GV.isDeclaration() and Declarations.count(GV.getName()) == 0 + and GV.hasExternalLinkage()) GV.setLinkage(GlobalValue::InternalLinkage); } @@ -1018,6 +1037,22 @@ void CodeGenerator::translate(uint64_t VirtualAddress) { revng_assert(!Result, "Linking failed"); } + // Add a call to the function to initialize the CPUState, if present. + // This is important on x86 architecture. + // We only add the call after the Linker has imported the + // initialize_env function from the helpers, because the declaration + // imported before with importHelperFunctionDeclaration() only has + // stub types and injecting the CallInst earlier would break + if (Function *InitEnv = TheModule->getFunction("initialize_env")) { + revng_assert(not InitEnv->getFunctionType()->isVarArg()); + revng_assert(InitEnv->getFunctionType()->getNumParams() == 1); + auto *CPUStateType = InitEnv->getFunctionType()->getParamType(0); + Instruction *InsertBefore = InitEnvInsertPoint; + auto *AddressComputation = Variables.computeEnvAddress(CPUStateType, + InsertBefore); + CallInst::Create(InitEnv, { AddressComputation }, "", InsertBefore); + } + Variables.setDataLayout(&TheModule->getDataLayout()); legacy::PassManager PM; diff --git a/tools/revamb/CodeGenerator.h b/tools/revamb/CodeGenerator.h index e0848a40f..fa62f62d7 100644 --- a/tools/revamb/CodeGenerator.h +++ b/tools/revamb/CodeGenerator.h @@ -51,6 +51,7 @@ public: /// \param Helpers path of the LLVM IR file containing the QEMU helpers. CodeGenerator(BinaryFile &Binary, Architecture &Target, + llvm::LLVMContext &TheContext, std::string Output, std::string Helpers, std::string EarlyLinked); @@ -85,7 +86,7 @@ private: /// Queries the HelpersModule for a function and adds it to TheModule. /// /// \param Name name of the imported function - llvm::Function *importHelperFunctionDefinition(llvm::StringRef Name); + llvm::Function *importHelperFunctionDeclaration(llvm::StringRef Name); private: Architecture TargetArchitecture; diff --git a/tools/revamb/FunctionBoundariesDetectionPass.cpp b/tools/revamb/FunctionBoundariesDetectionPass.cpp index 53f2cdc36..8e8f724b1 100644 --- a/tools/revamb/FunctionBoundariesDetectionPass.cpp +++ b/tools/revamb/FunctionBoundariesDetectionPass.cpp @@ -185,7 +185,7 @@ private: std::map> CallPredecessors; std::set ReturnPCs; std::set Returns; - ilist_iterator PostDispatcherIt; + Function::iterator PostDispatcherIt; std::map Coverage; // CFEP related data diff --git a/tools/revamb/JumpTargetManager.cpp b/tools/revamb/JumpTargetManager.cpp index cb1bc4ca6..eb5f862d7 100644 --- a/tools/revamb/JumpTargetManager.cpp +++ b/tools/revamb/JumpTargetManager.cpp @@ -253,7 +253,7 @@ bool TranslateDirectBranchesPass::forceFallthroughAfterHelper(CallInst *Call) { auto PCRegTy = PCReg->getType()->getPointerElementType(); bool ForceFallthrough = false; - BasicBlock::reverse_iterator It(make_reverse_iterator(Call)); + BasicBlock::reverse_iterator It(++Call->getReverseIterator()); auto *BB = Call->getParent(); auto EndIt = BB->rend(); while (!ForceFallthrough) { @@ -316,7 +316,7 @@ uint64_t TranslateDirectBranchesPass::getNextPC(Instruction *TheInstruction) { DominatorTree &DT = getAnalysis().getDomTree(); BasicBlock *Block = TheInstruction->getParent(); - BasicBlock::reverse_iterator It(make_reverse_iterator(TheInstruction)); + BasicBlock::reverse_iterator It(++TheInstruction->getReverseIterator()); while (true) { BasicBlock::reverse_iterator Begin(Block->rend()); @@ -408,11 +408,11 @@ JumpTargetManager::readRawValue(uint64_t Address, Constant *JumpTargetManager::readConstantPointer(Constant *Address, Type *PointerTy, Endianess ReadEndianess) { - auto *Value = readConstantInt(Address, - Binary.architecture().pointerSize() / 8, - ReadEndianess); - if (Value != nullptr) { - return ConstantExpr::getIntToPtr(Value, PointerTy); + Constant *ConstInt = readConstantInt(Address, + Binary.architecture().pointerSize() / 8, + ReadEndianess); + if (ConstInt != nullptr) { + return Constant::getIntegerValue(PointerTy, ConstInt->getUniqueInteger()); } else { return nullptr; } @@ -796,7 +796,7 @@ JumpTargetManager::getPC(Instruction *TheInstruction) const { if (TheInstruction->getIterator() == TheInstruction->getParent()->begin()) WorkList.push(--TheInstruction->getParent()->rend()); else - WorkList.push(make_reverse_iterator(TheInstruction)); + WorkList.push(++TheInstruction->getReverseIterator()); while (!WorkList.empty()) { auto I = WorkList.front(); @@ -1136,7 +1136,7 @@ JumpTargetManager::registerJT(uint64_t PC, JTReason::Values Reason) { if (isFirst(I)) { NewBlock = ContainingBlock; } else { - revng_assert(I != nullptr && I != ContainingBlock->end()); + revng_assert(I != nullptr && I->getIterator() != ContainingBlock->end()); NewBlock = ContainingBlock->splitBasicBlock(I); } diff --git a/tools/revamb/Main.cpp b/tools/revamb/Main.cpp index 80c07d46b..d82b200e9 100644 --- a/tools/revamb/Main.cpp +++ b/tools/revamb/Main.cpp @@ -25,6 +25,7 @@ extern "C" { // LLVM includes #include "llvm/ADT/ArrayRef.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/Object/Binary.h" #include "llvm/Object/ELF.h" @@ -200,14 +201,15 @@ int main(int argc, const char *argv[]) { // Translate everything Architecture TargetArchitecture; + llvm::LLVMContext RevambGlobalContext; CodeGenerator Generator(TheBinary, TargetArchitecture, + RevambGlobalContext, std::string(OutputPath), LibHelpersPath, EarlyLinkedPath); Generator.translate(EntryPointAddress); - Generator.serialize(); return EXIT_SUCCESS; diff --git a/tools/revamb/NoReturnAnalysis.cpp b/tools/revamb/NoReturnAnalysis.cpp index fb1cbea6f..2d123d9f5 100644 --- a/tools/revamb/NoReturnAnalysis.cpp +++ b/tools/revamb/NoReturnAnalysis.cpp @@ -40,7 +40,7 @@ void NoReturnAnalysis::registerSyscalls(llvm::Function *F) { if (NoDCE == nullptr) { Type *VoidTy = Type::getVoidTy(M->getContext()); Type *SNRTy = SyscallNumberRegister->getType()->getPointerElementType(); - auto *FunctionC = M->getOrInsertFunction("nodce", VoidTy, SNRTy, nullptr); + auto *FunctionC = M->getOrInsertFunction("nodce", VoidTy, SNRTy); NoDCE = cast(FunctionC); } @@ -133,7 +133,7 @@ void NoReturnAnalysis::registerKiller(uint64_t StoredValue, void NoReturnAnalysis::findInfinteLoops() { Function *F = Dispatcher->getParent(); - DominatorTreeBase DT(false); + DominatorTreeBase DT; DT.recalculate(*F); LoopInfo LI(DT); @@ -180,7 +180,7 @@ void NoReturnAnalysis::computeKillerSet(PredecessorsMap &CallPredecessors) { } // Compute the post-dominator tree on the CFG (in NoFunctionCallsCFG state) - DominatorTreeBase PDT(true); + DominatorTreeBase PDT; PDT.recalculate(*F); // The worklist initially contains only the sink but will be populated with diff --git a/tools/revamb/OSRA.cpp b/tools/revamb/OSRA.cpp index 37a56a21d..b2c76823c 100644 --- a/tools/revamb/OSRA.cpp +++ b/tools/revamb/OSRA.cpp @@ -277,7 +277,7 @@ public: Int64(IntegerType::get(getContext(&F), 64)), OSRs(OSRs), BVs(BVs), - PDT(true) {} + PDT() {} void run(); void dump(); @@ -434,7 +434,7 @@ private: using SubscribersType = SmallSet; std::map Subscriptions; - DominatorTreeBase PDT; + DominatorTreeBase PDT; }; void OSRA::propagateConstraints(Instruction *I, @@ -1410,9 +1410,8 @@ static uint64_t combineImpl(unsigned Opcode, bool Signed, Constant *Op1, Constant *Op2, - IntegerType *T, const DataLayout &DL) { - auto *R = ConstantFoldInstOperands(Opcode, T, { Op1, Op2 }, DL); + auto *R = ConstantFoldBinaryOpOperands(Opcode, Op1, Op2, DL); return getExtValue(R, Signed, DL); } @@ -1422,7 +1421,7 @@ static uint64_t combineImpl(unsigned Opcode, Constant *Op2, IntegerType *T, const DataLayout &DL) { - return combineImpl(Opcode, Signed, CI::get(T, Op1, Signed), Op2, T, DL); + return combineImpl(Opcode, Signed, CI::get(T, Op1, Signed), Op2, DL); } static uint64_t combineImpl(unsigned Opcode, @@ -1431,7 +1430,7 @@ static uint64_t combineImpl(unsigned Opcode, uint64_t Op2, IntegerType *T, const DataLayout &DL) { - return combineImpl(Opcode, Signed, Op1, CI::get(T, Op2, Signed), T, DL); + return combineImpl(Opcode, Signed, Op1, CI::get(T, Op2, Signed), DL); } uint64_t BoundedValue::performOp(uint64_t Op1, @@ -1455,7 +1454,7 @@ uint64_t BoundedValue::performOp(uint64_t Op1, auto *COp2 = CI::get(Ty, Op2, IsSigned); // Compute the result - auto *Result = ConstantFoldInstOperands(Opcode, Ty, { COp1, COp2 }, DL); + auto *Result = ConstantFoldBinaryOpOperands(Opcode, COp1, COp2, DL); return getExtValue(Result, IsSigned, DL); } @@ -1863,6 +1862,7 @@ OSRAPass::identifyOperands(std::map &OSRs, Clone->setOperand(0, Constants[0]); Clone->setOperand(1, Constants[1]); Constant *Result = ConstantFoldInstruction(Clone, DL); + Clone->deleteValue(); if (isa(Result)) return { nullptr, nullptr }; else diff --git a/tools/revamb/SET.cpp b/tools/revamb/SET.cpp index 6ae3b9fa7..5d944f73f 100644 --- a/tools/revamb/SET.cpp +++ b/tools/revamb/SET.cpp @@ -65,9 +65,12 @@ public: /// \brief Clean the operations stack void reset() { // Delete all the temporary instructions we created - for (Instruction *I : Operations) - if (I->getParent() == nullptr) - delete I; + for (Instruction *I : Operations) { + if (I->getParent() == nullptr) { + I->dropUnknownNonDebugMetadata(); + I->deleteValue(); + } + } Operations.clear(); OperationsSet.clear(); @@ -125,8 +128,10 @@ public: } // We have the ownership of instruction without parent - if (Op->getParent() == nullptr) - delete Op; + if (Op->getParent() == nullptr) { + Op->dropUnknownNonDebugMetadata(); + Op->deleteValue(); + } Operations.pop_back(); } @@ -142,8 +147,10 @@ public: } // If the given instruction doesn't have a parent we take ownership of it - if (I->getParent() == nullptr) - delete I; + if (I->getParent() == nullptr) { + I->dropUnknownNonDebugMetadata(); + I->deleteValue(); + } return false; } @@ -270,10 +277,7 @@ uint64_t OperationsStack::materialize(Constant *NewOperand) { } } - NewOperand = ConstantFoldInstOperands(I->getOpcode(), - I->getType(), - Operands, - DL); + NewOperand = ConstantFoldInstOperands(I, Operands, DL); revng_assert(NewOperand != nullptr); // TODO: this is an hack hiding a bigger problem if (isa(NewOperand)) { @@ -390,7 +394,7 @@ bool SET::enqueueStores(LoadInst *Start) { } Visited.insert(BB); - BasicBlock::reverse_iterator It(make_reverse_iterator(I)); + BasicBlock::reverse_iterator It(++I->getReverseIterator()); BasicBlock::reverse_iterator Begin(BB->rend()); bool Found = false; diff --git a/tools/revamb/SubGraph.h b/tools/revamb/SubGraph.h index d40d001aa..6e02fd844 100644 --- a/tools/revamb/SubGraph.h +++ b/tools/revamb/SubGraph.h @@ -121,18 +121,18 @@ namespace llvm { template struct GraphTraits> { using GraphType = SubGraph; - using NodeType = typename GraphType::Node; + using NodeRef = typename GraphType::Node *; using ChildIteratorType = typename GraphType::ChildIteratorType; using nodes_iterator = typename GraphType::nodes_iterator; // TODO: here G should be const - static NodeType *getEntryNode(GraphType &G) { return G.EntryNode; } + static NodeRef getEntryNode(GraphType &G) { return G.EntryNode; } - static ChildIteratorType child_begin(NodeType *Parent) { + static ChildIteratorType child_begin(NodeRef Parent) { return Parent->Children.begin(); } - static ChildIteratorType child_end(NodeType *Parent) { + static ChildIteratorType child_end(NodeRef Parent) { return Parent->Children.end(); }