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