xref: /freebsd/contrib/llvm-project/lldb/tools/lldb-instr/Instrument.cpp (revision 04eeddc0aa8e0a417a16eaf9d7d095207f4a8623)
10b57cec5SDimitry Andric #include "clang/AST/AST.h"
20b57cec5SDimitry Andric #include "clang/AST/ASTConsumer.h"
30b57cec5SDimitry Andric #include "clang/AST/RecursiveASTVisitor.h"
40b57cec5SDimitry Andric #include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
50b57cec5SDimitry Andric #include "clang/Frontend/ASTConsumers.h"
60b57cec5SDimitry Andric #include "clang/Frontend/CompilerInstance.h"
70b57cec5SDimitry Andric #include "clang/Frontend/FrontendActions.h"
80b57cec5SDimitry Andric #include "clang/Rewrite/Core/Rewriter.h"
90b57cec5SDimitry Andric #include "clang/Tooling/CommonOptionsParser.h"
100b57cec5SDimitry Andric #include "clang/Tooling/Tooling.h"
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h"
130b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
140b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include <sstream>
170b57cec5SDimitry Andric #include <string>
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric using namespace clang;
200b57cec5SDimitry Andric using namespace clang::driver;
210b57cec5SDimitry Andric using namespace clang::tooling;
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric static llvm::cl::OptionCategory InstrCategory("LLDB Instrumentation Generator");
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric class SBVisitor : public RecursiveASTVisitor<SBVisitor> {
260b57cec5SDimitry Andric public:
SBVisitor(Rewriter & R,ASTContext & Context)270b57cec5SDimitry Andric   SBVisitor(Rewriter &R, ASTContext &Context)
280b57cec5SDimitry Andric       : MyRewriter(R), Context(Context) {}
290b57cec5SDimitry Andric 
VisitCXXMethodDecl(CXXMethodDecl * Decl)300b57cec5SDimitry Andric   bool VisitCXXMethodDecl(CXXMethodDecl *Decl) {
310b57cec5SDimitry Andric     // Not all decls should be registered. Please refer to that method's
320b57cec5SDimitry Andric     // comment for details.
330b57cec5SDimitry Andric     if (ShouldSkip(Decl))
340b57cec5SDimitry Andric       return false;
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric     // Print 'bool' instead of '_Bool'.
370b57cec5SDimitry Andric     PrintingPolicy Policy(Context.getLangOpts());
380b57cec5SDimitry Andric     Policy.Bool = true;
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric     // Collect the functions parameter types and names.
410b57cec5SDimitry Andric     std::vector<std::string> ParamNames;
42*04eeddc0SDimitry Andric     if (!Decl->isStatic())
43*04eeddc0SDimitry Andric       ParamNames.push_back("this");
44*04eeddc0SDimitry Andric     for (auto *P : Decl->parameters())
450b57cec5SDimitry Andric       ParamNames.push_back(P->getNameAsString());
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric     // Construct the macros.
48*04eeddc0SDimitry Andric     std::string Buffer;
49*04eeddc0SDimitry Andric     llvm::raw_string_ostream Macro(Buffer);
50*04eeddc0SDimitry Andric     if (ParamNames.empty()) {
51*04eeddc0SDimitry Andric       Macro << "LLDB_INSTRUMENT()";
520b57cec5SDimitry Andric     } else {
53*04eeddc0SDimitry Andric       Macro << "LLDB_INSTRUMENT_VA(" << llvm::join(ParamNames, ", ") << ")";
540b57cec5SDimitry Andric     }
550b57cec5SDimitry Andric 
56*04eeddc0SDimitry Andric     Stmt *Body = Decl->getBody();
57*04eeddc0SDimitry Andric     for (auto &C : Body->children()) {
58*04eeddc0SDimitry Andric       if (C->getBeginLoc().isMacroID()) {
59*04eeddc0SDimitry Andric         CharSourceRange Range =
60*04eeddc0SDimitry Andric             MyRewriter.getSourceMgr().getExpansionRange(C->getSourceRange());
61*04eeddc0SDimitry Andric         MyRewriter.ReplaceText(Range, Macro.str());
62*04eeddc0SDimitry Andric       } else {
63*04eeddc0SDimitry Andric         Macro << ";";
640b57cec5SDimitry Andric         SourceLocation InsertLoc = Lexer::getLocForEndOfToken(
650b57cec5SDimitry Andric             Body->getBeginLoc(), 0, MyRewriter.getSourceMgr(),
660b57cec5SDimitry Andric             MyRewriter.getLangOpts());
67*04eeddc0SDimitry Andric         MyRewriter.InsertTextAfter(InsertLoc, Macro.str());
68*04eeddc0SDimitry Andric       }
69*04eeddc0SDimitry Andric       break;
700b57cec5SDimitry Andric     }
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric     return true;
730b57cec5SDimitry Andric   }
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric private:
760b57cec5SDimitry Andric   /// Determine whether we need to consider the given CXXMethodDecl.
770b57cec5SDimitry Andric   ///
780b57cec5SDimitry Andric   /// Currently we skip the following cases:
790b57cec5SDimitry Andric   ///  1. Decls outside the main source file,
800b57cec5SDimitry Andric   ///  2. Decls that are only present in the source file,
810b57cec5SDimitry Andric   ///  3. Decls that are not definitions,
820b57cec5SDimitry Andric   ///  4. Non-public methods,
830b57cec5SDimitry Andric   ///  5. Variadic methods.
840b57cec5SDimitry Andric   ///  6. Destructors.
ShouldSkip(CXXMethodDecl * Decl)850b57cec5SDimitry Andric   bool ShouldSkip(CXXMethodDecl *Decl) {
860b57cec5SDimitry Andric     // Skip anything outside the main file.
870b57cec5SDimitry Andric     if (!MyRewriter.getSourceMgr().isInMainFile(Decl->getBeginLoc()))
880b57cec5SDimitry Andric       return true;
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric     // Skip if the canonical decl in the current decl. It means that the method
910b57cec5SDimitry Andric     // is declared in the implementation and is therefore not exposed as part
920b57cec5SDimitry Andric     // of the API.
930b57cec5SDimitry Andric     if (Decl == Decl->getCanonicalDecl())
940b57cec5SDimitry Andric       return true;
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric     // Skip decls that have no body, i.e. are just declarations.
970b57cec5SDimitry Andric     Stmt *Body = Decl->getBody();
980b57cec5SDimitry Andric     if (!Body)
990b57cec5SDimitry Andric       return true;
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric     // Skip non-public methods.
1020b57cec5SDimitry Andric     AccessSpecifier AS = Decl->getAccess();
1030b57cec5SDimitry Andric     if (AS != AccessSpecifier::AS_public)
1040b57cec5SDimitry Andric       return true;
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric     // Skip variadic methods.
1070b57cec5SDimitry Andric     if (Decl->isVariadic())
1080b57cec5SDimitry Andric       return true;
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric     // Skip destructors.
1110b57cec5SDimitry Andric     if (isa<CXXDestructorDecl>(Decl))
1120b57cec5SDimitry Andric       return true;
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric     return false;
1150b57cec5SDimitry Andric   }
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric   Rewriter &MyRewriter;
1180b57cec5SDimitry Andric   ASTContext &Context;
1190b57cec5SDimitry Andric };
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric class SBConsumer : public ASTConsumer {
1220b57cec5SDimitry Andric public:
SBConsumer(Rewriter & R,ASTContext & Context)1230b57cec5SDimitry Andric   SBConsumer(Rewriter &R, ASTContext &Context) : Visitor(R, Context) {}
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric   // Override the method that gets called for each parsed top-level
1260b57cec5SDimitry Andric   // declaration.
HandleTopLevelDecl(DeclGroupRef DR)1270b57cec5SDimitry Andric   bool HandleTopLevelDecl(DeclGroupRef DR) override {
1280b57cec5SDimitry Andric     for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {
1290b57cec5SDimitry Andric       Visitor.TraverseDecl(*b);
1300b57cec5SDimitry Andric     }
1310b57cec5SDimitry Andric     return true;
1320b57cec5SDimitry Andric   }
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric private:
1350b57cec5SDimitry Andric   SBVisitor Visitor;
1360b57cec5SDimitry Andric };
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric class SBAction : public ASTFrontendAction {
1390b57cec5SDimitry Andric public:
1400b57cec5SDimitry Andric   SBAction() = default;
1410b57cec5SDimitry Andric 
BeginSourceFileAction(CompilerInstance & CI)142*04eeddc0SDimitry Andric   bool BeginSourceFileAction(CompilerInstance &CI) override { return true; }
1430b57cec5SDimitry Andric 
EndSourceFileAction()144*04eeddc0SDimitry Andric   void EndSourceFileAction() override { MyRewriter.overwriteChangedFiles(); }
1450b57cec5SDimitry Andric 
CreateASTConsumer(CompilerInstance & CI,StringRef File)1460b57cec5SDimitry Andric   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
1470b57cec5SDimitry Andric                                                  StringRef File) override {
1480b57cec5SDimitry Andric     MyRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());
1499dba64beSDimitry Andric     return std::make_unique<SBConsumer>(MyRewriter, CI.getASTContext());
1500b57cec5SDimitry Andric   }
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric private:
1530b57cec5SDimitry Andric   Rewriter MyRewriter;
1540b57cec5SDimitry Andric };
1550b57cec5SDimitry Andric 
main(int argc,const char ** argv)1560b57cec5SDimitry Andric int main(int argc, const char **argv) {
157fe6060f1SDimitry Andric   auto ExpectedParser = CommonOptionsParser::create(
158fe6060f1SDimitry Andric       argc, argv, InstrCategory, llvm::cl::OneOrMore,
1590b57cec5SDimitry Andric       "Utility for generating the macros for LLDB's "
1600b57cec5SDimitry Andric       "instrumentation framework.");
161fe6060f1SDimitry Andric   if (!ExpectedParser) {
162fe6060f1SDimitry Andric     llvm::errs() << ExpectedParser.takeError();
163fe6060f1SDimitry Andric     return 1;
164fe6060f1SDimitry Andric   }
165fe6060f1SDimitry Andric   CommonOptionsParser &OP = ExpectedParser.get();
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric   auto PCHOpts = std::make_shared<PCHContainerOperations>();
1689dba64beSDimitry Andric   PCHOpts->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());
1699dba64beSDimitry Andric   PCHOpts->registerReader(std::make_unique<ObjectFilePCHContainerReader>());
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric   ClangTool T(OP.getCompilations(), OP.getSourcePathList(), PCHOpts);
1720b57cec5SDimitry Andric   return T.run(newFrontendActionFactory<SBAction>().get());
1730b57cec5SDimitry Andric }
174