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.empty());
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.begin())) {
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