diff --git a/include/ExtractionBlock.h b/include/ExtractionBlock.h index 64d235140222bbae9eeff56de348457ed2ddbab4..c7d58e74cf8dae211729001986669df4f0182ac5 100644 --- a/include/ExtractionBlock.h +++ b/include/ExtractionBlock.h @@ -10,7 +10,11 @@ struct ExtractionBlock { ExtractionBlock(clang::SourceLocation b, clang::SourceLocation e, std::string c) { begin = b; end = e; - contents = c; + contents = std::move(c); + } + + bool operator==(const ExtractionBlock& other) const{ + return this->begin==other.begin&&this->end==other.end&&this->contents==other.contents; } clang::SourceLocation begin; diff --git a/include/PreprocessorExtract.h b/include/PreprocessorExtract.h index 5142569acfa7fb248ea601a797c4db641bb451af..bae98f63a4fbe5997a1fed03d5b68a64ec98588e 100644 --- a/include/PreprocessorExtract.h +++ b/include/PreprocessorExtract.h @@ -54,7 +54,7 @@ private: clang::SourceManager &sourceManager; clang::LangOptions languageOption; - void MacroDefined(const clang::Token &MacroNameTok, const clang::MacroDirective *MD); + void MacroDefined(const clang::Token &MacroNameTok, const clang::MacroDirective *MD) override; }; #endif //CTUAPEX_PREPROCESSOREXTRACT_H diff --git a/src/CTUApexConsumer.cpp b/src/CTUApexConsumer.cpp index 43181e805ee19dffe99d5f7cd16d12a384b426cf..eb65c0a52e4e5b8add17869f5c4a4f7070017f6d 100644 --- a/src/CTUApexConsumer.cpp +++ b/src/CTUApexConsumer.cpp @@ -8,6 +8,8 @@ #include "llvm/Demangle/Demangle.h" #include "FunctionFinderVisitor.h" +static bool generatedMain = false; + void CTUApexConsumer::outlineFunctions() { for (const auto &node: call_graph->getNodes()) { //check for each node in the graph, whether we found a corresponding node in the current ast @@ -43,7 +45,7 @@ void CTUApexConsumer::outlineFunctions() { void CTUApexConsumer::outlineGlobals() { //Fixme: does this need to extract cross TU as well? - SPDLOG_INFO("Compute set of used globals"); + std::unordered_set<clang::Decl *> availableGlobals; std::vector<ExtractionBlock> returnBlocks; for (const auto &node: call_graph->getNodes()) { @@ -53,19 +55,21 @@ void CTUApexConsumer::outlineGlobals() { GlobalsMarker gMarker; auto globalsSet = gMarker.get_nodes_to_outline( clang::cast<clang::FunctionDecl>(md.second->get_decl_node())); - for (const auto &func: globalsSet) { + for (const auto &decl: globalsSet) { ExtractionBlock eb; - eb.begin = func->getBeginLoc(); - eb.end = func->getEndLoc(); - clang::SourceRange range(eb.begin, eb.end); - clang::CharSourceRange charSourceRange(range, true); - eb.contents = clang::Lexer::getSourceText(charSourceRange, func->getASTContext().getSourceManager(), + eb.begin = decl->getBeginLoc(); + eb.end = decl->getEndLoc(); + clang::CharSourceRange charSourceRange({eb.begin, eb.end}, true); + eb.contents = clang::Lexer::getSourceText(charSourceRange, decl->getASTContext().getSourceManager(), clang::LangOptions(), nullptr).str(); globals.push_back(eb); } } } + //as we find globals in the order they are used, but want them in the order they are declared we need to sort the globals + std::sort(globals.begin(), globals.end(), + [](const ExtractionBlock &a, const ExtractionBlock &b) { return a.begin < b.begin; }); } void CTUApexConsumer::filterExtrationBlocks() { @@ -92,70 +96,56 @@ ExtractionBlock CTUApexConsumer::getNextExtractionBlock() { //as we will erase parts of the vectors later, potentially invalidating pointers in the process ExtractionBlock min; if (!includes.empty()) { - SPDLOG_TRACE("Setting include as assumed min"); min = includes.front(); } else if (!funcs.empty()) { - SPDLOG_TRACE("Setting funcs as assumed min"); min = funcs.front(); } else if (!globals.empty()) { - SPDLOG_TRACE("Setting globals as assumed min"); min = globals.front(); } else if (!macros.empty()) { - SPDLOG_TRACE("Setting macros as assumed min"); min = macros.front(); } else if (!pragmas.empty()) { - SPDLOG_TRACE("Setting pragmas as assumed min"); min = pragmas.front(); } while (!funcs.empty() && min.begin > funcs.front().begin) { - SPDLOG_TRACE("Overwriting with funcs as min"); min = funcs.front(); } while (!globals.empty() && min.begin > globals.front().begin) { - SPDLOG_TRACE("Overwriting with globals as min"); min = globals.front(); } while (!macros.empty() && min.begin > macros.front().begin) { - SPDLOG_TRACE("Overwriting with macros as min"); min = macros.front(); } while (!pragmas.empty() && min.begin > pragmas.front().begin) { - SPDLOG_TRACE("Overwriting with pragmas as min"); min = pragmas.front(); } //if the earliest blocks end is after another block, we fully contain the other block //we don't need to merge that block anymore - while (!includes.empty() && min.end >= includes.front().end) { - SPDLOG_TRACE("Erasing include entry"); - includes.erase(includes.begin()); - } - while (!funcs.empty() && min.end >= funcs.front().end) { - SPDLOG_TRACE("Erasing funcs entry"); - funcs.erase(funcs.begin()); - } - while (!globals.empty() && min.end >= globals.front().end) { - SPDLOG_TRACE("Erasing globals entry"); - globals.erase(globals.begin()); - } - while (!macros.empty() && min.end >= macros.front().end) { - SPDLOG_TRACE("Erasing macros entry"); - macros.erase(macros.begin()); - } - while (!pragmas.empty() && min.end >= pragmas.front().end) { - SPDLOG_TRACE("Erasing pragmas entry"); - pragmas.erase(pragmas.begin()); - } - + const auto &pred = [&min](const auto &elem) { return min.end >= elem.end; }; + includes.erase(std::remove_if(includes.begin(), includes.end(), pred), includes.end()); + funcs.erase(std::remove_if(funcs.begin(), funcs.end(), pred), funcs.end()); + globals.erase(std::remove_if(globals.begin(), globals.end(), pred), globals.end()); + macros.erase(std::remove_if(macros.begin(), macros.end(), pred), macros.end()); + pragmas.erase(std::remove_if(pragmas.begin(), pragmas.end(), pred), pragmas.end()); return min; } void CTUApexConsumer::HandleTranslationUnit(clang::ASTContext &Context) { + //Whole path with line and column + std::string path = Context.getSourceManager().getLocForEndOfFile( + Context.getSourceManager().getMainFileID()).printToString(Context.getSourceManager()); + //Only file name with line and column + path = path.substr(path.find_last_of('/') + 1); + //Only file name + path = path.substr(0, path.find_first_of(':')); + SPDLOG_INFO("Extracting from file: {}", path); + const auto &translation_unit = Context.getTranslationUnitDecl(); SPDLOG_INFO("Mapping functions to the call graph"); + FunctionFinderVisitor functionFinderVisitor(call_graph); functionFinderVisitor.TraverseTranslationUnitDecl(translation_unit); @@ -184,9 +174,11 @@ void CTUApexConsumer::HandleTranslationUnit(clang::ASTContext &Context) { SPDLOG_CRITICAL("WRAPPER CALLS CAN NOT YET BE IMPLEMENTED"); if (auto md = call_graph->getMain()->checkAndGet<ExtractionMetadata>(); md.first && - !md.second->isMarkedToExtract()) { + !md.second->isMarkedToExtract() && + !generatedMain) { //we have no main function and need to create or own outFile << "\nint main(){return 0;}\n"; + generatedMain = true; } diff --git a/src/CTUApexVisitor.cpp b/src/CTUApexVisitor.cpp index b8377046284671ed15df81c0c6da6ea9e24bc7b6..aee0f5d412cee24ebb0d1003cff4b518e3f1c16e 100644 --- a/src/CTUApexVisitor.cpp +++ b/src/CTUApexVisitor.cpp @@ -34,8 +34,6 @@ bool FunctionFinderVisitor::VisitFunctionTemplateDecl(clang::FunctionTemplateDec for (const auto &s: D->specializations()) { for (const auto &name: getMangledName(s)) { - assert(callgraph->hasNode(name)); - // we should find every node in the whole program callgraph if (!callgraph->hasNode(name)) { SPDLOG_WARN("Node {} is not in the call-graph. Graph might be wrong or incomplete!", name); @@ -71,8 +69,6 @@ bool FunctionFinderVisitor::VisitFunctionDecl(clang::FunctionDecl *functionDecl) for (const auto &name: possibleNames) { - assert(callgraph->hasNode(name)); - // we should find every node in the whole program callgraph if (!callgraph->hasNode(name)) { SPDLOG_WARN("Node {} is not in the call-graph. Graph might be wrong or incomplete!", name); diff --git a/src/PreprocessorExtract.cpp b/src/PreprocessorExtract.cpp index ef3e1241ca7eaefc4e387dea0726572f4de04554..2b8d0de20f693094889a9427cf9946b8c25a5272 100644 --- a/src/PreprocessorExtract.cpp +++ b/src/PreprocessorExtract.cpp @@ -76,7 +76,6 @@ inline void PreprocessorExtract::PragmaDirective(clang::SourceLocation Loc, // or enounter a \ followed by a newline, which means the pragma goes on in the next line for (int i = 0; !text.endswith("\n") || text.endswith("\\\n"); i++) { //only reset the assumed end of the sourcerange to keep object intact - llvm::outs() << text << "\n"; charSourceRange.setEnd(Loc.getLocWithOffset(i)); text = clang::Lexer::getSourceText(charSourceRange, sourceManager, languageOption); assert(i < 5000);//This is for debugging diff --git a/src/main.cpp b/src/main.cpp index bd214ffb91e8a9f69e40493a8e9b319dd2c710ae..78f818776dcaccdc525ae216b4571507e950a4aa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,7 +5,6 @@ //Wir machen Tooling #include "clang/Tooling/Tooling.h" //Wir benutzen die Visitor strategy -#include <clang/AST/RecursiveASTVisitor.h> //Wir müssen mit dem compiler interagieren können. #include <clang/Frontend/CompilerInstance.h> #include <spdlog/spdlog.h> @@ -146,21 +145,25 @@ std::vector<std::string> clangResourceDirBasedAdjuster(const CommandLineArgument void printMarkedFunctions(const metacg::Callgraph &cg) { std::cout << "Extracting:\n"; + size_t size=500; + char* a = static_cast<char *>(malloc(size * sizeof(char))); + int status; + size_t count=0; for (const auto &[_, node]: cg.getNodes()) { if (node->has<ExtractionMetadata>()) { - size_t size=500; - char* a = static_cast<char *>(malloc(size * sizeof(char))); - int status; + count++; if(llvm::itaniumDemangle(node->getFunctionName().c_str(),a,&size,&status);status==llvm::demangle_success){ if(llvm::StringRef b =a;!b.startswith("std::")){ - std::cout << "Node: " << demangle(node->getFunctionName()) << "\n"; + //std::cout << "Node: " << demangle(node->getFunctionName()) << "\n"; } } - free(a); } } + free(a); + std::cout<<"Marked: "<<count<<" functions\n"; } + int main(int argc, const char **argv) { auto ExpectedParser = CommonOptionsParser::create(argc, argv, CTUApex); @@ -212,9 +215,9 @@ int main(int argc, const char **argv) { auto &mcgManager = metacg::graph::MCGManager::get(); - //As the mcgReader spits out a warning for every occurance of a missing metadata, + //As the mcgReader spits out a warning for every occurrence of a missing metadata, //we silence all warnings for the duration of the read - const auto &lv = spdlog::get_level(); + const auto lv = spdlog::get_level(); spdlog::set_level(spdlog::level::off); mcgManager.addToManagedGraphs("activeGraph", mcgReader->read()); spdlog::set_level(lv); @@ -232,8 +235,12 @@ int main(int argc, const char **argv) { } } + + markFunctionsAlongCallpaths(cg); + //printMarkedFunctions(cg); + tool.run(argumentParsingFrontendActionFactory<CTUApexAction>(mcgManager.getCallgraph()).get()) ; return 0; -} +} \ No newline at end of file