503 lines · cpp
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-exception6//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 31using namespace lldb;32using namespace lldb_private;33 34char ObjCLanguageRuntime::ID = 0;35 36// Destructor37ObjCLanguageRuntime::~ObjCLanguageRuntime() = default;38 39ObjCLanguageRuntime::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 46bool 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 52bool 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 valid58 m_hash_to_isa_map.insert(std::make_pair(llvm::djbHash(class_name), isa));59 return true;60 }61 return false;62}63 64void 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%" PRIx6471 " 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 78void 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 90lldb::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 99lldb::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 108lldb::TypeSP109ObjCLanguageRuntime::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 unloaded115 TypeSP complete_type_sp(complete_class_iter->second.lock());116 117 if (complete_type_sp)118 return complete_type_sp;119 else120 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 159size_t ObjCLanguageRuntime::GetByteOffsetForIvar(CompilerType &parent_qual_type,160 const char *ivar_name) {161 return LLDB_INVALID_IVAR_OFFSET;162}163 164bool 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 else174 return false;175}176 177ObjCLanguageRuntime::ObjCISA178ObjCLanguageRuntime::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 185ObjCLanguageRuntime::ISAToDescriptorIterator186ObjCLanguageRuntime::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 through193 // the names and find a match194 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 to201 // isa/descriptor202 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 219std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator,220 ObjCLanguageRuntime::ISAToDescriptorIterator>221ObjCLanguageRuntime::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 230void 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 246ObjCLanguageRuntime::ObjCISA247ObjCLanguageRuntime::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 257ObjCLanguageRuntime::ClassDescriptorSP258ObjCLanguageRuntime::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 266ObjCLanguageRuntime::ClassDescriptorSP267ObjCLanguageRuntime::GetClassDescriptor(ValueObject &valobj) {268 ClassDescriptorSP objc_class_sp;269 // if we get an invalid VO (which might still happen when playing around with270 // pointers returned by the expression parser, don't consider this a valid271 // ObjC object)272 if (valobj.GetCompilerType().IsValid()) {273 addr_t isa_pointer = valobj.GetPointerValue().address;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 289ObjCLanguageRuntime::ClassDescriptorSP290ObjCLanguageRuntime::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 304ObjCLanguageRuntime::ClassDescriptorSP305ObjCLanguageRuntime::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 323ObjCLanguageRuntime::ClassDescriptorSP324ObjCLanguageRuntime::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 339CompilerType340ObjCLanguageRuntime::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 347ObjCLanguageRuntime::EncodingToType::~EncodingToType() = default;348 349ObjCLanguageRuntime::EncodingToTypeSP ObjCLanguageRuntime::GetEncodingToType() {350 return nullptr;351}352 353std::optional<uint64_t>354ObjCLanguageRuntime::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 388lldb::BreakpointPreconditionSP389ObjCLanguageRuntime::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:401void ObjCLanguageRuntime::ObjCExceptionPrecondition::AddClassName(402 const char *class_name) {403 m_class_names.insert(class_name);404}405 406ObjCLanguageRuntime::ObjCExceptionPrecondition::ObjCExceptionPrecondition() =407 default;408 409bool ObjCLanguageRuntime::ObjCExceptionPrecondition::EvaluatePrecondition(410 StoppointCallbackContext &context) {411 return true;412}413 414void ObjCLanguageRuntime::ObjCExceptionPrecondition::GetDescription(415 Stream &stream, lldb::DescriptionLevel level) {}416 417Status 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 426CompilerType ObjCLanguageRuntime::LookupInModulesVendor(ConstString class_name,427 Target &target) {428 assert(class_name);429 430 auto *persistent_state = llvm::cast<ClangPersistentVariables>(431 target.GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC));432 if (!persistent_state)433 return {};434 435 auto clang_modules_decl_vendor_sp =436 persistent_state->GetClangModulesDeclVendor();437 if (!clang_modules_decl_vendor_sp)438 return {};439 440 auto types = clang_modules_decl_vendor_sp->FindTypes(441 class_name, /*max_matches*/ UINT32_MAX);442 if (types.empty())443 return {};444 445 return types.front();446}447 448CompilerType ObjCLanguageRuntime::LookupInRuntime(ConstString class_name) {449 auto *runtime_vendor = GetDeclVendor();450 if (!runtime_vendor)451 return {};452 453 std::vector<CompilerDecl> compiler_decls;454 runtime_vendor->FindDecls(class_name, false, UINT32_MAX, compiler_decls);455 if (compiler_decls.empty())456 return {};457 458 auto *ctx =459 llvm::dyn_cast<TypeSystemClang>(compiler_decls[0].GetTypeSystem());460 if (!ctx)461 return {};462 463 return ctx->GetTypeForDecl(compiler_decls[0].GetOpaqueDecl());464}465 466std::optional<CompilerType>467ObjCLanguageRuntime::GetRuntimeType(CompilerType base_type) {468 CompilerType class_type;469 bool is_pointer_type = false;470 471 if (TypeSystemClang::IsObjCObjectPointerType(base_type, &class_type))472 is_pointer_type = true;473 else if (TypeSystemClang::IsObjCObjectOrInterfaceType(base_type))474 class_type = base_type;475 else476 return std::nullopt;477 478 if (!class_type)479 return std::nullopt;480 481 ConstString class_name(class_type.GetTypeName());482 if (!class_name)483 return std::nullopt;484 485 if (TypeSP complete_objc_class_type_sp =486 LookupInCompleteClassCache(class_name)) {487 if (CompilerType complete_class =488 complete_objc_class_type_sp->GetFullCompilerType();489 complete_class.GetCompleteType())490 return is_pointer_type ? complete_class.GetPointerType() : complete_class;491 }492 493 assert(m_process);494 if (CompilerType found =495 LookupInModulesVendor(class_name, m_process->GetTarget()))496 return is_pointer_type ? found.GetPointerType() : found;497 498 if (CompilerType found = LookupInRuntime(class_name))499 return is_pointer_type ? found.GetPointerType() : found;500 501 return std::nullopt;502}503