brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.8 KiB · b1f2a66 Raw
432 lines · cpp
1//===-- AppleObjCRuntimeV1.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 9#include "AppleObjCRuntimeV1.h"10#include "AppleObjCDeclVendor.h"11#include "AppleObjCTrampolineHandler.h"12 13#include "clang/AST/Type.h"14 15#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"16#include "lldb/Breakpoint/BreakpointLocation.h"17#include "lldb/Core/Module.h"18#include "lldb/Core/PluginManager.h"19#include "lldb/Expression/FunctionCaller.h"20#include "lldb/Expression/UtilityFunction.h"21#include "lldb/Symbol/Symbol.h"22#include "lldb/Target/ExecutionContext.h"23#include "lldb/Target/Process.h"24#include "lldb/Target/RegisterContext.h"25#include "lldb/Target/Target.h"26#include "lldb/Target/Thread.h"27#include "lldb/Utility/ConstString.h"28#include "lldb/Utility/LLDBLog.h"29#include "lldb/Utility/Log.h"30#include "lldb/Utility/Scalar.h"31#include "lldb/Utility/Status.h"32#include "lldb/Utility/StreamString.h"33 34#include <memory>35#include <vector>36 37using namespace lldb;38using namespace lldb_private;39 40char AppleObjCRuntimeV1::ID = 0;41 42AppleObjCRuntimeV1::AppleObjCRuntimeV1(Process *process)43    : AppleObjCRuntime(process), m_hash_signature(),44      m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS) {}45 46// for V1 runtime we just try to return a class name as that is the minimum47// level of support required for the data formatters to work48bool AppleObjCRuntimeV1::GetDynamicTypeAndAddress(49    ValueObject &in_value, lldb::DynamicValueType use_dynamic,50    TypeAndOrName &class_type_or_name, Address &address,51    Value::ValueType &value_type, llvm::ArrayRef<uint8_t> &local_buffer) {52  class_type_or_name.Clear();53  value_type = Value::ValueType::Scalar;54  if (CouldHaveDynamicValue(in_value)) {55    auto class_descriptor(GetClassDescriptor(in_value));56    if (class_descriptor && class_descriptor->IsValid() &&57        class_descriptor->GetClassName()) {58      const addr_t object_ptr = in_value.GetPointerValue().address;59      address.SetRawAddress(object_ptr);60      class_type_or_name.SetName(class_descriptor->GetClassName());61    }62  }63  return !class_type_or_name.IsEmpty();64}65 66// Static Functions67lldb_private::LanguageRuntime *68AppleObjCRuntimeV1::CreateInstance(Process *process,69                                   lldb::LanguageType language) {70  // FIXME: This should be a MacOS or iOS process, and we need to look for the71  // OBJC section to make72  // sure we aren't using the V1 runtime.73  if (language == eLanguageTypeObjC) {74    ModuleSP objc_module_sp;75 76    if (AppleObjCRuntime::GetObjCVersion(process, objc_module_sp) ==77        ObjCRuntimeVersions::eAppleObjC_V1)78      return new AppleObjCRuntimeV1(process);79    else80      return nullptr;81  } else82    return nullptr;83}84 85void AppleObjCRuntimeV1::Initialize() {86  PluginManager::RegisterPlugin(87      GetPluginNameStatic(), "Apple Objective-C Language Runtime - Version 1",88      CreateInstance,89      /*command_callback = */ nullptr, GetBreakpointExceptionPrecondition);90}91 92void AppleObjCRuntimeV1::Terminate() {93  PluginManager::UnregisterPlugin(CreateInstance);94}95 96BreakpointResolverSP97AppleObjCRuntimeV1::CreateExceptionResolver(const BreakpointSP &bkpt,98                                            bool catch_bp, bool throw_bp) {99  BreakpointResolverSP resolver_sp;100 101  if (throw_bp)102    resolver_sp = std::make_shared<BreakpointResolverName>(103        bkpt, std::get<1>(GetExceptionThrowLocation()).AsCString(),104        eFunctionNameTypeBase, eLanguageTypeUnknown, Breakpoint::Exact, 0,105        /*offset_is_insn_count = */ false, eLazyBoolNo);106  // FIXME: don't do catch yet.107  return resolver_sp;108}109 110struct BufStruct {111  char contents[2048];112};113 114llvm::Expected<std::unique_ptr<UtilityFunction>>115AppleObjCRuntimeV1::CreateObjectChecker(std::string name,116                                        ExecutionContext &exe_ctx) {117  std::unique_ptr<BufStruct> buf(new BufStruct);118 119  int strformatsize =120      snprintf(&buf->contents[0], sizeof(buf->contents),121               "struct __objc_class                                         "122               "           \n"123               "{                                                           "124               "           \n"125               "   struct __objc_class *isa;                                "126               "           \n"127               "   struct __objc_class *super_class;                        "128               "           \n"129               "   const char *name;                                        "130               "           \n"131               "   // rest of struct elided because unused                  "132               "           \n"133               "};                                                          "134               "           \n"135               "                                                            "136               "           \n"137               "struct __objc_object                                        "138               "           \n"139               "{                                                           "140               "           \n"141               "   struct __objc_class *isa;                                "142               "           \n"143               "};                                                          "144               "           \n"145               "                                                            "146               "           \n"147               "extern \"C\" void                                           "148               "           \n"149               "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector)       "150               "           \n"151               "{                                                           "152               "           \n"153               "   struct __objc_object *obj = (struct "154               "__objc_object*)$__lldb_arg_obj; \n"155               "   if ($__lldb_arg_obj == (void *)0)                     "156               "                                \n"157               "       return; // nil is ok                              "158               "   (int)strlen(obj->isa->name);                             "159               "           \n"160               "}                                                           "161               "           \n",162               name.c_str());163  assert(strformatsize < (int)sizeof(buf->contents));164  UNUSED_IF_ASSERT_DISABLED(strformatsize);165 166  return GetTargetRef().CreateUtilityFunction(buf->contents, std::move(name),167                                              eLanguageTypeC, exe_ctx);168}169 170AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1(171    ValueObject &isa_pointer) {172  Initialize(isa_pointer.GetValueAsUnsigned(0), isa_pointer.GetProcessSP());173}174 175AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1(176    ObjCISA isa, lldb::ProcessSP process_sp) {177  Initialize(isa, process_sp);178}179 180void AppleObjCRuntimeV1::ClassDescriptorV1::Initialize(181    ObjCISA isa, lldb::ProcessSP process_sp) {182  if (!isa || !process_sp) {183    m_valid = false;184    return;185  }186 187  m_valid = true;188 189  Status error;190 191  m_isa = process_sp->ReadPointerFromMemory(isa, error);192 193  if (error.Fail()) {194    m_valid = false;195    return;196  }197 198  uint32_t ptr_size = process_sp->GetAddressByteSize();199 200  if (!IsPointerValid(m_isa, ptr_size)) {201    m_valid = false;202    return;203  }204 205  m_parent_isa = process_sp->ReadPointerFromMemory(m_isa + ptr_size, error);206 207  if (error.Fail()) {208    m_valid = false;209    return;210  }211 212  if (!IsPointerValid(m_parent_isa, ptr_size, true)) {213    m_valid = false;214    return;215  }216 217  lldb::addr_t name_ptr =218      process_sp->ReadPointerFromMemory(m_isa + 2 * ptr_size, error);219 220  if (error.Fail()) {221    m_valid = false;222    return;223  }224 225  lldb::WritableDataBufferSP buffer_sp(new DataBufferHeap(1024, 0));226 227  size_t count = process_sp->ReadCStringFromMemory(228      name_ptr, (char *)buffer_sp->GetBytes(), 1024, error);229 230  if (error.Fail()) {231    m_valid = false;232    return;233  }234 235  if (count)236    m_name = ConstString(reinterpret_cast<const char *>(buffer_sp->GetBytes()));237  else238    m_name = ConstString();239 240  m_instance_size = process_sp->ReadUnsignedIntegerFromMemory(241      m_isa + 5 * ptr_size, ptr_size, 0, error);242 243  if (error.Fail()) {244    m_valid = false;245    return;246  }247 248  m_process_wp = lldb::ProcessWP(process_sp);249}250 251AppleObjCRuntime::ClassDescriptorSP252AppleObjCRuntimeV1::ClassDescriptorV1::GetSuperclass() {253  if (!m_valid)254    return AppleObjCRuntime::ClassDescriptorSP();255  ProcessSP process_sp = m_process_wp.lock();256  if (!process_sp)257    return AppleObjCRuntime::ClassDescriptorSP();258  return ObjCLanguageRuntime::ClassDescriptorSP(259      new AppleObjCRuntimeV1::ClassDescriptorV1(m_parent_isa, process_sp));260}261 262AppleObjCRuntime::ClassDescriptorSP263AppleObjCRuntimeV1::ClassDescriptorV1::GetMetaclass() const {264  return ClassDescriptorSP();265}266 267bool AppleObjCRuntimeV1::ClassDescriptorV1::Describe(268    std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func,269    std::function<bool(const char *, const char *)> const &instance_method_func,270    std::function<bool(const char *, const char *)> const &class_method_func,271    std::function<bool(const char *, const char *, lldb::addr_t,272                       uint64_t)> const &ivar_func) const {273  return false;274}275 276lldb::addr_t AppleObjCRuntimeV1::GetTaggedPointerObfuscator() {277  return 0;278}279 280lldb::addr_t AppleObjCRuntimeV1::GetISAHashTablePointer() {281  if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS) {282    ModuleSP objc_module_sp(GetObjCModule());283 284    if (!objc_module_sp)285      return LLDB_INVALID_ADDRESS;286 287    static ConstString g_objc_debug_class_hash("_objc_debug_class_hash");288 289    const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(290        g_objc_debug_class_hash, lldb::eSymbolTypeData);291    if (symbol && symbol->ValueIsAddress()) {292      Process *process = GetProcess();293      if (process) {294 295        lldb::addr_t objc_debug_class_hash_addr =296            symbol->GetAddressRef().GetLoadAddress(&process->GetTarget());297 298        if (objc_debug_class_hash_addr != LLDB_INVALID_ADDRESS) {299          Status error;300          lldb::addr_t objc_debug_class_hash_ptr =301              process->ReadPointerFromMemory(objc_debug_class_hash_addr, error);302          if (objc_debug_class_hash_ptr != 0 &&303              objc_debug_class_hash_ptr != LLDB_INVALID_ADDRESS) {304            m_isa_hash_table_ptr = objc_debug_class_hash_ptr;305          }306        }307      }308    }309  }310  return m_isa_hash_table_ptr;311}312 313void AppleObjCRuntimeV1::UpdateISAToDescriptorMapIfNeeded() {314  // TODO: implement HashTableSignature...315  Process *process = GetProcess();316 317  if (process) {318    // Update the process stop ID that indicates the last time we updated the319    // map, whether it was successful or not.320    m_isa_to_descriptor_stop_id = process->GetStopID();321 322    Log *log = GetLog(LLDBLog::Process);323 324    ProcessSP process_sp = process->shared_from_this();325 326    ModuleSP objc_module_sp(GetObjCModule());327 328    if (!objc_module_sp)329      return;330 331    lldb::addr_t hash_table_ptr = GetISAHashTablePointer();332    if (hash_table_ptr != LLDB_INVALID_ADDRESS) {333      // Read the NXHashTable struct:334      //335      // typedef struct {336      //     const NXHashTablePrototype *prototype;337      //     unsigned   count;338      //     unsigned   nbBuckets;339      //     void       *buckets;340      //     const void *info;341      // } NXHashTable;342 343      Status error;344      DataBufferHeap buffer(1024, 0);345      if (process->ReadMemory(hash_table_ptr, buffer.GetBytes(), 20, error) ==346          20) {347        const uint32_t addr_size = m_process->GetAddressByteSize();348        const ByteOrder byte_order = m_process->GetByteOrder();349        DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(), byte_order,350                           addr_size);351        lldb::offset_t offset = addr_size; // Skip prototype352        const uint32_t count = data.GetU32(&offset);353        const uint32_t num_buckets = data.GetU32(&offset);354        const addr_t buckets_ptr = data.GetAddress(&offset);355        if (m_hash_signature.NeedsUpdate(count, num_buckets, buckets_ptr)) {356          m_hash_signature.UpdateSignature(count, num_buckets, buckets_ptr);357 358          const uint32_t data_size = num_buckets * 2 * sizeof(uint32_t);359          buffer.SetByteSize(data_size);360 361          if (process->ReadMemory(buckets_ptr, buffer.GetBytes(), data_size,362                                  error) == data_size) {363            data.SetData(buffer.GetBytes(), buffer.GetByteSize(), byte_order);364            offset = 0;365            for (uint32_t bucket_idx = 0; bucket_idx < num_buckets;366                 ++bucket_idx) {367              const uint32_t bucket_isa_count = data.GetU32(&offset);368              const lldb::addr_t bucket_data = data.GetU32(&offset);369 370              if (bucket_isa_count == 0)371                continue;372 373              ObjCISA isa;374              if (bucket_isa_count == 1) {375                // When we only have one entry in the bucket, the bucket data376                // is the "isa"377                isa = bucket_data;378                if (isa) {379                  if (!ISAIsCached(isa)) {380                    ClassDescriptorSP descriptor_sp(381                        new ClassDescriptorV1(isa, process_sp));382 383                    if (log && log->GetVerbose())384                      LLDB_LOGF(log,385                                "AppleObjCRuntimeV1 added (ObjCISA)0x%" PRIx64386                                " from _objc_debug_class_hash to "387                                "isa->descriptor cache",388                                isa);389 390                    AddClass(isa, descriptor_sp);391                  }392                }393              } else {394                // When we have more than one entry in the bucket, the bucket395                // data is a pointer to an array of "isa" values396                addr_t isa_addr = bucket_data;397                for (uint32_t isa_idx = 0; isa_idx < bucket_isa_count;398                     ++isa_idx, isa_addr += addr_size) {399                  isa = m_process->ReadPointerFromMemory(isa_addr, error);400 401                  if (isa && isa != LLDB_INVALID_ADDRESS) {402                    if (!ISAIsCached(isa)) {403                      ClassDescriptorSP descriptor_sp(404                          new ClassDescriptorV1(isa, process_sp));405 406                      if (log && log->GetVerbose())407                        LLDB_LOGF(408                            log,409                            "AppleObjCRuntimeV1 added (ObjCISA)0x%" PRIx64410                            " from _objc_debug_class_hash to isa->descriptor "411                            "cache",412                            isa);413 414                      AddClass(isa, descriptor_sp);415                    }416                  }417                }418              }419            }420          }421        }422      }423    }424  } else {425    m_isa_to_descriptor_stop_id = UINT32_MAX;426  }427}428 429DeclVendor *AppleObjCRuntimeV1::GetDeclVendor() {430  return nullptr;431}432