1 //===-- ObjCLanguageRuntime.cpp ---------------------------------*- C++ -*-===// 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 "lldb/Core/MappedHash.h" 13 #include "lldb/Core/Module.h" 14 #include "lldb/Core/PluginManager.h" 15 #include "lldb/Core/ValueObject.h" 16 #include "lldb/Symbol/ClangASTContext.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/Target.h" 23 #include "lldb/Utility/Log.h" 24 #include "lldb/Utility/Timer.h" 25 26 #include "llvm/ADT/StringRef.h" 27 #include "llvm/Support/DJB.h" 28 29 using namespace lldb; 30 using namespace lldb_private; 31 32 char ObjCLanguageRuntime::ID = 0; 33 34 // Destructor 35 ObjCLanguageRuntime::~ObjCLanguageRuntime() {} 36 37 ObjCLanguageRuntime::ObjCLanguageRuntime(Process *process) 38 : LanguageRuntime(process), m_impl_cache(), 39 m_has_new_literals_and_indexing(eLazyBoolCalculate), 40 m_isa_to_descriptor(), m_hash_to_isa_map(), m_type_size_cache(), 41 m_isa_to_descriptor_stop_id(UINT32_MAX), m_complete_class_cache(), 42 m_negative_complete_class_cache() {} 43 44 bool ObjCLanguageRuntime::IsWhitelistedRuntimeValue(ConstString name) { 45 static ConstString g_self = ConstString("self"); 46 static ConstString g_cmd = ConstString("_cmd"); 47 return name == g_self || name == g_cmd; 48 } 49 50 bool ObjCLanguageRuntime::AddClass(ObjCISA isa, 51 const ClassDescriptorSP &descriptor_sp, 52 const char *class_name) { 53 if (isa != 0) { 54 m_isa_to_descriptor[isa] = descriptor_sp; 55 // class_name is assumed to be valid 56 m_hash_to_isa_map.insert(std::make_pair(llvm::djbHash(class_name), isa)); 57 return true; 58 } 59 return false; 60 } 61 62 void ObjCLanguageRuntime::AddToMethodCache(lldb::addr_t class_addr, 63 lldb::addr_t selector, 64 lldb::addr_t impl_addr) { 65 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 66 if (log) { 67 log->Printf("Caching: class 0x%" PRIx64 " selector 0x%" PRIx64 68 " implementation 0x%" PRIx64 ".", 69 class_addr, selector, impl_addr); 70 } 71 m_impl_cache.insert(std::pair<ClassAndSel, lldb::addr_t>( 72 ClassAndSel(class_addr, selector), impl_addr)); 73 } 74 75 lldb::addr_t ObjCLanguageRuntime::LookupInMethodCache(lldb::addr_t class_addr, 76 lldb::addr_t selector) { 77 MsgImplMap::iterator pos, end = m_impl_cache.end(); 78 pos = m_impl_cache.find(ClassAndSel(class_addr, selector)); 79 if (pos != end) 80 return (*pos).second; 81 return LLDB_INVALID_ADDRESS; 82 } 83 84 lldb::TypeSP 85 ObjCLanguageRuntime::LookupInCompleteClassCache(ConstString &name) { 86 CompleteClassMap::iterator complete_class_iter = 87 m_complete_class_cache.find(name); 88 89 if (complete_class_iter != m_complete_class_cache.end()) { 90 // Check the weak pointer to make sure the type hasn't been unloaded 91 TypeSP complete_type_sp(complete_class_iter->second.lock()); 92 93 if (complete_type_sp) 94 return complete_type_sp; 95 else 96 m_complete_class_cache.erase(name); 97 } 98 99 if (m_negative_complete_class_cache.count(name) > 0) 100 return TypeSP(); 101 102 const ModuleList &modules = m_process->GetTarget().GetImages(); 103 104 SymbolContextList sc_list; 105 const size_t matching_symbols = 106 modules.FindSymbolsWithNameAndType(name, eSymbolTypeObjCClass, sc_list); 107 108 if (matching_symbols) { 109 SymbolContext sc; 110 111 sc_list.GetContextAtIndex(0, sc); 112 113 ModuleSP module_sp(sc.module_sp); 114 115 if (!module_sp) 116 return TypeSP(); 117 118 const bool exact_match = true; 119 const uint32_t max_matches = UINT32_MAX; 120 TypeList types; 121 122 llvm::DenseSet<SymbolFile *> searched_symbol_files; 123 const uint32_t num_types = module_sp->FindTypes( 124 name, exact_match, max_matches, searched_symbol_files, types); 125 126 if (num_types) { 127 uint32_t i; 128 for (i = 0; i < num_types; ++i) { 129 TypeSP type_sp(types.GetTypeAtIndex(i)); 130 131 if (ClangASTContext::IsObjCObjectOrInterfaceType( 132 type_sp->GetForwardCompilerType())) { 133 if (type_sp->IsCompleteObjCClass()) { 134 m_complete_class_cache[name] = type_sp; 135 return type_sp; 136 } 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 ConstString 228 ObjCLanguageRuntime::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) { 229 ClassDescriptorSP objc_class_sp(GetNonKVOClassDescriptor(isa)); 230 if (objc_class_sp) 231 return objc_class_sp->GetClassName(); 232 return ConstString(); 233 } 234 235 ObjCLanguageRuntime::ClassDescriptorSP 236 ObjCLanguageRuntime::GetClassDescriptorFromClassName( 237 ConstString class_name) { 238 ISAToDescriptorIterator pos = GetDescriptorIterator(class_name); 239 if (pos != m_isa_to_descriptor.end()) 240 return pos->second; 241 return ClassDescriptorSP(); 242 } 243 244 ObjCLanguageRuntime::ClassDescriptorSP 245 ObjCLanguageRuntime::GetClassDescriptor(ValueObject &valobj) { 246 ClassDescriptorSP objc_class_sp; 247 // if we get an invalid VO (which might still happen when playing around with 248 // pointers returned by the expression parser, don't consider this a valid 249 // ObjC object) 250 if (valobj.GetCompilerType().IsValid()) { 251 addr_t isa_pointer = valobj.GetPointerValue(); 252 if (isa_pointer != LLDB_INVALID_ADDRESS) { 253 ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); 254 255 Process *process = exe_ctx.GetProcessPtr(); 256 if (process) { 257 Status error; 258 ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); 259 if (isa != LLDB_INVALID_ADDRESS) 260 objc_class_sp = GetClassDescriptorFromISA(isa); 261 } 262 } 263 } 264 return objc_class_sp; 265 } 266 267 ObjCLanguageRuntime::ClassDescriptorSP 268 ObjCLanguageRuntime::GetNonKVOClassDescriptor(ValueObject &valobj) { 269 ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp( 270 GetClassDescriptor(valobj)); 271 if (objc_class_sp) { 272 if (!objc_class_sp->IsKVO()) 273 return objc_class_sp; 274 275 ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass()); 276 if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid()) 277 return non_kvo_objc_class_sp; 278 } 279 return ClassDescriptorSP(); 280 } 281 282 ObjCLanguageRuntime::ClassDescriptorSP 283 ObjCLanguageRuntime::GetClassDescriptorFromISA(ObjCISA isa) { 284 if (isa) { 285 UpdateISAToDescriptorMap(); 286 ObjCLanguageRuntime::ISAToDescriptorIterator pos = 287 m_isa_to_descriptor.find(isa); 288 if (pos != m_isa_to_descriptor.end()) 289 return pos->second; 290 } 291 return ClassDescriptorSP(); 292 } 293 294 ObjCLanguageRuntime::ClassDescriptorSP 295 ObjCLanguageRuntime::GetNonKVOClassDescriptor(ObjCISA isa) { 296 if (isa) { 297 ClassDescriptorSP objc_class_sp = GetClassDescriptorFromISA(isa); 298 if (objc_class_sp && objc_class_sp->IsValid()) { 299 if (!objc_class_sp->IsKVO()) 300 return objc_class_sp; 301 302 ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass()); 303 if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid()) 304 return non_kvo_objc_class_sp; 305 } 306 } 307 return ClassDescriptorSP(); 308 } 309 310 CompilerType 311 ObjCLanguageRuntime::EncodingToType::RealizeType(const char *name, 312 bool for_expression) { 313 if (m_scratch_ast_ctx_up) 314 return RealizeType(*m_scratch_ast_ctx_up, name, for_expression); 315 return CompilerType(); 316 } 317 318 CompilerType ObjCLanguageRuntime::EncodingToType::RealizeType( 319 ClangASTContext &ast_ctx, const char *name, bool for_expression) { 320 clang::ASTContext *clang_ast = ast_ctx.getASTContext(); 321 if (!clang_ast) 322 return CompilerType(); 323 return RealizeType(*clang_ast, name, for_expression); 324 } 325 326 ObjCLanguageRuntime::EncodingToType::~EncodingToType() {} 327 328 ObjCLanguageRuntime::EncodingToTypeSP ObjCLanguageRuntime::GetEncodingToType() { 329 return nullptr; 330 } 331 332 bool ObjCLanguageRuntime::GetTypeBitSize(const CompilerType &compiler_type, 333 uint64_t &size) { 334 void *opaque_ptr = compiler_type.GetOpaqueQualType(); 335 size = m_type_size_cache.Lookup(opaque_ptr); 336 // an ObjC object will at least have an ISA, so 0 is definitely not OK 337 if (size > 0) 338 return true; 339 340 ClassDescriptorSP class_descriptor_sp = 341 GetClassDescriptorFromClassName(compiler_type.GetTypeName()); 342 if (!class_descriptor_sp) 343 return false; 344 345 int32_t max_offset = INT32_MIN; 346 uint64_t sizeof_max = 0; 347 bool found = false; 348 349 for (size_t idx = 0; idx < class_descriptor_sp->GetNumIVars(); idx++) { 350 const auto &ivar = class_descriptor_sp->GetIVarAtIndex(idx); 351 int32_t cur_offset = ivar.m_offset; 352 if (cur_offset > max_offset) { 353 max_offset = cur_offset; 354 sizeof_max = ivar.m_size; 355 found = true; 356 } 357 } 358 359 size = 8 * (max_offset + sizeof_max); 360 if (found) 361 m_type_size_cache.Insert(opaque_ptr, size); 362 363 return found; 364 } 365 366 lldb::BreakpointPreconditionSP 367 ObjCLanguageRuntime::GetBreakpointExceptionPrecondition(LanguageType language, 368 bool throw_bp) { 369 if (language != eLanguageTypeObjC) 370 return lldb::BreakpointPreconditionSP(); 371 if (!throw_bp) 372 return lldb::BreakpointPreconditionSP(); 373 BreakpointPreconditionSP precondition_sp( 374 new ObjCLanguageRuntime::ObjCExceptionPrecondition()); 375 return precondition_sp; 376 } 377 378 // Exception breakpoint Precondition class for ObjC: 379 void ObjCLanguageRuntime::ObjCExceptionPrecondition::AddClassName( 380 const char *class_name) { 381 m_class_names.insert(class_name); 382 } 383 384 ObjCLanguageRuntime::ObjCExceptionPrecondition::ObjCExceptionPrecondition() {} 385 386 bool ObjCLanguageRuntime::ObjCExceptionPrecondition::EvaluatePrecondition( 387 StoppointCallbackContext &context) { 388 return true; 389 } 390 391 void ObjCLanguageRuntime::ObjCExceptionPrecondition::GetDescription( 392 Stream &stream, lldb::DescriptionLevel level) {} 393 394 Status ObjCLanguageRuntime::ObjCExceptionPrecondition::ConfigurePrecondition( 395 Args &args) { 396 Status error; 397 if (args.GetArgumentCount() > 0) 398 error.SetErrorString( 399 "The ObjC Exception breakpoint doesn't support extra options."); 400 return error; 401 } 402 403 llvm::Optional<CompilerType> 404 ObjCLanguageRuntime::GetRuntimeType(CompilerType base_type) { 405 CompilerType class_type; 406 bool is_pointer_type = false; 407 408 if (ClangASTContext::IsObjCObjectPointerType(base_type, &class_type)) 409 is_pointer_type = true; 410 else if (ClangASTContext::IsObjCObjectOrInterfaceType(base_type)) 411 class_type = base_type; 412 else 413 return llvm::None; 414 415 if (!class_type) 416 return llvm::None; 417 418 ConstString class_name(class_type.GetConstTypeName()); 419 if (!class_name) 420 return llvm::None; 421 422 TypeSP complete_objc_class_type_sp = LookupInCompleteClassCache(class_name); 423 if (!complete_objc_class_type_sp) 424 return llvm::None; 425 426 CompilerType complete_class( 427 complete_objc_class_type_sp->GetFullCompilerType()); 428 if (complete_class.GetCompleteType()) { 429 if (is_pointer_type) 430 return complete_class.GetPointerType(); 431 else 432 return complete_class; 433 } 434 435 return llvm::None; 436 } 437