LLDB mainline
ASTResultSynthesizer.cpp
Go to the documentation of this file.
1//===-- ASTResultSynthesizer.cpp ------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
11#include "ClangASTImporter.h"
13
15#include "lldb/Target/Target.h"
18#include "lldb/Utility/Log.h"
19#include "clang/AST/ASTContext.h"
20#include "clang/AST/Decl.h"
21#include "clang/AST/DeclCXX.h"
22#include "clang/AST/DeclGroup.h"
23#include "clang/AST/DeclObjC.h"
24#include "clang/AST/Expr.h"
25#include "clang/AST/Stmt.h"
26#include "clang/Parse/Parser.h"
27#include "clang/Sema/SemaDiagnostic.h"
28#include "llvm/Support/Casting.h"
29#include "llvm/Support/raw_ostream.h"
30#include <cstdlib>
31
32using namespace llvm;
33using namespace clang;
34using namespace lldb_private;
35
37 bool top_level, Target &target)
38 : m_ast_context(nullptr), m_passthrough(passthrough),
39 m_passthrough_sema(nullptr), m_target(target), m_sema(nullptr),
40 m_top_level(top_level) {
41 if (!m_passthrough)
42 return;
43
44 m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough);
45}
46
48
49void ASTResultSynthesizer::Initialize(ASTContext &Context) {
50 m_ast_context = &Context;
51
52 if (m_passthrough)
53 m_passthrough->Initialize(Context);
54}
55
58
59 if (NamedDecl *named_decl = dyn_cast<NamedDecl>(D)) {
60 if (log && log->GetVerbose()) {
61 if (named_decl->getIdentifier())
62 LLDB_LOGF(log, "TransformTopLevelDecl(%s)",
63 named_decl->getIdentifier()->getNameStart());
64 else if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D))
65 LLDB_LOGF(log, "TransformTopLevelDecl(%s)",
66 method_decl->getSelector().getAsString().c_str());
67 else
68 LLDB_LOGF(log, "TransformTopLevelDecl(<complex>)");
69 }
70
71 if (m_top_level) {
72 RecordPersistentDecl(named_decl);
73 }
74 }
75
76 if (LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D)) {
77 RecordDecl::decl_iterator decl_iterator;
78
79 for (decl_iterator = linkage_spec_decl->decls_begin();
80 decl_iterator != linkage_spec_decl->decls_end(); ++decl_iterator) {
81 TransformTopLevelDecl(*decl_iterator);
82 }
83 } else if (!m_top_level) {
84 if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D)) {
85 if (m_ast_context &&
86 !method_decl->getSelector().getAsString().compare("$__lldb_expr:")) {
87 RecordPersistentTypes(method_decl);
88 SynthesizeObjCMethodResult(method_decl);
89 }
90 } else if (FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D)) {
91 // When completing user input the body of the function may be a nullptr.
92 if (m_ast_context && function_decl->hasBody() &&
93 !function_decl->getNameInfo().getAsString().compare("$__lldb_expr")) {
94 RecordPersistentTypes(function_decl);
95 SynthesizeFunctionResult(function_decl);
96 }
97 }
98 }
99}
100
102 DeclGroupRef::iterator decl_iterator;
103
104 for (decl_iterator = D.begin(); decl_iterator != D.end(); ++decl_iterator) {
105 Decl *decl = *decl_iterator;
106
108 }
109
110 if (m_passthrough)
111 return m_passthrough->HandleTopLevelDecl(D);
112 return true;
113}
114
117
118 if (!m_sema)
119 return false;
120
121 FunctionDecl *function_decl = FunDecl;
122
123 if (!function_decl)
124 return false;
125
126 if (log && log->GetVerbose()) {
127 std::string s;
128 raw_string_ostream os(s);
129
130 function_decl->print(os);
131
132 os.flush();
133
134 LLDB_LOGF(log, "Untransformed function AST:\n%s", s.c_str());
135 }
136
137 Stmt *function_body = function_decl->getBody();
138 CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(function_body);
139
140 bool ret = SynthesizeBodyResult(compound_stmt, function_decl);
141
142 if (log && log->GetVerbose()) {
143 std::string s;
144 raw_string_ostream os(s);
145
146 function_decl->print(os);
147
148 os.flush();
149
150 LLDB_LOGF(log, "Transformed function AST:\n%s", s.c_str());
151 }
152
153 return ret;
154}
155
157 ObjCMethodDecl *MethodDecl) {
159
160 if (!m_sema)
161 return false;
162
163 if (!MethodDecl)
164 return false;
165
166 if (log && log->GetVerbose()) {
167 std::string s;
168 raw_string_ostream os(s);
169
170 MethodDecl->print(os);
171
172 os.flush();
173
174 LLDB_LOGF(log, "Untransformed method AST:\n%s", s.c_str());
175 }
176
177 Stmt *method_body = MethodDecl->getBody();
178
179 if (!method_body)
180 return false;
181
182 CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(method_body);
183
184 bool ret = SynthesizeBodyResult(compound_stmt, MethodDecl);
185
186 if (log && log->GetVerbose()) {
187 std::string s;
188 raw_string_ostream os(s);
189
190 MethodDecl->print(os);
191
192 os.flush();
193
194 LLDB_LOGF(log, "Transformed method AST:\n%s", s.c_str());
195 }
196
197 return ret;
198}
199
200/// Returns true if LLDB can take the address of the given lvalue for the sake
201/// of capturing the expression result. Returns false if LLDB should instead
202/// store the expression result in a result variable.
203static bool CanTakeAddressOfLValue(const Expr *lvalue_expr) {
204 assert(lvalue_expr->getValueKind() == VK_LValue &&
205 "lvalue_expr not a lvalue");
206
207 QualType qt = lvalue_expr->getType();
208 // If the lvalue has const-qualified non-volatile integral or enum type, then
209 // the underlying value might come from a const static data member as
210 // described in C++11 [class.static.data]p3. If that's the case, then the
211 // value might not have an address if the user didn't also define the member
212 // in a namespace scope. Taking the address would cause that LLDB later fails
213 // to link the expression, so those lvalues should be stored in a result
214 // variable.
215 if (qt->isIntegralOrEnumerationType() && qt.isConstQualified() &&
216 !qt.isVolatileQualified())
217 return false;
218 return true;
219}
220
222 DeclContext *DC) {
224
225 ASTContext &Ctx(*m_ast_context);
226
227 if (!Body)
228 return false;
229
230 if (Body->body_empty())
231 return false;
232
233 Stmt **last_stmt_ptr = Body->body_end() - 1;
234 Stmt *last_stmt = *last_stmt_ptr;
235
236 while (isa<NullStmt>(last_stmt)) {
237 if (last_stmt_ptr != Body->body_begin()) {
238 last_stmt_ptr--;
239 last_stmt = *last_stmt_ptr;
240 } else {
241 return false;
242 }
243 }
244
245 Expr *last_expr = dyn_cast<Expr>(last_stmt);
246
247 if (!last_expr)
248 // No auxiliary variable necessary; expression returns void
249 return true;
250
251 // In C++11, last_expr can be a LValueToRvalue implicit cast. Strip that off
252 // if that's the case.
253
254 do {
255 ImplicitCastExpr *implicit_cast = dyn_cast<ImplicitCastExpr>(last_expr);
256
257 if (!implicit_cast)
258 break;
259
260 if (implicit_cast->getCastKind() != CK_LValueToRValue)
261 break;
262
263 last_expr = implicit_cast->getSubExpr();
264 } while (false);
265
266 // is_lvalue is used to record whether the expression returns an assignable
267 // Lvalue or an Rvalue. This is relevant because they are handled
268 // differently.
269 //
270 // For Lvalues
271 //
272 // - In AST result synthesis (here!) the expression E is transformed into an
273 // initialization T *$__lldb_expr_result_ptr = &E.
274 //
275 // - In structure allocation, a pointer-sized slot is allocated in the
276 // struct that is to be passed into the expression.
277 //
278 // - In IR transformations, reads and writes to $__lldb_expr_result_ptr are
279 // redirected at an entry in the struct ($__lldb_arg) passed into the
280 // expression. (Other persistent variables are treated similarly, having
281 // been materialized as references, but in those cases the value of the
282 // reference itself is never modified.)
283 //
284 // - During materialization, $0 (the result persistent variable) is ignored.
285 //
286 // - During dematerialization, $0 is marked up as a load address with value
287 // equal to the contents of the structure entry.
288 //
289 // - Note: if we cannot take an address of the resulting Lvalue (e.g. it's
290 // a static const member without an out-of-class definition), then we
291 // follow the Rvalue route.
292 //
293 // For Rvalues
294 //
295 // - In AST result synthesis the expression E is transformed into an
296 // initialization static T $__lldb_expr_result = E.
297 //
298 // - In structure allocation, a pointer-sized slot is allocated in the
299 // struct that is to be passed into the expression.
300 //
301 // - In IR transformations, an instruction is inserted at the beginning of
302 // the function to dereference the pointer resident in the slot. Reads and
303 // writes to $__lldb_expr_result are redirected at that dereferenced
304 // version. Guard variables for the static variable are excised.
305 //
306 // - During materialization, $0 (the result persistent variable) is
307 // populated with the location of a newly-allocated area of memory.
308 //
309 // - During dematerialization, $0 is ignored.
310
311 bool is_lvalue = last_expr->getValueKind() == VK_LValue &&
312 last_expr->getObjectKind() == OK_Ordinary;
313
314 QualType expr_qual_type = last_expr->getType();
315 const clang::Type *expr_type = expr_qual_type.getTypePtr();
316
317 if (!expr_type)
318 return false;
319
320 if (expr_type->isVoidType())
321 return true;
322
323 if (log) {
324 std::string s = expr_qual_type.getAsString();
325
326 LLDB_LOGF(log, "Last statement is an %s with type: %s",
327 (is_lvalue ? "lvalue" : "rvalue"), s.c_str());
328 }
329
330 clang::VarDecl *result_decl = nullptr;
331
332 if (is_lvalue && CanTakeAddressOfLValue(last_expr)) {
333 IdentifierInfo *result_ptr_id;
334
335 if (expr_type->isFunctionType())
336 result_ptr_id =
337 &Ctx.Idents.get("$__lldb_expr_result"); // functions actually should
338 // be treated like function
339 // pointers
340 else
341 result_ptr_id = &Ctx.Idents.get("$__lldb_expr_result_ptr");
342
343 m_sema->RequireCompleteType(last_expr->getSourceRange().getBegin(),
344 expr_qual_type,
345 clang::diag::err_incomplete_type);
346
347 QualType ptr_qual_type;
348
349 if (expr_qual_type->getAs<ObjCObjectType>() != nullptr)
350 ptr_qual_type = Ctx.getObjCObjectPointerType(expr_qual_type);
351 else
352 ptr_qual_type = Ctx.getPointerType(expr_qual_type);
353
354 result_decl =
355 VarDecl::Create(Ctx, DC, SourceLocation(), SourceLocation(),
356 result_ptr_id, ptr_qual_type, nullptr, SC_Static);
357
358 if (!result_decl)
359 return false;
360
361 ExprResult address_of_expr =
362 m_sema->CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, last_expr);
363 if (address_of_expr.get())
364 m_sema->AddInitializerToDecl(result_decl, address_of_expr.get(), true);
365 else
366 return false;
367 } else {
368 IdentifierInfo &result_id = Ctx.Idents.get("$__lldb_expr_result");
369
370 result_decl =
371 VarDecl::Create(Ctx, DC, SourceLocation(), SourceLocation(), &result_id,
372 expr_qual_type, nullptr, SC_Static);
373
374 if (!result_decl)
375 return false;
376
377 m_sema->AddInitializerToDecl(result_decl, last_expr, true);
378 }
379
380 DC->addDecl(result_decl);
381
382 ///////////////////////////////
383 // call AddInitializerToDecl
384 //
385
386 // m_sema->AddInitializerToDecl(result_decl, last_expr);
387
388 /////////////////////////////////
389 // call ConvertDeclToDeclGroup
390 //
391
392 Sema::DeclGroupPtrTy result_decl_group_ptr;
393
394 result_decl_group_ptr = m_sema->ConvertDeclToDeclGroup(result_decl);
395
396 ////////////////////////
397 // call ActOnDeclStmt
398 //
399
400 StmtResult result_initialization_stmt_result(m_sema->ActOnDeclStmt(
401 result_decl_group_ptr, SourceLocation(), SourceLocation()));
402
403 ////////////////////////////////////////////////
404 // replace the old statement with the new one
405 //
406
407 *last_stmt_ptr = static_cast<Stmt *>(result_initialization_stmt_result.get());
408
409 return true;
410}
411
413 if (m_passthrough)
414 m_passthrough->HandleTranslationUnit(Ctx);
415}
416
417void ASTResultSynthesizer::RecordPersistentTypes(DeclContext *FunDeclCtx) {
418 typedef DeclContext::specific_decl_iterator<TypeDecl> TypeDeclIterator;
419
420 for (TypeDeclIterator i = TypeDeclIterator(FunDeclCtx->decls_begin()),
421 e = TypeDeclIterator(FunDeclCtx->decls_end());
422 i != e; ++i) {
424 }
425}
426
428 if (!D->getIdentifier())
429 return;
430
431 StringRef name = D->getName();
432 if (name.empty() || name.front() != '$')
433 return;
434
435 LLDB_LOG(GetLog(LLDBLog::Expressions), "Recording persistent type {0}", name);
436
437 m_decls.push_back(D);
438}
439
442
443 if (!D->getIdentifier())
444 return;
445
446 StringRef name = D->getName();
447 if (name.empty())
448 return;
449
450 LLDB_LOG(GetLog(LLDBLog::Expressions), "Recording persistent decl {0}", name);
451
452 m_decls.push_back(D);
453}
454
456 auto *state =
458 if (!state)
459 return;
460
461 auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state);
462
464 m_target, m_ast_context->getLangOpts());
465
466 for (clang::NamedDecl *decl : m_decls) {
467 StringRef name = decl->getName();
468
469 Decl *D_scratch = persistent_vars->GetClangASTImporter()->DeportDecl(
470 &scratch_ts_sp->getASTContext(), decl);
471
472 if (!D_scratch) {
474
475 if (log) {
476 std::string s;
477 llvm::raw_string_ostream ss(s);
478 decl->dump(ss);
479 ss.flush();
480
481 LLDB_LOGF(log, "Couldn't commit persistent decl: %s\n", s.c_str());
482 }
483
484 continue;
485 }
486
487 if (NamedDecl *NamedDecl_scratch = dyn_cast<NamedDecl>(D_scratch))
488 persistent_vars->RegisterPersistentDecl(ConstString(name),
489 NamedDecl_scratch, scratch_ts_sp);
490 }
491}
492
494 if (m_passthrough)
495 m_passthrough->HandleTagDeclDefinition(D);
496}
497
499 if (m_passthrough)
500 m_passthrough->CompleteTentativeDefinition(D);
501}
502
503void ASTResultSynthesizer::HandleVTable(CXXRecordDecl *RD) {
504 if (m_passthrough)
505 m_passthrough->HandleVTable(RD);
506}
507
509 if (m_passthrough)
510 m_passthrough->PrintStats();
511}
512
514 m_sema = &S;
515
517 m_passthrough_sema->InitializeSema(S);
518}
519
521 m_sema = nullptr;
522
524 m_passthrough_sema->ForgetSema();
525}
static bool CanTakeAddressOfLValue(const Expr *lvalue_expr)
Returns true if LLDB can take the address of the given lvalue for the sake of capturing the expressio...
#define lldbassert(x)
Definition: LLDBAssert.h:15
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition: Log.h:342
#define LLDB_LOGF(log,...)
Definition: Log.h:349
clang::ASTContext * m_ast_context
The AST context to use for identifiers and types.
clang::ASTConsumer * m_passthrough
The ASTConsumer down the chain, for passthrough.
clang::SemaConsumer * m_passthrough_sema
The SemaConsumer down the chain, for passthrough.
void CommitPersistentDecls()
The parse has succeeded, so record its persistent decls.
void RecordPersistentTypes(clang::DeclContext *FunDeclCtx)
Given a DeclContext for a function or method, find all types declared in the context and record any p...
void RecordPersistentDecl(clang::NamedDecl *D)
Given a NamedDecl, register it as a pointer type in the target's scratch AST context.
bool SynthesizeBodyResult(clang::CompoundStmt *Body, clang::DeclContext *DC)
Process a function body and produce the result variable and initialization.
bool SynthesizeFunctionResult(clang::FunctionDecl *FunDecl)
Process a function and produce the result variable and initialization.
Target & m_target
The target, which contains the persistent variable store and the.
~ASTResultSynthesizer() override
Destructor.
ASTResultSynthesizer(clang::ASTConsumer *passthrough, bool top_level, Target &target)
Constructor.
void HandleTagDeclDefinition(clang::TagDecl *D) override
Passthrough stub.
void InitializeSema(clang::Sema &S) override
Set the Sema object to use when performing transforms, and pass it on.
void TransformTopLevelDecl(clang::Decl *D)
Hunt the given Decl for FunctionDecls named $__lldb_expr, recursing as necessary through LinkageSpecD...
bool SynthesizeObjCMethodResult(clang::ObjCMethodDecl *MethodDecl)
Process an Objective-C method and produce the result variable and initialization.
bool HandleTopLevelDecl(clang::DeclGroupRef D) override
Examine a list of Decls to find the function $__lldb_expr and transform its code.
std::vector< clang::NamedDecl * > m_decls
Persistent declarations to register assuming the expression succeeds.
void CompleteTentativeDefinition(clang::VarDecl *D) override
Passthrough stub.
void HandleVTable(clang::CXXRecordDecl *RD) override
Passthrough stub.
void HandleTranslationUnit(clang::ASTContext &Ctx) override
Passthrough stub.
void ForgetSema() override
Reset the Sema to NULL now that transformations are done.
void PrintStats() override
Passthrough stub.
void Initialize(clang::ASTContext &Context) override
Link this consumer with a particular AST context.
void MaybeRecordPersistentType(clang::TypeDecl *D)
Given a TypeDecl, if it declares a type whose name starts with a dollar sign, register it as a pointe...
clang::Sema * m_sema
The Sema to use.
A uniqued constant string class.
Definition: ConstString.h:40
bool GetVerbose() const
Definition: Log.cpp:313
static lldb::TypeSystemClangSP GetForTarget(Target &target, std::optional< IsolatedASTKind > ast_kind=DefaultAST, bool create_on_demand=true)
Returns the scratch TypeSystemClang for the given target.
PersistentExpressionState * GetPersistentExpressionStateForLanguage(lldb::LanguageType language)
Definition: Target.cpp:2486
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:314
@ eLanguageTypeC
Non-standardized C, such as K&R.
std::shared_ptr< lldb_private::TypeSystemClang > TypeSystemClangSP
Definition: lldb-forward.h:458
Definition: Debugger.h:53