diff --git a/functioncallidentification.cpp b/functioncallidentification.cpp index caa91a591..8225ef049 100644 --- a/functioncallidentification.cpp +++ b/functioncallidentification.cpp @@ -24,6 +24,8 @@ bool FunctionCallIdentification::runOnFunction(llvm::Function &F) { auto &GCBI = getAnalysis(); + FallthroughAddresses.clear(); + // Create function call marker // TODO: we could factor this out Module *M = F.getParent(); @@ -216,6 +218,8 @@ bool FunctionCallIdentification::runOnFunction(llvm::Function &F) { LinkRegister }; + FallthroughAddresses.insert(ReturnPC); + // If the instruction before the terminator is a call to exitTB, inject // the call to function_call before it, so it doesn't get purged auto It = Terminator->getIterator(); diff --git a/functioncallidentification.h b/functioncallidentification.h index f31563869..d8422e8ec 100644 --- a/functioncallidentification.h +++ b/functioncallidentification.h @@ -59,8 +59,41 @@ public: return isCall(BB->getTerminator()); } + llvm::BasicBlock *getFallthrough(llvm::BasicBlock *BB) const { + return getFallthrough(BB->getTerminator()); + } + + llvm::BasicBlock *getFallthrough(llvm::TerminatorInst *T) const { + assert(T != nullptr); + llvm::Instruction *Previous = getPrevious(T); + while (Previous != nullptr && isMarker(Previous)) { + auto *Call = llvm::cast(Previous); + if (Call->getCalledFunction() == FunctionCall) { + auto *Fallthrough = llvm::cast(Call->getOperand(1)); + return Fallthrough->getBasicBlock(); + } + + Previous = getPrevious(Previous); + } + + abort(); + } + + bool isFallthrough(uint64_t Address) const { + return FallthroughAddresses.count(Address) != 0; + } + + bool isFallthrough(llvm::BasicBlock *BB) const { + return isFallthrough(getBasicBlockPC(BB)); + } + + bool isFallthrough(llvm::TerminatorInst *I) const { + return isFallthrough(I->getParent()); + } + private: llvm::Function *FunctionCall; + std::set FallthroughAddresses; }; #endif // _FUNCTIONCALLIDENTIFICATION_H