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