From f0246d151803fd47fb660fbaeb109ceb13dbf697 Mon Sep 17 00:00:00 2001 From: Greg Clayton Date: Thu, 11 Oct 2012 18:07:21 +0000 Subject: [PATCH] Dynamic type code must be efficient and fast. Now it is. Added ObjC v1 support for getting the complete list of ISA values. The main flow of the AppleObjCRuntime subclasses is now they must override "virtual bool UpdateISAToDescriptorMap_Impl();". This function will update the complete list of ISA values and create ClassDescriptorSP objects for each one. Now we have the complete list of valid ISA values which we can use for verification when doing dynamic typing. Refactored a bunch of stuff so that the AppleObjCRuntime subclasses don't have to implement as many functions as they used to. llvm-svn: 165730 --- lldb/include/lldb/Core/FormatNavigator.h | 6 +- lldb/include/lldb/Target/ObjCLanguageRuntime.h | 33 ++- lldb/source/Core/ValueObject.cpp | 9 +- .../ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp | 40 ++- .../ObjC/AppleObjCRuntime/AppleObjCRuntime.h | 18 +- .../ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp | 182 ++++++++++--- .../ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h | 13 +- .../ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp | 303 +++++++-------------- .../ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h | 15 +- lldb/source/Target/ObjCLanguageRuntime.cpp | 99 ++++--- 10 files changed, 379 insertions(+), 339 deletions(-) diff --git a/lldb/include/lldb/Core/FormatNavigator.h b/lldb/include/lldb/Core/FormatNavigator.h index 4c0af74..cdabd63 100644 --- a/lldb/include/lldb/Core/FormatNavigator.h +++ b/lldb/include/lldb/Core/FormatNavigator.h @@ -504,14 +504,14 @@ protected: log->Printf("no valid ObjC runtime, skipping dynamic"); return false; } - ObjCLanguageRuntime::ObjCISA isa = runtime->GetISA(valobj); - if (runtime->IsValidISA(isa) == false) + ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp (runtime->GetClassDescriptor(valobj)); + if (!objc_class_sp) { if (log) log->Printf("invalid ISA, skipping dynamic"); return false; } - ConstString name = runtime->GetActualTypeName(isa); + ConstString name (objc_class_sp->GetClassName()); if (log) log->Printf("dynamic type inferred is %s - looking for direct dynamic match", name.GetCString()); if (Get(name, entry)) diff --git a/lldb/include/lldb/Target/ObjCLanguageRuntime.h b/lldb/include/lldb/Target/ObjCLanguageRuntime.h index 97cefdc..7be517b 100644 --- a/lldb/include/lldb/Target/ObjCLanguageRuntime.h +++ b/lldb/include/lldb/Target/ObjCLanguageRuntime.h @@ -174,12 +174,18 @@ public: virtual ClassDescriptorSP GetClassDescriptor (ValueObject& in_value); + ClassDescriptorSP + GetNonKVOClassDescriptor (ValueObject& in_value); + + virtual ClassDescriptorSP + GetClassDescriptor (const ConstString &class_name); + virtual ClassDescriptorSP GetClassDescriptor (ObjCISA isa); ClassDescriptorSP GetNonKVOClassDescriptor (ObjCISA isa); - + virtual ~ObjCLanguageRuntime(); @@ -200,10 +206,7 @@ public: virtual lldb::ThreadPlanSP GetStepThroughTrampolinePlan (Thread &thread, bool stop_others) = 0; - - virtual ClassDescriptorSP - CreateClassDescriptor (ObjCISA isa) = 0; - + lldb::addr_t LookupInMethodCache (lldb::addr_t class_addr, lldb::addr_t sel); @@ -231,17 +234,15 @@ public: return eObjC_VersionUnknown; } - virtual bool - IsValidISA(ObjCISA isa) = 0; - - virtual ObjCISA - GetISA(ValueObject& valobj) = 0; - - virtual void - UpdateISAToDescriptorMap_Impl() + bool + IsValidISA(ObjCISA isa) { - // to be implemented by runtimes if they support doing this + UpdateISAToDescriptorMap(); + return m_isa_to_descriptor_cache.count(isa) > 0; } + + virtual bool + UpdateISAToDescriptorMap_Impl() = 0; void UpdateISAToDescriptorMap() @@ -249,9 +250,7 @@ public: if (m_isa_to_descriptor_cache_is_up_to_date) return; - m_isa_to_descriptor_cache_is_up_to_date = true; - - UpdateISAToDescriptorMap_Impl(); + m_isa_to_descriptor_cache_is_up_to_date = UpdateISAToDescriptorMap_Impl(); } virtual ObjCISA diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index fe34724..9debcc0 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -3223,12 +3223,11 @@ DumpValueObject_Impl (Stream &s, s.Printf(", dynamic type: unknown) "); else { - ObjCLanguageRuntime::ObjCISA isa = runtime->GetISA(*valobj); - if (!runtime->IsValidISA(isa)) - s.Printf(", dynamic type: unknown) "); + ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp (runtime->GetNonKVOClassDescriptor(*valobj)); + if (objc_class_sp) + s.Printf(", dynamic type: %s) ", objc_class_sp->GetClassName().GetCString()); else - s.Printf(", dynamic type: %s) ", - runtime->GetActualTypeName(isa).GetCString()); + s.Printf(", dynamic type: unknown) "); } } } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp index 4d001d8..995a438 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp @@ -168,6 +168,30 @@ AppleObjCRuntime::GetObjectDescription (Stream &strm, Value &value, ExecutionCon return cstr_len > 0; } +lldb::ModuleSP +AppleObjCRuntime::GetObjCModule () +{ + ModuleSP module_sp (m_objc_module_wp.lock()); + if (module_sp) + return module_sp; + + Process *process = GetProcess(); + if (process) + { + ModuleList& modules = process->GetTarget().GetImages(); + for (uint32_t idx = 0; idx < modules.GetSize(); idx++) + { + module_sp = modules.GetModuleAtIndex(idx); + if (AppleObjCRuntime::AppleIsModuleObjCLibrary(module_sp)) + { + m_objc_module_wp = module_sp; + return module_sp; + } + } + } + return ModuleSP(); +} + Address * AppleObjCRuntime::GetPrintForDebuggerAddr() { @@ -211,15 +235,17 @@ AppleObjCRuntime::GetDynamicTypeAndAddress (ValueObject &in_value, bool AppleObjCRuntime::AppleIsModuleObjCLibrary (const ModuleSP &module_sp) { - const FileSpec &module_file_spec = module_sp->GetFileSpec(); - static ConstString ObjCName ("libobjc.A.dylib"); - - if (module_file_spec) + if (module_sp) { - if (module_file_spec.GetFilename() == ObjCName) - return true; + const FileSpec &module_file_spec = module_sp->GetFileSpec(); + static ConstString ObjCName ("libobjc.A.dylib"); + + if (module_file_spec) + { + if (module_file_spec.GetFilename() == ObjCName) + return true; + } } - return false; } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h index e835a0c..e5d2c0f 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h @@ -63,17 +63,10 @@ public: virtual lldb::ThreadPlanSP GetStepThroughTrampolinePlan (Thread &thread, bool stop_others); - virtual bool - IsValidISA(ObjCISA isa) - { - return false; - } - - virtual ObjCISA - GetISA(ValueObject& valobj) - { - return 0; - } + // Get the "libobjc.A.dylib" module from the current target if we can find + // it, also cache it once it is found to ensure quick lookups. + lldb::ModuleSP + GetObjCModule (); //------------------------------------------------------------------ // Static Functions @@ -111,8 +104,9 @@ protected: bool m_read_objc_library; std::auto_ptr m_objc_trampoline_handler_ap; lldb::BreakpointSP m_objc_exception_bp_sp; + lldb::ModuleWP m_objc_module_wp; - AppleObjCRuntime(Process *process) : + AppleObjCRuntime(Process *process) : lldb_private::ObjCLanguageRuntime(process), m_read_objc_library (false), m_objc_trampoline_handler_ap(NULL) diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp index 3996476..2624d5c2 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp @@ -24,6 +24,7 @@ #include "lldb/Expression/ClangFunction.h" #include "lldb/Expression/ClangUtilityFunction.h" #include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/Symbol.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" @@ -155,35 +156,35 @@ AppleObjCRuntimeV1::CreateObjectChecker(const char *name) // this code relies on the assumption that an Objective-C object always starts // with an ISA at offset 0. -ObjCLanguageRuntime::ObjCISA -AppleObjCRuntimeV1::GetISA(ValueObject& valobj) -{ -// if (ClangASTType::GetMinimumLanguage(valobj.GetClangAST(),valobj.GetClangType()) != eLanguageTypeObjC) +//ObjCLanguageRuntime::ObjCISA +//AppleObjCRuntimeV1::GetISA(ValueObject& valobj) +//{ +//// if (ClangASTType::GetMinimumLanguage(valobj.GetClangAST(),valobj.GetClangType()) != eLanguageTypeObjC) +//// return 0; +// +// // if we get an invalid VO (which might still happen when playing around +// // with pointers returned by the expression parser, don't consider this +// // a valid ObjC object) +// if (valobj.GetValue().GetContextType() == Value::eContextTypeInvalid) // return 0; - - // if we get an invalid VO (which might still happen when playing around - // with pointers returned by the expression parser, don't consider this - // a valid ObjC object) - if (valobj.GetValue().GetContextType() == Value::eContextTypeInvalid) - return 0; - - addr_t isa_pointer = valobj.GetPointerValue(); - - ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); - - Process *process = exe_ctx.GetProcessPtr(); - if (process) - { - uint8_t pointer_size = process->GetAddressByteSize(); - - Error error; - return process->ReadUnsignedIntegerFromMemory (isa_pointer, - pointer_size, - 0, - error); - } - return 0; -} +// +// addr_t isa_pointer = valobj.GetPointerValue(); +// +// ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); +// +// Process *process = exe_ctx.GetProcessPtr(); +// if (process) +// { +// uint8_t pointer_size = process->GetAddressByteSize(); +// +// Error error; +// return process->ReadUnsignedIntegerFromMemory (isa_pointer, +// pointer_size, +// 0, +// error); +// } +// return 0; +//} AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1 (ValueObject &isa_pointer) { @@ -287,11 +288,124 @@ AppleObjCRuntimeV1::ClassDescriptorV1::GetSuperclass () return ObjCLanguageRuntime::ClassDescriptorSP(new AppleObjCRuntimeV1::ClassDescriptorV1(m_parent_isa,process_sp)); } -ObjCLanguageRuntime::ClassDescriptorSP -AppleObjCRuntimeV1::CreateClassDescriptor (ObjCISA isa) +bool +AppleObjCRuntimeV1::UpdateISAToDescriptorMap_Impl() { - ClassDescriptorSP objc_class_sp; - if (isa != 0) - objc_class_sp.reset (new ClassDescriptorV1(isa,m_process->CalculateProcess())); - return objc_class_sp; + lldb::LogSP log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + Process *process_ptr = GetProcess(); + + if (!process_ptr) + return false; + + ProcessSP process_sp = process_ptr->shared_from_this(); + + ModuleSP objc_module_sp(GetObjCModule()); + + if (!objc_module_sp) + return false; + + uint32_t isa_count = 0; + + static ConstString g_objc_debug_class_hash("_objc_debug_class_hash"); + + const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(g_objc_debug_class_hash, lldb::eSymbolTypeData); + if (symbol) + { + lldb::addr_t objc_debug_class_hash_addr = symbol->GetAddress().GetLoadAddress(&process_sp->GetTarget()); + + if (objc_debug_class_hash_addr != LLDB_INVALID_ADDRESS) + { + Error error; + lldb::addr_t objc_debug_class_hash_ptr = process_sp->ReadPointerFromMemory(objc_debug_class_hash_addr, error); + if (error.Success() && objc_debug_class_hash_ptr != 0 && objc_debug_class_hash_ptr != LLDB_INVALID_ADDRESS) + { + // Read the NXHashTable struct: + // + // typedef struct { + // const NXHashTablePrototype *prototype; + // unsigned count; + // unsigned nbBuckets; + // void *buckets; + // const void *info; + // } NXHashTable; + + DataBufferHeap buffer(1024, 0); + if (process_sp->ReadMemory(objc_debug_class_hash_ptr, buffer.GetBytes(), 20, error) == 20) + { + const uint32_t addr_size = m_process->GetAddressByteSize(); + const ByteOrder byte_order = m_process->GetByteOrder(); + DataExtractor data (buffer.GetBytes(), buffer.GetByteSize(), byte_order, addr_size); + uint32_t offset = addr_size + 4; // Skip prototype + const uint32_t num_buckets = data.GetU32(&offset); + const addr_t buckets_ptr = data.GetPointer(&offset); + + const uint32_t data_size = num_buckets * 2 * sizeof(uint32_t); + buffer.SetByteSize(data_size); + + if (process_sp->ReadMemory(buckets_ptr, buffer.GetBytes(), data_size, error) == data_size) + { + data.SetData(buffer.GetBytes(), buffer.GetByteSize(), byte_order); + offset = 0; + for (uint32_t bucket_idx = 0; bucket_idx < num_buckets; ++bucket_idx) + { + const uint32_t bucket_isa_count = data.GetU32 (&offset); + const lldb::addr_t bucket_data = data.GetU32 (&offset); + + + if (bucket_isa_count == 0) + continue; + + isa_count += bucket_isa_count; + + ObjCISA isa; + if (bucket_isa_count == 1) + { + // When we only have one entry in the bucket, the bucket data is the "isa" + isa = bucket_data; + if (isa) + { + if (m_isa_to_descriptor_cache.count(isa) == 0) + { + ClassDescriptorSP descriptor_sp (new ClassDescriptorV1(isa, process_sp)); + + if (log && log->GetVerbose()) + log->Printf("AppleObjCRuntimeV1 added (ObjCISA)0x%llx from _objc_debug_class_hash to isa->descriptor cache", isa); + + m_isa_to_descriptor_cache[isa] = descriptor_sp; + } + } + } + else + { + // When we have more than one entry in the bucket, the bucket data is a pointer + // to an array of "isa" values + addr_t isa_addr = bucket_data; + for (uint32_t isa_idx = 0; isa_idx < bucket_isa_count; ++isa_idx, isa_addr += addr_size) + { + isa = m_process->ReadPointerFromMemory(isa_addr, error); + + if (isa && isa != LLDB_INVALID_ADDRESS) + { + if (m_isa_to_descriptor_cache.count(isa) == 0) + { + ClassDescriptorSP descriptor_sp (new ClassDescriptorV1(isa, process_sp)); + + if (log && log->GetVerbose()) + log->Printf("AppleObjCRuntimeV1 added (ObjCISA)0x%llx from _objc_debug_class_hash to isa->descriptor cache", isa); + + m_isa_to_descriptor_cache[isa] = descriptor_sp; + } + } + } + } + } + } + } + } + } + } + + return isa_count > 0; } + diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h index 579fdbc..d85350c 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h @@ -124,17 +124,8 @@ public: } virtual bool - IsValidISA(ObjCISA isa) - { - return (isa != 0) && ( (isa % 2) == 0); - } - - virtual ObjCISA - GetISA(ValueObject& valobj); - - virtual ClassDescriptorSP - CreateClassDescriptor (ObjCISA isa); - + UpdateISAToDescriptorMap_Impl(); + protected: virtual lldb::BreakpointResolverSP CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp); diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index f37102e..7867281 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -585,7 +585,7 @@ AppleObjCRuntimeV2::GetByteOffsetForIvar (ClangASTType &parent_ast_type, const c bool AppleObjCRuntimeV2::IsTaggedPointer(addr_t ptr) { - return (ptr & 0x01); + return (ptr & 1); } class RemoteNXMapTable @@ -597,7 +597,7 @@ public: m_end_iterator(*this, -1), m_load_addr(load_addr), m_map_pair_size(m_process_sp->GetAddressByteSize() * 2), - m_NXMAPNOTAKEY(m_process_sp->GetAddressByteSize() == 8 ? 0xffffffffffffffffull : 0xffffffffull) + m_NXMAPNOTAKEY(m_process_sp->GetAddressByteSize() == 8 ? UINT64_MAX : UINT32_MAX) { lldb::addr_t cursor = load_addr; @@ -1668,49 +1668,45 @@ private: }; ObjCLanguageRuntime::ClassDescriptorSP -AppleObjCRuntimeV2::CreateClassDescriptor (ObjCISA isa) -{ - UpdateISAToDescriptorMap(); - - ISAToDescriptorMap::const_iterator di = m_isa_to_descriptor_cache.find(isa); - - if (di == m_isa_to_descriptor_cache.end()) - return ObjCLanguageRuntime::ClassDescriptorSP(); - else - return di->second; -} - -ObjCLanguageRuntime::ClassDescriptorSP -AppleObjCRuntimeV2::GetClassDescriptor (ValueObject& in_value) +AppleObjCRuntimeV2::GetClassDescriptor (ValueObject& valobj) { ClassDescriptorSP objc_class_sp; - uint64_t ptr_value = in_value.GetValueAsUnsigned(0); - if (ptr_value) + // if we get an invalid VO (which might still happen when playing around + // with pointers returned by the expression parser, don't consider this + // a valid ObjC object) + if (valobj.GetValue().GetContextType() != Value::eContextTypeInvalid) { - if (ptr_value & 1) - objc_class_sp = ClassDescriptorSP(new ClassDescriptorV2Tagged(in_value)); + addr_t isa_pointer = valobj.GetPointerValue(); + + // tagged pointer + if (IsTaggedPointer(isa_pointer)) + { + objc_class_sp.reset (new ClassDescriptorV2Tagged(valobj)); + + // probably an invalid tagged pointer - say it's wrong + if (objc_class_sp->IsValid()) + return objc_class_sp; + else + objc_class_sp.reset(); + } else - objc_class_sp = ObjCLanguageRuntime::GetClassDescriptor (in_value); + { + ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); + + Process *process = exe_ctx.GetProcessPtr(); + if (process) + { + Error error; + ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); + if (isa != LLDB_INVALID_ADDRESS) + objc_class_sp = ObjCLanguageRuntime::GetClassDescriptor (isa); + } + } } return objc_class_sp; } -ModuleSP FindLibobjc (Target &target) -{ - ModuleList& modules = target.GetImages(); - for (uint32_t idx = 0; idx < modules.GetSize(); idx++) - { - lldb::ModuleSP module_sp = modules.GetModuleAtIndex(idx); - if (!module_sp) - continue; - if (strncmp(module_sp->GetFileSpec().GetFilename().AsCString(""), "libobjc.", sizeof("libobjc.") - 1) == 0) - return module_sp; - } - - return ModuleSP(); -} - -void +bool AppleObjCRuntimeV2::UpdateISAToDescriptorMap_Impl() { lldb::LogSP log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); @@ -1718,193 +1714,105 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMap_Impl() Process *process_ptr = GetProcess(); if (!process_ptr) - return; - - ProcessSP process_sp = process_ptr->shared_from_this(); + return false; - Target &target(process_sp->GetTarget()); + ProcessSP process_sp (process_ptr->shared_from_this()); - ModuleSP objc_module_sp(FindLibobjc(target)); + ModuleSP objc_module_sp(GetObjCModule()); if (!objc_module_sp) - return; - - do - { - SymbolContextList sc_list; - - size_t num_symbols = objc_module_sp->FindSymbolsWithNameAndType(ConstString("gdb_objc_realized_classes"), - lldb::eSymbolTypeData, - sc_list); - - if (!num_symbols) - break; - - SymbolContext gdb_objc_realized_classes_sc; - - if (!sc_list.GetContextAtIndex(0, gdb_objc_realized_classes_sc)) - break; - - AddressRange gdb_objc_realized_classes_addr_range; - - const uint32_t scope = eSymbolContextSymbol; - const uint32_t range_idx = 0; - bool use_inline_block_range = false; + return false; - if (!gdb_objc_realized_classes_sc.GetAddressRange(scope, - range_idx, - use_inline_block_range, - gdb_objc_realized_classes_addr_range)) - break; - - lldb::addr_t gdb_objc_realized_classes_ptr = gdb_objc_realized_classes_addr_range.GetBaseAddress().GetLoadAddress(&target); - - if (gdb_objc_realized_classes_ptr == LLDB_INVALID_ADDRESS) - break; - - // - - lldb::addr_t gdb_objc_realized_classes_nxmaptable_ptr; + uint32_t num_map_table_isas = 0; + uint32_t num_objc_opt_ro_isas = 0; + + static ConstString g_gdb_objc_realized_classes("gdb_objc_realized_classes"); + + const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(g_gdb_objc_realized_classes, lldb::eSymbolTypeData); + if (symbol) + { + lldb::addr_t gdb_objc_realized_classes_ptr = symbol->GetAddress().GetLoadAddress(&process_sp->GetTarget()); + if (gdb_objc_realized_classes_ptr != LLDB_INVALID_ADDRESS) { + // + + lldb::addr_t gdb_objc_realized_classes_nxmaptable_ptr; + Error err; gdb_objc_realized_classes_nxmaptable_ptr = process_sp->ReadPointerFromMemory(gdb_objc_realized_classes_ptr, err); - if (!err.Success()) - break; - } - - RemoteNXMapTable gdb_objc_realized_classes(process_sp, gdb_objc_realized_classes_nxmaptable_ptr); - - for (RemoteNXMapTable::element elt : gdb_objc_realized_classes) - { - if (m_isa_to_descriptor_cache.count(elt.second)) - continue; - - ClassDescriptorSP descriptor_sp = ClassDescriptorSP(new ClassDescriptorV2(*this, elt.second)); - - if (log && log->GetVerbose()) - log->Printf("AppleObjCRuntimeV2 added (ObjCISA)0x%llx (%s) from dynamic table to isa->descriptor cache", elt.second, elt.first.AsCString()); + if (err.Success()) + { + RemoteNXMapTable gdb_objc_realized_classes(process_sp, gdb_objc_realized_classes_nxmaptable_ptr); - m_isa_to_descriptor_cache[elt.second] = descriptor_sp; + for (RemoteNXMapTable::element elt : gdb_objc_realized_classes) + { + ++num_map_table_isas; + + if (m_isa_to_descriptor_cache.count(elt.second)) + continue; + + ClassDescriptorSP descriptor_sp = ClassDescriptorSP(new ClassDescriptorV2(*this, elt.second)); + + if (log && log->GetVerbose()) + log->Printf("AppleObjCRuntimeV2 added (ObjCISA)0x%llx (%s) from dynamic table to isa->descriptor cache", elt.second, elt.first.AsCString()); + + m_isa_to_descriptor_cache[elt.second] = descriptor_sp; + } + } } } - while(0); - do + ObjectFile *objc_object = objc_module_sp->GetObjectFile(); + + if (objc_object) { - ObjectFile *objc_object = objc_module_sp->GetObjectFile(); - - if (!objc_object) - break; - SectionList *section_list = objc_object->GetSectionList(); - - if (!section_list) - break; - - SectionSP TEXT_section_sp = section_list->FindSectionByName(ConstString("__TEXT")); - - if (!TEXT_section_sp) - break; - - SectionList &TEXT_children = TEXT_section_sp->GetChildren(); - - SectionSP objc_opt_section_sp = TEXT_children.FindSectionByName(ConstString("__objc_opt_ro")); - - if (!objc_opt_section_sp) - break; - - lldb::addr_t objc_opt_ptr = objc_opt_section_sp->GetLoadBaseAddress(&target); - - if (objc_opt_ptr == LLDB_INVALID_ADDRESS) - break; - - RemoteObjCOpt objc_opt(process_sp, objc_opt_ptr); - - for (ObjCLanguageRuntime::ObjCISA objc_isa : objc_opt) + + if (section_list) { - if (m_isa_to_descriptor_cache.count(objc_isa)) - continue; - - ClassDescriptorSP descriptor_sp = ClassDescriptorSP(new ClassDescriptorV2(*this, objc_isa)); + SectionSP text_segment_sp (section_list->FindSectionByName(ConstString("__TEXT"))); - if (log && log->GetVerbose()) - log->Printf("AppleObjCRuntimeV2 added (ObjCISA)0x%llx (%s) from static table to isa->descriptor cache", objc_isa, descriptor_sp->GetClassName().AsCString()); - - m_isa_to_descriptor_cache[objc_isa] = descriptor_sp; + if (text_segment_sp) + { + SectionSP objc_opt_section_sp (text_segment_sp->GetChildren().FindSectionByName(ConstString("__objc_opt_ro"))); + + if (objc_opt_section_sp) + { + lldb::addr_t objc_opt_ptr = objc_opt_section_sp->GetLoadBaseAddress(&process_sp->GetTarget()); + + if (objc_opt_ptr != LLDB_INVALID_ADDRESS) + { + RemoteObjCOpt objc_opt(process_sp, objc_opt_ptr); + + for (ObjCLanguageRuntime::ObjCISA objc_isa : objc_opt) + { + ++num_objc_opt_ro_isas; + if (m_isa_to_descriptor_cache.count(objc_isa)) + continue; + + ClassDescriptorSP descriptor_sp = ClassDescriptorSP(new ClassDescriptorV2(*this, objc_isa)); + + if (log && log->GetVerbose()) + log->Printf("AppleObjCRuntimeV2 added (ObjCISA)0x%llx (%s) from static table to isa->descriptor cache", objc_isa, descriptor_sp->GetClassName().AsCString()); + + m_isa_to_descriptor_cache[objc_isa] = descriptor_sp; + } + } + } + } } } - while (0); -} - -// this code relies on the assumption that an Objective-C object always starts -// with an ISA at offset 0. an ISA is effectively a pointer to an instance of -// struct class_t in the ObjCv2 runtime -ObjCLanguageRuntime::ObjCISA -AppleObjCRuntimeV2::GetISA(ValueObject& valobj) -{ -// if (ClangASTType::GetMinimumLanguage(valobj.GetClangAST(),valobj.GetClangType()) != eLanguageTypeObjC) -// return 0; -// - // if we get an invalid VO (which might still happen when playing around - // with pointers returned by the expression parser, don't consider this - // a valid ObjC object) - if (valobj.GetValue().GetContextType() == Value::eContextTypeInvalid) - return 0; - addr_t isa_pointer = valobj.GetPointerValue(); - - // tagged pointer - if (IsTaggedPointer(isa_pointer)) - { - ClassDescriptorV2Tagged descriptor(valobj); - - // probably an invalid tagged pointer - say it's wrong - if (!descriptor.IsValid()) - return 0; - - static const ConstString g_objc_tagged_isa_nsatom_name ("NSAtom"); - static const ConstString g_objc_tagged_isa_nsnumber_name ("NSNumber"); - static const ConstString g_objc_tagged_isa_nsdatets_name ("NSDateTS"); - static const ConstString g_objc_tagged_isa_nsmanagedobject_name ("NSManagedObject"); - static const ConstString g_objc_tagged_isa_nsdate_name ("NSDate"); - - ConstString class_name_const_string = descriptor.GetClassName(); - - if (class_name_const_string == g_objc_tagged_isa_nsatom_name) - return g_objc_Tagged_ISA_NSAtom; - if (class_name_const_string == g_objc_tagged_isa_nsnumber_name) - return g_objc_Tagged_ISA_NSNumber; - if (class_name_const_string == g_objc_tagged_isa_nsdatets_name) - return g_objc_Tagged_ISA_NSDateTS; - if (class_name_const_string == g_objc_tagged_isa_nsmanagedobject_name) - return g_objc_Tagged_ISA_NSManagedObject; - if (class_name_const_string == g_objc_tagged_isa_nsdate_name) - return g_objc_Tagged_ISA_NSDate; - return g_objc_Tagged_ISA; - } - - ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); - - Process *process = exe_ctx.GetProcessPtr(); - if (process) - { - Error error; - ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); - if (isa != LLDB_INVALID_ADDRESS) - return isa; - } - return 0; // For some reason zero is being used to indicate invalid ISA instead of LLDB_INVALID_ADDRESS + return num_objc_opt_ro_isas > 0 && num_map_table_isas > 0; } + // TODO: should we have a transparent_kvo parameter here to say if we // want to replace the KVO swizzled class with the actual user-level type? ConstString AppleObjCRuntimeV2::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) { - if (!IsValidISA(isa)) - return ConstString(); - if (isa == g_objc_Tagged_ISA) { static const ConstString g_objc_tagged_isa_name ("_lldb_Tagged_ObjC_ISA"); @@ -1935,7 +1843,6 @@ AppleObjCRuntimeV2::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) static const ConstString g_objc_tagged_isa_nsdate_name ("NSDate"); return g_objc_tagged_isa_nsdate_name; } - return ObjCLanguageRuntime::GetActualTypeName(isa); } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h index 361ebcf..480b596 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h @@ -73,14 +73,8 @@ public: virtual size_t GetByteOffsetForIvar (ClangASTType &parent_qual_type, const char *ivar_name); - virtual void - UpdateISAToDescriptorMap_Impl(); - virtual bool - IsValidISA (ObjCLanguageRuntime::ObjCISA isa) - { - return (isa != 0); - } + UpdateISAToDescriptorMap_Impl(); // none of these are valid ISAs - we use them to infer the type // of tagged pointers - if we have something meaningful to say @@ -94,19 +88,12 @@ public: static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSManagedObject = 5; static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSDate = 6; - - virtual ObjCLanguageRuntime::ObjCISA - GetISA(ValueObject& valobj); - virtual ConstString GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa); virtual ClassDescriptorSP GetClassDescriptor (ValueObject& in_value); - virtual ClassDescriptorSP - CreateClassDescriptor (ObjCISA isa); - virtual TypeVendor * GetTypeVendor(); diff --git a/lldb/source/Target/ObjCLanguageRuntime.cpp b/lldb/source/Target/ObjCLanguageRuntime.cpp index 98bb0c4..4fb41c8 100644 --- a/lldb/source/Target/ObjCLanguageRuntime.cpp +++ b/lldb/source/Target/ObjCLanguageRuntime.cpp @@ -31,6 +31,7 @@ ObjCLanguageRuntime::~ObjCLanguageRuntime() ObjCLanguageRuntime::ObjCLanguageRuntime (Process *process) : LanguageRuntime (process), m_has_new_literals_and_indexing (eLazyBoolCalculate), + m_isa_to_descriptor_cache(), m_isa_to_descriptor_cache_is_up_to_date (false) { @@ -284,24 +285,10 @@ ObjCLanguageRuntime::ClassDescriptor::IsPointerValid (lldb::addr_t value, ObjCLanguageRuntime::ObjCISA ObjCLanguageRuntime::GetISA(const ConstString &name) { - // Try once regardless of whether the map has been brought up to date. We - // might have encountered the relevant isa directly. - for (const ISAToDescriptorMap::value_type &val : m_isa_to_descriptor_cache) - if (val.second && val.second->GetClassName() == name) - return val.first; - - // If the map is up to date and we didn't find the isa, give up. - if (m_isa_to_descriptor_cache_is_up_to_date) - return 0; - - // Try again after bringing the map up to date. UpdateISAToDescriptorMap(); - for (const ISAToDescriptorMap::value_type &val : m_isa_to_descriptor_cache) if (val.second && val.second->GetClassName() == name) return val.first; - - // Now we know for sure that the class isn't there. Give up. return 0; } @@ -318,8 +305,6 @@ ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa) return 0; } -// TODO: should we have a transparent_kvo parameter here to say if we -// want to replace the KVO swizzled class with the actual user-level type? ConstString ObjCLanguageRuntime::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) { @@ -330,34 +315,74 @@ ObjCLanguageRuntime::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) } ObjCLanguageRuntime::ClassDescriptorSP -ObjCLanguageRuntime::GetClassDescriptor (ValueObject& in_value) +ObjCLanguageRuntime::GetClassDescriptor (const ConstString &class_name) { - ObjCISA isa = GetISA(in_value); - if (isa) - return GetClassDescriptor (isa); + UpdateISAToDescriptorMap(); + for (const ISAToDescriptorMap::value_type &val : m_isa_to_descriptor_cache) + if (val.second && val.second->GetClassName() == class_name) + return val.second; return ClassDescriptorSP(); + } ObjCLanguageRuntime::ClassDescriptorSP -ObjCLanguageRuntime::GetClassDescriptor (ObjCISA isa) +ObjCLanguageRuntime::GetClassDescriptor (ValueObject& valobj) { ClassDescriptorSP objc_class_sp; - if (isa) + // if we get an invalid VO (which might still happen when playing around + // with pointers returned by the expression parser, don't consider this + // a valid ObjC object) + if (valobj.GetValue().GetContextType() != Value::eContextTypeInvalid) { - ObjCLanguageRuntime::ISAToDescriptorIterator found = m_isa_to_descriptor_cache.find(isa); - ObjCLanguageRuntime::ISAToDescriptorIterator end = m_isa_to_descriptor_cache.end(); - - if (found != end && found->second) - return found->second; - - objc_class_sp = CreateClassDescriptor(isa); - if (objc_class_sp && objc_class_sp->IsValid()) - m_isa_to_descriptor_cache[isa] = objc_class_sp; + addr_t isa_pointer = valobj.GetPointerValue(); + if (isa_pointer != LLDB_INVALID_ADDRESS) + { + ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); + + Process *process = exe_ctx.GetProcessPtr(); + if (process) + { + Error error; + ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); + if (isa != LLDB_INVALID_ADDRESS) + objc_class_sp = GetClassDescriptor (isa); + } + } } return objc_class_sp; } ObjCLanguageRuntime::ClassDescriptorSP +ObjCLanguageRuntime::GetNonKVOClassDescriptor (ValueObject& valobj) +{ + ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp (GetClassDescriptor (valobj)); + if (objc_class_sp) + { + if (!objc_class_sp->IsKVO()) + return objc_class_sp; + + ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass()); + if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid()) + return non_kvo_objc_class_sp; + } + return ClassDescriptorSP(); +} + + +ObjCLanguageRuntime::ClassDescriptorSP +ObjCLanguageRuntime::GetClassDescriptor (ObjCISA isa) +{ + if (isa) + { + UpdateISAToDescriptorMap(); + ObjCLanguageRuntime::ISAToDescriptorIterator pos = m_isa_to_descriptor_cache.find(isa); + if (pos != m_isa_to_descriptor_cache.end()) + return pos->second; + } + return ClassDescriptorSP(); +} + +ObjCLanguageRuntime::ClassDescriptorSP ObjCLanguageRuntime::GetNonKVOClassDescriptor (ObjCISA isa) { if (isa) @@ -365,14 +390,12 @@ ObjCLanguageRuntime::GetNonKVOClassDescriptor (ObjCISA isa) ClassDescriptorSP objc_class_sp = GetClassDescriptor (isa); if (objc_class_sp && objc_class_sp->IsValid()) { - if (objc_class_sp->IsKVO()) - { - ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass()); - if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid()) - return non_kvo_objc_class_sp; - } - else + if (!objc_class_sp->IsKVO()) return objc_class_sp; + + ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass()); + if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid()) + return non_kvo_objc_class_sp; } } return ClassDescriptorSP(); -- 2.7.4