1 //===-- ObjCLanguageRuntime.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 #include "clang/AST/Type.h" 10 11 #include "lldb/Core/Log.h" 12 #include "lldb/Core/MappedHash.h" 13 #include "lldb/Core/Module.h" 14 #include "lldb/Core/PluginManager.h" 15 #include "lldb/Core/Timer.h" 16 #include "lldb/Core/ValueObject.h" 17 #include "lldb/Symbol/ClangASTContext.h" 18 #include "lldb/Symbol/Type.h" 19 #include "lldb/Symbol/TypeList.h" 20 #include "lldb/Target/ObjCLanguageRuntime.h" 21 #include "lldb/Target/Target.h" 22 23 #include "llvm/ADT/StringRef.h" 24 25 using namespace lldb; 26 using namespace lldb_private; 27 28 //---------------------------------------------------------------------- 29 // Destructor 30 //---------------------------------------------------------------------- 31 ObjCLanguageRuntime::~ObjCLanguageRuntime() 32 { 33 } 34 35 ObjCLanguageRuntime::ObjCLanguageRuntime (Process *process) : 36 LanguageRuntime (process), 37 m_has_new_literals_and_indexing (eLazyBoolCalculate), 38 m_isa_to_descriptor(), 39 m_isa_to_descriptor_stop_id (UINT32_MAX) 40 { 41 42 } 43 44 bool 45 ObjCLanguageRuntime::AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, const char *class_name) 46 { 47 if (isa != 0) 48 { 49 m_isa_to_descriptor[isa] = descriptor_sp; 50 // class_name is assumed to be valid 51 m_hash_to_isa_map.insert(std::make_pair(MappedHash::HashStringUsingDJB(class_name), isa)); 52 return true; 53 } 54 return false; 55 } 56 57 void 58 ObjCLanguageRuntime::AddToMethodCache (lldb::addr_t class_addr, lldb::addr_t selector, lldb::addr_t impl_addr) 59 { 60 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 61 if (log) 62 { 63 log->Printf ("Caching: class 0x%" PRIx64 " selector 0x%" PRIx64 " implementation 0x%" PRIx64 ".", class_addr, selector, impl_addr); 64 } 65 m_impl_cache.insert (std::pair<ClassAndSel,lldb::addr_t> (ClassAndSel(class_addr, selector), impl_addr)); 66 } 67 68 lldb::addr_t 69 ObjCLanguageRuntime::LookupInMethodCache (lldb::addr_t class_addr, lldb::addr_t selector) 70 { 71 MsgImplMap::iterator pos, end = m_impl_cache.end(); 72 pos = m_impl_cache.find (ClassAndSel(class_addr, selector)); 73 if (pos != end) 74 return (*pos).second; 75 return LLDB_INVALID_ADDRESS; 76 } 77 78 79 lldb::TypeSP 80 ObjCLanguageRuntime::LookupInCompleteClassCache (ConstString &name) 81 { 82 CompleteClassMap::iterator complete_class_iter = m_complete_class_cache.find(name); 83 84 if (complete_class_iter != m_complete_class_cache.end()) 85 { 86 // Check the weak pointer to make sure the type hasn't been unloaded 87 TypeSP complete_type_sp (complete_class_iter->second.lock()); 88 89 if (complete_type_sp) 90 return complete_type_sp; 91 else 92 m_complete_class_cache.erase(name); 93 } 94 95 if (m_negative_complete_class_cache.count(name) > 0) 96 return TypeSP(); 97 98 const ModuleList &modules = m_process->GetTarget().GetImages(); 99 100 SymbolContextList sc_list; 101 const size_t matching_symbols = modules.FindSymbolsWithNameAndType (name, 102 eSymbolTypeObjCClass, 103 sc_list); 104 105 if (matching_symbols) 106 { 107 SymbolContext sc; 108 109 sc_list.GetContextAtIndex(0, sc); 110 111 ModuleSP module_sp(sc.module_sp); 112 113 if (!module_sp) 114 return TypeSP(); 115 116 const SymbolContext null_sc; 117 const bool exact_match = true; 118 const uint32_t max_matches = UINT32_MAX; 119 TypeList types; 120 121 const uint32_t num_types = module_sp->FindTypes (null_sc, 122 name, 123 exact_match, 124 max_matches, 125 types); 126 127 if (num_types) 128 { 129 uint32_t i; 130 for (i = 0; i < num_types; ++i) 131 { 132 TypeSP type_sp (types.GetTypeAtIndex(i)); 133 134 if (type_sp->GetClangForwardType().IsObjCObjectOrInterfaceType()) 135 { 136 if (type_sp->IsCompleteObjCClass()) 137 { 138 m_complete_class_cache[name] = type_sp; 139 return type_sp; 140 } 141 } 142 } 143 } 144 } 145 m_negative_complete_class_cache.insert(name); 146 return TypeSP(); 147 } 148 149 size_t 150 ObjCLanguageRuntime::GetByteOffsetForIvar (ClangASTType &parent_qual_type, const char *ivar_name) 151 { 152 return LLDB_INVALID_IVAR_OFFSET; 153 } 154 155 void 156 ObjCLanguageRuntime::MethodName::Clear() 157 { 158 m_full.Clear(); 159 m_class.Clear(); 160 m_category.Clear(); 161 m_selector.Clear(); 162 m_type = eTypeUnspecified; 163 m_category_is_valid = false; 164 } 165 166 //bool 167 //ObjCLanguageRuntime::MethodName::SetName (const char *name, bool strict) 168 //{ 169 // Clear(); 170 // if (name && name[0]) 171 // { 172 // // If "strict" is true. then the method must be specified with a 173 // // '+' or '-' at the beginning. If "strict" is false, then the '+' 174 // // or '-' can be omitted 175 // bool valid_prefix = false; 176 // 177 // if (name[0] == '+' || name[0] == '-') 178 // { 179 // valid_prefix = name[1] == '['; 180 // } 181 // else if (!strict) 182 // { 183 // // "strict" is false, the name just needs to start with '[' 184 // valid_prefix = name[0] == '['; 185 // } 186 // 187 // if (valid_prefix) 188 // { 189 // static RegularExpression g_regex("^([-+]?)\\[([A-Za-z_][A-Za-z_0-9]*)(\\([A-Za-z_][A-Za-z_0-9]*\\))? ([A-Za-z_][A-Za-z_0-9:]*)\\]$"); 190 // llvm::StringRef matches[4]; 191 // // Since we are using a global regular expression, we must use the threadsafe version of execute 192 // if (g_regex.ExecuteThreadSafe(name, matches, 4)) 193 // { 194 // m_full.SetCString(name); 195 // if (matches[0].empty()) 196 // m_type = eTypeUnspecified; 197 // else if (matches[0][0] == '+') 198 // m_type = eTypeClassMethod; 199 // else 200 // m_type = eTypeInstanceMethod; 201 // m_class.SetString(matches[1]); 202 // m_selector.SetString(matches[3]); 203 // if (!matches[2].empty()) 204 // m_category.SetString(matches[2]); 205 // } 206 // } 207 // } 208 // return IsValid(strict); 209 //} 210 211 bool 212 ObjCLanguageRuntime::MethodName::SetName (const char *name, bool strict) 213 { 214 Clear(); 215 if (name && name[0]) 216 { 217 // If "strict" is true. then the method must be specified with a 218 // '+' or '-' at the beginning. If "strict" is false, then the '+' 219 // or '-' can be omitted 220 bool valid_prefix = false; 221 222 if (name[0] == '+' || name[0] == '-') 223 { 224 valid_prefix = name[1] == '['; 225 if (name[0] == '+') 226 m_type = eTypeClassMethod; 227 else 228 m_type = eTypeInstanceMethod; 229 } 230 else if (!strict) 231 { 232 // "strict" is false, the name just needs to start with '[' 233 valid_prefix = name[0] == '['; 234 } 235 236 if (valid_prefix) 237 { 238 int name_len = strlen (name); 239 // Objective C methods must have at least: 240 // "-[" or "+[" prefix 241 // One character for a class name 242 // One character for the space between the class name 243 // One character for the method name 244 // "]" suffix 245 if (name_len >= (5 + (strict ? 1 : 0)) && name[name_len - 1] == ']') 246 { 247 m_full.SetCStringWithLength(name, name_len); 248 } 249 } 250 } 251 return IsValid(strict); 252 } 253 254 const ConstString & 255 ObjCLanguageRuntime::MethodName::GetClassName () 256 { 257 if (!m_class) 258 { 259 if (IsValid(false)) 260 { 261 const char *full = m_full.GetCString(); 262 const char *class_start = (full[0] == '[' ? full + 1 : full + 2); 263 const char *paren_pos = strchr (class_start, '('); 264 if (paren_pos) 265 { 266 m_class.SetCStringWithLength (class_start, paren_pos - class_start); 267 } 268 else 269 { 270 // No '(' was found in the full name, we can definitively say 271 // that our category was valid (and empty). 272 m_category_is_valid = true; 273 const char *space_pos = strchr (full, ' '); 274 if (space_pos) 275 { 276 m_class.SetCStringWithLength (class_start, space_pos - class_start); 277 if (!m_class_category) 278 { 279 // No category in name, so we can also fill in the m_class_category 280 m_class_category = m_class; 281 } 282 } 283 } 284 } 285 } 286 return m_class; 287 } 288 289 const ConstString & 290 ObjCLanguageRuntime::MethodName::GetClassNameWithCategory () 291 { 292 if (!m_class_category) 293 { 294 if (IsValid(false)) 295 { 296 const char *full = m_full.GetCString(); 297 const char *class_start = (full[0] == '[' ? full + 1 : full + 2); 298 const char *space_pos = strchr (full, ' '); 299 if (space_pos) 300 { 301 m_class_category.SetCStringWithLength (class_start, space_pos - class_start); 302 // If m_class hasn't been filled in and the class with category doesn't 303 // contain a '(', then we can also fill in the m_class 304 if (!m_class && strchr (m_class_category.GetCString(), '(') == NULL) 305 { 306 m_class = m_class_category; 307 // No '(' was found in the full name, we can definitively say 308 // that our category was valid (and empty). 309 m_category_is_valid = true; 310 311 } 312 } 313 } 314 } 315 return m_class_category; 316 } 317 318 const ConstString & 319 ObjCLanguageRuntime::MethodName::GetSelector () 320 { 321 if (!m_selector) 322 { 323 if (IsValid(false)) 324 { 325 const char *full = m_full.GetCString(); 326 const char *space_pos = strchr (full, ' '); 327 if (space_pos) 328 { 329 ++space_pos; // skip the space 330 m_selector.SetCStringWithLength (space_pos, m_full.GetLength() - (space_pos - full) - 1); 331 } 332 } 333 } 334 return m_selector; 335 } 336 337 const ConstString & 338 ObjCLanguageRuntime::MethodName::GetCategory () 339 { 340 if (!m_category_is_valid && !m_category) 341 { 342 if (IsValid(false)) 343 { 344 m_category_is_valid = true; 345 const char *full = m_full.GetCString(); 346 const char *class_start = (full[0] == '[' ? full + 1 : full + 2); 347 const char *open_paren_pos = strchr (class_start, '('); 348 if (open_paren_pos) 349 { 350 ++open_paren_pos; // Skip the open paren 351 const char *close_paren_pos = strchr (open_paren_pos, ')'); 352 if (close_paren_pos) 353 m_category.SetCStringWithLength (open_paren_pos, close_paren_pos - open_paren_pos); 354 } 355 } 356 } 357 return m_category; 358 } 359 360 ConstString 361 ObjCLanguageRuntime::MethodName::GetFullNameWithoutCategory (bool empty_if_no_category) 362 { 363 if (IsValid(false)) 364 { 365 if (HasCategory()) 366 { 367 StreamString strm; 368 if (m_type == eTypeClassMethod) 369 strm.PutChar('+'); 370 else if (m_type == eTypeInstanceMethod) 371 strm.PutChar('-'); 372 strm.Printf("[%s %s]", GetClassName().GetCString(), GetSelector().GetCString()); 373 return ConstString(strm.GetString().c_str()); 374 } 375 376 if (!empty_if_no_category) 377 { 378 // Just return the full name since it doesn't have a category 379 return GetFullName(); 380 } 381 } 382 return ConstString(); 383 } 384 385 size_t 386 ObjCLanguageRuntime::MethodName::GetFullNames (std::vector<ConstString> &names, bool append) 387 { 388 if (!append) 389 names.clear(); 390 if (IsValid(false)) 391 { 392 StreamString strm; 393 const bool is_class_method = m_type == eTypeClassMethod; 394 const bool is_instance_method = m_type == eTypeInstanceMethod; 395 const ConstString &category = GetCategory(); 396 if (is_class_method || is_instance_method) 397 { 398 names.push_back (m_full); 399 if (category) 400 { 401 strm.Printf("%c[%s %s]", 402 is_class_method ? '+' : '-', 403 GetClassName().GetCString(), 404 GetSelector().GetCString()); 405 names.push_back(ConstString(strm.GetString().c_str())); 406 } 407 } 408 else 409 { 410 const ConstString &class_name = GetClassName(); 411 const ConstString &selector = GetSelector(); 412 strm.Printf("+[%s %s]", class_name.GetCString(), selector.GetCString()); 413 names.push_back(ConstString(strm.GetString().c_str())); 414 strm.Clear(); 415 strm.Printf("-[%s %s]", class_name.GetCString(), selector.GetCString()); 416 names.push_back(ConstString(strm.GetString().c_str())); 417 strm.Clear(); 418 if (category) 419 { 420 strm.Printf("+[%s(%s) %s]", class_name.GetCString(), category.GetCString(), selector.GetCString()); 421 names.push_back(ConstString(strm.GetString().c_str())); 422 strm.Clear(); 423 strm.Printf("-[%s(%s) %s]", class_name.GetCString(), category.GetCString(), selector.GetCString()); 424 names.push_back(ConstString(strm.GetString().c_str())); 425 } 426 } 427 } 428 return names.size(); 429 } 430 431 432 bool 433 ObjCLanguageRuntime::ClassDescriptor::IsPointerValid (lldb::addr_t value, 434 uint32_t ptr_size, 435 bool allow_NULLs, 436 bool allow_tagged, 437 bool check_version_specific) const 438 { 439 if (!value) 440 return allow_NULLs; 441 if ( (value % 2) == 1 && allow_tagged) 442 return true; 443 if ((value % ptr_size) == 0) 444 return (check_version_specific ? CheckPointer(value,ptr_size) : true); 445 else 446 return false; 447 } 448 449 ObjCLanguageRuntime::ObjCISA 450 ObjCLanguageRuntime::GetISA(const ConstString &name) 451 { 452 ISAToDescriptorIterator pos = GetDescriptorIterator (name); 453 if (pos != m_isa_to_descriptor.end()) 454 return pos->first; 455 return 0; 456 } 457 458 ObjCLanguageRuntime::ISAToDescriptorIterator 459 ObjCLanguageRuntime::GetDescriptorIterator (const ConstString &name) 460 { 461 ISAToDescriptorIterator end = m_isa_to_descriptor.end(); 462 463 if (name) 464 { 465 UpdateISAToDescriptorMap(); 466 if (m_hash_to_isa_map.empty()) 467 { 468 // No name hashes were provided, we need to just linearly power through the 469 // names and find a match 470 for (ISAToDescriptorIterator pos = m_isa_to_descriptor.begin(); pos != end; ++pos) 471 { 472 if (pos->second->GetClassName() == name) 473 return pos; 474 } 475 } 476 else 477 { 478 // Name hashes were provided, so use them to efficiently lookup name to isa/descriptor 479 const uint32_t name_hash = MappedHash::HashStringUsingDJB (name.GetCString()); 480 std::pair <HashToISAIterator, HashToISAIterator> range = m_hash_to_isa_map.equal_range(name_hash); 481 for (HashToISAIterator range_pos = range.first; range_pos != range.second; ++range_pos) 482 { 483 ISAToDescriptorIterator pos = m_isa_to_descriptor.find (range_pos->second); 484 if (pos != m_isa_to_descriptor.end()) 485 { 486 if (pos->second->GetClassName() == name) 487 return pos; 488 } 489 } 490 } 491 } 492 return end; 493 } 494 495 496 ObjCLanguageRuntime::ObjCISA 497 ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa) 498 { 499 ClassDescriptorSP objc_class_sp (GetClassDescriptorFromISA(isa)); 500 if (objc_class_sp) 501 { 502 ClassDescriptorSP objc_super_class_sp (objc_class_sp->GetSuperclass()); 503 if (objc_super_class_sp) 504 return objc_super_class_sp->GetISA(); 505 } 506 return 0; 507 } 508 509 ConstString 510 ObjCLanguageRuntime::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) 511 { 512 ClassDescriptorSP objc_class_sp (GetNonKVOClassDescriptor(isa)); 513 if (objc_class_sp) 514 return objc_class_sp->GetClassName(); 515 return ConstString(); 516 } 517 518 ObjCLanguageRuntime::ClassDescriptorSP 519 ObjCLanguageRuntime::GetClassDescriptorFromClassName (const ConstString &class_name) 520 { 521 ISAToDescriptorIterator pos = GetDescriptorIterator (class_name); 522 if (pos != m_isa_to_descriptor.end()) 523 return pos->second; 524 return ClassDescriptorSP(); 525 526 } 527 528 ObjCLanguageRuntime::ClassDescriptorSP 529 ObjCLanguageRuntime::GetClassDescriptor (ValueObject& valobj) 530 { 531 ClassDescriptorSP objc_class_sp; 532 // if we get an invalid VO (which might still happen when playing around 533 // with pointers returned by the expression parser, don't consider this 534 // a valid ObjC object) 535 if (valobj.GetClangType().IsValid()) 536 { 537 addr_t isa_pointer = valobj.GetPointerValue(); 538 if (isa_pointer != LLDB_INVALID_ADDRESS) 539 { 540 ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); 541 542 Process *process = exe_ctx.GetProcessPtr(); 543 if (process) 544 { 545 Error error; 546 ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); 547 if (isa != LLDB_INVALID_ADDRESS) 548 objc_class_sp = GetClassDescriptorFromISA (isa); 549 } 550 } 551 } 552 return objc_class_sp; 553 } 554 555 ObjCLanguageRuntime::ClassDescriptorSP 556 ObjCLanguageRuntime::GetNonKVOClassDescriptor (ValueObject& valobj) 557 { 558 ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp (GetClassDescriptor (valobj)); 559 if (objc_class_sp) 560 { 561 if (!objc_class_sp->IsKVO()) 562 return objc_class_sp; 563 564 ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass()); 565 if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid()) 566 return non_kvo_objc_class_sp; 567 } 568 return ClassDescriptorSP(); 569 } 570 571 572 ObjCLanguageRuntime::ClassDescriptorSP 573 ObjCLanguageRuntime::GetClassDescriptorFromISA (ObjCISA isa) 574 { 575 if (isa) 576 { 577 UpdateISAToDescriptorMap(); 578 ObjCLanguageRuntime::ISAToDescriptorIterator pos = m_isa_to_descriptor.find(isa); 579 if (pos != m_isa_to_descriptor.end()) 580 return pos->second; 581 } 582 return ClassDescriptorSP(); 583 } 584 585 ObjCLanguageRuntime::ClassDescriptorSP 586 ObjCLanguageRuntime::GetNonKVOClassDescriptor (ObjCISA isa) 587 { 588 if (isa) 589 { 590 ClassDescriptorSP objc_class_sp = GetClassDescriptorFromISA (isa); 591 if (objc_class_sp && objc_class_sp->IsValid()) 592 { 593 if (!objc_class_sp->IsKVO()) 594 return objc_class_sp; 595 596 ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass()); 597 if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid()) 598 return non_kvo_objc_class_sp; 599 } 600 } 601 return ClassDescriptorSP(); 602 } 603 604 605 606