brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.1 KiB · 2b2ca08 Raw
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