1 //===-- AppleObjCDeclVendor.cpp ---------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "AppleObjCDeclVendor.h" 11 12 #include "Plugins/ExpressionParser/Clang/ASTDumper.h" 13 #include "lldb/Core/Module.h" 14 #include "lldb/Symbol/ClangExternalASTSourceCommon.h" 15 #include "lldb/Symbol/ClangUtil.h" 16 #include "lldb/Target/ObjCLanguageRuntime.h" 17 #include "lldb/Target/Process.h" 18 #include "lldb/Target/Target.h" 19 #include "lldb/Utility/Log.h" 20 21 #include "clang/AST/ASTContext.h" 22 #include "clang/AST/DeclObjC.h" 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 (0); 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 NULL; 178 179 const 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 = NULL; 208 int brace_depth = 0; 209 210 uint32_t stepsLeft = 256; 211 212 while (1) { 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 = NULL; 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 NULL; 324 325 clang::ASTContext &ast_ctx(interface_decl->getASTContext()); 326 327 clang::QualType return_qual_type; 328 329 const bool isInstance = instance; 330 const bool isVariadic = false; 331 const bool isSynthesized = false; 332 const bool isImplicitlyDeclared = true; 333 const bool isDefined = false; 334 const clang::ObjCMethodDecl::ImplementationControl impControl = 335 clang::ObjCMethodDecl::None; 336 const bool HasRelatedResultType = false; 337 const bool for_expression = true; 338 339 std::vector<clang::IdentifierInfo *> selector_components; 340 341 const char *name_cursor = name; 342 bool is_zero_argument = true; 343 344 while (*name_cursor != '\0') { 345 const char *colon_loc = strchr(name_cursor, ':'); 346 if (!colon_loc) { 347 selector_components.push_back( 348 &ast_ctx.Idents.get(llvm::StringRef(name_cursor))); 349 break; 350 } else { 351 is_zero_argument = false; 352 selector_components.push_back(&ast_ctx.Idents.get( 353 llvm::StringRef(name_cursor, colon_loc - name_cursor))); 354 name_cursor = colon_loc + 1; 355 } 356 } 357 358 clang::IdentifierInfo **identifier_infos = selector_components.data(); 359 if (!identifier_infos) { 360 return NULL; 361 } 362 363 clang::Selector sel = ast_ctx.Selectors.getSelector( 364 is_zero_argument ? 0 : selector_components.size(), 365 identifier_infos); 366 367 clang::QualType ret_type = 368 ClangUtil::GetQualType(type_realizer_sp->RealizeType( 369 interface_decl->getASTContext(), m_type_vector[0].c_str(), 370 for_expression)); 371 372 if (ret_type.isNull()) 373 return NULL; 374 375 clang::ObjCMethodDecl *ret = clang::ObjCMethodDecl::Create( 376 ast_ctx, clang::SourceLocation(), clang::SourceLocation(), sel, 377 ret_type, NULL, interface_decl, isInstance, isVariadic, isSynthesized, 378 isImplicitlyDeclared, isDefined, impControl, HasRelatedResultType); 379 380 std::vector<clang::ParmVarDecl *> parm_vars; 381 382 for (size_t ai = 3, ae = m_type_vector.size(); ai != ae; ++ai) { 383 const bool for_expression = true; 384 clang::QualType arg_type = 385 ClangUtil::GetQualType(type_realizer_sp->RealizeType( 386 ast_ctx, m_type_vector[ai].c_str(), for_expression)); 387 388 if (arg_type.isNull()) 389 return NULL; // well, we just wasted a bunch of time. Wish we could 390 // delete the stuff we'd just made! 391 392 parm_vars.push_back(clang::ParmVarDecl::Create( 393 ast_ctx, ret, clang::SourceLocation(), clang::SourceLocation(), NULL, 394 arg_type, NULL, clang::SC_None, NULL)); 395 } 396 397 ret->setMethodParams(ast_ctx, 398 llvm::ArrayRef<clang::ParmVarDecl *>(parm_vars), 399 llvm::ArrayRef<clang::SourceLocation>()); 400 401 return ret; 402 } 403 404 explicit operator bool() { return m_is_valid; } 405 406 size_t GetNumTypes() { return m_type_vector.size(); } 407 408 const char *GetTypeAtIndex(size_t idx) { return m_type_vector[idx].c_str(); } 409 410 private: 411 typedef std::vector<std::string> TypeVector; 412 413 TypeVector m_type_vector; 414 bool m_is_valid; 415 }; 416 417 bool AppleObjCDeclVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl) { 418 Log *log(GetLogIfAllCategoriesSet( 419 LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? 420 421 ClangASTMetadata *metadata = m_external_source->GetMetadata(interface_decl); 422 ObjCLanguageRuntime::ObjCISA objc_isa = 0; 423 if (metadata) 424 objc_isa = metadata->GetISAPtr(); 425 426 if (!objc_isa) 427 return false; 428 429 if (!interface_decl->hasExternalVisibleStorage()) 430 return true; 431 432 interface_decl->startDefinition(); 433 434 interface_decl->setHasExternalVisibleStorage(false); 435 interface_decl->setHasExternalLexicalStorage(false); 436 437 ObjCLanguageRuntime::ClassDescriptorSP descriptor = 438 m_runtime.GetClassDescriptorFromISA(objc_isa); 439 440 if (!descriptor) 441 return false; 442 443 auto superclass_func = [interface_decl, 444 this](ObjCLanguageRuntime::ObjCISA isa) { 445 clang::ObjCInterfaceDecl *superclass_decl = GetDeclForISA(isa); 446 447 if (!superclass_decl) 448 return; 449 450 FinishDecl(superclass_decl); 451 clang::ASTContext *context = m_ast_ctx.getASTContext(); 452 interface_decl->setSuperClass(context->getTrivialTypeSourceInfo( 453 context->getObjCInterfaceType(superclass_decl))); 454 }; 455 456 auto instance_method_func = 457 [log, interface_decl, 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 = 464 method_type.BuildMethod(interface_decl, name, true, m_type_realizer_sp); 465 466 if (log) 467 log->Printf("[ AOTV::FD] Instance method [%s] [%s]", name, types); 468 469 if (method_decl) 470 interface_decl->addDecl(method_decl); 471 472 return false; 473 }; 474 475 auto class_method_func = [log, interface_decl, 476 this](const char *name, const char *types) -> bool { 477 if (!name || !types) 478 return false; // skip this one 479 480 ObjCRuntimeMethodType method_type(types); 481 482 clang::ObjCMethodDecl *method_decl = method_type.BuildMethod( 483 interface_decl, name, false, m_type_realizer_sp); 484 485 if (log) 486 log->Printf("[ AOTV::FD] Class method [%s] [%s]", name, types); 487 488 if (method_decl) 489 interface_decl->addDecl(method_decl); 490 491 return false; 492 }; 493 494 auto ivar_func = [log, interface_decl, 495 this](const char *name, const char *type, 496 lldb::addr_t offset_ptr, uint64_t size) -> bool { 497 if (!name || !type) 498 return false; 499 500 const bool for_expression = false; 501 502 if (log) 503 log->Printf( 504 "[ AOTV::FD] Instance variable [%s] [%s], offset at %" PRIx64, name, 505 type, offset_ptr); 506 507 CompilerType ivar_type = m_runtime.GetEncodingToType()->RealizeType( 508 m_ast_ctx, type, for_expression); 509 510 if (ivar_type.IsValid()) { 511 clang::TypeSourceInfo *const type_source_info = nullptr; 512 const bool is_synthesized = false; 513 clang::ObjCIvarDecl *ivar_decl = clang::ObjCIvarDecl::Create( 514 *m_ast_ctx.getASTContext(), interface_decl, clang::SourceLocation(), 515 clang::SourceLocation(), &m_ast_ctx.getASTContext()->Idents.get(name), 516 ClangUtil::GetQualType(ivar_type), 517 type_source_info, // TypeSourceInfo * 518 clang::ObjCIvarDecl::Public, 0, is_synthesized); 519 520 if (ivar_decl) { 521 interface_decl->addDecl(ivar_decl); 522 } 523 } 524 525 return false; 526 }; 527 528 if (log) { 529 ASTDumper method_dumper((clang::Decl *)interface_decl); 530 531 log->Printf("[AppleObjCDeclVendor::FinishDecl] Finishing Objective-C " 532 "interface for %s", 533 descriptor->GetClassName().AsCString()); 534 } 535 536 if (!descriptor->Describe(superclass_func, instance_method_func, 537 class_method_func, ivar_func)) 538 return false; 539 540 if (log) { 541 ASTDumper method_dumper((clang::Decl *)interface_decl); 542 543 log->Printf( 544 "[AppleObjCDeclVendor::FinishDecl] Finished Objective-C interface"); 545 546 method_dumper.ToLog(log, " [AOTV::FD] "); 547 } 548 549 return true; 550 } 551 552 uint32_t 553 AppleObjCDeclVendor::FindDecls(const ConstString &name, bool append, 554 uint32_t max_matches, 555 std::vector<clang::NamedDecl *> &decls) { 556 static unsigned int invocation_id = 0; 557 unsigned int current_id = invocation_id++; 558 559 Log *log(GetLogIfAllCategoriesSet( 560 LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? 561 562 if (log) 563 log->Printf("AppleObjCDeclVendor::FindTypes [%u] ('%s', %s, %u, )", 564 current_id, (const char *)name.AsCString(), 565 append ? "true" : "false", max_matches); 566 567 if (!append) 568 decls.clear(); 569 570 uint32_t ret = 0; 571 572 do { 573 // See if the type is already in our ASTContext. 574 575 clang::ASTContext *ast_ctx = m_ast_ctx.getASTContext(); 576 577 clang::IdentifierInfo &identifier_info = 578 ast_ctx->Idents.get(name.GetStringRef()); 579 clang::DeclarationName decl_name = 580 ast_ctx->DeclarationNames.getIdentifier(&identifier_info); 581 582 clang::DeclContext::lookup_result lookup_result = 583 ast_ctx->getTranslationUnitDecl()->lookup(decl_name); 584 585 if (!lookup_result.empty()) { 586 if (clang::ObjCInterfaceDecl *result_iface_decl = 587 llvm::dyn_cast<clang::ObjCInterfaceDecl>(lookup_result[0])) { 588 if (log) { 589 clang::QualType result_iface_type = 590 ast_ctx->getObjCInterfaceType(result_iface_decl); 591 ASTDumper dumper(result_iface_type); 592 593 uint64_t isa_value = LLDB_INVALID_ADDRESS; 594 ClangASTMetadata *metadata = 595 m_external_source->GetMetadata(result_iface_decl); 596 if (metadata) 597 isa_value = metadata->GetISAPtr(); 598 599 log->Printf("AOCTV::FT [%u] Found %s (isa 0x%" PRIx64 600 ") in the ASTContext", 601 current_id, dumper.GetCString(), isa_value); 602 } 603 604 decls.push_back(result_iface_decl); 605 ret++; 606 break; 607 } else { 608 if (log) 609 log->Printf("AOCTV::FT [%u] There's something in the ASTContext, but " 610 "it's not something we know about", 611 current_id); 612 break; 613 } 614 } else if (log) { 615 log->Printf("AOCTV::FT [%u] Couldn't find %s in the ASTContext", 616 current_id, name.AsCString()); 617 } 618 619 // It's not. If it exists, we have to put it into our ASTContext. 620 621 ObjCLanguageRuntime::ObjCISA isa = m_runtime.GetISA(name); 622 623 if (!isa) { 624 if (log) 625 log->Printf("AOCTV::FT [%u] Couldn't find the isa", current_id); 626 627 break; 628 } 629 630 clang::ObjCInterfaceDecl *iface_decl = GetDeclForISA(isa); 631 632 if (!iface_decl) { 633 if (log) 634 log->Printf("AOCTV::FT [%u] Couldn't get the Objective-C interface for " 635 "isa 0x%" PRIx64, 636 current_id, (uint64_t)isa); 637 638 break; 639 } 640 641 if (log) { 642 clang::QualType new_iface_type = 643 ast_ctx->getObjCInterfaceType(iface_decl); 644 ASTDumper dumper(new_iface_type); 645 log->Printf("AOCTV::FT [%u] Created %s (isa 0x%" PRIx64 ")", current_id, 646 dumper.GetCString(), (uint64_t)isa); 647 } 648 649 decls.push_back(iface_decl); 650 ret++; 651 break; 652 } while (0); 653 654 return ret; 655 } 656