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