From 4332026a99d94c75dcf6029ad0045fce6925e562 Mon Sep 17 00:00:00 2001 From: Vladislav Kalugin Date: Wed, 23 Aug 2023 18:58:36 +0300 Subject: [PATCH] remove instructionInfoTable --- include/klee/Core/Interpreter.h | 13 +- include/klee/Module/InstructionInfoTable.h | 160 ++++++------ include/klee/Module/KInstruction.h | 39 ++- include/klee/Module/KModule.h | 58 +++-- lib/Basic/Statistics.cpp | 2 +- lib/Core/ExecutionState.cpp | 13 +- lib/Core/Executor.cpp | 34 +-- lib/Core/Executor.h | 6 +- lib/Core/Searcher.cpp | 2 +- lib/Core/StatsTracker.cpp | 143 ++++++----- lib/Core/TargetedExecutionManager.cpp | 22 +- lib/Core/TargetedExecutionManager.h | 6 - lib/Module/InstructionInfoTable.cpp | 278 +++++++-------------- lib/Module/KInstruction.cpp | 71 +++++- lib/Module/KModule.cpp | 168 +++++++------ tools/klee/main.cpp | 30 ++- 16 files changed, 539 insertions(+), 506 deletions(-) diff --git a/include/klee/Core/Interpreter.h b/include/klee/Core/Interpreter.h index 5b9443bbff3..8a97c484a49 100644 --- a/include/klee/Core/Interpreter.h +++ b/include/klee/Core/Interpreter.h @@ -21,6 +21,7 @@ #include #include +#include "llvm/ADT/StringRef.h" #include using nonstd::optional; @@ -61,6 +62,12 @@ class InterpreterHandler { const char *suffix, bool isError = false) = 0; }; +// TODO remove +using FInstructions = std::unordered_map< + std::string, + std::unordered_map< + unsigned, std::unordered_map>>>; + class Interpreter { public: enum class GuidanceKind { @@ -140,9 +147,9 @@ class Interpreter { setModule(std::vector> &userModules, std::vector> &libsModules, const ModuleOptions &opts, - const std::unordered_set &mainModuleFunctions, - const std::unordered_set &mainModuleGlobals, - std::unique_ptr origInfos) = 0; + std::set &mainModuleFunctions, + std::set &mainModuleGlobals, + FInstructions &&origInstructions) = 0; // supply a tree stream writer which the interpreter will use // to record the concrete path (as a stream of '0' and '1' bytes). diff --git a/include/klee/Module/InstructionInfoTable.h b/include/klee/Module/InstructionInfoTable.h index 9da3b100d04..0f123f0315f 100644 --- a/include/klee/Module/InstructionInfoTable.h +++ b/include/klee/Module/InstructionInfoTable.h @@ -1,11 +1,11 @@ -//===-- InstructionInfoTable.h ----------------------------------*- C++ -*-===// -// -// The KLEE Symbolic Virtual Machine -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// +////===-- InstructionInfoTable.h ----------------------------------*- C++ -*-===// +//// +//// The KLEE Symbolic Virtual Machine +//// +//// This file is distributed under the University of Illinois Open Source +//// License. See LICENSE.TXT for details. +//// +////===----------------------------------------------------------------------===// #ifndef KLEE_INSTRUCTIONINFOTABLE_H #define KLEE_INSTRUCTIONINFOTABLE_H @@ -31,81 +31,68 @@ class Module; namespace klee { -// TODO move to methods of kInstruction -/// @brief InstructionInfo stores debug information for a KInstruction. -struct InstructionInfo { - /// @brief The instruction id. - unsigned id; - /// @brief Line number in source file. - // unsigned line; - /// @brief Column number in source file. - // unsigned column; - /// @brief Line number in generated assembly.ll. - llvm::Optional assemblyLine; - /// @brief Source file name. -// const std::string &file; - -public: - InstructionInfo(unsigned id, llvm::Optional assemblyLine) - : id{id}, assemblyLine{assemblyLine} {} -}; - -/// @brief FunctionInfo stores debug information for a KFunction. -struct FunctionInfo { // TODO clear this too - /// @brief The function id. - unsigned id; - /// @brief Line number in source file. - unsigned line; - /// @brief Line number in generated assembly.ll. - llvm::Optional assemblyLine; - /// @brief Source file name. - const std::string &file; - -public: - FunctionInfo(unsigned id, const std::string &file, unsigned line, - llvm::Optional assemblyLine) - : id{id}, line{line}, assemblyLine{assemblyLine}, file{file} {} - - FunctionInfo(const FunctionInfo &) = delete; - FunctionInfo &operator=(FunctionInfo const &) = delete; - - FunctionInfo(FunctionInfo &&) = default; -}; - -class InstructionInfoTable { -public: - using Instructions = std::unordered_map< - std::string, - std::unordered_map< - unsigned int, - std::unordered_map>>>; - using LocationToFunctionsMap = - std::unordered_map>; - -private: - std::unordered_map> - infos; // TODO change to llvm::Instruction* -> KInstruction* - std::unordered_map> - functionInfos; - std::vector> internedStrings; // TODO remove - LocationToFunctionsMap fileNameToFunctions; // TODO remove - std::unordered_set filesNames; // TODO remove - Instructions insts; // TODO remove when move prepare target to main - -public: - explicit InstructionInfoTable( - const llvm::Module &m, std::unique_ptr assemblyFS, - bool withInstructions = false); - - unsigned getMaxID() const; - const InstructionInfo &getInfo(const llvm::Instruction &) const; - const FunctionInfo &getFunctionInfo(const llvm::Function &) const; - const LocationToFunctionsMap &getFileNameToFunctions() const; - const std::unordered_set &getFilesNames() const; - Instructions getInstructions(); -}; +//// TODO move to methods of kInstruction +///// @brief InstructionInfo stores debug information for a KInstruction. +//struct InstructionInfo { +// /// @brief The instruction id. +//// unsigned id; // TODO move to kInstruction +// /// @brief Line number in source file. +// // unsigned line; +// /// @brief Column number in source file. +// // unsigned column; +// /// @brief Line number in generated assembly.ll. +//// llvm::Optional assemblyLine; +// /// @brief Source file name. +//// const std::string &file; +// +//public: +// InstructionInfo(unsigned id) {} +//}; +// +///// @brief FunctionInfo stores debug information for a KFunction. +//struct FunctionInfo { // TODO clear this too +// /// @brief The function id. +//// unsigned id; // TODO move to kFunction +// /// @brief Line number in source file. +//// unsigned line; +// /// @brief Line number in generated assembly.ll. +//// llvm::Optional assemblyLine; +// /// @brief Source file name. +//// const std::string &file; +// +//public: +// FunctionInfo(unsigned id) {} +// +// FunctionInfo(const FunctionInfo &) = delete; +// FunctionInfo &operator=(FunctionInfo const &) = delete; +// +// FunctionInfo(FunctionInfo &&) = default; +//}; +// +//class InstructionInfoTable { +//public: +// using LocationToFunctionsMap = +// std::unordered_map>; +// +//private: +// std::unordered_map> infos; +// std::unordered_map> +// functionInfos; +// LocationToFunctionsMap fileNameToFunctions; // TODO remove +//// Instructions insts; // TODO remove when move prepare target to main +// +//public: +// explicit InstructionInfoTable( +// const llvm::Module &m); +// +//// unsigned getMaxID() const; +// const InstructionInfo &getInfo(const llvm::Instruction &) const; +// const FunctionInfo &getFunctionInfo(const llvm::Function &) const; +// const LocationToFunctionsMap &getFileNameToFunctions() const; +//// Instructions getInstructions(); +//}; struct LocationInfo { std::string file; @@ -113,9 +100,12 @@ struct LocationInfo { size_t column; }; + +// TODO need unify with kFunction +LocationInfo getLocationInfo(const llvm::Function *func); + // TODO need unify with kInstruction -LocationInfo getLocationInfo(const llvm::Instruction &Inst, - const FunctionInfo *f); +LocationInfo getLocationInfo(const llvm::Instruction *inst); } // namespace klee diff --git a/include/klee/Module/KInstruction.h b/include/klee/Module/KInstruction.h index 4ed8b6d9a03..976d053fb1e 100644 --- a/include/klee/Module/KInstruction.h +++ b/include/klee/Module/KInstruction.h @@ -16,10 +16,12 @@ #include "klee/Support/CompilerWarning.h" DISABLE_WARNING_PUSH DISABLE_WARNING_DEPRECATED_DECLARATIONS +#include "KModule.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/raw_ostream.h" DISABLE_WARNING_POP +#include #include namespace llvm { @@ -28,7 +30,7 @@ class Instruction; namespace klee { class Executor; -struct InstructionInfo; +//struct InstructionInfo; class KModule; struct KBlock; @@ -36,7 +38,7 @@ struct KBlock; /// during execution. struct KInstruction { llvm::Instruction *inst; - const InstructionInfo *info; // TODO remove it +// const InstructionInfo *info; // TODO remove it /// Value numbers for each operand. -1 is an invalid value, /// otherwise negative numbers are indices (negated and offset by @@ -45,18 +47,27 @@ struct KInstruction { int *operands; KBlock *parent; +private: // Instruction index in the basic block - size_t index; // TODO maybe change to pointer or size_t + const unsigned globalIndex; /// Destination register index. // unsigned dest; public: + /// Unique index for KFunction and KInstruction inside KModule + /// from 0 to [KFunction + KInstruction] + [[nodiscard]] unsigned getGlobalIndex() const; /// Instruction index in the basic block - [[nodiscard]] unsigned getIndex() const; // TODO change to uintptr_t + [[nodiscard]] unsigned getIndex() const; /// Destination register index. - [[nodiscard]] unsigned getDest() const; // TODO change to uintptr_t + [[nodiscard]] unsigned getDest() const; - KInstruction() = default; // TODO remove default constructor + KInstruction(const std::unordered_map + &_instructionToRegisterMap, + llvm::Instruction *_inst, KModule *_km, KBlock *_kb, + unsigned &_globalIndexInc); + + KInstruction() = delete; // TODO remove default constructor explicit KInstruction(const KInstruction &ki) = delete; virtual ~KInstruction(); @@ -66,6 +77,14 @@ struct KInstruction { [[nodiscard]] std::string getSourceLocationString() const; [[nodiscard]] std::string toString() const; + + [[nodiscard]] inline KBlock *getKBlock() const { return parent; } + [[nodiscard]] inline KFunction *getKFunction() const { + return getKBlock()->parent; + } + [[nodiscard]] inline KModule *getKModule() const { + return getKFunction()->parent; + } }; struct KGEPInstruction : KInstruction { @@ -80,7 +99,13 @@ struct KGEPInstruction : KInstruction { uint64_t offset; public: - KGEPInstruction() = default; + KGEPInstruction(const std::unordered_map + &_instructionToRegisterMap, + llvm::Instruction *_inst, KModule *_km, KBlock *_kb, + unsigned &_globalIndexInc) + : KInstruction(_instructionToRegisterMap, _inst, _km, _kb, + _globalIndexInc) {} + KGEPInstruction() = delete; explicit KGEPInstruction(const KGEPInstruction &ki) = delete; }; } // namespace klee diff --git a/include/klee/Module/KModule.h b/include/klee/Module/KModule.h index 06bb86fe986..e4eb4327294 100644 --- a/include/klee/Module/KModule.h +++ b/include/klee/Module/KModule.h @@ -73,7 +73,8 @@ struct KBlock { public: KBlock(KFunction *, llvm::BasicBlock *, KModule *, const std::unordered_map &, - KInstruction **); + KInstruction **, unsigned &globalIndexInc); + KBlock() = delete; KBlock(const KBlock &) = delete; KBlock &operator=(const KBlock &) = delete; virtual ~KBlock() = default; @@ -81,10 +82,6 @@ struct KBlock { virtual KBlockType getKBlockType() const { return KBlockType::Base; } static bool classof(const KBlock *) { return true; } - void - handleKInstruction(const std::unordered_map - &instructionToRegisterMap, - llvm::Instruction *inst, KModule *km, KInstruction *ki); KInstruction *getFirstInstruction() const noexcept { return instructions[0]; } KInstruction *getLastInstruction() const noexcept { return instructions[numInstructions - 1]; @@ -103,9 +100,11 @@ struct KCallBlock : KBlock { std::set calledFunctions; public: + KCallBlock() = delete; KCallBlock(KFunction *, llvm::BasicBlock *, KModule *, const std::unordered_map &, - std::set, KInstruction **); + std::set, KInstruction **, + unsigned &globalIndexInc); static bool classof(const KCallBlock *) { return true; } static bool classof(const KBlock *E) { return E->getKBlockType() == KBlockType::Call; @@ -119,9 +118,10 @@ struct KCallBlock : KBlock { struct KReturnBlock : KBlock { public: + KReturnBlock() = delete; KReturnBlock(KFunction *, llvm::BasicBlock *, KModule *, const std::unordered_map &, - KInstruction **); + KInstruction **, unsigned &globalIndexInc); static bool classof(const KReturnBlock *) { return true; } static bool classof(const KBlock *E) { return E->getKBlockType() == KBlockType::Return; @@ -132,6 +132,7 @@ struct KReturnBlock : KBlock { struct KFunction : public KCallable { private: std::unordered_map labelMap; + const unsigned globalIndex; public: KModule *parent; @@ -149,7 +150,6 @@ struct KFunction : public KCallable { std::vector returnKBlocks; std::vector kCallBlocks; - /// count of instructions in function unsigned numInstructions; // unsigned numArgs; @@ -164,7 +164,8 @@ struct KFunction : public KCallable { /// "coverable" for statistics and search heuristics. // bool trackCoverage; - explicit KFunction(llvm::Function *, KModule *); + explicit KFunction(llvm::Function *, KModule *, unsigned &); + KFunction() = delete; KFunction(const KFunction &) = delete; KFunction &operator=(const KFunction &) = delete; @@ -194,6 +195,13 @@ struct KFunction : public KCallable { static bool classof(const KCallable *callable) { return callable->getKind() == CK_Function; } + + [[nodiscard]] size_t getLine() const; + [[nodiscard]] std::string getSourceFilepath() const; + + /// Unique index for KFunction and KInstruction inside KModule + /// from 0 to [KFunction + KInstruction] + [[nodiscard]] inline unsigned getGlobalIndex() const { return globalIndex; } }; class KConstant { @@ -214,6 +222,7 @@ class KConstant { class KModule { private: bool withPosixRuntime; // TODO move to opts + unsigned maxGlobalIndex; public: std::unique_ptr module; @@ -224,22 +233,26 @@ class KModule { std::unordered_map functionMap; std::unordered_map> callMap; std::unordered_map functionNameMap; -// std::unordered_map functionIDMap; + // std::unordered_map functionIDMap; [[nodiscard]] unsigned getFunctionId(const llvm::Function *) const; // Functions which escape (may be called indirectly) // XXX change to KFunction std::set escapingFunctions; - // TODO change to StringRef - std::unordered_set mainModuleFunctions; + std::set mainModuleFunctions; + + std::set mainModuleGlobals; - // TODO change to StringRef - std::unordered_set mainModuleGlobals; + using FInstructions = std::unordered_map< + std::string, + std::unordered_map< + unsigned, + std::unordered_map>>>; - InstructionInfoTable::Instructions origInfos; + FInstructions origInstructions; - std::unique_ptr infos; +// std::unique_ptr infos; std::vector constants; std::unordered_map> @@ -251,6 +264,9 @@ class KModule { // Functions which are part of KLEE runtime std::set internalFunctions; + // instruction to assembly.ll line empty if no statistic enabled + std::unordered_map asmLineMap; + // Mark function with functionName as part of the KLEE runtime void addInternalFunction(const char *functionName); // Replace std functions with KLEE intrinsics @@ -304,6 +320,16 @@ class KModule { bool inMainModule(const llvm::GlobalVariable &v); bool WithPOSIXRuntime() { return withPosixRuntime; } + + std::optional getAsmLine(const uintptr_t ref) const; + std::optional getAsmLine(const llvm::Function *func) const; + std::optional getAsmLine(const llvm::Instruction *inst) const; + + inline unsigned getMaxGlobalIndex() const { + return maxGlobalIndex; + } + unsigned getGlobalIndex(const llvm::Function *func) const; + unsigned getGlobalIndex(const llvm::Instruction *inst) const; }; } // namespace klee diff --git a/lib/Basic/Statistics.cpp b/lib/Basic/Statistics.cpp index 170ea839e0c..50d9e8bf1fa 100644 --- a/lib/Basic/Statistics.cpp +++ b/lib/Basic/Statistics.cpp @@ -50,7 +50,7 @@ Statistic *StatisticManager::getStatisticByName(const std::string &name) const { return 0; } -StatisticManager *klee::theStatisticManager = 0; +StatisticManager *klee::theStatisticManager = nullptr; static StatisticManager &getStatisticManager() { static StatisticManager sm; diff --git a/lib/Core/ExecutionState.cpp b/lib/Core/ExecutionState.cpp index f647271525a..688f85ef42d 100644 --- a/lib/Core/ExecutionState.cpp +++ b/lib/Core/ExecutionState.cpp @@ -406,13 +406,14 @@ void ExecutionState::dumpStack(llvm::raw_ostream &out) const { const StackFrame &sf = stack.valueStack().at(ri); Function *f = csf.kf->function; - const InstructionInfo &ii = *target->info; +// const InstructionInfo &ii = *target->info; out << "\t#" << i; - if (ii.assemblyLine.hasValue()) { - std::stringstream AssStream; - AssStream << std::setw(8) << std::setfill('0') - << ii.assemblyLine.getValue(); - out << AssStream.str(); + auto assemblyLine = target->getKModule()->getAsmLine(target->inst); + if (assemblyLine.has_value()) { + std::stringstream AsmStream; + AsmStream << std::setw(8) << std::setfill('0') + << assemblyLine.value(); + out << AsmStream.str(); } out << " in " << f->getName().str() << "("; // Yawn, we could go up and print varargs if we wanted to. diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp index 3f277a5b107..ddadce7ce90 100644 --- a/lib/Core/Executor.cpp +++ b/lib/Core/Executor.cpp @@ -528,9 +528,9 @@ llvm::Module * Executor::setModule(std::vector> &userModules, std::vector> &libsModules, const ModuleOptions &opts, - const std::unordered_set &mainModuleFunctions, - const std::unordered_set &mainModuleGlobals, - std::unique_ptr origInfos) { + std::set &mainModuleFunctions, + std::set &mainModuleGlobals, + FInstructions &&origInstructions) { assert(!kmodule && !userModules.empty() && "can only register one module"); // XXX gross @@ -577,16 +577,12 @@ Executor::setModule(std::vector> &userModules, kmodule->checkModule(); // 4.) Manifest the module - kmodule->mainModuleFunctions.insert(mainModuleFunctions.begin(), - mainModuleFunctions.end()); - kmodule->mainModuleGlobals.insert(mainModuleGlobals.begin(), - mainModuleGlobals.end()); + std::swap(kmodule->mainModuleFunctions, mainModuleFunctions); + std::swap(kmodule->mainModuleGlobals, mainModuleGlobals); kmodule->manifest(interpreterHandler, interpreterOpts.Guidance, StatsTracker::useStatistics()); - if (origInfos) { - kmodule->origInfos = origInfos->getInstructions(); - } + kmodule->origInstructions = origInstructions; specialFunctionHandler->bind(); @@ -1574,8 +1570,11 @@ void Executor::printDebugInstructions(ExecutionState &state) { !DebugPrintInstructions.isSet(FILE_COMPACT)) { (*stream) << " " << state.pc->getSourceLocationString() << ':'; } - if (state.pc->info->assemblyLine.hasValue()) { - (*stream) << state.pc->info->assemblyLine.getValue() << ':'; + { + auto asmLine = state.pc->getKModule()->getAsmLine(state.pc->inst); + if (asmLine.has_value()) { + (*stream) << asmLine.value() << ':'; + } } (*stream) << state.getID() << ":"; (*stream) << "["; @@ -4670,7 +4669,7 @@ void Executor::terminateStateOnError(ExecutionState &state, std::string message = messaget.str(); static std::set> emittedErrors; const KInstruction *ki = getLastNonKleeInternalInstruction(state); - const InstructionInfo &ii = *ki->info; +// const InstructionInfo &ii = *ki->info; Instruction *lastInst = ki->inst; if (EmitAllErrors || @@ -4691,8 +4690,11 @@ void Executor::terminateStateOnError(ExecutionState &state, if (!filepath.empty()) { msg << "File: " << filepath << '\n' << "Line: " << ki->getLine() << '\n'; - if (ii.assemblyLine.hasValue()) { - msg << "assembly.ll line: " << ii.assemblyLine.getValue() << '\n'; + { + auto asmLine = ki->getKModule()->getAsmLine(ki->inst); + if (asmLine.has_value()) { + msg << "assembly.ll line: " << asmLine.value() << '\n'; + } } msg << "State: " << state.getID() << '\n'; } @@ -7263,7 +7265,7 @@ void Executor::dumpStates() { uint64_t md2u = computeMinDistToUncovered(es->pc, sf.minDistToUncoveredOnReturn); uint64_t icnt = theStatisticManager->getIndexedValue(stats::instructions, - es->pc->info->id); + es->pc->getGlobalIndex()); uint64_t cpicnt = sf.callPathNode->statistics.getValue(stats::instructions); diff --git a/lib/Core/Executor.h b/lib/Core/Executor.h index 1ffb47fd7d5..1a5f52403f7 100644 --- a/lib/Core/Executor.h +++ b/lib/Core/Executor.h @@ -726,9 +726,9 @@ class Executor : public Interpreter { setModule(std::vector> &userModules, std::vector> &libsModules, const ModuleOptions &opts, - const std::unordered_set &mainModuleFunctions, - const std::unordered_set &mainModuleGlobals, - std::unique_ptr origInfos) override; + std::set &mainModuleFunctions, + std::set &mainModuleGlobals, + FInstructions &&origInstructions) override; void useSeeds(const std::vector *seeds) override { usingSeeds = seeds; diff --git a/lib/Core/Searcher.cpp b/lib/Core/Searcher.cpp index 5522316555f..9200dcaf4b3 100644 --- a/lib/Core/Searcher.cpp +++ b/lib/Core/Searcher.cpp @@ -390,7 +390,7 @@ double WeightedRandomSearcher::getWeight(ExecutionState *es) { return std::pow(0.5, es->depth); case InstCount: { uint64_t count = theStatisticManager->getIndexedValue(stats::instructions, - es->pc->info->id); + es->pc->getGlobalIndex()); double inv = 1. / std::max((uint64_t)1, count); return inv * inv; } diff --git a/lib/Core/StatsTracker.cpp b/lib/Core/StatsTracker.cpp index 5de92e8428d..88edb4c6a07 100644 --- a/lib/Core/StatsTracker.cpp +++ b/lib/Core/StatsTracker.cpp @@ -233,27 +233,28 @@ StatsTracker::StatsTracker(Executor &_executor, std::string _objectFilename, } if (useStatistics() || userSearcherRequiresMD2U()) - theStatisticManager->useIndexedStats(km->infos->getMaxID()); + theStatisticManager->useIndexedStats(km->getMaxGlobalIndex()); for (auto &kfp : km->functions) { KFunction *kf = kfp.get(); -// kf->trackCoverage = 1; + // kf->trackCoverage = 1; for (unsigned i = 0; i < kf->numInstructions; ++i) { KInstruction *ki = kf->instructions[i]; if (OutputIStats) { - unsigned id = ki->info->id; + unsigned id = ki->getGlobalIndex(); theStatisticManager->setIndex(id); - if (instructionIsCoverable(ki->inst)) + if (instructionIsCoverable(ki->inst)) { ++stats::uncoveredInstructions; + } } -// if (kf->trackCoverage) { - if (BranchInst *bi = dyn_cast(ki->inst)) - if (!bi->isUnconditional()) - numBranches++; -// } + // if (kf->trackCoverage) { + if (BranchInst *bi = dyn_cast(ki->inst)) + if (!bi->isUnconditional()) + numBranches++; + // } } } @@ -394,9 +395,9 @@ void StatsTracker::stepInstruction(ExecutionState &es) { Instruction *inst = es.pc->inst; const KInstruction *ki = es.pc; - const InstructionInfo &ii = *es.pc->info; + // const InstructionInfo &ii = *es.pc->info; InfoStackFrame &sf = es.stack.infoStack().back(); - theStatisticManager->setIndex(ii.id); + theStatisticManager->setIndex(ki->getGlobalIndex()); if (UseCallPaths) theStatisticManager->setContext(&sf.callPathNode->statistics); @@ -405,7 +406,7 @@ void StatsTracker::stepInstruction(ExecutionState &es) { if (instructionIsCoverable(inst)) { if (!theStatisticManager->getIndexedValue(stats::coveredInstructions, - ii.id)) { + ki->getGlobalIndex())) { // Checking for actual stoppoints avoids inconsistencies due // to line number propogation. // @@ -699,8 +700,9 @@ void StatsTracker::updateStateStatistics(uint64_t addend) { ie = executor.states.end(); it != ie; ++it) { ExecutionState &state = **it; - const InstructionInfo &ii = *state.pc->info; - theStatisticManager->incrementIndexedValue(stats::states, ii.id, addend); + // const InstructionInfo &ii = *state.pc->info; + theStatisticManager->incrementIndexedValue( + stats::states, state.pc->getGlobalIndex(), addend); if (UseCallPaths) state.stack.infoStack().back().callPathNode->statistics.incrementValue( stats::states, addend); @@ -769,39 +771,42 @@ void StatsTracker::writeIStats() { of << "ob=" << llvm::sys::path::filename(objectFilename).str() << "\n"; - for (Module::iterator fnIt = m->begin(), fn_ie = m->end(); fnIt != fn_ie; - ++fnIt) { - if (!fnIt->isDeclaration()) { + for (auto &fnIt : *m) { + if (!fnIt.isDeclaration()) { // Always try to write the filename before the function name, as otherwise // KCachegrind can create two entries for the function, one with an // unnamed file and one without. - Function *fn = &*fnIt; - const FunctionInfo &ii = executor.kmodule->infos->getFunctionInfo(*fn); - if (ii.file != sourceFile) { - of << "fl=" << ii.file << "\n"; - sourceFile = ii.file; + Function *fn = &fnIt; + auto fnl = getLocationInfo(fn); + // const FunctionInfo &ii = + // executor.kmodule->infos->getFunctionInfo(*fn); + if (fnl.file != sourceFile) { + of << "fl=" << fnl.file << "\n"; + sourceFile = fnl.file; } - of << "fn=" << fnIt->getName().str() << "\n"; - for (Function::iterator bbIt = fnIt->begin(), bb_ie = fnIt->end(); + of << "fn=" << fnIt.getName().str() << "\n"; + for (Function::iterator bbIt = fnIt.begin(), bb_ie = fnIt.end(); bbIt != bb_ie; ++bbIt) { for (BasicBlock::iterator it = bbIt->begin(), ie = bbIt->end(); it != ie; ++it) { Instruction *instr = &*it; - const InstructionInfo &ii = executor.kmodule->infos->getInfo(*instr); +// const InstructionInfo &ii = executor.kmodule->infos->getInfo(*instr); // TODO unify with KInstrtuction - auto &f = executor.kmodule->infos->getFunctionInfo(*fnIt); - auto locationInfo = getLocationInfo(*instr, &f); + auto locationInfo = getLocationInfo(instr); - unsigned index = ii.id; + unsigned index = executor.kmodule->getGlobalIndex(instr); if (locationInfo.file != sourceFile) { of << "fl=" << locationInfo.file << "\n"; sourceFile = locationInfo.file; } - assert(ii.assemblyLine.hasValue()); - of << ii.assemblyLine.getValue() << " "; + { // TODO remove copypaste + auto asmLine = executor.kmodule->getAsmLine(instr); + assert(asmLine.has_value()); + of << asmLine.value() << " "; + } of << locationInfo.line << " "; for (unsigned i = 0; i < nStats; i++) @@ -813,25 +818,30 @@ void StatsTracker::writeIStats() { (isa(instr) || isa(instr))) { CallSiteSummaryTable::iterator it = callSiteStats.find(instr); if (it != callSiteStats.end()) { - for (auto fit = it->second.begin(), fie = it->second.end(); - fit != fie; ++fit) { - const Function *f = fit->first; - CallSiteInfo &csi = fit->second; - const FunctionInfo &fii = - executor.kmodule->infos->getFunctionInfo(*f); - - if (fii.file != "" && fii.file != sourceFile) - of << "cfl=" << fii.file << "\n"; + for (auto &fit : it->second) { + const Function *f = fit.first; + CallSiteInfo &csi = fit.second; + // const FunctionInfo &fii = + // executor.kmodule->infos->getFunctionInfo(*f); + auto fli = getLocationInfo(f); + if (fli.file != "" && fli.file != sourceFile) + of << "cfl=" << fli.file << "\n"; of << "cfn=" << f->getName().str() << "\n"; of << "calls=" << csi.count << " "; - assert(fii.assemblyLine.hasValue()); - of << fii.assemblyLine.getValue() << " "; + { + auto asmLine = executor.kmodule->getAsmLine(f); + assert(asmLine.has_value()); + of << asmLine.value() << " "; + } - of << fii.line << "\n"; + of << fli.line << "\n"; - assert(ii.assemblyLine.hasValue()); - of << ii.assemblyLine.getValue() << " "; + { + auto asmLine = executor.kmodule->getAsmLine(instr); + assert(asmLine.has_value()); + of << asmLine.value() << " "; + } of << locationInfo.line << " "; for (unsigned i = 0; i < nStats; i++) { @@ -898,14 +908,14 @@ uint64_t klee::computeMinDistToUncovered(const KInstruction *ki, uint64_t minDistAtRA) { StatisticManager &sm = *theStatisticManager; if (minDistAtRA == 0) { // unreachable on return, best is local - return sm.getIndexedValue(stats::minDistToUncovered, ki->info->id); + return sm.getIndexedValue(stats::minDistToUncovered, ki->getGlobalIndex()); } else { uint64_t minDistLocal = - sm.getIndexedValue(stats::minDistToUncovered, ki->info->id); + sm.getIndexedValue(stats::minDistToUncovered, ki->getGlobalIndex()); uint64_t distToReturn = - sm.getIndexedValue(stats::minDistToReturn, ki->info->id); + sm.getIndexedValue(stats::minDistToReturn, ki->getGlobalIndex()); - if (distToReturn == 0) { // return unreachable, best is local + if (distToReturn == 0) { // return unreachable, best is local return minDistLocal; } else if (!minDistLocal) { // no local reachable return distToReturn + minDistAtRA; @@ -919,7 +929,7 @@ void StatsTracker::computeReachableUncovered() { KModule *km = executor.kmodule.get(); const auto m = km->module.get(); static bool init = true; - const InstructionInfoTable &infos = *km->infos; + // const InstructionInfoTable &infos = *km->infos; StatisticManager &sm = *theStatisticManager; if (init) { @@ -982,11 +992,10 @@ void StatsTracker::computeReachableUncovered() { // Not sure if I should bother to preorder here. XXX I should. for (Function::iterator bbIt = fnIt->begin(), bb_ie = fnIt->end(); bbIt != bb_ie; ++bbIt) { - for (BasicBlock::iterator it = bbIt->begin(), ie = bbIt->end(); - it != ie; ++it) { - Instruction *inst = &*it; + for (auto &it : *bbIt) { + Instruction *inst = ⁢ instructions.push_back(inst); - unsigned id = infos.getInfo(*inst).id; + unsigned id = km->getGlobalIndex(inst); sm.setIndexedValue(stats::minDistToReturn, id, isa(inst)); } } @@ -998,7 +1007,7 @@ void StatsTracker::computeReachableUncovered() { bool changed; do { changed = false; - for (auto & instruction : instructions) { + for (auto &instruction : instructions) { Instruction *inst = instruction; unsigned bestThrough = 0; @@ -1019,7 +1028,7 @@ void StatsTracker::computeReachableUncovered() { } if (bestThrough) { - unsigned id = infos.getInfo(*instruction).id; + unsigned id = km->getGlobalIndex(instruction); uint64_t best, cur = best = sm.getIndexedValue(stats::minDistToReturn, id); std::vector succs = getSuccs(instruction); @@ -1027,7 +1036,7 @@ void StatsTracker::computeReachableUncovered() { ie = succs.end(); it2 != ie; ++it2) { uint64_t dist = sm.getIndexedValue(stats::minDistToReturn, - infos.getInfo(*(*it2)).id); + km->getGlobalIndex(*it2)); if (dist) { uint64_t val = bestThrough + dist; if (best == 0 || val < best) @@ -1063,7 +1072,7 @@ void StatsTracker::computeReachableUncovered() { for (BasicBlock::iterator it = bbIt->begin(), ie = bbIt->end(); it != ie; ++it) { Instruction *inst = &*it; - unsigned id = infos.getInfo(*inst).id; + unsigned id = km->getGlobalIndex(inst); instructions.push_back(inst); sm.setIndexedValue( stats::minDistToUncovered, id, @@ -1080,24 +1089,22 @@ void StatsTracker::computeReachableUncovered() { changed = false; for (auto inst : instructions) { uint64_t best, cur = best = sm.getIndexedValue(stats::minDistToUncovered, - infos.getInfo(*inst).id); + km->getGlobalIndex(inst)); unsigned bestThrough = 0; if (isa(inst) || isa(inst)) { std::vector &targets = callTargets[inst]; - for (std::vector::iterator fnIt = targets.begin(), - ie = targets.end(); - fnIt != ie; ++fnIt) { - uint64_t dist = functionShortestPath[*fnIt]; + for (auto &target : targets) { + uint64_t dist = functionShortestPath[target]; if (dist) { dist = 1 + dist; // count instruction itself if (bestThrough == 0 || dist < bestThrough) bestThrough = dist; } - if (!(*fnIt)->isDeclaration()) { + if (!target->isDeclaration()) { uint64_t calleeDist = sm.getIndexedValue( - stats::minDistToUncovered, infos.getFunctionInfo(*(*fnIt)).id); + stats::minDistToUncovered, km->getGlobalIndex(target)); if (calleeDist) { calleeDist = 1 + calleeDist; // count instruction itself if (best == 0 || calleeDist < best) @@ -1111,11 +1118,9 @@ void StatsTracker::computeReachableUncovered() { if (bestThrough) { std::vector succs = getSuccs(inst); - for (std::vector::iterator it2 = succs.begin(), - ie = succs.end(); - it2 != ie; ++it2) { + for (auto &succ : succs) { uint64_t dist = sm.getIndexedValue(stats::minDistToUncovered, - infos.getInfo(*(*it2)).id); + km->getGlobalIndex(succ)); if (dist) { uint64_t val = bestThrough + dist; if (best == 0 || val < best) @@ -1125,7 +1130,7 @@ void StatsTracker::computeReachableUncovered() { } if (best != cur) { - sm.setIndexedValue(stats::minDistToUncovered, infos.getInfo(*inst).id, + sm.setIndexedValue(stats::minDistToUncovered, km->getGlobalIndex(inst), best); changed = true; } diff --git a/lib/Core/TargetedExecutionManager.cpp b/lib/Core/TargetedExecutionManager.cpp index a375bf35dcf..b2ac4eb5248 100644 --- a/lib/Core/TargetedExecutionManager.cpp +++ b/lib/Core/TargetedExecutionManager.cpp @@ -318,24 +318,32 @@ TargetedExecutionManager::LocationToBlocks TargetedExecutionManager::prepareAllLocations(KModule *kmodule, Locations &locations) const { LocationToBlocks locToBlocks; - const auto &infos = kmodule->infos; +// const auto &infos = kmodule->infos; + + std::unordered_map> + fileNameToFunctions; + + for (const auto &kfunc : kmodule->functions) { + fileNameToFunctions[kfunc->getSourceFilepath()].insert(kfunc->function); + } + for (auto it = locations.begin(); it != locations.end(); ++it) { auto loc = *it; - for (const auto &fileName : infos->getFilesNames()) { - if (kmodule->origInfos.count(fileName) == 0) { + for (const auto &[fileName, origInstsInFile] : kmodule->origInstructions) { + if (kmodule->origInstructions.count(fileName) == 0) { continue; } if (!loc->isInside(fileName)) { continue; } - const auto &relatedFunctions = - infos->getFileNameToFunctions().at(fileName); + const auto &relatedFunctions = fileNameToFunctions.at(fileName); for (const auto func : relatedFunctions) { const auto kfunc = kmodule->functionMap[func]; - const auto &fi = infos->getFunctionInfo(*kfunc->function); - const auto &origInstsInFile = kmodule->origInfos.at(fi.file); + // const auto &fi = infos->getFunctionInfo(*kfunc->function); + // const auto &origInstsInFile = + // kmodule->origInstructions.at(kfunc->getSourceFilepath()); for (const auto &kblock : kfunc->blocks) { auto b = kblock.get(); diff --git a/lib/Core/TargetedExecutionManager.h b/lib/Core/TargetedExecutionManager.h index 7d5b285d41f..011cbf86b67 100644 --- a/lib/Core/TargetedExecutionManager.h +++ b/lib/Core/TargetedExecutionManager.h @@ -96,12 +96,6 @@ class TargetedExecutionManager { using StatesSet = std::unordered_set; using TargetToStateUnorderedSetMap = TargetHashMap; - using Instructions = std::unordered_map< - std::string, - std::unordered_map< - unsigned int, - std::unordered_map>>>; - std::unordered_set brokenTraces; std::unordered_set reportedTraces; diff --git a/lib/Module/InstructionInfoTable.cpp b/lib/Module/InstructionInfoTable.cpp index fc33be39c86..3c2b613e874 100644 --- a/lib/Module/InstructionInfoTable.cpp +++ b/lib/Module/InstructionInfoTable.cpp @@ -35,135 +35,42 @@ DISABLE_WARNING_POP #include namespace klee { -class InstructionToLineAnnotator : public llvm::AssemblyAnnotationWriter { -private: - std::unordered_map mapping = {}; - -public: - void emitInstructionAnnot(const llvm::Instruction *i, - llvm::formatted_raw_ostream &os) override { - os.flush(); - mapping.emplace(reinterpret_cast(i), os.getLine() + 1); - } - - void emitFunctionAnnot(const llvm::Function *f, - llvm::formatted_raw_ostream &os) override { - os.flush(); - mapping.emplace(reinterpret_cast(f), os.getLine() + 1); - } - - std::unordered_map getMapping() const { return mapping; } -}; - -static std::unordered_map -buildInstructionToLineMap(const llvm::Module &m, - std::unique_ptr assemblyFS) { - - InstructionToLineAnnotator a; - - m.print(*assemblyFS, &a); - assemblyFS->flush(); - - return a.getMapping(); -} class DebugInfoExtractor { - std::vector> &internedStrings; - std::unordered_map lineTable; const llvm::Module &module; - bool withAsm = false; public: - DebugInfoExtractor( - std::vector> &_internedStrings, - const llvm::Module &_module, - std::unique_ptr assemblyFS) - : internedStrings(_internedStrings), module(_module) { - if (assemblyFS) { - withAsm = true; - lineTable = buildInstructionToLineMap(module, std::move(assemblyFS)); - } - } - - std::string &getInternedString(const std::string &s) { - auto found = std::find_if(internedStrings.begin(), internedStrings.end(), - [&s](const std::unique_ptr &item) { - return *item.get() == s; - }); - if (found != internedStrings.end()) - return *found->get(); - - auto newItem = std::unique_ptr(new std::string(s)); - auto result = newItem.get(); - - internedStrings.emplace_back(std::move(newItem)); - return *result; - } - - std::unique_ptr getFunctionInfo(const llvm::Function &Func) { - llvm::Optional asmLine; - if (withAsm) { - asmLine = lineTable.at(reinterpret_cast(&Func)); - } - auto dsub = Func.getSubprogram(); + DebugInfoExtractor(const llvm::Module &_module) + : module(_module) {} + +// std::unique_ptr getFunctionInfo(const llvm::Function &Func) { +// // Fallback: Mark as unknown +// return std::make_unique(FunctionInfo(0)); +// } + +// std::unique_ptr +// getInstructionInfo(const llvm::Instruction &Inst, const FunctionInfo *f) { +// return std::make_unique(InstructionInfo(0)); +// } +}; - if (dsub != nullptr) { - auto path = dsub->getFilename(); - return std::make_unique(FunctionInfo( - 0, getInternedString(path.str()), dsub->getLine(), asmLine)); - } +// TODO need some unify with kFunction +LocationInfo getLocationInfo(const llvm::Function *func) { + const auto dsub = func->getSubprogram(); - // Fallback: Mark as unknown - return std::make_unique( - FunctionInfo(0, getInternedString(""), 0, asmLine)); + if (dsub != nullptr) { + auto path = dsub->getFilename(); + return {path.str(), dsub->getLine(), 0}; // TODO why not use column here? } - std::unique_ptr - getInstructionInfo(const llvm::Instruction &Inst, const FunctionInfo *f) { - llvm::Optional asmLine; - if (withAsm) { - asmLine = lineTable.at(reinterpret_cast(&Inst)); - } - - // Retrieve debug information associated with instruction - auto dl = Inst.getDebugLoc(); - - // Check if a valid debug location is assigned to the instruction. - if (dl.get() != nullptr) { - auto full_path = dl->getFilename(); - auto line = dl.getLine(); - auto column = dl.getCol(); - - // Still, if the line is unknown, take the context of the instruction to - // narrow it down - if (line == 0) { - if (auto LexicalBlock = - llvm::dyn_cast(dl.getScope())) { - line = LexicalBlock->getLine(); - column = LexicalBlock->getColumn(); - } - } - return std::make_unique(InstructionInfo( - 0, asmLine)); - } - - if (f != nullptr) { - // If nothing found, use the surrounding function - return std::make_unique( - InstructionInfo(0, asmLine)); - } - // If nothing found, use the surrounding function - return std::make_unique( - InstructionInfo(0, asmLine)); - } -}; + return {"", 0, 0}; +} // TODO need some unify with kInstruction -LocationInfo getLocationInfo(const llvm::Instruction &Inst, - const FunctionInfo *f) { +LocationInfo getLocationInfo(const llvm::Instruction *inst) { // Retrieve debug information associated with instruction - auto dl = Inst.getDebugLoc(); + const auto &dl = inst->getDebugLoc(); // Check if a valid debug location is assigned to the instruction. if (dl.get() != nullptr) { @@ -183,83 +90,70 @@ LocationInfo getLocationInfo(const llvm::Instruction &Inst, return {full_path.str(), line, column}; } - if (f != nullptr) { - // If nothing found, use the surrounding function - return {f->file, f->line, 0}; - } - // If nothing found, use the surrounding function - return {"", 0, 0}; -} - -InstructionInfoTable::InstructionInfoTable( - const llvm::Module &m, std::unique_ptr assemblyFS, - bool withInstructions) { - // Generate all debug instruction information - DebugInfoExtractor DI(internedStrings, m, std::move(assemblyFS)); - - for (const auto &Func : m) { - auto F = DI.getFunctionInfo(Func); - auto FR = F.get(); - functionInfos.emplace(&Func, std::move(F)); - - for (auto it = llvm::inst_begin(Func), ie = llvm::inst_end(Func); it != ie; - ++it) { - auto instr = &*it; - auto instInfo = DI.getInstructionInfo(*instr, FR); - auto locationInfo = getLocationInfo(*instr, FR); - if (withInstructions) { - insts[locationInfo.file][locationInfo.line][locationInfo.column].insert( - instr->getOpcode()); - } - filesNames.insert(locationInfo.file); - fileNameToFunctions[locationInfo.file].insert(&Func); - infos.emplace(instr, std::move(instInfo)); - } - } - - // Make sure that every item has a unique ID - size_t idCounter = 0; - for (auto &item : infos) - item.second->id = idCounter++; - for (auto &item : functionInfos) - item.second->id = idCounter++; -} - -unsigned InstructionInfoTable::getMaxID() const { - return infos.size() + functionInfos.size(); + return getLocationInfo(inst->getParent()->getParent()); } -const InstructionInfo & -InstructionInfoTable::getInfo(const llvm::Instruction &inst) const { - auto it = infos.find(&inst); - if (it == infos.end()) - llvm::report_fatal_error("invalid instruction, not present in " - "initial module!"); - return *it->second.get(); -} - -const FunctionInfo & -InstructionInfoTable::getFunctionInfo(const llvm::Function &f) const { - auto found = functionInfos.find(&f); - if (found == functionInfos.end()) - llvm::report_fatal_error("invalid instruction, not present in " - "initial module!"); - - return *found->second.get(); -} - -const InstructionInfoTable::LocationToFunctionsMap & -InstructionInfoTable::getFileNameToFunctions() const { - return fileNameToFunctions; -} - -const std::unordered_set & -InstructionInfoTable::getFilesNames() const { - return filesNames; -} - -InstructionInfoTable::Instructions InstructionInfoTable::getInstructions() { - return std::move(insts); -} +//InstructionInfoTable::InstructionInfoTable(const llvm::Module &m) { +// // Generate all debug instruction information +// DebugInfoExtractor DI(m); +// +// for (const auto &Func : m) { +// auto F = DI.getFunctionInfo(Func); +// auto FR = F.get(); +// functionInfos.emplace(&Func, std::move(F)); +// +// for (auto it = llvm::inst_begin(Func), ie = llvm::inst_end(Func); it != ie; +// ++it) { +// auto instr = &*it; +// auto instInfo = DI.getInstructionInfo(*instr, FR); +// auto locationInfo = getLocationInfo(instr); +//// if (withInstructions) { +//// insts[locationInfo.file][locationInfo.line][locationInfo.column].insert( +//// instr->getOpcode()); +//// } +// fileNameToFunctions[locationInfo.file].insert(&Func); +// infos.emplace(instr, std::move(instInfo)); +// } +// } +// +// // Make sure that every item has a unique ID +// size_t idCounter = 0; +//// for (auto &item : infos) +//// item.second->id = idCounter++; +//// for (auto &item : functionInfos) +//// item.second->id = idCounter++; +//} + +//unsigned InstructionInfoTable::getMaxID() const { +// return infos.size() + functionInfos.size(); +//} + +//const InstructionInfo & +//InstructionInfoTable::getInfo(const llvm::Instruction &inst) const { +// auto it = infos.find(&inst); +// if (it == infos.end()) +// llvm::report_fatal_error("invalid instruction, not present in " +// "initial module!"); +// return *it->second.get(); +//} +// +//const FunctionInfo & +//InstructionInfoTable::getFunctionInfo(const llvm::Function &f) const { +// auto found = functionInfos.find(&f); +// if (found == functionInfos.end()) +// llvm::report_fatal_error("invalid instruction, not present in " +// "initial module!"); +// +// return *found->second.get(); +//} +// +//const InstructionInfoTable::LocationToFunctionsMap & +//InstructionInfoTable::getFileNameToFunctions() const { +// return fileNameToFunctions; +//} + +//InstructionInfoTable::Instructions InstructionInfoTable::getInstructions() { +// return std::move(insts); +//} } // namespace klee diff --git a/lib/Module/KInstruction.cpp b/lib/Module/KInstruction.cpp index 6c7a7d9d3f5..7ac212d218f 100644 --- a/lib/Module/KInstruction.cpp +++ b/lib/Module/KInstruction.cpp @@ -18,6 +18,8 @@ DISABLE_WARNING_DEPRECATED_DECLARATIONS #include "llvm/IR/DebugInfoMetadata.h" DISABLE_WARNING_POP +#include +#include #include using namespace llvm; @@ -25,29 +27,71 @@ using namespace klee; /***/ +static int getOperandNum( + Value *v, + const std::unordered_map &instructionToRegisterMap, + KModule *km, KInstruction *ki) { + if (Instruction *inst = dyn_cast(v)) { + return instructionToRegisterMap.at(inst); + } else if (Argument *a = dyn_cast(v)) { + return a->getArgNo(); + } else if (isa(v) || isa(v) || + isa(v)) { + return -1; + } else { + assert(isa(v)); + Constant *c = cast(v); + return -(km->getConstantID(c, ki) + 2); + } +} + +KInstruction::KInstruction( + const std::unordered_map + &_instructionToRegisterMap, + llvm::Instruction *_inst, KModule *_km, KBlock *_kb, + unsigned &_globalIndexInc) + : inst(_inst), parent(_kb), globalIndex(_globalIndexInc++) { + // ki->parent = this; + // ki->index = i; + // ki->dest = instructionToRegisterMap[inst]; + if (isa(inst) || isa(inst)) { + const llvm::CallBase &cs = cast(*inst); + Value *val = cs.getCalledOperand(); + unsigned numArgs = cs.arg_size(); + operands = new int[numArgs + 1]; + operands[0] = getOperandNum(val, _instructionToRegisterMap, _km, this); + for (unsigned j = 0; j < numArgs; j++) { + Value *v = cs.getArgOperand(j); + operands[j + 1] = getOperandNum(v, _instructionToRegisterMap, _km, this); + } + } else { + unsigned numOperands = inst->getNumOperands(); + operands = new int[numOperands]; + for (unsigned j = 0; j < numOperands; j++) { + Value *v = inst->getOperand(j); + operands[j] = getOperandNum(v, _instructionToRegisterMap, _km, this); + } + } +} + KInstruction::~KInstruction() { delete[] operands; } size_t KInstruction::getLine() const { - auto &f = - parent->parent->parent->infos->getFunctionInfo(*parent->parent->function); - auto locationInfo = getLocationInfo(*inst, &f); + auto locationInfo = getLocationInfo(inst); return locationInfo.line; } size_t KInstruction::getColumn() const { - auto &f = - parent->parent->parent->infos->getFunctionInfo(*parent->parent->function); - auto locationInfo = getLocationInfo(*inst, &f); + auto locationInfo = getLocationInfo(inst); return locationInfo.column; } // TODO problem files with same name std::string KInstruction::getSourceFilepath() const { - auto &f = - parent->parent->parent->infos->getFunctionInfo(*parent->parent->function); - auto locationInfo = getLocationInfo(*inst, &f); + auto locationInfo = getLocationInfo(inst); return locationInfo.file; } + std::string KInstruction::getSourceLocationString() const { std::string filePath = getSourceFilepath(); if (!filePath.empty()) { @@ -64,9 +108,14 @@ std::string KInstruction::toString() const { inst->getOpcodeName() + ")"; } -unsigned KInstruction::getIndex() const { return index; } +unsigned KInstruction::getGlobalIndex() const { return globalIndex; } + +unsigned KInstruction::getIndex() const { + return getGlobalIndex() - getKFunction()->getGlobalIndex() - + getKBlock()->getId() - 1; +} unsigned KInstruction::getDest() const { - return parent->parent->getNumArgs() + index + + return parent->parent->getNumArgs() + getIndex() + (parent->instructions - parent->parent->instructions); } diff --git a/lib/Module/KModule.cpp b/lib/Module/KModule.cpp index 049648f5dd8..f73a9804ae8 100644 --- a/lib/Module/KModule.cpp +++ b/lib/Module/KModule.cpp @@ -26,6 +26,7 @@ DISABLE_WARNING_PUSH DISABLE_WARNING_DEPRECATED_DECLARATIONS #include "llvm/Bitcode/BitcodeWriter.h" +#include "llvm/IR/AssemblyAnnotationWriter.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" @@ -37,6 +38,7 @@ DISABLE_WARNING_DEPRECATED_DECLARATIONS #include "llvm/IR/Verifier.h" #include "llvm/Linker/Linker.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/FormattedStream.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_os_ostream.h" #include "llvm/Support/raw_ostream.h" @@ -46,7 +48,10 @@ DISABLE_WARNING_DEPRECATED_DECLARATIONS #include "llvm/Transforms/Utils/Cloning.h" DISABLE_WARNING_POP +#include +#include #include +#include using namespace llvm; using namespace klee; @@ -337,6 +342,38 @@ void KModule::optimiseAndPrepare( pm3.run(*module); } +class InstructionToLineAnnotator : public llvm::AssemblyAnnotationWriter { +private: + std::unordered_map mapping = {}; + +public: + void emitInstructionAnnot(const llvm::Instruction *i, + llvm::formatted_raw_ostream &os) override { + os.flush(); + mapping.emplace(reinterpret_cast(i), os.getLine() + 1); + } + + void emitFunctionAnnot(const llvm::Function *f, + llvm::formatted_raw_ostream &os) override { + os.flush(); + mapping.emplace(reinterpret_cast(f), os.getLine() + 1); + } + + std::unordered_map getMapping() const { return mapping; } +}; + +static std::unordered_map +buildInstructionToLineMap(const llvm::Module &m, + std::unique_ptr assemblyFS) { + + InstructionToLineAnnotator a; + + m.print(*assemblyFS, &a); + assemblyFS->flush(); + + return a.getMapping(); +} + void KModule::manifest(InterpreterHandler *ih, Interpreter::GuidanceKind guidance, bool forceSourceOutput) { @@ -352,19 +389,20 @@ void KModule::manifest(InterpreterHandler *ih, if (OutputSource || forceSourceOutput) { assemblyFS = ih->openOutputFile("assembly.ll"); } - infos = - std::make_unique(*module, std::move(assemblyFS)); + asmLineMap = buildInstructionToLineMap(*module, std::move(assemblyFS)); +// infos = std::make_unique(*module); } std::vector declarations; unsigned functionID = 0; + maxGlobalIndex = 0; for (auto &Function : module->functions()) { if (Function.isDeclaration()) { declarations.push_back(&Function); } - auto kf = std::unique_ptr(new KFunction(&Function, this)); + auto kf = std::make_unique(&Function, this, maxGlobalIndex); llvm::Function *function = &Function; for (auto &BasicBlock : *function) { @@ -372,11 +410,11 @@ void KModule::manifest(InterpreterHandler *ih, KBlock *kb = kf->blockMap[&BasicBlock]; for (unsigned i = 0; i < numInstructions; ++i) { KInstruction *ki = kb->instructions[i]; - ki->info = &infos->getInfo(*ki->inst); +// ki->info = &infos->getInfo(*ki->inst); } } -// functionIDMap[&Function] = functionID; + // functionIDMap[&Function] = functionID; kf->id = functionID; functionID++; functionNameMap.insert({kf->getName().str(), kf.get()}); @@ -426,6 +464,19 @@ void KModule::manifest(InterpreterHandler *ih, } } +std::optional KModule::getAsmLine(const uintptr_t ref) const { + if (!asmLineMap.empty()) { + return asmLineMap.at(ref); + } + return std::nullopt; +} +std::optional KModule::getAsmLine(const llvm::Function *func) const { + return getAsmLine(reinterpret_cast(func)); +} +std::optional KModule::getAsmLine(const llvm::Instruction *inst) const { + return getAsmLine(reinterpret_cast(inst)); +} + void KModule::checkModule() { InstructionOperandTypeCheckPass *operandTypeCheckPass = new InstructionOperandTypeCheckPass(); @@ -505,6 +556,14 @@ unsigned KModule::getConstantID(Constant *c, KInstruction *ki) { unsigned KModule::getFunctionId(const llvm::Function *func) const { return functionMap.at(func)->id; } +unsigned KModule::getGlobalIndex(const llvm::Function *func) const { + return functionMap.at(func)->getGlobalIndex(); +} +unsigned KModule::getGlobalIndex(const llvm::Instruction *inst) const { + return functionMap.at(inst->getFunction()) + ->instructionMap.at(inst) + ->getGlobalIndex(); +} /***/ @@ -514,55 +573,10 @@ KConstant::KConstant(llvm::Constant *_ct, unsigned _id, KInstruction *_ki) { ki = _ki; } -/***/ - -static int getOperandNum( - Value *v, - const std::unordered_map &instructionToRegisterMap, - KModule *km, KInstruction *ki) { - if (Instruction *inst = dyn_cast(v)) { - return instructionToRegisterMap.at(inst); - } else if (Argument *a = dyn_cast(v)) { - return a->getArgNo(); - } else if (isa(v) || isa(v) || - isa(v)) { - return -1; - } else { - assert(isa(v)); - Constant *c = cast(v); - return -(km->getConstantID(c, ki) + 2); - } -} - -void KBlock::handleKInstruction( - const std::unordered_map &instructionToRegisterMap, - llvm::Instruction *inst, KModule *km, KInstruction *ki) { - ki->parent = this; - ki->inst = inst; - // ki->dest = instructionToRegisterMap[inst]; // TODO - if (isa(inst) || isa(inst)) { - const CallBase &cs = cast(*inst); - Value *val = cs.getCalledOperand(); - unsigned numArgs = cs.arg_size(); - ki->operands = new int[numArgs + 1]; - ki->operands[0] = getOperandNum(val, instructionToRegisterMap, km, ki); - for (unsigned j = 0; j < numArgs; j++) { - Value *v = cs.getArgOperand(j); - ki->operands[j + 1] = getOperandNum(v, instructionToRegisterMap, km, ki); - } - } else { - unsigned numOperands = inst->getNumOperands(); - ki->operands = new int[numOperands]; - for (unsigned j = 0; j < numOperands; j++) { - Value *v = inst->getOperand(j); - ki->operands[j] = getOperandNum(v, instructionToRegisterMap, km, ki); - } - } -} - -KFunction::KFunction(llvm::Function *_function, KModule *_km) - : KCallable(CK_Function), parent(_km), function(_function), - numInstructions(0), entryKBlock(nullptr) { +KFunction::KFunction(llvm::Function *_function, KModule *_km, + unsigned &globalIndexInc) + : KCallable(CK_Function), globalIndex(globalIndexInc++), parent(_km), + function(_function), entryKBlock(nullptr), numInstructions(0) { for (auto &BasicBlock : *function) { numInstructions += BasicBlock.size(); // numBlocks++; @@ -595,18 +609,18 @@ KFunction::KFunction(llvm::Function *_function, KModule *_km) if (f) { calledFunctions.insert(f); } - KCallBlock *ckb = + auto *ckb = new KCallBlock(this, &*bbit, parent, instructionToRegisterMap, - calledFunctions, &instructions[n]); + calledFunctions, &instructions[n], globalIndexInc); kCallBlocks.push_back(ckb); kb = ckb; } else if (SplitReturns && isa(lit)) { kb = new KReturnBlock(this, &*bbit, parent, instructionToRegisterMap, - &instructions[n]); + &instructions[n], globalIndexInc); returnKBlocks.push_back(kb); } else { kb = new KBlock(this, &*bbit, parent, instructionToRegisterMap, - &instructions[n]); + &instructions[n], globalIndexInc); } for (unsigned i = 0; i < kb->numInstructions; i++, n++) { instructionMap[instructions[n]->inst] = instructions[n]; @@ -622,6 +636,17 @@ KFunction::KFunction(llvm::Function *_function, KModule *_km) } } +size_t KFunction::getLine() const { + auto locationInfo = getLocationInfo(function); + return locationInfo.line; +} + +// TODO problem files with same name +std::string KFunction::getSourceFilepath() const { + auto locationInfo = getLocationInfo(function); + return locationInfo.file; +} + KFunction::~KFunction() { for (unsigned i = 0; i < numInstructions; ++i) delete instructions[i]; @@ -632,12 +657,12 @@ KBlock::KBlock( KFunction *_kfunction, llvm::BasicBlock *block, KModule *km, const std::unordered_map &instructionToRegisterMap, // TODO remove instructionToRegisterMap - KInstruction **instructionsKF) + KInstruction **instructionsKF, unsigned &globalIndexInc) : parent(_kfunction), basicBlock(block), numInstructions(0) { numInstructions += block->size(); instructions = instructionsKF; - size_t i = 0; +// size_t i = 0; for (auto &it : *block) { KInstruction *ki; @@ -645,17 +670,15 @@ KBlock::KBlock( case Instruction::GetElementPtr: case Instruction::InsertValue: case Instruction::ExtractValue: - ki = new KGEPInstruction(); + ki = new KGEPInstruction(instructionToRegisterMap, &it, km, this, + globalIndexInc); break; default: - ki = new KInstruction(); + ki = new KInstruction(instructionToRegisterMap, &it, km, this, + globalIndexInc); break; } - - Instruction *inst = ⁢ - ki->index = i; // TODO - handleKInstruction(instructionToRegisterMap, inst, km, ki); - instructions[i++] = ki; + instructions[ki->getIndex()] = ki; // registerToInstructionMap[ki->getDest()] = ki; } } @@ -663,11 +686,12 @@ KBlock::KBlock( KCallBlock::KCallBlock( KFunction *_kfunction, llvm::BasicBlock *block, KModule *km, const std::unordered_map &instructionToRegisterMap, - std::set _calledFunctions, KInstruction **instructionsKF) + std::set _calledFunctions, KInstruction **instructionsKF, + unsigned &globalIndexInc) : KBlock::KBlock(_kfunction, block, km, instructionToRegisterMap, - instructionsKF), + instructionsKF, globalIndexInc), kcallInstruction(this->instructions[0]), - calledFunctions(_calledFunctions) {} + calledFunctions(std::move(_calledFunctions)) {} bool KCallBlock::intrinsic() const { if (calledFunctions.size() != 1) { @@ -695,9 +719,9 @@ KFunction *KCallBlock::getKFunction() const { KReturnBlock::KReturnBlock( KFunction *_kfunction, llvm::BasicBlock *block, KModule *km, const std::unordered_map &instructionToRegisterMap, - KInstruction **instructionsKF) + KInstruction **instructionsKF, unsigned &globalIndexInc) : KBlock::KBlock(_kfunction, block, km, instructionToRegisterMap, - instructionsKF) {} + instructionsKF, globalIndexInc) {} std::string KBlock::getLabel() const { std::string _label; diff --git a/tools/klee/main.cpp b/tools/klee/main.cpp index 04bdaadcfea..bb419992166 100644 --- a/tools/klee/main.cpp +++ b/tools/klee/main.cpp @@ -64,6 +64,7 @@ DISABLE_WARNING_POP #include #include #include +#include #include using json = nlohmann::json; @@ -1189,7 +1190,7 @@ createLibCWrapper(std::vector> &userModules, args.push_back(llvm::ConstantExpr::getBitCast( cast(inModuleReference.getCallee()), ft->getParamType(0))); - args.push_back(&*(stub->arg_begin())); // argc + args.push_back(&*(stub->arg_begin())); // argc auto arg_it = stub->arg_begin(); args.push_back(&*(++arg_it)); // argv args.push_back(Constant::getNullValue(ft->getParamType(3))); // app_init @@ -1543,13 +1544,19 @@ int main(int argc, char **argv, char **envp) { } llvm::Module *mainModule = loadedUserModules.front().get(); - std::unique_ptr origInfos; - std::unique_ptr assemblyFS; + KModule::FInstructions origInstructions; if (UseGuidedSearch == Interpreter::GuidanceKind::ErrorGuidance) { + for (const auto &Func : *mainModule) { + for (const auto &instr : llvm::instructions(Func)) { + auto locationInfo = getLocationInfo(&instr); + origInstructions[locationInfo.file][locationInfo.line] + [locationInfo.column] + .insert(instr.getOpcode()); + } + } + std::vector args; - origInfos = std::make_unique( - *mainModule, std::move(assemblyFS), true); args.push_back(llvm::Type::getInt32Ty(ctx)); // argc args.push_back(llvm::PointerType::get( Type::getInt8PtrTy(ctx), @@ -1568,15 +1575,16 @@ int main(int argc, char **argv, char **envp) { EntryPoint = stubEntryPoint; } - std::unordered_set mainModuleFunctions; + std::set mainModuleFunctions; for (auto &Function : *mainModule) { if (!Function.isDeclaration()) { - mainModuleFunctions.insert(Function.getName().str()); + mainModuleFunctions.insert(Function.getName()); } } - std::unordered_set mainModuleGlobals; - for (const auto &gv : mainModule->globals()) - mainModuleGlobals.insert(gv.getName().str()); + std::set mainModuleGlobals; + for (const auto &gv : mainModule->globals()) { + mainModuleGlobals.insert(gv.getName()); + } const std::string &module_triple = mainModule->getTargetTriple(); std::string host_triple = llvm::sys::getDefaultTargetTriple(); @@ -1811,7 +1819,7 @@ int main(int argc, char **argv, char **envp) { auto finalModule = interpreter->setModule( loadedUserModules, loadedLibsModules, Opts, mainModuleFunctions, - mainModuleGlobals, std::move(origInfos)); + mainModuleGlobals, std::move(origInstructions)); externalsAndGlobalsCheck(finalModule); if (InteractiveMode) {