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