1 //===-- AppleObjCDeclVendor.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
9 #include "AppleObjCDeclVendor.h"
10
11 #include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
12 #include "Plugins/ExpressionParser/Clang/ClangUtil.h"
13 #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
14 #include "lldb/Core/Module.h"
15 #include "lldb/Target/Process.h"
16 #include "lldb/Target/Target.h"
17 #include "lldb/Utility/Log.h"
18
19 #include "clang/AST/ASTContext.h"
20 #include "clang/AST/DeclObjC.h"
21 #include "clang/AST/ExternalASTSource.h"
22
23 using namespace lldb_private;
24
25 class lldb_private::AppleObjCExternalASTSource
26 : public clang::ExternalASTSource {
27 public:
AppleObjCExternalASTSource(AppleObjCDeclVendor & decl_vendor)28 AppleObjCExternalASTSource(AppleObjCDeclVendor &decl_vendor)
29 : m_decl_vendor(decl_vendor) {}
30
FindExternalVisibleDeclsByName(const clang::DeclContext * decl_ctx,clang::DeclarationName name)31 bool FindExternalVisibleDeclsByName(const clang::DeclContext *decl_ctx,
32 clang::DeclarationName name) override {
33
34 Log *log(GetLogIfAllCategoriesSet(
35 LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
36
37 if (log) {
38 LLDB_LOGF(log,
39 "AppleObjCExternalASTSource::FindExternalVisibleDeclsByName"
40 " on (ASTContext*)%p Looking for %s in (%sDecl*)%p",
41 static_cast<void *>(&decl_ctx->getParentASTContext()),
42 name.getAsString().c_str(), decl_ctx->getDeclKindName(),
43 static_cast<const void *>(decl_ctx));
44 }
45
46 do {
47 const clang::ObjCInterfaceDecl *interface_decl =
48 llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl_ctx);
49
50 if (!interface_decl)
51 break;
52
53 clang::ObjCInterfaceDecl *non_const_interface_decl =
54 const_cast<clang::ObjCInterfaceDecl *>(interface_decl);
55
56 if (!m_decl_vendor.FinishDecl(non_const_interface_decl))
57 break;
58
59 clang::DeclContext::lookup_result result =
60 non_const_interface_decl->lookup(name);
61
62 return (result.size() != 0);
63 } while (false);
64
65 SetNoExternalVisibleDeclsForName(decl_ctx, name);
66 return false;
67 }
68
CompleteType(clang::TagDecl * tag_decl)69 void CompleteType(clang::TagDecl *tag_decl) override {
70
71 Log *log(GetLogIfAllCategoriesSet(
72 LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
73
74 LLDB_LOGF(log,
75 "AppleObjCExternalASTSource::CompleteType on "
76 "(ASTContext*)%p Completing (TagDecl*)%p named %s",
77 static_cast<void *>(&tag_decl->getASTContext()),
78 static_cast<void *>(tag_decl), tag_decl->getName().str().c_str());
79
80 LLDB_LOG(log, " AOEAS::CT Before:\n{1}", ClangUtil::DumpDecl(tag_decl));
81
82 LLDB_LOG(log, " AOEAS::CT After:{1}", ClangUtil::DumpDecl(tag_decl));
83
84 return;
85 }
86
CompleteType(clang::ObjCInterfaceDecl * interface_decl)87 void CompleteType(clang::ObjCInterfaceDecl *interface_decl) override {
88
89 Log *log(GetLogIfAllCategoriesSet(
90 LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
91
92 if (log) {
93 LLDB_LOGF(log,
94 "AppleObjCExternalASTSource::CompleteType on "
95 "(ASTContext*)%p Completing (ObjCInterfaceDecl*)%p named %s",
96 static_cast<void *>(&interface_decl->getASTContext()),
97 static_cast<void *>(interface_decl),
98 interface_decl->getName().str().c_str());
99
100 LLDB_LOGF(log, " AOEAS::CT Before:");
101 LLDB_LOG(log, " [CT] {0}", ClangUtil::DumpDecl(interface_decl));
102 }
103
104 m_decl_vendor.FinishDecl(interface_decl);
105
106 if (log) {
107 LLDB_LOGF(log, " [CT] After:");
108 LLDB_LOG(log, " [CT] {0}", ClangUtil::DumpDecl(interface_decl));
109 }
110 return;
111 }
112
layoutRecordType(const clang::RecordDecl * Record,uint64_t & Size,uint64_t & Alignment,llvm::DenseMap<const clang::FieldDecl *,uint64_t> & FieldOffsets,llvm::DenseMap<const clang::CXXRecordDecl *,clang::CharUnits> & BaseOffsets,llvm::DenseMap<const clang::CXXRecordDecl *,clang::CharUnits> & VirtualBaseOffsets)113 bool layoutRecordType(
114 const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
115 llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
116 llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
117 &BaseOffsets,
118 llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
119 &VirtualBaseOffsets) override {
120 return false;
121 }
122
StartTranslationUnit(clang::ASTConsumer * Consumer)123 void StartTranslationUnit(clang::ASTConsumer *Consumer) override {
124 clang::TranslationUnitDecl *translation_unit_decl =
125 m_decl_vendor.m_ast_ctx.getASTContext().getTranslationUnitDecl();
126 translation_unit_decl->setHasExternalVisibleStorage();
127 translation_unit_decl->setHasExternalLexicalStorage();
128 }
129
130 private:
131 AppleObjCDeclVendor &m_decl_vendor;
132 };
133
AppleObjCDeclVendor(ObjCLanguageRuntime & runtime)134 AppleObjCDeclVendor::AppleObjCDeclVendor(ObjCLanguageRuntime &runtime)
135 : ClangDeclVendor(eAppleObjCDeclVendor), m_runtime(runtime),
136 m_ast_ctx(
137 "AppleObjCDeclVendor AST",
138 runtime.GetProcess()->GetTarget().GetArchitecture().GetTriple()),
139 m_type_realizer_sp(m_runtime.GetEncodingToType()) {
140 m_external_source = new AppleObjCExternalASTSource(*this);
141 llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> external_source_owning_ptr(
142 m_external_source);
143 m_ast_ctx.getASTContext().setExternalSource(external_source_owning_ptr);
144 }
145
146 clang::ObjCInterfaceDecl *
GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa)147 AppleObjCDeclVendor::GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa) {
148 ISAToInterfaceMap::const_iterator iter = m_isa_to_interface.find(isa);
149
150 if (iter != m_isa_to_interface.end())
151 return iter->second;
152
153 clang::ASTContext &ast_ctx = m_ast_ctx.getASTContext();
154
155 ObjCLanguageRuntime::ClassDescriptorSP descriptor =
156 m_runtime.GetClassDescriptorFromISA(isa);
157
158 if (!descriptor)
159 return nullptr;
160
161 ConstString name(descriptor->GetClassName());
162
163 clang::IdentifierInfo &identifier_info =
164 ast_ctx.Idents.get(name.GetStringRef());
165
166 clang::ObjCInterfaceDecl *new_iface_decl = clang::ObjCInterfaceDecl::Create(
167 ast_ctx, ast_ctx.getTranslationUnitDecl(), clang::SourceLocation(),
168 &identifier_info, nullptr, nullptr);
169
170 ClangASTMetadata meta_data;
171 meta_data.SetISAPtr(isa);
172 m_ast_ctx.SetMetadata(new_iface_decl, meta_data);
173
174 new_iface_decl->setHasExternalVisibleStorage();
175 new_iface_decl->setHasExternalLexicalStorage();
176
177 ast_ctx.getTranslationUnitDecl()->addDecl(new_iface_decl);
178
179 m_isa_to_interface[isa] = new_iface_decl;
180
181 return new_iface_decl;
182 }
183
184 class ObjCRuntimeMethodType {
185 public:
ObjCRuntimeMethodType(const char * types)186 ObjCRuntimeMethodType(const char *types) : m_is_valid(false) {
187 const char *cursor = types;
188 enum ParserState { Start = 0, InType, InPos } state = Start;
189 const char *type = nullptr;
190 int brace_depth = 0;
191
192 uint32_t stepsLeft = 256;
193
194 while (true) {
195 if (--stepsLeft == 0) {
196 m_is_valid = false;
197 return;
198 }
199
200 switch (state) {
201 case Start: {
202 switch (*cursor) {
203 default:
204 state = InType;
205 type = cursor;
206 break;
207 case '\0':
208 m_is_valid = true;
209 return;
210 case '0':
211 case '1':
212 case '2':
213 case '3':
214 case '4':
215 case '5':
216 case '6':
217 case '7':
218 case '8':
219 case '9':
220 m_is_valid = false;
221 return;
222 }
223 } break;
224 case InType: {
225 switch (*cursor) {
226 default:
227 ++cursor;
228 break;
229 case '0':
230 case '1':
231 case '2':
232 case '3':
233 case '4':
234 case '5':
235 case '6':
236 case '7':
237 case '8':
238 case '9':
239 if (!brace_depth) {
240 state = InPos;
241 if (type) {
242 m_type_vector.push_back(std::string(type, (cursor - type)));
243 } else {
244 m_is_valid = false;
245 return;
246 }
247 type = nullptr;
248 } else {
249 ++cursor;
250 }
251 break;
252 case '[':
253 case '{':
254 case '(':
255 ++brace_depth;
256 ++cursor;
257 break;
258 case ']':
259 case '}':
260 case ')':
261 if (!brace_depth) {
262 m_is_valid = false;
263 return;
264 }
265 --brace_depth;
266 ++cursor;
267 break;
268 case '\0':
269 m_is_valid = false;
270 return;
271 }
272 } break;
273 case InPos: {
274 switch (*cursor) {
275 default:
276 state = InType;
277 type = cursor;
278 break;
279 case '0':
280 case '1':
281 case '2':
282 case '3':
283 case '4':
284 case '5':
285 case '6':
286 case '7':
287 case '8':
288 case '9':
289 ++cursor;
290 break;
291 case '\0':
292 m_is_valid = true;
293 return;
294 }
295 } break;
296 }
297 }
298 }
299
300 clang::ObjCMethodDecl *
BuildMethod(TypeSystemClang & clang_ast_ctxt,clang::ObjCInterfaceDecl * interface_decl,const char * name,bool instance,ObjCLanguageRuntime::EncodingToTypeSP type_realizer_sp)301 BuildMethod(TypeSystemClang &clang_ast_ctxt,
302 clang::ObjCInterfaceDecl *interface_decl, const char *name,
303 bool instance,
304 ObjCLanguageRuntime::EncodingToTypeSP type_realizer_sp) {
305 if (!m_is_valid || m_type_vector.size() < 3)
306 return nullptr;
307
308 clang::ASTContext &ast_ctx(interface_decl->getASTContext());
309
310 const bool isInstance = instance;
311 const bool isVariadic = false;
312 const bool isPropertyAccessor = false;
313 const bool isSynthesizedAccessorStub = false;
314 const bool isImplicitlyDeclared = true;
315 const bool isDefined = false;
316 const clang::ObjCMethodDecl::ImplementationControl impControl =
317 clang::ObjCMethodDecl::None;
318 const bool HasRelatedResultType = false;
319 const bool for_expression = true;
320
321 std::vector<clang::IdentifierInfo *> selector_components;
322
323 const char *name_cursor = name;
324 bool is_zero_argument = true;
325
326 while (*name_cursor != '\0') {
327 const char *colon_loc = strchr(name_cursor, ':');
328 if (!colon_loc) {
329 selector_components.push_back(
330 &ast_ctx.Idents.get(llvm::StringRef(name_cursor)));
331 break;
332 } else {
333 is_zero_argument = false;
334 selector_components.push_back(&ast_ctx.Idents.get(
335 llvm::StringRef(name_cursor, colon_loc - name_cursor)));
336 name_cursor = colon_loc + 1;
337 }
338 }
339
340 clang::IdentifierInfo **identifier_infos = selector_components.data();
341 if (!identifier_infos) {
342 return nullptr;
343 }
344
345 clang::Selector sel = ast_ctx.Selectors.getSelector(
346 is_zero_argument ? 0 : selector_components.size(),
347 identifier_infos);
348
349 clang::QualType ret_type =
350 ClangUtil::GetQualType(type_realizer_sp->RealizeType(
351 clang_ast_ctxt, m_type_vector[0].c_str(), for_expression));
352
353 if (ret_type.isNull())
354 return nullptr;
355
356 clang::ObjCMethodDecl *ret = clang::ObjCMethodDecl::Create(
357 ast_ctx, clang::SourceLocation(), clang::SourceLocation(), sel,
358 ret_type, nullptr, interface_decl, isInstance, isVariadic,
359 isPropertyAccessor, isSynthesizedAccessorStub, isImplicitlyDeclared,
360 isDefined, impControl, HasRelatedResultType);
361
362 std::vector<clang::ParmVarDecl *> parm_vars;
363
364 for (size_t ai = 3, ae = m_type_vector.size(); ai != ae; ++ai) {
365 const bool for_expression = true;
366 clang::QualType arg_type =
367 ClangUtil::GetQualType(type_realizer_sp->RealizeType(
368 clang_ast_ctxt, m_type_vector[ai].c_str(), for_expression));
369
370 if (arg_type.isNull())
371 return nullptr; // well, we just wasted a bunch of time. Wish we could
372 // delete the stuff we'd just made!
373
374 parm_vars.push_back(clang::ParmVarDecl::Create(
375 ast_ctx, ret, clang::SourceLocation(), clang::SourceLocation(),
376 nullptr, arg_type, nullptr, clang::SC_None, nullptr));
377 }
378
379 ret->setMethodParams(ast_ctx,
380 llvm::ArrayRef<clang::ParmVarDecl *>(parm_vars),
381 llvm::ArrayRef<clang::SourceLocation>());
382
383 return ret;
384 }
385
operator bool()386 explicit operator bool() { return m_is_valid; }
387
GetNumTypes()388 size_t GetNumTypes() { return m_type_vector.size(); }
389
GetTypeAtIndex(size_t idx)390 const char *GetTypeAtIndex(size_t idx) { return m_type_vector[idx].c_str(); }
391
392 private:
393 typedef std::vector<std::string> TypeVector;
394
395 TypeVector m_type_vector;
396 bool m_is_valid;
397 };
398
FinishDecl(clang::ObjCInterfaceDecl * interface_decl)399 bool AppleObjCDeclVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl) {
400 Log *log(GetLogIfAllCategoriesSet(
401 LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
402
403 ClangASTMetadata *metadata = m_ast_ctx.GetMetadata(interface_decl);
404 ObjCLanguageRuntime::ObjCISA objc_isa = 0;
405 if (metadata)
406 objc_isa = metadata->GetISAPtr();
407
408 if (!objc_isa)
409 return false;
410
411 if (!interface_decl->hasExternalVisibleStorage())
412 return true;
413
414 interface_decl->startDefinition();
415
416 interface_decl->setHasExternalVisibleStorage(false);
417 interface_decl->setHasExternalLexicalStorage(false);
418
419 ObjCLanguageRuntime::ClassDescriptorSP descriptor =
420 m_runtime.GetClassDescriptorFromISA(objc_isa);
421
422 if (!descriptor)
423 return false;
424
425 auto superclass_func = [interface_decl,
426 this](ObjCLanguageRuntime::ObjCISA isa) {
427 clang::ObjCInterfaceDecl *superclass_decl = GetDeclForISA(isa);
428
429 if (!superclass_decl)
430 return;
431
432 FinishDecl(superclass_decl);
433 clang::ASTContext &context = m_ast_ctx.getASTContext();
434 interface_decl->setSuperClass(context.getTrivialTypeSourceInfo(
435 context.getObjCInterfaceType(superclass_decl)));
436 };
437
438 auto instance_method_func =
439 [log, interface_decl, this](const char *name, const char *types) -> bool {
440 if (!name || !types)
441 return false; // skip this one
442
443 ObjCRuntimeMethodType method_type(types);
444
445 clang::ObjCMethodDecl *method_decl = method_type.BuildMethod(
446 m_ast_ctx, interface_decl, name, true, m_type_realizer_sp);
447
448 LLDB_LOGF(log, "[ AOTV::FD] Instance method [%s] [%s]", name, types);
449
450 if (method_decl)
451 interface_decl->addDecl(method_decl);
452
453 return false;
454 };
455
456 auto class_method_func = [log, interface_decl,
457 this](const char *name, const char *types) -> bool {
458 if (!name || !types)
459 return false; // skip this one
460
461 ObjCRuntimeMethodType method_type(types);
462
463 clang::ObjCMethodDecl *method_decl = method_type.BuildMethod(
464 m_ast_ctx, interface_decl, name, false, m_type_realizer_sp);
465
466 LLDB_LOGF(log, "[ AOTV::FD] Class method [%s] [%s]", name, types);
467
468 if (method_decl)
469 interface_decl->addDecl(method_decl);
470
471 return false;
472 };
473
474 auto ivar_func = [log, interface_decl,
475 this](const char *name, const char *type,
476 lldb::addr_t offset_ptr, uint64_t size) -> bool {
477 if (!name || !type)
478 return false;
479
480 const bool for_expression = false;
481
482 LLDB_LOGF(log,
483 "[ AOTV::FD] Instance variable [%s] [%s], offset at %" PRIx64,
484 name, type, offset_ptr);
485
486 CompilerType ivar_type = m_runtime.GetEncodingToType()->RealizeType(
487 m_ast_ctx, type, for_expression);
488
489 if (ivar_type.IsValid()) {
490 clang::TypeSourceInfo *const type_source_info = nullptr;
491 const bool is_synthesized = false;
492 clang::ObjCIvarDecl *ivar_decl = clang::ObjCIvarDecl::Create(
493 m_ast_ctx.getASTContext(), interface_decl, clang::SourceLocation(),
494 clang::SourceLocation(), &m_ast_ctx.getASTContext().Idents.get(name),
495 ClangUtil::GetQualType(ivar_type),
496 type_source_info, // TypeSourceInfo *
497 clang::ObjCIvarDecl::Public, nullptr, is_synthesized);
498
499 if (ivar_decl) {
500 interface_decl->addDecl(ivar_decl);
501 }
502 }
503
504 return false;
505 };
506
507 LLDB_LOG(log,
508 "[AppleObjCDeclVendor::FinishDecl] Finishing Objective-C "
509 "interface for %s",
510 descriptor->GetClassName().AsCString());
511
512 if (!descriptor->Describe(superclass_func, instance_method_func,
513 class_method_func, ivar_func))
514 return false;
515
516 if (log) {
517 LLDB_LOGF(
518 log,
519 "[AppleObjCDeclVendor::FinishDecl] Finished Objective-C interface");
520
521 LLDB_LOG(log, " [AOTV::FD] {0}", ClangUtil::DumpDecl(interface_decl));
522 }
523
524 return true;
525 }
526
FindDecls(ConstString name,bool append,uint32_t max_matches,std::vector<CompilerDecl> & decls)527 uint32_t AppleObjCDeclVendor::FindDecls(ConstString name, bool append,
528 uint32_t max_matches,
529 std::vector<CompilerDecl> &decls) {
530
531 Log *log(GetLogIfAllCategoriesSet(
532 LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
533
534 LLDB_LOGF(log, "AppleObjCDeclVendor::FindDecls ('%s', %s, %u, )",
535 (const char *)name.AsCString(), append ? "true" : "false",
536 max_matches);
537
538 if (!append)
539 decls.clear();
540
541 uint32_t ret = 0;
542
543 do {
544 // See if the type is already in our ASTContext.
545
546 clang::ASTContext &ast_ctx = m_ast_ctx.getASTContext();
547
548 clang::IdentifierInfo &identifier_info =
549 ast_ctx.Idents.get(name.GetStringRef());
550 clang::DeclarationName decl_name =
551 ast_ctx.DeclarationNames.getIdentifier(&identifier_info);
552
553 clang::DeclContext::lookup_result lookup_result =
554 ast_ctx.getTranslationUnitDecl()->lookup(decl_name);
555
556 if (!lookup_result.empty()) {
557 if (clang::ObjCInterfaceDecl *result_iface_decl =
558 llvm::dyn_cast<clang::ObjCInterfaceDecl>(lookup_result[0])) {
559 if (log) {
560 clang::QualType result_iface_type =
561 ast_ctx.getObjCInterfaceType(result_iface_decl);
562
563 uint64_t isa_value = LLDB_INVALID_ADDRESS;
564 ClangASTMetadata *metadata = m_ast_ctx.GetMetadata(result_iface_decl);
565 if (metadata)
566 isa_value = metadata->GetISAPtr();
567
568 LLDB_LOG(log,
569 "AOCTV::FT Found %s (isa 0x%" PRIx64 ") in the ASTContext",
570 result_iface_type.getAsString(), isa_value);
571 }
572
573 decls.push_back(m_ast_ctx.GetCompilerDecl(result_iface_decl));
574 ret++;
575 break;
576 } else {
577 LLDB_LOGF(log, "AOCTV::FT There's something in the ASTContext, but "
578 "it's not something we know about");
579 break;
580 }
581 } else if (log) {
582 LLDB_LOGF(log, "AOCTV::FT Couldn't find %s in the ASTContext",
583 name.AsCString());
584 }
585
586 // It's not. If it exists, we have to put it into our ASTContext.
587
588 ObjCLanguageRuntime::ObjCISA isa = m_runtime.GetISA(name);
589
590 if (!isa) {
591 LLDB_LOGF(log, "AOCTV::FT Couldn't find the isa");
592
593 break;
594 }
595
596 clang::ObjCInterfaceDecl *iface_decl = GetDeclForISA(isa);
597
598 if (!iface_decl) {
599 LLDB_LOGF(log,
600 "AOCTV::FT Couldn't get the Objective-C interface for "
601 "isa 0x%" PRIx64,
602 (uint64_t)isa);
603
604 break;
605 }
606
607 if (log) {
608 clang::QualType new_iface_type = ast_ctx.getObjCInterfaceType(iface_decl);
609
610 LLDB_LOG(log, "AOCTV::FT Created {1} (isa 0x{2:x})",
611 new_iface_type.getAsString(), (uint64_t)isa);
612 }
613
614 decls.push_back(m_ast_ctx.GetCompilerDecl(iface_decl));
615 ret++;
616 break;
617 } while (false);
618
619 return ret;
620 }
621