From 7859f9de7822db8aaa27f44ecfe1c224d41aa8cd Mon Sep 17 00:00:00 2001 From: Alessandro Di Federico Date: Wed, 24 Aug 2016 23:00:14 +0200 Subject: [PATCH] Keep track of how jump targets have been met This commit registers for each jump target how we met it, as a flag. It also keeps track of which pointers in global data have been involved in materialization performed by SET: those who are not are of special interest for us, since they are likely function pointers, and are therefore marked with a specific flag. --- codegenerator.cpp | 2 + jumptargetmanager.cpp | 131 ++++++++++++++++++++++++------------------ jumptargetmanager.h | 63 ++++++++++++++++---- 3 files changed, 131 insertions(+), 65 deletions(-) diff --git a/codegenerator.cpp b/codegenerator.cpp index aabe5f771..f14ee2bb1 100644 --- a/codegenerator.cpp +++ b/codegenerator.cpp @@ -964,6 +964,8 @@ void CodeGenerator::translate(uint64_t VirtualAddress, JumpTargets.translateIndirectJumps(); + JumpTargets.finalizeJumpTargets(); + purgeDeadBlocks(MainFunction); Translator.finalizeNewPCMarkers(CoveragePath, EnableTracing); Debug->generateDebugInfo(); diff --git a/jumptargetmanager.cpp b/jumptargetmanager.cpp index 859f8bd2e..c2ef23440 100644 --- a/jumptargetmanager.cpp +++ b/jumptargetmanager.cpp @@ -11,6 +11,7 @@ #include // LLVM includes +#include "llvm/ADT/Optional.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" @@ -301,34 +302,13 @@ uint64_t TranslateDirectBranchesPass::getNextPC(Instruction *TheInstruction) { llvm_unreachable("Can't find the PC marker"); } -Constant *JumpTargetManager::readConstantPointer(Constant *Address, - Type *PointerTy) const { - auto *Value = readConstantInt(Address, SourceArchitecture.pointerSize()); - if (Value != nullptr) { - return ConstantExpr::getIntToPtr(Value, PointerTy); - } else { - return nullptr; - } -} +Optional JumpTargetManager::readRawValue(uint64_t Address, + unsigned Size) const { + assert(Size <= 8 * sizeof(uint64_t)); -ConstantInt *JumpTargetManager::readConstantInt(Constant *ConstantAddress, - unsigned Size) const { - // TODO: register that the value has been used externally - return readConstantInternal(ConstantAddress, Size); -} - -ConstantInt *JumpTargetManager::readConstantInternal(Constant *ConstantAddress, - unsigned Size) const { + // TODO: create a IsLittleEndian field in JumpTargetManager? const DataLayout &DL = TheModule.getDataLayout(); - if (ConstantAddress->getType()->isPointerTy()) { - using CE = ConstantExpr; - auto IntPtrTy = Type::getIntNTy(Context, SourceArchitecture.pointerSize()); - ConstantAddress = CE::getPtrToInt(ConstantAddress, IntPtrTy); - } - - uint64_t Address = getZExtValue(ConstantAddress, DL); - for (auto &Segment : Segments) { // Note: we also consider writeable memory areas because, despite being // modifiable, can contain useful information @@ -341,38 +321,63 @@ ConstantInt *JumpTargetManager::readConstantInternal(Constant *ConstantAddress, using support::endian::read; using support::endianness; - uint64_t Value; switch (Size) { case 1: - Value = read(Start); - break; + return read(Start); case 2: if (DL.isLittleEndian()) - Value = read(Start); + return read(Start); else - Value = read(Start); - break; + return read(Start); case 4: if (DL.isLittleEndian()) - Value = read(Start); + return read(Start); else - Value = read(Start); - break; + return read(Start); case 8: if (DL.isLittleEndian()) - Value = read(Start); + return read(Start); else - Value = read(Start); - break; + return read(Start); default: - llvm_unreachable("Unexpected read size"); + assert(false && "Unexpected read size"); } - - return ConstantInt::get(IntegerType::get(Context, Size * 8), Value); } } - return nullptr; + return Optional(); +} + +Constant *JumpTargetManager::readConstantPointer(Constant *Address, + Type *PointerTy) { + auto *Value = readConstantInt(Address, + SourceArchitecture.pointerSize() / 8); + if (Value != nullptr) { + return ConstantExpr::getIntToPtr(Value, PointerTy); + } else { + return nullptr; + } +} + +ConstantInt *JumpTargetManager::readConstantInt(Constant *ConstantAddress, + unsigned Size) { + const DataLayout &DL = TheModule.getDataLayout(); + + if (ConstantAddress->getType()->isPointerTy()) { + using CE = ConstantExpr; + auto IntPtrTy = Type::getIntNTy(Context, SourceArchitecture.pointerSize()); + ConstantAddress = CE::getPtrToInt(ConstantAddress, IntPtrTy); + } + + uint64_t Address = getZExtValue(ConstantAddress, DL); + UnusedCodePointers.erase(Address); + + auto Result = readRawValue(Address, Size); + if (Result.hasValue()) + return ConstantInt::get(IntegerType::get(Context, Size * 8), + Result.getValue()); + else + return nullptr; } template @@ -418,20 +423,29 @@ JumpTargetManager::JumpTargetManager(Function *TheFunction, void JumpTargetManager::harvestGlobalData() { for (auto& Segment : Segments) { auto *Data = cast(Segment.Variable->getInitializer()); + uint64_t StartVirtualAddress = Segment.StartVirtualAddress; const unsigned char *DataStart = Data->getRawDataValues().bytes_begin(); const unsigned char *DataEnd = Data->getRawDataValues().bytes_end(); using endianness = support::endianness; if (SourceArchitecture.pointerSize() == 64) { if (SourceArchitecture.isLittleEndian()) - findCodePointers(DataStart, DataEnd); + findCodePointers(StartVirtualAddress, + DataStart, + DataEnd); else - findCodePointers(DataStart, DataEnd); + findCodePointers(StartVirtualAddress, + DataStart, + DataEnd); } else if (SourceArchitecture.pointerSize() == 32) { if (SourceArchitecture.isLittleEndian()) - findCodePointers(DataStart, DataEnd); + findCodePointers(StartVirtualAddress, + DataStart, + DataEnd); else - findCodePointers(DataStart, DataEnd); + findCodePointers(StartVirtualAddress, + DataStart, + DataEnd); } } @@ -441,15 +455,19 @@ void JumpTargetManager::harvestGlobalData() { } template -void JumpTargetManager::findCodePointers(const unsigned char *Start, +void JumpTargetManager::findCodePointers(uint64_t StartVirtualAddress, + const unsigned char *Start, const unsigned char *End) { using support::endian::read; using support::endianness; - for (; Start < End - sizeof(value_type); Start++) { + for (auto Pos = Start; Pos < End - sizeof(value_type); Pos++) { uint64_t Value = read(endian), - 1>(Start); - registerJT(Value, GlobalData); + 1>(Pos); + BasicBlock *Result = registerJT(Value, GlobalData); + + if (Result != nullptr) + UnusedCodePointers.insert(StartVirtualAddress + (Pos - Start)); } } @@ -486,9 +504,10 @@ BasicBlock *JumpTargetManager::newPC(uint64_t PC, bool& ShouldContinue) { // It wasn't planned to visit it, so we've already been there, just jump // there - assert(!JTIt->second->empty()); + BasicBlock *BB = JTIt->second.head(); + assert(!BB->empty()); ShouldContinue = false; - return JTIt->second; + return BB; } // Check if we already translated this PC even if it's not associated to a @@ -1016,7 +1035,7 @@ void JumpTargetManager::unvisit(BasicBlock *BB) { BasicBlock *JumpTargetManager::getBlockAt(uint64_t PC) { auto TargetIt = JumpTargets.find(PC); assert(TargetIt != JumpTargets.end()); - return TargetIt->second; + return TargetIt->second.head(); } // TODO: register Reason @@ -1028,8 +1047,10 @@ BasicBlock *JumpTargetManager::registerJT(uint64_t PC, JTReason Reason) { BlockMap::iterator TargetIt = JumpTargets.find(PC); if (TargetIt != JumpTargets.end()) { // Case 1: there's already a BasicBlock for that address, return it - unvisit(TargetIt->second); - return TargetIt->second; + BasicBlock *BB = TargetIt->second.head(); + TargetIt->second.setReason(Reason); + unvisit(BB); + return BB; } // Did we already meet this PC (i.e. do we know what's the associated @@ -1069,7 +1090,7 @@ BasicBlock *JumpTargetManager::registerJT(uint64_t PC, JTReason Reason) { DispatcherSwitch->addCase(ConstantInt::get(SwitchType, PC), NewBlock); // Associate the PC with the chosen basic block - JumpTargets[PC] = NewBlock; + JumpTargets[PC] = JumpTarget(NewBlock, Reason); return NewBlock; } diff --git a/jumptargetmanager.h b/jumptargetmanager.h index 82659e738..7ef7f590f 100644 --- a/jumptargetmanager.h +++ b/jumptargetmanager.h @@ -7,6 +7,12 @@ #include #include +// LLVM includes +#include "llvm/ADT/Optional.h" + +// Local includes +#include "ir-helpers.h" + // Forward declarations namespace llvm { class BasicBlock; @@ -249,7 +255,9 @@ public: /// immediately preceeding bytes SETToPC = 16, ///< Obtained from SET on a store to the PC SETNotToPC = 32, ///< Obtained from SET (but not from a PC-store) - SumJump = 64, ///< Obtained from the "sumjump" heuristic + UnusedGlobalData = 64, ///< Obtained digging in global data, buf never used + /// by SET. Likely a function pointer. + SumJump = 128, ///< Obtained from the "sumjump" heuristic }; /// \brief Return, and, if necessary, register the basic block associated to @@ -297,13 +305,14 @@ public: /// \return a `ConstantInt` with the read value or `nullptr` in case it wasn't /// possible to read the value (e.g., \p Address is not inside any of /// the segments). - llvm::ConstantInt *readConstantInt(llvm::Constant *Address, - unsigned Size) const; + llvm::ConstantInt *readConstantInt(llvm::Constant *Address, unsigned Size); /// \brief Reads a pointer-sized value from a segment /// \see readConstantInt llvm::Constant *readConstantPointer(llvm::Constant *Address, - llvm::Type *PointerTy) const; + llvm::Type *PointerTy); + + llvm::Optional readRawValue(uint64_t Address, unsigned Size) const; /// \brief Register a new basic block in terms of the input architecture /// @@ -379,14 +388,28 @@ public: /// \brief Increment the counter of emitted branches since the last reset void newBranch() { NewBranches++; } + /// \brief Finalizes information about the jump targets + /// + /// Call this function once no more jump targets can be discovered. It will + /// fix all the pending information. In particular, those pointers to code + /// that have never been touched by SET will be considered and their pointee + /// will be marked with UnusedGlobalData. + void finalizeJumpTargets() { + unsigned ReadSize = SourceArchitecture.pointerSize() / 8; + for (uint64_t MemoryAddress : UnusedCodePointers) { + uint64_t PC = readRawValue(MemoryAddress, ReadSize).getValue(); + registerJT(PC, UnusedGlobalData); + } + + // We no longer need this information + UnusedCodePointers.clear(); + } + /// \brief Return the next call to exitTB after I, or nullptr if it can't find /// one llvm::CallInst *findNextExitTB(llvm::Instruction *I); private: - llvm::ConstantInt *readConstantInternal(llvm::Constant *Address, - unsigned Size) const; - /// \brief Return an iterator to the entry containing the given address range typename std::map::iterator containingOriginalBB(uint64_t Address) { @@ -409,14 +432,32 @@ private: bool JumpDirectly); template - void findCodePointers(const unsigned char *Start, const unsigned char *End); + void findCodePointers(uint64_t StartVirtualAddress, + const unsigned char *Start, + const unsigned char *End); void harvest(); void handleSumJump(llvm::Instruction *SumJump); private: - using BlockMap = std::map; + class JumpTarget { + public: + JumpTarget() : BB(nullptr), Reasons(0) { } + JumpTarget(llvm::BasicBlock *BB) : BB(BB), Reasons(0) { } + JumpTarget(llvm::BasicBlock *BB, + JTReason Reason) : BB(BB), Reasons(Reason) { } + + llvm::BasicBlock *head() const { return BB; } + bool hasReason(JTReason Reason) const { return (Reasons & Reason) != 0; } + void setReason(JTReason Reason) { Reasons |= Reason; } + + private: + llvm::BasicBlock *BB; + uint32_t Reasons; + }; + + using BlockMap = std::map; using InstructionMap = std::map; llvm::Module &TheModule; @@ -438,12 +479,14 @@ private: std::set Visited; std::vector& Segments; - Architecture& SourceArchitecture; + Architecture &SourceArchitecture; bool EnableOSRA; std::map OriginalBBStats; unsigned NewBranches = 0; + + std::set UnusedCodePointers; }; #endif // _JUMPTARGETMANAGER_H