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