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