From eea2f58ce057b63e8420d2e1e332c97330d2f0e0 Mon Sep 17 00:00:00 2001 From: Vladislav Kalugin Date: Wed, 5 Apr 2023 17:41:50 +0300 Subject: [PATCH] Remove double print assembly.ll --- include/klee/Module/InstructionInfoTable.h | 13 ++-- lib/Core/ExecutionState.cpp | 9 ++- lib/Core/Executor.cpp | 16 ++-- lib/Core/StatsTracker.cpp | 14 +++- lib/Module/CMakeLists.txt | 1 + lib/Module/InstructionInfoTable.cpp | 75 +++++++++---------- lib/Module/KModule.cpp | 20 ++--- lib/Module/StreamWithLine.cpp | 85 ++++++++++++++++++++++ lib/Module/StreamWithLine.h | 25 +++++++ lib/Runner/run_klee.cpp | 1 - 10 files changed, 189 insertions(+), 70 deletions(-) create mode 100644 lib/Module/StreamWithLine.cpp create mode 100644 lib/Module/StreamWithLine.h diff --git a/include/klee/Module/InstructionInfoTable.h b/include/klee/Module/InstructionInfoTable.h index 31836cbcc7..06ae59f2f3 100644 --- a/include/klee/Module/InstructionInfoTable.h +++ b/include/klee/Module/InstructionInfoTable.h @@ -10,6 +10,8 @@ #ifndef KLEE_INSTRUCTIONINFOTABLE_H #define KLEE_INSTRUCTIONINFOTABLE_H +#include +#include #include #include #include @@ -32,13 +34,13 @@ struct InstructionInfo { /// @brief Column number in source file. unsigned column; /// @brief Line number in generated assembly.ll. - unsigned assemblyLine; + llvm::Optional assemblyLine; /// @brief Source file name. const std::string &file; public: InstructionInfo(unsigned id, const std::string &file, unsigned line, - unsigned column, unsigned assemblyLine) + unsigned column, llvm::Optional assemblyLine) : id{id}, line{line}, column{column}, assemblyLine{assemblyLine}, file{file} {} }; @@ -50,13 +52,13 @@ struct FunctionInfo { /// @brief Line number in source file. unsigned line; /// @brief Line number in generated assembly.ll. - uint64_t assemblyLine; + llvm::Optional assemblyLine; /// @brief Source file name. const std::string &file; public: FunctionInfo(unsigned id, const std::string &file, unsigned line, - uint64_t assemblyLine) + llvm::Optional assemblyLine) : id{id}, line{line}, assemblyLine{assemblyLine}, file{file} {} FunctionInfo(const FunctionInfo &) = delete; @@ -74,7 +76,8 @@ class InstructionInfoTable { std::vector> internedStrings; public: - explicit InstructionInfoTable(const llvm::Module &m); + explicit InstructionInfoTable( + const llvm::Module &m, std::unique_ptr assemblyFS); unsigned getMaxID() const; const InstructionInfo &getInfo(const llvm::Instruction &) const; diff --git a/lib/Core/ExecutionState.cpp b/lib/Core/ExecutionState.cpp index 6aaa08a140..5b8cebccf7 100644 --- a/lib/Core/ExecutionState.cpp +++ b/lib/Core/ExecutionState.cpp @@ -438,9 +438,12 @@ void ExecutionState::dumpStack(llvm::raw_ostream &out) const { Function *f = sf.kf->function; const InstructionInfo &ii = *target->info; out << "\t#" << idx++; - std::stringstream AssStream; - AssStream << std::setw(8) << std::setfill('0') << ii.assemblyLine; - out << AssStream.str(); + if (ii.assemblyLine.hasValue()) { + std::stringstream AssStream; + AssStream << std::setw(8) << std::setfill('0') + << ii.assemblyLine.getValue(); + out << AssStream.str(); + } out << " in " << f->getName().str() << " ("; // Yawn, we could go up and print varargs if we wanted to. unsigned index = 0; diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp index 4afb840b8f..08ca1bb5d6 100644 --- a/lib/Core/Executor.cpp +++ b/lib/Core/Executor.cpp @@ -1461,9 +1461,10 @@ void Executor::printDebugInstructions(ExecutionState &state) { !DebugPrintInstructions.isSet(FILE_COMPACT)) { (*stream) << " " << state.pc->getSourceLocation() << ':'; } - - (*stream) << state.pc->info->assemblyLine << ':' << state.getID(); - + if (state.pc->info->assemblyLine.hasValue()) { + (*stream) << state.pc->info->assemblyLine.getValue() << ':'; + } + (*stream) << state.getID(); if (DebugPrintInstructions.isSet(STDERR_ALL) || DebugPrintInstructions.isSet(FILE_ALL)) (*stream) << ':' << *(state.pc->inst); @@ -4197,10 +4198,11 @@ void Executor::terminateStateOnError(ExecutionState &state, llvm::raw_string_ostream msg(MsgString); msg << "Error: " << message << '\n'; if (!ii.file.empty()) { - msg << "File: " << ii.file << '\n' - << "Line: " << ii.line << '\n' - << "assembly.ll line: " << ii.assemblyLine << '\n' - << "State: " << state.getID() << '\n'; + msg << "File: " << ii.file << '\n' << "Line: " << ii.line << '\n'; + if (ii.assemblyLine.hasValue()) { + msg << "assembly.ll line: " << ii.assemblyLine.getValue() << '\n'; + } + msg << "State: " << state.getID() << '\n'; } msg << "Stack: \n"; state.dumpStack(msg); diff --git a/lib/Core/StatsTracker.cpp b/lib/Core/StatsTracker.cpp index f7da36bc22..862010d9f6 100644 --- a/lib/Core/StatsTracker.cpp +++ b/lib/Core/StatsTracker.cpp @@ -744,7 +744,10 @@ void StatsTracker::writeIStats() { of << "fl=" << ii.file << "\n"; sourceFile = ii.file; } - of << ii.assemblyLine << " "; + + assert(ii.assemblyLine.hasValue()); + of << ii.assemblyLine.getValue() << " "; + of << ii.line << " "; for (unsigned i = 0; i < nStats; i++) if (istatsMask.test(i)) @@ -766,10 +769,15 @@ void StatsTracker::writeIStats() { of << "cfl=" << fii.file << "\n"; of << "cfn=" << f->getName().str() << "\n"; of << "calls=" << csi.count << " "; - of << fii.assemblyLine << " "; + + assert(fii.assemblyLine.hasValue()); + of << fii.assemblyLine.getValue() << " "; + of << fii.line << "\n"; - of << ii.assemblyLine << " "; + assert(ii.assemblyLine.hasValue()); + of << ii.assemblyLine.getValue() << " "; + of << ii.line << " "; for (unsigned i = 0; i < nStats; i++) { if (istatsMask.test(i)) { diff --git a/lib/Module/CMakeLists.txt b/lib/Module/CMakeLists.txt index b113910832..e1dde40d26 100644 --- a/lib/Module/CMakeLists.txt +++ b/lib/Module/CMakeLists.txt @@ -24,6 +24,7 @@ set(KLEE_MODULE_COMPONENT_SRCS PhiCleaner.cpp RaiseAsm.cpp ReturnSplitter.cpp + StreamWithLine.cpp ) if (USE_WORKAROUND_LLVM_PR39177) diff --git a/lib/Module/InstructionInfoTable.cpp b/lib/Module/InstructionInfoTable.cpp index 8fed51e1e5..31c9a7962b 100644 --- a/lib/Module/InstructionInfoTable.cpp +++ b/lib/Module/InstructionInfoTable.cpp @@ -10,6 +10,7 @@ #include "klee/Module/InstructionInfoTable.h" #include "klee/Config/Version.h" +#include "StreamWithLine.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/AssemblyAnnotationWriter.h" #include "llvm/IR/DebugInfo.h" @@ -25,6 +26,7 @@ #include "llvm/Support/FormattedStream.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" +#include #include #include @@ -35,64 +37,47 @@ using namespace klee; class InstructionToLineAnnotator : public llvm::AssemblyAnnotationWriter { public: void emitInstructionAnnot(const llvm::Instruction *i, - llvm::formatted_raw_ostream &os) { - os << "%%%"; - os << reinterpret_cast(i); + llvm::formatted_raw_ostream &os) override { + os << "%%%" + std::to_string(reinterpret_cast(i)); } void emitFunctionAnnot(const llvm::Function *f, - llvm::formatted_raw_ostream &os) { - os << "%%%"; - os << reinterpret_cast(f); + llvm::formatted_raw_ostream &os) override { + os << "%%%" + std::to_string(reinterpret_cast(f)); } }; -static std::map -buildInstructionToLineMap(const llvm::Module &m) { +static std::unordered_map +buildInstructionToLineMap(const llvm::Module &m, + std::unique_ptr assemblyFS) { - std::map mapping; + std::unordered_map mapping; InstructionToLineAnnotator a; - std::string str; - llvm::raw_string_ostream os(str); + StreamWithLine os(std::move(assemblyFS)); m.print(os, &a); os.flush(); - const char *s; - - unsigned line = 1; - for (s = str.c_str(); *s; s++) { - if (*s != '\n') - continue; - - line++; - if (s[1] != '%' || s[2] != '%' || s[3] != '%') - continue; - - s += 4; - char *end; - uint64_t value = strtoull(s, &end, 10); - if (end != s) { - mapping.insert(std::make_pair(value, line)); - } - s = end; - } - - return mapping; + return os.getMapping(); } class DebugInfoExtractor { std::vector> &internedStrings; - std::map lineTable; + std::unordered_map lineTable; const llvm::Module &module; + bool withAsm = false; public: DebugInfoExtractor( std::vector> &_internedStrings, - const llvm::Module &_module) + const llvm::Module &_module, + std::unique_ptr assemblyFS) : internedStrings(_internedStrings), module(_module) { - lineTable = buildInstructionToLineMap(module); + if (assemblyFS) { + withAsm = true; + lineTable = buildInstructionToLineMap(module, std::move(assemblyFS)); + } } std::string &getInternedString(const std::string &s) { @@ -111,7 +96,10 @@ class DebugInfoExtractor { } std::unique_ptr getFunctionInfo(const llvm::Function &Func) { - auto asmLine = lineTable.at(reinterpret_cast(&Func)); + llvm::Optional asmLine; + if (withAsm) { + asmLine = lineTable.at(reinterpret_cast(&Func)); + } auto dsub = Func.getSubprogram(); if (dsub != nullptr) { @@ -127,7 +115,10 @@ class DebugInfoExtractor { std::unique_ptr getInstructionInfo(const llvm::Instruction &Inst, const FunctionInfo *f) { - auto asmLine = lineTable.at(reinterpret_cast(&Inst)); + llvm::Optional asmLine; + if (withAsm) { + asmLine = lineTable.at(reinterpret_cast(&Inst)); + } // Retrieve debug information associated with instruction auto dl = Inst.getDebugLoc(); @@ -161,18 +152,20 @@ class DebugInfoExtractor { } }; -InstructionInfoTable::InstructionInfoTable(const llvm::Module &m) { +InstructionInfoTable::InstructionInfoTable( + const llvm::Module &m, std::unique_ptr assemblyFS) { // Generate all debug instruction information - DebugInfoExtractor DI(internedStrings, m); + DebugInfoExtractor DI(internedStrings, m, std::move(assemblyFS)); + for (const auto &Func : m) { auto F = DI.getFunctionInfo(Func); auto FR = F.get(); - functionInfos.insert(std::make_pair(&Func, std::move(F))); + functionInfos.emplace(&Func, std::move(F)); for (auto it = llvm::inst_begin(Func), ie = llvm::inst_end(Func); it != ie; ++it) { auto instr = &*it; - infos.insert(std::make_pair(instr, DI.getInstructionInfo(*instr, FR))); + infos.emplace(instr, DI.getInstructionInfo(*instr, FR)); } } diff --git a/lib/Module/KModule.cpp b/lib/Module/KModule.cpp index cf39d2ab58..ccd69cf63f 100644 --- a/lib/Module/KModule.cpp +++ b/lib/Module/KModule.cpp @@ -347,11 +347,6 @@ void KModule::optimiseAndPrepare( } void KModule::manifest(InterpreterHandler *ih, bool forceSourceOutput) { - if (OutputSource || forceSourceOutput) { - std::unique_ptr os(ih->openOutputFile("assembly.ll")); - assert(os && !os->has_error() && "unable to open source output"); - *os << *module; - } if (OutputModule) { std::unique_ptr f(ih->openOutputFile("final.bc")); @@ -362,14 +357,19 @@ void KModule::manifest(InterpreterHandler *ih, bool forceSourceOutput) { #endif } - /* Build shadow structures */ - - infos = std::unique_ptr( - new InstructionInfoTable(*module.get())); + { + /* Build shadow structures */ + std::unique_ptr assemblyFS; + if (OutputSource || forceSourceOutput) { + assemblyFS = ih->openOutputFile("assembly.ll"); + } + infos = + std::make_unique(*module, std::move(assemblyFS)); + } std::vector declarations; - for (auto &Function : *module) { + for (auto &Function : module->functions()) { if (Function.isDeclaration()) { declarations.push_back(&Function); } diff --git a/lib/Module/StreamWithLine.cpp b/lib/Module/StreamWithLine.cpp new file mode 100644 index 0000000000..ae7f26c22b --- /dev/null +++ b/lib/Module/StreamWithLine.cpp @@ -0,0 +1,85 @@ +#include "StreamWithLine.h" + +StreamWithLine::StreamWithLine(std::unique_ptr assemblyFS) + : assemblyFS(std::move(assemblyFS)), value(), state(State::NewLine) {} + +void StreamWithLine::write_impl(const char *Ptr, size_t Size) { + const char *start = Ptr; + const char *end = Ptr + Size; + for (const char *ch = Ptr; ch < end; ++ch) { + switch (state) { + case State::NewLine: + if (*ch == '%') { + assemblyFS->write(start, ch - start); + start = ch; + state = State::FirstP; + continue; + } + break; + case State::FirstP: + if (*ch == '%') { + state = State::SecondP; + continue; + } + assemblyFS->write("%", 1); + start = ch; + break; + case State::SecondP: + if (*ch == '%') { + state = State::ThirdP; + continue; + } + assemblyFS->write("%%", 2); + start = ch; + break; + case State::ThirdP: + if (isdigit(*ch)) { + value = *ch; + state = State::Num; + continue; + } + assemblyFS->write("%%%", 3); + start = ch; + break; + case State::Num: + if (isdigit(*ch)) { + value += *ch; + state = State::Num; + continue; + } + start = ch; + mapping.emplace(stoull(value), line); + break; + case State::Another: + break; + } + + if (*ch == '\n') { + state = State::NewLine; + line++; + continue; + } + state = State::Another; + } + + switch (state) { + case State::NewLine: + assemblyFS->write(start, end - start); + case State::Another: + assemblyFS->write(start, end - start); + break; + case State::FirstP: + case State::SecondP: + case State::ThirdP: + case State::Num: + break; + } + + curPos += Size; +} + +uint64_t StreamWithLine::current_pos() const { return curPos; } + +std::unordered_map StreamWithLine::getMapping() const { + return mapping; +} diff --git a/lib/Module/StreamWithLine.h b/lib/Module/StreamWithLine.h new file mode 100644 index 0000000000..0bd3d42ad6 --- /dev/null +++ b/lib/Module/StreamWithLine.h @@ -0,0 +1,25 @@ +#ifndef KLEE_STREAMWITHLINE_H +#define KLEE_STREAMWITHLINE_H + +#include +#include + +class StreamWithLine : public llvm::raw_ostream { + std::unique_ptr assemblyFS; + + uint64_t line = 0; + uint64_t curPos = 0; + std::string value; + std::unordered_map mapping = {}; + enum State { NewLine, FirstP, SecondP, ThirdP, Num, Another } state; + + void write_impl(const char *Ptr, size_t Size) override; + uint64_t current_pos() const override; + +public: + explicit StreamWithLine(std::unique_ptr assemblyFS); + + std::unordered_map getMapping() const; +}; + +#endif // KLEE_STREAMWITHLINE_H diff --git a/lib/Runner/run_klee.cpp b/lib/Runner/run_klee.cpp index 937e2f1974..e4480faf41 100644 --- a/lib/Runner/run_klee.cpp +++ b/lib/Runner/run_klee.cpp @@ -1679,7 +1679,6 @@ int run_klee(int argc, char **argv, char **envp) { auto finalModule = interpreter->setModule(loadedModules, Opts, mainModuleFunctions); - if (InteractiveMode) { klee_message("KLEE finish preprocessing."); std::ifstream entrypoints(EntryPointsFile);