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/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 24 using namespace lldb_private; 25 26 class lldb_private::AppleObjCExternalASTSource 27 : public clang::ExternalASTSource { 28 public: 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 129 private: 130 AppleObjCDeclVendor &m_decl_vendor; 131 }; 132 133 AppleObjCDeclVendor::AppleObjCDeclVendor(ObjCLanguageRuntime &runtime) 134 : ClangDeclVendor(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 m_external_source = new AppleObjCExternalASTSource(*this); 140 llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> external_source_owning_ptr( 141 m_external_source); 142 m_ast_ctx->getASTContext().setExternalSource(external_source_owning_ptr); 143 } 144 145 clang::ObjCInterfaceDecl * 146 AppleObjCDeclVendor::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 183 class ObjCRuntimeMethodType { 184 public: 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 could 371 // 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 391 private: 392 typedef std::vector<std::string> TypeVector; 393 394 TypeVector m_type_vector; 395 bool m_is_valid = false; 396 }; 397 398 bool 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 one 441 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 one 459 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 526 uint32_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 uint32_t ret = 0; 541 542 do { 543 // See if the type is already in our ASTContext. 544 545 clang::ASTContext &ast_ctx = m_ast_ctx->getASTContext(); 546 547 clang::IdentifierInfo &identifier_info = 548 ast_ctx.Idents.get(name.GetStringRef()); 549 clang::DeclarationName decl_name = 550 ast_ctx.DeclarationNames.getIdentifier(&identifier_info); 551 552 clang::DeclContext::lookup_result lookup_result = 553 ast_ctx.getTranslationUnitDecl()->lookup(decl_name); 554 555 if (!lookup_result.empty()) { 556 if (clang::ObjCInterfaceDecl *result_iface_decl = 557 llvm::dyn_cast<clang::ObjCInterfaceDecl>(*lookup_result.begin())) { 558 if (log) { 559 clang::QualType result_iface_type = 560 ast_ctx.getObjCInterfaceType(result_iface_decl); 561 562 uint64_t isa_value = LLDB_INVALID_ADDRESS; 563 if (std::optional<ClangASTMetadata> metadata = 564 m_ast_ctx->GetMetadata(result_iface_decl)) 565 isa_value = metadata->GetISAPtr(); 566 567 LLDB_LOGF(log, 568 "AOCTV::FT Found %s (isa 0x%" PRIx64 ") in the ASTContext", 569 result_iface_type.getAsString().data(), isa_value); 570 } 571 572 decls.push_back(m_ast_ctx->GetCompilerDecl(result_iface_decl)); 573 ret++; 574 break; 575 } else { 576 LLDB_LOGF(log, "AOCTV::FT There's something in the ASTContext, but " 577 "it's not something we know about"); 578 break; 579 } 580 } else if (log) { 581 LLDB_LOGF(log, "AOCTV::FT Couldn't find %s in the ASTContext", 582 name.AsCString()); 583 } 584 585 // It's not. If it exists, we have to put it into our ASTContext. 586 587 ObjCLanguageRuntime::ObjCISA isa = m_runtime.GetISA(name); 588 589 if (!isa) { 590 LLDB_LOGF(log, "AOCTV::FT Couldn't find the isa"); 591 592 break; 593 } 594 595 clang::ObjCInterfaceDecl *iface_decl = GetDeclForISA(isa); 596 597 if (!iface_decl) { 598 LLDB_LOGF(log, 599 "AOCTV::FT Couldn't get the Objective-C interface for " 600 "isa 0x%" PRIx64, 601 (uint64_t)isa); 602 603 break; 604 } 605 606 if (log) { 607 clang::QualType new_iface_type = ast_ctx.getObjCInterfaceType(iface_decl); 608 609 LLDB_LOG(log, "AOCTV::FT Created {0} (isa 0x{1:x})", 610 new_iface_type.getAsString(), (uint64_t)isa); 611 } 612 613 decls.push_back(m_ast_ctx->GetCompilerDecl(iface_decl)); 614 ret++; 615 break; 616 } while (false); 617 618 return ret; 619 } 620