1 #include "clang/AST/AST.h"
2 #include "clang/AST/ASTConsumer.h"
3 #include "clang/AST/RecursiveASTVisitor.h"
4 #include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
5 #include "clang/Frontend/ASTConsumers.h"
6 #include "clang/Frontend/CompilerInstance.h"
7 #include "clang/Frontend/FrontendActions.h"
8 #include "clang/Rewrite/Core/Rewriter.h"
9 #include "clang/Tooling/CommonOptionsParser.h"
10 #include "clang/Tooling/Tooling.h"
11
12 #include "llvm/ADT/StringExtras.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/Support/raw_ostream.h"
15
16 #include <sstream>
17 #include <string>
18
19 using namespace clang;
20 using namespace clang::driver;
21 using namespace clang::tooling;
22
23 static llvm::cl::OptionCategory InstrCategory("LLDB Instrumentation Generator");
24
25 /// Get the macro name for recording method calls.
26 ///
27 /// LLDB_RECORD_METHOD
28 /// LLDB_RECORD_METHOD_CONST
29 /// LLDB_RECORD_METHOD_NO_ARGS
30 /// LLDB_RECORD_METHOD_CONST_NO_ARGS
31 /// LLDB_RECORD_STATIC_METHOD
32 /// LLDB_RECORD_STATIC_METHOD_NO_ARGS
GetRecordMethodMacroName(bool Static,bool Const,bool NoArgs)33 static std::string GetRecordMethodMacroName(bool Static, bool Const,
34 bool NoArgs) {
35 std::string Macro;
36 llvm::raw_string_ostream OS(Macro);
37
38 OS << "LLDB_RECORD";
39 if (Static)
40 OS << "_STATIC";
41 OS << "_METHOD";
42 if (Const)
43 OS << "_CONST";
44 if (NoArgs)
45 OS << "_NO_ARGS";
46
47 return OS.str();
48 }
49
50 /// Get the macro name for register methods.
51 ///
52 /// LLDB_REGISTER_CONSTRUCTOR
53 /// LLDB_REGISTER_METHOD
54 /// LLDB_REGISTER_METHOD_CONST
55 /// LLDB_REGISTER_STATIC_METHOD
GetRegisterMethodMacroName(bool Static,bool Const)56 static std::string GetRegisterMethodMacroName(bool Static, bool Const) {
57 std::string Macro;
58 llvm::raw_string_ostream OS(Macro);
59
60 OS << "LLDB_REGISTER";
61 if (Static)
62 OS << "_STATIC";
63 OS << "_METHOD";
64 if (Const)
65 OS << "_CONST";
66
67 return OS.str();
68 }
69
GetRecordMethodMacro(StringRef Result,StringRef Class,StringRef Method,StringRef Signature,StringRef Values,bool Static,bool Const)70 static std::string GetRecordMethodMacro(StringRef Result, StringRef Class,
71 StringRef Method, StringRef Signature,
72 StringRef Values, bool Static,
73 bool Const) {
74 std::string Macro;
75 llvm::raw_string_ostream OS(Macro);
76
77 OS << GetRecordMethodMacroName(Static, Const, Values.empty());
78 OS << "(" << Result << ", " << Class << ", " << Method;
79
80 if (!Values.empty()) {
81 OS << ", (" << Signature << "), " << Values << ");\n\n";
82 } else {
83 OS << ");\n\n";
84 }
85
86 return OS.str();
87 }
88
GetRecordConstructorMacro(StringRef Class,StringRef Signature,StringRef Values)89 static std::string GetRecordConstructorMacro(StringRef Class,
90 StringRef Signature,
91 StringRef Values) {
92 std::string Macro;
93 llvm::raw_string_ostream OS(Macro);
94 if (!Values.empty()) {
95 OS << "LLDB_RECORD_CONSTRUCTOR(" << Class << ", (" << Signature << "), "
96 << Values << ");\n\n";
97 } else {
98 OS << "LLDB_RECORD_CONSTRUCTOR_NO_ARGS(" << Class << ");\n\n";
99 }
100 return OS.str();
101 }
102
GetRecordDummyMacro(StringRef Result,StringRef Class,StringRef Method,StringRef Signature,StringRef Values)103 static std::string GetRecordDummyMacro(StringRef Result, StringRef Class,
104 StringRef Method, StringRef Signature,
105 StringRef Values) {
106 assert(!Values.empty());
107 std::string Macro;
108 llvm::raw_string_ostream OS(Macro);
109
110 OS << "LLDB_RECORD_DUMMY(" << Result << ", " << Class << ", " << Method;
111 OS << ", (" << Signature << "), " << Values << ");\n\n";
112
113 return OS.str();
114 }
115
GetRegisterConstructorMacro(StringRef Class,StringRef Signature)116 static std::string GetRegisterConstructorMacro(StringRef Class,
117 StringRef Signature) {
118 std::string Macro;
119 llvm::raw_string_ostream OS(Macro);
120 OS << "LLDB_REGISTER_CONSTRUCTOR(" << Class << ", (" << Signature << "));\n";
121 return OS.str();
122 }
123
GetRegisterMethodMacro(StringRef Result,StringRef Class,StringRef Method,StringRef Signature,bool Static,bool Const)124 static std::string GetRegisterMethodMacro(StringRef Result, StringRef Class,
125 StringRef Method, StringRef Signature,
126 bool Static, bool Const) {
127 std::string Macro;
128 llvm::raw_string_ostream OS(Macro);
129 OS << GetRegisterMethodMacroName(Static, Const);
130 OS << "(" << Result << ", " << Class << ", " << Method << ", (" << Signature
131 << "));\n";
132 return OS.str();
133 }
134
135 class SBReturnVisitor : public RecursiveASTVisitor<SBReturnVisitor> {
136 public:
SBReturnVisitor(Rewriter & R)137 SBReturnVisitor(Rewriter &R) : MyRewriter(R) {}
138
VisitReturnStmt(ReturnStmt * Stmt)139 bool VisitReturnStmt(ReturnStmt *Stmt) {
140 Expr *E = Stmt->getRetValue();
141
142 if (E->getBeginLoc().isMacroID())
143 return false;
144
145 SourceRange R(E->getBeginLoc(), E->getEndLoc());
146
147 StringRef WrittenExpr = Lexer::getSourceText(
148 CharSourceRange::getTokenRange(R), MyRewriter.getSourceMgr(),
149 MyRewriter.getLangOpts());
150
151 std::string ReplacementText =
152 "LLDB_RECORD_RESULT(" + WrittenExpr.str() + ")";
153 MyRewriter.ReplaceText(R, ReplacementText);
154
155 return true;
156 }
157
158 private:
159 Rewriter &MyRewriter;
160 };
161
162 class SBVisitor : public RecursiveASTVisitor<SBVisitor> {
163 public:
SBVisitor(Rewriter & R,ASTContext & Context)164 SBVisitor(Rewriter &R, ASTContext &Context)
165 : MyRewriter(R), Context(Context) {}
166
VisitCXXMethodDecl(CXXMethodDecl * Decl)167 bool VisitCXXMethodDecl(CXXMethodDecl *Decl) {
168 // Not all decls should be registered. Please refer to that method's
169 // comment for details.
170 if (ShouldSkip(Decl))
171 return false;
172
173 // Skip CXXMethodDecls that already starts with a macro. This should make
174 // it easier to rerun the tool to find missing macros.
175 Stmt *Body = Decl->getBody();
176 for (auto &C : Body->children()) {
177 if (C->getBeginLoc().isMacroID())
178 return false;
179 break;
180 }
181
182 // Print 'bool' instead of '_Bool'.
183 PrintingPolicy Policy(Context.getLangOpts());
184 Policy.Bool = true;
185
186 // Unsupported signatures get a dummy macro.
187 bool ShouldInsertDummy = false;
188
189 // Collect the functions parameter types and names.
190 std::vector<std::string> ParamTypes;
191 std::vector<std::string> ParamNames;
192 for (auto *P : Decl->parameters()) {
193 QualType T = P->getType();
194 ParamTypes.push_back(T.getAsString(Policy));
195 ParamNames.push_back(P->getNameAsString());
196
197 // Currently we don't support functions that have function pointers as an
198 // argument, in which case we insert a dummy macro.
199 ShouldInsertDummy |= T->isFunctionPointerType();
200 }
201
202 // Convert the two lists to string for the macros.
203 std::string ParamTypesStr = llvm::join(ParamTypes, ", ");
204 std::string ParamNamesStr = llvm::join(ParamNames, ", ");
205
206 CXXRecordDecl *Record = Decl->getParent();
207 QualType ReturnType = Decl->getReturnType();
208
209 // Construct the macros.
210 std::string Macro;
211 if (ShouldInsertDummy) {
212 // Don't insert a register call for dummy macros.
213 Macro = GetRecordDummyMacro(
214 ReturnType.getAsString(Policy), Record->getNameAsString(),
215 Decl->getNameAsString(), ParamTypesStr, ParamNamesStr);
216
217 } else if (isa<CXXConstructorDecl>(Decl)) {
218 llvm::outs() << GetRegisterConstructorMacro(Record->getNameAsString(),
219 ParamTypesStr);
220
221 Macro = GetRecordConstructorMacro(Record->getNameAsString(),
222 ParamTypesStr, ParamNamesStr);
223 } else {
224 llvm::outs() << GetRegisterMethodMacro(
225 ReturnType.getAsString(Policy), Record->getNameAsString(),
226 Decl->getNameAsString(), ParamTypesStr, Decl->isStatic(),
227 Decl->isConst());
228
229 Macro = GetRecordMethodMacro(
230 ReturnType.getAsString(Policy), Record->getNameAsString(),
231 Decl->getNameAsString(), ParamTypesStr, ParamNamesStr,
232 Decl->isStatic(), Decl->isConst());
233 }
234
235 // Insert the macro at the beginning of the function. We don't attempt to
236 // fix the formatting and instead rely on clang-format to fix it after the
237 // tool has run. This is also the reason that the macros end with two
238 // newlines, counting on clang-format to normalize this in case the macro
239 // got inserted before an existing newline.
240 SourceLocation InsertLoc = Lexer::getLocForEndOfToken(
241 Body->getBeginLoc(), 0, MyRewriter.getSourceMgr(),
242 MyRewriter.getLangOpts());
243 MyRewriter.InsertTextAfter(InsertLoc, Macro);
244
245 // If the function returns a class or struct, we need to wrap its return
246 // statement(s).
247 bool ShouldRecordResult = ReturnType->isStructureOrClassType() ||
248 ReturnType->getPointeeCXXRecordDecl();
249 if (!ShouldInsertDummy && ShouldRecordResult) {
250 SBReturnVisitor Visitor(MyRewriter);
251 Visitor.TraverseDecl(Decl);
252 }
253
254 return true;
255 }
256
257 private:
258 /// Determine whether we need to consider the given CXXMethodDecl.
259 ///
260 /// Currently we skip the following cases:
261 /// 1. Decls outside the main source file,
262 /// 2. Decls that are only present in the source file,
263 /// 3. Decls that are not definitions,
264 /// 4. Non-public methods,
265 /// 5. Variadic methods.
266 /// 6. Destructors.
ShouldSkip(CXXMethodDecl * Decl)267 bool ShouldSkip(CXXMethodDecl *Decl) {
268 // Skip anything outside the main file.
269 if (!MyRewriter.getSourceMgr().isInMainFile(Decl->getBeginLoc()))
270 return true;
271
272 // Skip if the canonical decl in the current decl. It means that the method
273 // is declared in the implementation and is therefore not exposed as part
274 // of the API.
275 if (Decl == Decl->getCanonicalDecl())
276 return true;
277
278 // Skip decls that have no body, i.e. are just declarations.
279 Stmt *Body = Decl->getBody();
280 if (!Body)
281 return true;
282
283 // Skip non-public methods.
284 AccessSpecifier AS = Decl->getAccess();
285 if (AS != AccessSpecifier::AS_public)
286 return true;
287
288 // Skip variadic methods.
289 if (Decl->isVariadic())
290 return true;
291
292 // Skip destructors.
293 if (isa<CXXDestructorDecl>(Decl))
294 return true;
295
296 return false;
297 }
298
299 Rewriter &MyRewriter;
300 ASTContext &Context;
301 };
302
303 class SBConsumer : public ASTConsumer {
304 public:
SBConsumer(Rewriter & R,ASTContext & Context)305 SBConsumer(Rewriter &R, ASTContext &Context) : Visitor(R, Context) {}
306
307 // Override the method that gets called for each parsed top-level
308 // declaration.
HandleTopLevelDecl(DeclGroupRef DR)309 bool HandleTopLevelDecl(DeclGroupRef DR) override {
310 for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {
311 Visitor.TraverseDecl(*b);
312 }
313 return true;
314 }
315
316 private:
317 SBVisitor Visitor;
318 };
319
320 class SBAction : public ASTFrontendAction {
321 public:
322 SBAction() = default;
323
BeginSourceFileAction(CompilerInstance & CI)324 bool BeginSourceFileAction(CompilerInstance &CI) override {
325 llvm::outs() << "{\n";
326 return true;
327 }
328
EndSourceFileAction()329 void EndSourceFileAction() override {
330 llvm::outs() << "}\n";
331 MyRewriter.overwriteChangedFiles();
332 }
333
CreateASTConsumer(CompilerInstance & CI,StringRef File)334 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
335 StringRef File) override {
336 MyRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());
337 return std::make_unique<SBConsumer>(MyRewriter, CI.getASTContext());
338 }
339
340 private:
341 Rewriter MyRewriter;
342 };
343
main(int argc,const char ** argv)344 int main(int argc, const char **argv) {
345 CommonOptionsParser OP(argc, argv, InstrCategory,
346 "Utility for generating the macros for LLDB's "
347 "instrumentation framework.");
348
349 auto PCHOpts = std::make_shared<PCHContainerOperations>();
350 PCHOpts->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());
351 PCHOpts->registerReader(std::make_unique<ObjectFilePCHContainerReader>());
352
353 ClangTool T(OP.getCompilations(), OP.getSourcePathList(), PCHOpts);
354 return T.run(newFrontendActionFactory<SBAction>().get());
355 }
356