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