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