xref: /openbsd-src/gnu/llvm/lldb/tools/lldb-instr/Instrument.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1061da546Spatrick #include "clang/AST/AST.h"
2061da546Spatrick #include "clang/AST/ASTConsumer.h"
3061da546Spatrick #include "clang/AST/RecursiveASTVisitor.h"
4061da546Spatrick #include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
5061da546Spatrick #include "clang/Frontend/ASTConsumers.h"
6061da546Spatrick #include "clang/Frontend/CompilerInstance.h"
7061da546Spatrick #include "clang/Frontend/FrontendActions.h"
8061da546Spatrick #include "clang/Rewrite/Core/Rewriter.h"
9061da546Spatrick #include "clang/Tooling/CommonOptionsParser.h"
10061da546Spatrick #include "clang/Tooling/Tooling.h"
11061da546Spatrick 
12061da546Spatrick #include "llvm/ADT/StringExtras.h"
13061da546Spatrick #include "llvm/ADT/StringRef.h"
14061da546Spatrick #include "llvm/Support/raw_ostream.h"
15061da546Spatrick 
16061da546Spatrick #include <sstream>
17061da546Spatrick #include <string>
18061da546Spatrick 
19061da546Spatrick using namespace clang;
20061da546Spatrick using namespace clang::driver;
21061da546Spatrick using namespace clang::tooling;
22061da546Spatrick 
23061da546Spatrick static llvm::cl::OptionCategory InstrCategory("LLDB Instrumentation Generator");
24061da546Spatrick 
25061da546Spatrick class SBVisitor : public RecursiveASTVisitor<SBVisitor> {
26061da546Spatrick public:
SBVisitor(Rewriter & R,ASTContext & Context)27061da546Spatrick   SBVisitor(Rewriter &R, ASTContext &Context)
28061da546Spatrick       : MyRewriter(R), Context(Context) {}
29061da546Spatrick 
VisitCXXMethodDecl(CXXMethodDecl * Decl)30061da546Spatrick   bool VisitCXXMethodDecl(CXXMethodDecl *Decl) {
31061da546Spatrick     // Not all decls should be registered. Please refer to that method's
32061da546Spatrick     // comment for details.
33061da546Spatrick     if (ShouldSkip(Decl))
34061da546Spatrick       return false;
35061da546Spatrick 
36061da546Spatrick     // Print 'bool' instead of '_Bool'.
37061da546Spatrick     PrintingPolicy Policy(Context.getLangOpts());
38061da546Spatrick     Policy.Bool = true;
39061da546Spatrick 
40061da546Spatrick     // Collect the functions parameter types and names.
41061da546Spatrick     std::vector<std::string> ParamNames;
42*f6aab3d8Srobert     if (!Decl->isStatic())
43*f6aab3d8Srobert       ParamNames.push_back("this");
44*f6aab3d8Srobert     for (auto *P : Decl->parameters())
45061da546Spatrick       ParamNames.push_back(P->getNameAsString());
46061da546Spatrick 
47061da546Spatrick     // Construct the macros.
48*f6aab3d8Srobert     std::string Buffer;
49*f6aab3d8Srobert     llvm::raw_string_ostream Macro(Buffer);
50*f6aab3d8Srobert     if (ParamNames.empty()) {
51*f6aab3d8Srobert       Macro << "LLDB_INSTRUMENT()";
52061da546Spatrick     } else {
53*f6aab3d8Srobert       Macro << "LLDB_INSTRUMENT_VA(" << llvm::join(ParamNames, ", ") << ")";
54061da546Spatrick     }
55061da546Spatrick 
56*f6aab3d8Srobert     Stmt *Body = Decl->getBody();
57*f6aab3d8Srobert     for (auto &C : Body->children()) {
58*f6aab3d8Srobert       if (C->getBeginLoc().isMacroID()) {
59*f6aab3d8Srobert         CharSourceRange Range =
60*f6aab3d8Srobert             MyRewriter.getSourceMgr().getExpansionRange(C->getSourceRange());
61*f6aab3d8Srobert         MyRewriter.ReplaceText(Range, Macro.str());
62*f6aab3d8Srobert       } else {
63*f6aab3d8Srobert         Macro << ";";
64061da546Spatrick         SourceLocation InsertLoc = Lexer::getLocForEndOfToken(
65061da546Spatrick             Body->getBeginLoc(), 0, MyRewriter.getSourceMgr(),
66061da546Spatrick             MyRewriter.getLangOpts());
67*f6aab3d8Srobert         MyRewriter.InsertTextAfter(InsertLoc, Macro.str());
68*f6aab3d8Srobert       }
69*f6aab3d8Srobert       break;
70061da546Spatrick     }
71061da546Spatrick 
72061da546Spatrick     return true;
73061da546Spatrick   }
74061da546Spatrick 
75061da546Spatrick private:
76061da546Spatrick   /// Determine whether we need to consider the given CXXMethodDecl.
77061da546Spatrick   ///
78061da546Spatrick   /// Currently we skip the following cases:
79061da546Spatrick   ///  1. Decls outside the main source file,
80061da546Spatrick   ///  2. Decls that are only present in the source file,
81061da546Spatrick   ///  3. Decls that are not definitions,
82061da546Spatrick   ///  4. Non-public methods,
83061da546Spatrick   ///  5. Variadic methods.
84061da546Spatrick   ///  6. Destructors.
ShouldSkip(CXXMethodDecl * Decl)85061da546Spatrick   bool ShouldSkip(CXXMethodDecl *Decl) {
86061da546Spatrick     // Skip anything outside the main file.
87061da546Spatrick     if (!MyRewriter.getSourceMgr().isInMainFile(Decl->getBeginLoc()))
88061da546Spatrick       return true;
89061da546Spatrick 
90061da546Spatrick     // Skip if the canonical decl in the current decl. It means that the method
91061da546Spatrick     // is declared in the implementation and is therefore not exposed as part
92061da546Spatrick     // of the API.
93061da546Spatrick     if (Decl == Decl->getCanonicalDecl())
94061da546Spatrick       return true;
95061da546Spatrick 
96061da546Spatrick     // Skip decls that have no body, i.e. are just declarations.
97061da546Spatrick     Stmt *Body = Decl->getBody();
98061da546Spatrick     if (!Body)
99061da546Spatrick       return true;
100061da546Spatrick 
101061da546Spatrick     // Skip non-public methods.
102061da546Spatrick     AccessSpecifier AS = Decl->getAccess();
103061da546Spatrick     if (AS != AccessSpecifier::AS_public)
104061da546Spatrick       return true;
105061da546Spatrick 
106061da546Spatrick     // Skip variadic methods.
107061da546Spatrick     if (Decl->isVariadic())
108061da546Spatrick       return true;
109061da546Spatrick 
110061da546Spatrick     // Skip destructors.
111061da546Spatrick     if (isa<CXXDestructorDecl>(Decl))
112061da546Spatrick       return true;
113061da546Spatrick 
114061da546Spatrick     return false;
115061da546Spatrick   }
116061da546Spatrick 
117061da546Spatrick   Rewriter &MyRewriter;
118061da546Spatrick   ASTContext &Context;
119061da546Spatrick };
120061da546Spatrick 
121061da546Spatrick class SBConsumer : public ASTConsumer {
122061da546Spatrick public:
SBConsumer(Rewriter & R,ASTContext & Context)123061da546Spatrick   SBConsumer(Rewriter &R, ASTContext &Context) : Visitor(R, Context) {}
124061da546Spatrick 
125061da546Spatrick   // Override the method that gets called for each parsed top-level
126061da546Spatrick   // declaration.
HandleTopLevelDecl(DeclGroupRef DR)127061da546Spatrick   bool HandleTopLevelDecl(DeclGroupRef DR) override {
128061da546Spatrick     for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {
129061da546Spatrick       Visitor.TraverseDecl(*b);
130061da546Spatrick     }
131061da546Spatrick     return true;
132061da546Spatrick   }
133061da546Spatrick 
134061da546Spatrick private:
135061da546Spatrick   SBVisitor Visitor;
136061da546Spatrick };
137061da546Spatrick 
138061da546Spatrick class SBAction : public ASTFrontendAction {
139061da546Spatrick public:
140061da546Spatrick   SBAction() = default;
141061da546Spatrick 
BeginSourceFileAction(CompilerInstance & CI)142*f6aab3d8Srobert   bool BeginSourceFileAction(CompilerInstance &CI) override { return true; }
143061da546Spatrick 
EndSourceFileAction()144*f6aab3d8Srobert   void EndSourceFileAction() override { MyRewriter.overwriteChangedFiles(); }
145061da546Spatrick 
CreateASTConsumer(CompilerInstance & CI,StringRef File)146061da546Spatrick   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
147061da546Spatrick                                                  StringRef File) override {
148061da546Spatrick     MyRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());
149061da546Spatrick     return std::make_unique<SBConsumer>(MyRewriter, CI.getASTContext());
150061da546Spatrick   }
151061da546Spatrick 
152061da546Spatrick private:
153061da546Spatrick   Rewriter MyRewriter;
154061da546Spatrick };
155061da546Spatrick 
main(int argc,const char ** argv)156061da546Spatrick int main(int argc, const char **argv) {
157be691f3bSpatrick   auto ExpectedParser = CommonOptionsParser::create(
158be691f3bSpatrick       argc, argv, InstrCategory, llvm::cl::OneOrMore,
159061da546Spatrick       "Utility for generating the macros for LLDB's "
160061da546Spatrick       "instrumentation framework.");
161be691f3bSpatrick   if (!ExpectedParser) {
162be691f3bSpatrick     llvm::errs() << ExpectedParser.takeError();
163be691f3bSpatrick     return 1;
164be691f3bSpatrick   }
165be691f3bSpatrick   CommonOptionsParser &OP = ExpectedParser.get();
166061da546Spatrick 
167061da546Spatrick   auto PCHOpts = std::make_shared<PCHContainerOperations>();
168061da546Spatrick   PCHOpts->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());
169061da546Spatrick   PCHOpts->registerReader(std::make_unique<ObjectFilePCHContainerReader>());
170061da546Spatrick 
171061da546Spatrick   ClangTool T(OP.getCompilations(), OP.getSourcePathList(), PCHOpts);
172061da546Spatrick   return T.run(newFrontendActionFactory<SBAction>().get());
173061da546Spatrick }
174