1 //===-- ObjCLanguageRuntime.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 #include "clang/AST/Type.h" 9 10 #include "ObjCLanguageRuntime.h" 11 12 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 13 #include "lldb/Core/MappedHash.h" 14 #include "lldb/Core/Module.h" 15 #include "lldb/Core/PluginManager.h" 16 #include "lldb/Core/ValueObject.h" 17 #include "lldb/Symbol/SymbolContext.h" 18 #include "lldb/Symbol/SymbolFile.h" 19 #include "lldb/Symbol/Type.h" 20 #include "lldb/Symbol/TypeList.h" 21 #include "lldb/Symbol/Variable.h" 22 #include "lldb/Target/ABI.h" 23 #include "lldb/Target/Target.h" 24 #include "lldb/Utility/LLDBLog.h" 25 #include "lldb/Utility/Log.h" 26 #include "lldb/Utility/Timer.h" 27 28 #include "llvm/ADT/StringRef.h" 29 #include "llvm/Support/DJB.h" 30 31 using namespace lldb; 32 using namespace lldb_private; 33 34 char ObjCLanguageRuntime::ID = 0; 35 36 // Destructor 37 ObjCLanguageRuntime::~ObjCLanguageRuntime() = default; 38 39 ObjCLanguageRuntime::ObjCLanguageRuntime(Process *process) 40 : LanguageRuntime(process), m_impl_cache(), m_impl_str_cache(), 41 m_has_new_literals_and_indexing(eLazyBoolCalculate), 42 m_isa_to_descriptor(), m_hash_to_isa_map(), m_type_size_cache(), 43 m_isa_to_descriptor_stop_id(UINT32_MAX), m_complete_class_cache(), 44 m_negative_complete_class_cache() {} 45 46 bool ObjCLanguageRuntime::IsAllowedRuntimeValue(ConstString name) { 47 static ConstString g_self = ConstString("self"); 48 static ConstString g_cmd = ConstString("_cmd"); 49 return name == g_self || name == g_cmd; 50 } 51 52 bool ObjCLanguageRuntime::AddClass(ObjCISA isa, 53 const ClassDescriptorSP &descriptor_sp, 54 const char *class_name) { 55 if (isa != 0) { 56 m_isa_to_descriptor[isa] = descriptor_sp; 57 // class_name is assumed to be valid 58 m_hash_to_isa_map.insert(std::make_pair(llvm::djbHash(class_name), isa)); 59 return true; 60 } 61 return false; 62 } 63 64 void ObjCLanguageRuntime::AddToMethodCache(lldb::addr_t class_addr, 65 lldb::addr_t selector, 66 lldb::addr_t impl_addr) { 67 Log *log = GetLog(LLDBLog::Step); 68 if (log) { 69 LLDB_LOGF(log, 70 "Caching: class 0x%" PRIx64 " selector 0x%" PRIx64 71 " implementation 0x%" PRIx64 ".", 72 class_addr, selector, impl_addr); 73 } 74 m_impl_cache.insert(std::pair<ClassAndSel, lldb::addr_t>( 75 ClassAndSel(class_addr, selector), impl_addr)); 76 } 77 78 void ObjCLanguageRuntime::AddToMethodCache(lldb::addr_t class_addr, 79 llvm::StringRef sel_str, 80 lldb::addr_t impl_addr) { 81 Log *log = GetLog(LLDBLog::Step); 82 83 LLDB_LOG(log, "Caching: class {0} selector {1} implementation {2}.", 84 class_addr, sel_str, impl_addr); 85 86 m_impl_str_cache.insert(std::pair<ClassAndSelStr, lldb::addr_t>( 87 ClassAndSelStr(class_addr, sel_str), impl_addr)); 88 } 89 90 lldb::addr_t ObjCLanguageRuntime::LookupInMethodCache(lldb::addr_t class_addr, 91 lldb::addr_t selector) { 92 MsgImplMap::iterator pos, end = m_impl_cache.end(); 93 pos = m_impl_cache.find(ClassAndSel(class_addr, selector)); 94 if (pos != end) 95 return (*pos).second; 96 return LLDB_INVALID_ADDRESS; 97 } 98 99 lldb::addr_t ObjCLanguageRuntime::LookupInMethodCache(lldb::addr_t class_addr, 100 llvm::StringRef sel_str) { 101 MsgImplStrMap::iterator pos, end = m_impl_str_cache.end(); 102 pos = m_impl_str_cache.find(ClassAndSelStr(class_addr, sel_str)); 103 if (pos != end) 104 return (*pos).second; 105 return LLDB_INVALID_ADDRESS; 106 } 107 108 lldb::TypeSP 109 ObjCLanguageRuntime::LookupInCompleteClassCache(ConstString &name) { 110 CompleteClassMap::iterator complete_class_iter = 111 m_complete_class_cache.find(name); 112 113 if (complete_class_iter != m_complete_class_cache.end()) { 114 // Check the weak pointer to make sure the type hasn't been unloaded 115 TypeSP complete_type_sp(complete_class_iter->second.lock()); 116 117 if (complete_type_sp) 118 return complete_type_sp; 119 else 120 m_complete_class_cache.erase(name); 121 } 122 123 if (m_negative_complete_class_cache.count(name) > 0) 124 return TypeSP(); 125 126 const ModuleList &modules = m_process->GetTarget().GetImages(); 127 128 SymbolContextList sc_list; 129 modules.FindSymbolsWithNameAndType(name, eSymbolTypeObjCClass, sc_list); 130 const size_t matching_symbols = sc_list.GetSize(); 131 132 if (matching_symbols) { 133 SymbolContext sc; 134 135 sc_list.GetContextAtIndex(0, sc); 136 137 ModuleSP module_sp(sc.module_sp); 138 139 if (!module_sp) 140 return TypeSP(); 141 142 const bool exact_match = true; 143 const uint32_t max_matches = UINT32_MAX; 144 TypeList types; 145 146 llvm::DenseSet<SymbolFile *> searched_symbol_files; 147 module_sp->FindTypes(name, exact_match, max_matches, searched_symbol_files, 148 types); 149 150 for (uint32_t i = 0; i < types.GetSize(); ++i) { 151 TypeSP type_sp(types.GetTypeAtIndex(i)); 152 153 if (TypeSystemClang::IsObjCObjectOrInterfaceType( 154 type_sp->GetForwardCompilerType())) { 155 if (TypePayloadClang(type_sp->GetPayload()).IsCompleteObjCClass()) { 156 m_complete_class_cache[name] = type_sp; 157 return type_sp; 158 } 159 } 160 } 161 } 162 m_negative_complete_class_cache.insert(name); 163 return TypeSP(); 164 } 165 166 size_t ObjCLanguageRuntime::GetByteOffsetForIvar(CompilerType &parent_qual_type, 167 const char *ivar_name) { 168 return LLDB_INVALID_IVAR_OFFSET; 169 } 170 171 bool ObjCLanguageRuntime::ClassDescriptor::IsPointerValid( 172 lldb::addr_t value, uint32_t ptr_size, bool allow_NULLs, bool allow_tagged, 173 bool check_version_specific) const { 174 if (!value) 175 return allow_NULLs; 176 if ((value % 2) == 1 && allow_tagged) 177 return true; 178 if ((value % ptr_size) == 0) 179 return (check_version_specific ? CheckPointer(value, ptr_size) : true); 180 else 181 return false; 182 } 183 184 ObjCLanguageRuntime::ObjCISA 185 ObjCLanguageRuntime::GetISA(ConstString name) { 186 ISAToDescriptorIterator pos = GetDescriptorIterator(name); 187 if (pos != m_isa_to_descriptor.end()) 188 return pos->first; 189 return 0; 190 } 191 192 ObjCLanguageRuntime::ISAToDescriptorIterator 193 ObjCLanguageRuntime::GetDescriptorIterator(ConstString name) { 194 ISAToDescriptorIterator end = m_isa_to_descriptor.end(); 195 196 if (name) { 197 UpdateISAToDescriptorMap(); 198 if (m_hash_to_isa_map.empty()) { 199 // No name hashes were provided, we need to just linearly power through 200 // the names and find a match 201 for (ISAToDescriptorIterator pos = m_isa_to_descriptor.begin(); 202 pos != end; ++pos) { 203 if (pos->second->GetClassName() == name) 204 return pos; 205 } 206 } else { 207 // Name hashes were provided, so use them to efficiently lookup name to 208 // isa/descriptor 209 const uint32_t name_hash = llvm::djbHash(name.GetStringRef()); 210 std::pair<HashToISAIterator, HashToISAIterator> range = 211 m_hash_to_isa_map.equal_range(name_hash); 212 for (HashToISAIterator range_pos = range.first; range_pos != range.second; 213 ++range_pos) { 214 ISAToDescriptorIterator pos = 215 m_isa_to_descriptor.find(range_pos->second); 216 if (pos != m_isa_to_descriptor.end()) { 217 if (pos->second->GetClassName() == name) 218 return pos; 219 } 220 } 221 } 222 } 223 return end; 224 } 225 226 std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator, 227 ObjCLanguageRuntime::ISAToDescriptorIterator> 228 ObjCLanguageRuntime::GetDescriptorIteratorPair(bool update_if_needed) { 229 if (update_if_needed) 230 UpdateISAToDescriptorMapIfNeeded(); 231 232 return std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator, 233 ObjCLanguageRuntime::ISAToDescriptorIterator>( 234 m_isa_to_descriptor.begin(), m_isa_to_descriptor.end()); 235 } 236 237 ObjCLanguageRuntime::ObjCISA 238 ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa) { 239 ClassDescriptorSP objc_class_sp(GetClassDescriptorFromISA(isa)); 240 if (objc_class_sp) { 241 ClassDescriptorSP objc_super_class_sp(objc_class_sp->GetSuperclass()); 242 if (objc_super_class_sp) 243 return objc_super_class_sp->GetISA(); 244 } 245 return 0; 246 } 247 248 ObjCLanguageRuntime::ClassDescriptorSP 249 ObjCLanguageRuntime::GetClassDescriptorFromClassName( 250 ConstString class_name) { 251 ISAToDescriptorIterator pos = GetDescriptorIterator(class_name); 252 if (pos != m_isa_to_descriptor.end()) 253 return pos->second; 254 return ClassDescriptorSP(); 255 } 256 257 ObjCLanguageRuntime::ClassDescriptorSP 258 ObjCLanguageRuntime::GetClassDescriptor(ValueObject &valobj) { 259 ClassDescriptorSP objc_class_sp; 260 // if we get an invalid VO (which might still happen when playing around with 261 // pointers returned by the expression parser, don't consider this a valid 262 // ObjC object) 263 if (valobj.GetCompilerType().IsValid()) { 264 addr_t isa_pointer = valobj.GetPointerValue(); 265 if (isa_pointer != LLDB_INVALID_ADDRESS) { 266 ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); 267 268 Process *process = exe_ctx.GetProcessPtr(); 269 if (process) { 270 Status error; 271 ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); 272 if (isa != LLDB_INVALID_ADDRESS) 273 objc_class_sp = GetClassDescriptorFromISA(isa); 274 } 275 } 276 } 277 return objc_class_sp; 278 } 279 280 ObjCLanguageRuntime::ClassDescriptorSP 281 ObjCLanguageRuntime::GetNonKVOClassDescriptor(ValueObject &valobj) { 282 ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp( 283 GetClassDescriptor(valobj)); 284 if (objc_class_sp) { 285 if (!objc_class_sp->IsKVO()) 286 return objc_class_sp; 287 288 ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass()); 289 if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid()) 290 return non_kvo_objc_class_sp; 291 } 292 return ClassDescriptorSP(); 293 } 294 295 ObjCLanguageRuntime::ClassDescriptorSP 296 ObjCLanguageRuntime::GetClassDescriptorFromISA(ObjCISA isa) { 297 if (isa) { 298 UpdateISAToDescriptorMap(); 299 300 ObjCLanguageRuntime::ISAToDescriptorIterator pos = 301 m_isa_to_descriptor.find(isa); 302 if (pos != m_isa_to_descriptor.end()) 303 return pos->second; 304 305 if (ABISP abi_sp = m_process->GetABI()) { 306 pos = m_isa_to_descriptor.find(abi_sp->FixCodeAddress(isa)); 307 if (pos != m_isa_to_descriptor.end()) 308 return pos->second; 309 } 310 } 311 return ClassDescriptorSP(); 312 } 313 314 ObjCLanguageRuntime::ClassDescriptorSP 315 ObjCLanguageRuntime::GetNonKVOClassDescriptor(ObjCISA isa) { 316 if (isa) { 317 ClassDescriptorSP objc_class_sp = GetClassDescriptorFromISA(isa); 318 if (objc_class_sp && objc_class_sp->IsValid()) { 319 if (!objc_class_sp->IsKVO()) 320 return objc_class_sp; 321 322 ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass()); 323 if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid()) 324 return non_kvo_objc_class_sp; 325 } 326 } 327 return ClassDescriptorSP(); 328 } 329 330 CompilerType 331 ObjCLanguageRuntime::EncodingToType::RealizeType(const char *name, 332 bool for_expression) { 333 if (m_scratch_ast_ctx_up) 334 return RealizeType(*m_scratch_ast_ctx_up, name, for_expression); 335 return CompilerType(); 336 } 337 338 ObjCLanguageRuntime::EncodingToType::~EncodingToType() = default; 339 340 ObjCLanguageRuntime::EncodingToTypeSP ObjCLanguageRuntime::GetEncodingToType() { 341 return nullptr; 342 } 343 344 bool ObjCLanguageRuntime::GetTypeBitSize(const CompilerType &compiler_type, 345 uint64_t &size) { 346 void *opaque_ptr = compiler_type.GetOpaqueQualType(); 347 size = m_type_size_cache.Lookup(opaque_ptr); 348 // an ObjC object will at least have an ISA, so 0 is definitely not OK 349 if (size > 0) 350 return true; 351 352 ClassDescriptorSP class_descriptor_sp = 353 GetClassDescriptorFromClassName(compiler_type.GetTypeName()); 354 if (!class_descriptor_sp) 355 return false; 356 357 int32_t max_offset = INT32_MIN; 358 uint64_t sizeof_max = 0; 359 bool found = false; 360 361 for (size_t idx = 0; idx < class_descriptor_sp->GetNumIVars(); idx++) { 362 const auto &ivar = class_descriptor_sp->GetIVarAtIndex(idx); 363 int32_t cur_offset = ivar.m_offset; 364 if (cur_offset > max_offset) { 365 max_offset = cur_offset; 366 sizeof_max = ivar.m_size; 367 found = true; 368 } 369 } 370 371 size = 8 * (max_offset + sizeof_max); 372 if (found) 373 m_type_size_cache.Insert(opaque_ptr, size); 374 375 return found; 376 } 377 378 lldb::BreakpointPreconditionSP 379 ObjCLanguageRuntime::GetBreakpointExceptionPrecondition(LanguageType language, 380 bool throw_bp) { 381 if (language != eLanguageTypeObjC) 382 return lldb::BreakpointPreconditionSP(); 383 if (!throw_bp) 384 return lldb::BreakpointPreconditionSP(); 385 BreakpointPreconditionSP precondition_sp( 386 new ObjCLanguageRuntime::ObjCExceptionPrecondition()); 387 return precondition_sp; 388 } 389 390 // Exception breakpoint Precondition class for ObjC: 391 void ObjCLanguageRuntime::ObjCExceptionPrecondition::AddClassName( 392 const char *class_name) { 393 m_class_names.insert(class_name); 394 } 395 396 ObjCLanguageRuntime::ObjCExceptionPrecondition::ObjCExceptionPrecondition() = 397 default; 398 399 bool ObjCLanguageRuntime::ObjCExceptionPrecondition::EvaluatePrecondition( 400 StoppointCallbackContext &context) { 401 return true; 402 } 403 404 void ObjCLanguageRuntime::ObjCExceptionPrecondition::GetDescription( 405 Stream &stream, lldb::DescriptionLevel level) {} 406 407 Status ObjCLanguageRuntime::ObjCExceptionPrecondition::ConfigurePrecondition( 408 Args &args) { 409 Status error; 410 if (args.GetArgumentCount() > 0) 411 error.SetErrorString( 412 "The ObjC Exception breakpoint doesn't support extra options."); 413 return error; 414 } 415 416 llvm::Optional<CompilerType> 417 ObjCLanguageRuntime::GetRuntimeType(CompilerType base_type) { 418 CompilerType class_type; 419 bool is_pointer_type = false; 420 421 if (TypeSystemClang::IsObjCObjectPointerType(base_type, &class_type)) 422 is_pointer_type = true; 423 else if (TypeSystemClang::IsObjCObjectOrInterfaceType(base_type)) 424 class_type = base_type; 425 else 426 return llvm::None; 427 428 if (!class_type) 429 return llvm::None; 430 431 ConstString class_name(class_type.GetTypeName()); 432 if (!class_name) 433 return llvm::None; 434 435 TypeSP complete_objc_class_type_sp = LookupInCompleteClassCache(class_name); 436 if (!complete_objc_class_type_sp) 437 return llvm::None; 438 439 CompilerType complete_class( 440 complete_objc_class_type_sp->GetFullCompilerType()); 441 if (complete_class.GetCompleteType()) { 442 if (is_pointer_type) 443 return complete_class.GetPointerType(); 444 else 445 return complete_class; 446 } 447 448 return llvm::None; 449 } 450