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/Module.h" 14 #include "lldb/Core/PluginManager.h" 15 #include "lldb/Symbol/SymbolContext.h" 16 #include "lldb/Symbol/SymbolFile.h" 17 #include "lldb/Symbol/Type.h" 18 #include "lldb/Symbol/TypeList.h" 19 #include "lldb/Symbol/Variable.h" 20 #include "lldb/Target/ABI.h" 21 #include "lldb/Target/Target.h" 22 #include "lldb/Utility/LLDBLog.h" 23 #include "lldb/Utility/Log.h" 24 #include "lldb/Utility/Timer.h" 25 #include "lldb/ValueObject/ValueObject.h" 26 27 #include "llvm/ADT/StringRef.h" 28 #include "llvm/Support/DJB.h" 29 #include <optional> 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 TypeQuery query(name.GetStringRef(), TypeQueryOptions::e_exact_match); 143 TypeResults results; 144 module_sp->FindTypes(query, results); 145 for (const TypeSP &type_sp : results.GetTypeMap().Types()) { 146 if (TypeSystemClang::IsObjCObjectOrInterfaceType( 147 type_sp->GetForwardCompilerType())) { 148 if (TypePayloadClang(type_sp->GetPayload()).IsCompleteObjCClass()) { 149 m_complete_class_cache[name] = type_sp; 150 return type_sp; 151 } 152 } 153 } 154 } 155 m_negative_complete_class_cache.insert(name); 156 return TypeSP(); 157 } 158 159 size_t ObjCLanguageRuntime::GetByteOffsetForIvar(CompilerType &parent_qual_type, 160 const char *ivar_name) { 161 return LLDB_INVALID_IVAR_OFFSET; 162 } 163 164 bool ObjCLanguageRuntime::ClassDescriptor::IsPointerValid( 165 lldb::addr_t value, uint32_t ptr_size, bool allow_NULLs, bool allow_tagged, 166 bool check_version_specific) const { 167 if (!value) 168 return allow_NULLs; 169 if ((value % 2) == 1 && allow_tagged) 170 return true; 171 if ((value % ptr_size) == 0) 172 return (check_version_specific ? CheckPointer(value, ptr_size) : true); 173 else 174 return false; 175 } 176 177 ObjCLanguageRuntime::ObjCISA 178 ObjCLanguageRuntime::GetISA(ConstString name) { 179 ISAToDescriptorIterator pos = GetDescriptorIterator(name); 180 if (pos != m_isa_to_descriptor.end()) 181 return pos->first; 182 return 0; 183 } 184 185 ObjCLanguageRuntime::ISAToDescriptorIterator 186 ObjCLanguageRuntime::GetDescriptorIterator(ConstString name) { 187 ISAToDescriptorIterator end = m_isa_to_descriptor.end(); 188 189 if (name) { 190 UpdateISAToDescriptorMap(); 191 if (m_hash_to_isa_map.empty()) { 192 // No name hashes were provided, we need to just linearly power through 193 // the names and find a match 194 for (ISAToDescriptorIterator pos = m_isa_to_descriptor.begin(); 195 pos != end; ++pos) { 196 if (pos->second->GetClassName() == name) 197 return pos; 198 } 199 } else { 200 // Name hashes were provided, so use them to efficiently lookup name to 201 // isa/descriptor 202 const uint32_t name_hash = llvm::djbHash(name.GetStringRef()); 203 std::pair<HashToISAIterator, HashToISAIterator> range = 204 m_hash_to_isa_map.equal_range(name_hash); 205 for (HashToISAIterator range_pos = range.first; range_pos != range.second; 206 ++range_pos) { 207 ISAToDescriptorIterator pos = 208 m_isa_to_descriptor.find(range_pos->second); 209 if (pos != m_isa_to_descriptor.end()) { 210 if (pos->second->GetClassName() == name) 211 return pos; 212 } 213 } 214 } 215 } 216 return end; 217 } 218 219 std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator, 220 ObjCLanguageRuntime::ISAToDescriptorIterator> 221 ObjCLanguageRuntime::GetDescriptorIteratorPair(bool update_if_needed) { 222 if (update_if_needed) 223 UpdateISAToDescriptorMapIfNeeded(); 224 225 return std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator, 226 ObjCLanguageRuntime::ISAToDescriptorIterator>( 227 m_isa_to_descriptor.begin(), m_isa_to_descriptor.end()); 228 } 229 230 void ObjCLanguageRuntime::ReadObjCLibraryIfNeeded( 231 const ModuleList &module_list) { 232 if (!HasReadObjCLibrary()) { 233 std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex()); 234 235 size_t num_modules = module_list.GetSize(); 236 for (size_t i = 0; i < num_modules; i++) { 237 auto mod = module_list.GetModuleAtIndex(i); 238 if (IsModuleObjCLibrary(mod)) { 239 ReadObjCLibrary(mod); 240 break; 241 } 242 } 243 } 244 } 245 246 ObjCLanguageRuntime::ObjCISA 247 ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa) { 248 ClassDescriptorSP objc_class_sp(GetClassDescriptorFromISA(isa)); 249 if (objc_class_sp) { 250 ClassDescriptorSP objc_super_class_sp(objc_class_sp->GetSuperclass()); 251 if (objc_super_class_sp) 252 return objc_super_class_sp->GetISA(); 253 } 254 return 0; 255 } 256 257 ObjCLanguageRuntime::ClassDescriptorSP 258 ObjCLanguageRuntime::GetClassDescriptorFromClassName( 259 ConstString class_name) { 260 ISAToDescriptorIterator pos = GetDescriptorIterator(class_name); 261 if (pos != m_isa_to_descriptor.end()) 262 return pos->second; 263 return ClassDescriptorSP(); 264 } 265 266 ObjCLanguageRuntime::ClassDescriptorSP 267 ObjCLanguageRuntime::GetClassDescriptor(ValueObject &valobj) { 268 ClassDescriptorSP objc_class_sp; 269 // if we get an invalid VO (which might still happen when playing around with 270 // pointers returned by the expression parser, don't consider this a valid 271 // ObjC object) 272 if (valobj.GetCompilerType().IsValid()) { 273 addr_t isa_pointer = valobj.GetPointerValue(); 274 if (isa_pointer != LLDB_INVALID_ADDRESS) { 275 ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); 276 277 Process *process = exe_ctx.GetProcessPtr(); 278 if (process) { 279 Status error; 280 ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); 281 if (isa != LLDB_INVALID_ADDRESS) 282 objc_class_sp = GetClassDescriptorFromISA(isa); 283 } 284 } 285 } 286 return objc_class_sp; 287 } 288 289 ObjCLanguageRuntime::ClassDescriptorSP 290 ObjCLanguageRuntime::GetNonKVOClassDescriptor(ValueObject &valobj) { 291 ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp( 292 GetClassDescriptor(valobj)); 293 if (objc_class_sp) { 294 if (!objc_class_sp->IsKVO()) 295 return objc_class_sp; 296 297 ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass()); 298 if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid()) 299 return non_kvo_objc_class_sp; 300 } 301 return ClassDescriptorSP(); 302 } 303 304 ObjCLanguageRuntime::ClassDescriptorSP 305 ObjCLanguageRuntime::GetClassDescriptorFromISA(ObjCISA isa) { 306 if (isa) { 307 UpdateISAToDescriptorMap(); 308 309 ObjCLanguageRuntime::ISAToDescriptorIterator pos = 310 m_isa_to_descriptor.find(isa); 311 if (pos != m_isa_to_descriptor.end()) 312 return pos->second; 313 314 if (ABISP abi_sp = m_process->GetABI()) { 315 pos = m_isa_to_descriptor.find(abi_sp->FixCodeAddress(isa)); 316 if (pos != m_isa_to_descriptor.end()) 317 return pos->second; 318 } 319 } 320 return ClassDescriptorSP(); 321 } 322 323 ObjCLanguageRuntime::ClassDescriptorSP 324 ObjCLanguageRuntime::GetNonKVOClassDescriptor(ObjCISA isa) { 325 if (isa) { 326 ClassDescriptorSP objc_class_sp = GetClassDescriptorFromISA(isa); 327 if (objc_class_sp && objc_class_sp->IsValid()) { 328 if (!objc_class_sp->IsKVO()) 329 return objc_class_sp; 330 331 ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass()); 332 if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid()) 333 return non_kvo_objc_class_sp; 334 } 335 } 336 return ClassDescriptorSP(); 337 } 338 339 CompilerType 340 ObjCLanguageRuntime::EncodingToType::RealizeType(const char *name, 341 bool for_expression) { 342 if (m_scratch_ast_ctx_sp) 343 return RealizeType(*m_scratch_ast_ctx_sp, name, for_expression); 344 return CompilerType(); 345 } 346 347 ObjCLanguageRuntime::EncodingToType::~EncodingToType() = default; 348 349 ObjCLanguageRuntime::EncodingToTypeSP ObjCLanguageRuntime::GetEncodingToType() { 350 return nullptr; 351 } 352 353 std::optional<uint64_t> 354 ObjCLanguageRuntime::GetTypeBitSize(const CompilerType &compiler_type) { 355 void *opaque_ptr = compiler_type.GetOpaqueQualType(); 356 uint64_t cached_size = m_type_size_cache.Lookup(opaque_ptr); 357 if (cached_size > 0) 358 return cached_size; 359 360 ClassDescriptorSP class_descriptor_sp = 361 GetClassDescriptorFromClassName(compiler_type.GetTypeName()); 362 if (!class_descriptor_sp) 363 return {}; 364 365 int32_t max_offset = INT32_MIN; 366 uint64_t sizeof_max = 0; 367 bool found = false; 368 369 for (size_t idx = 0; idx < class_descriptor_sp->GetNumIVars(); idx++) { 370 const auto &ivar = class_descriptor_sp->GetIVarAtIndex(idx); 371 int32_t cur_offset = ivar.m_offset; 372 if (cur_offset > max_offset) { 373 max_offset = cur_offset; 374 sizeof_max = ivar.m_size; 375 found = true; 376 } 377 } 378 379 uint64_t size = 8 * (max_offset + sizeof_max); 380 if (found && size > 0) { 381 m_type_size_cache.Insert(opaque_ptr, size); 382 return size; 383 } 384 385 return {}; 386 } 387 388 lldb::BreakpointPreconditionSP 389 ObjCLanguageRuntime::GetBreakpointExceptionPrecondition(LanguageType language, 390 bool throw_bp) { 391 if (language != eLanguageTypeObjC) 392 return lldb::BreakpointPreconditionSP(); 393 if (!throw_bp) 394 return lldb::BreakpointPreconditionSP(); 395 BreakpointPreconditionSP precondition_sp( 396 new ObjCLanguageRuntime::ObjCExceptionPrecondition()); 397 return precondition_sp; 398 } 399 400 // Exception breakpoint Precondition class for ObjC: 401 void ObjCLanguageRuntime::ObjCExceptionPrecondition::AddClassName( 402 const char *class_name) { 403 m_class_names.insert(class_name); 404 } 405 406 ObjCLanguageRuntime::ObjCExceptionPrecondition::ObjCExceptionPrecondition() = 407 default; 408 409 bool ObjCLanguageRuntime::ObjCExceptionPrecondition::EvaluatePrecondition( 410 StoppointCallbackContext &context) { 411 return true; 412 } 413 414 void ObjCLanguageRuntime::ObjCExceptionPrecondition::GetDescription( 415 Stream &stream, lldb::DescriptionLevel level) {} 416 417 Status ObjCLanguageRuntime::ObjCExceptionPrecondition::ConfigurePrecondition( 418 Args &args) { 419 Status error; 420 if (args.GetArgumentCount() > 0) 421 error = Status::FromErrorString( 422 "The ObjC Exception breakpoint doesn't support extra options."); 423 return error; 424 } 425 426 std::optional<CompilerType> 427 ObjCLanguageRuntime::GetRuntimeType(CompilerType base_type) { 428 CompilerType class_type; 429 bool is_pointer_type = false; 430 431 if (TypeSystemClang::IsObjCObjectPointerType(base_type, &class_type)) 432 is_pointer_type = true; 433 else if (TypeSystemClang::IsObjCObjectOrInterfaceType(base_type)) 434 class_type = base_type; 435 else 436 return std::nullopt; 437 438 if (!class_type) 439 return std::nullopt; 440 441 ConstString class_name(class_type.GetTypeName()); 442 if (!class_name) 443 return std::nullopt; 444 445 TypeSP complete_objc_class_type_sp = LookupInCompleteClassCache(class_name); 446 if (!complete_objc_class_type_sp) 447 return std::nullopt; 448 449 CompilerType complete_class( 450 complete_objc_class_type_sp->GetFullCompilerType()); 451 if (complete_class.GetCompleteType()) { 452 if (is_pointer_type) 453 return complete_class.GetPointerType(); 454 else 455 return complete_class; 456 } 457 458 return std::nullopt; 459 } 460