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