diff options
10 files changed, 379 insertions, 339 deletions
diff --git a/lldb/include/lldb/Core/FormatNavigator.h b/lldb/include/lldb/Core/FormatNavigator.h index 4c0af74ff5c..cdabd6344c2 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 97cefdc8df7..7be517b0853 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 fe34724e311..9debcc0318a 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 4d001d857dc..995a438ca89 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 e835a0c94af..e5d2c0f5e06 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<lldb_private::AppleObjCTrampolineHandler> 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 3996476a87a..2624d5c289c 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 579fdbcb9f1..d85350c1d11 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 f37102e52b6..786728147ba 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; - - // <rdar://problem/10763513> - - 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) { + // <rdar://problem/10763513> + + 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 361ebcfa3ee..480b5969dab 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 98bb0c44dad..4fb41c843e5 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(); |