[Lldb-commits] [lldb] r230299 - Update LLDB to read a newer format of Objective-C class information from the dyld shared cache

Enrico Granata egranata at apple.com
Mon Feb 23 18:11:06 PST 2015


Author: enrico
Date: Mon Feb 23 20:11:06 2015
New Revision: 230299

URL: http://llvm.org/viewvc/llvm-project?rev=230299&view=rev
Log:
Update LLDB to read a newer format of Objective-C class information from the dyld shared cache
Also, since most of the time the lack of such information is a serious problem that hinders productive debugging, emit an actual user visible warning when this occurs (once per process)

Fixes rdar://19898507


Modified:
    lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
    lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h

Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp?rev=230299&r1=230298&r2=230299&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp Mon Feb 23 20:11:06 2015
@@ -19,12 +19,14 @@
 
 #include "lldb/Core/ClangForward.h"
 #include "lldb/Core/ConstString.h"
+#include "lldb/Core/Debugger.h"
 #include "lldb/Core/Error.h"
 #include "lldb/Core/Log.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/Scalar.h"
 #include "lldb/Core/Section.h"
+#include "lldb/Core/Stream.h"
 #include "lldb/Core/StreamString.h"
 #include "lldb/Core/Timer.h"
 #include "lldb/Core/ValueObjectVariable.h"
@@ -158,7 +160,7 @@ extern "C"
     int printf(const char * format, ...);
 }
 
-//#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN
+// #define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN
 #ifdef ENABLE_DEBUG_PRINTF
 #define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
 #else
@@ -217,12 +219,14 @@ __lldb_apple_objc_v2_get_shared_cache_cl
         DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt->selopt_offset);
         DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt->headeropt_offset);
         DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt->clsopt_offset);
-        if (objc_opt->version == 12)
+        if (objc_opt->version == 12 || objc_opt->version == 13)
         {
             const objc_clsopt_t* clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt + objc_opt->clsopt_offset);
             const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
             ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
-            int32_t zeroOffset = 16;
+            int32_t invalidEntryOffset = 0;
+            if (objc_opt->version == 12)
+                invalidEntryOffset = 16;
             const uint8_t *checkbytes = &clsopt->tab[clsopt->mask+1];
             const int32_t *offsets = (const int32_t *)(checkbytes + clsopt->capacity);
             const objc_classheader_t *classOffsets = (const objc_classheader_t *)(offsets + clsopt->capacity);
@@ -234,8 +238,8 @@ __lldb_apple_objc_v2_get_shared_cache_cl
                 const int32_t clsOffset = classOffsets[i].clsOffset;
                 if (clsOffset & 1)
                     continue; // duplicate
-                else if (clsOffset == zeroOffset)
-                    continue; // zero offset
+                else if (clsOffset == invalidEntryOffset)
+                    continue; // invalid offset
                 
                 if (class_infos && idx < max_class_infos)
                 {
@@ -262,8 +266,8 @@ __lldb_apple_objc_v2_get_shared_cache_cl
                 const int32_t clsOffset = duplicateClassOffsets[i].clsOffset;
                 if (clsOffset & 1)
                     continue; // duplicate
-                else if (clsOffset == zeroOffset)
-                    continue; // zero offset
+                else if (clsOffset == invalidEntryOffset)
+                    continue; // invalid offset
                 
                 if (class_infos && idx < max_class_infos)
                 {
@@ -354,7 +358,8 @@ AppleObjCRuntimeV2::AppleObjCRuntimeV2 (
     m_loaded_objc_opt (false),
     m_non_pointer_isa_cache_ap(NonPointerISACache::CreateInstance(*this,objc_module_sp)),
     m_tagged_pointer_vendor_ap(TaggedPointerVendor::CreateInstance(*this,objc_module_sp)),
-    m_encoding_to_type_sp()
+    m_encoding_to_type_sp(),
+    m_noclasses_warning_emitted(false)
 {
     static const ConstString g_gdb_object_getClass("gdb_object_getClass");
     m_has_object_getClass = (objc_module_sp->FindFirstSymbolWithNameAndType(g_gdb_object_getClass, eSymbolTypeCode) != NULL);
@@ -1174,7 +1179,7 @@ AppleObjCRuntimeV2::UpdateISAToDescripto
     return success;
 }
 
-void
+uint32_t
 AppleObjCRuntimeV2::ParseClassInfoArray (const DataExtractor &data, uint32_t num_class_infos)
 {
     // Parses an array of "num_class_infos" packed ClassInfo structures:
@@ -1186,6 +1191,8 @@ AppleObjCRuntimeV2::ParseClassInfoArray
     //    } __attribute__((__packed__));
 
     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+    
+    uint32_t num_parsed = 0;
 
     // Iterate through all ClassInfo structures
     lldb::offset_t offset = 0;
@@ -1211,19 +1218,21 @@ AppleObjCRuntimeV2::ParseClassInfoArray
             const uint32_t name_hash = data.GetU32(&offset);
             ClassDescriptorSP descriptor_sp (new ClassDescriptorV2(*this, isa, NULL));
             AddClass (isa, descriptor_sp, name_hash);
+            num_parsed++;
             if (log && log->GetVerbose())
                 log->Printf("AppleObjCRuntimeV2 added isa=0x%" PRIx64 ", hash=0x%8.8x, name=%s", isa, name_hash,descriptor_sp->GetClassName().AsCString("<unknown>"));
         }
     }
+    return num_parsed;
 }
 
-bool
+AppleObjCRuntimeV2::DescriptorMapUpdateResult
 AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache()
 {
     Process *process = GetProcess();
     
     if (process == NULL)
-        return false;
+        return DescriptorMapUpdateResult::Fail();
     
     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
     
@@ -1232,13 +1241,13 @@ AppleObjCRuntimeV2::UpdateISAToDescripto
     ThreadSP thread_sp = process->GetThreadList().GetSelectedThread();
     
     if (!thread_sp)
-        return false;
+        return DescriptorMapUpdateResult::Fail();
     
     thread_sp->CalculateExecutionContext(exe_ctx);
     ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext();
     
     if (!ast)
-        return false;
+        return DescriptorMapUpdateResult::Fail();
     
     Address function_address;
     
@@ -1251,7 +1260,7 @@ AppleObjCRuntimeV2::UpdateISAToDescripto
     const lldb::addr_t objc_opt_ptr = GetSharedCacheReadOnlyAddress();
     
     if (objc_opt_ptr == LLDB_INVALID_ADDRESS)
-        return false;
+        return DescriptorMapUpdateResult::Fail();
     
     // Read the total number of classes from the hash table
     const uint32_t num_classes = 128*1024;
@@ -1259,7 +1268,7 @@ AppleObjCRuntimeV2::UpdateISAToDescripto
     {
         if (log)
             log->Printf ("No dynamic classes found in gdb_objc_realized_classes_addr.");
-        return false;
+        return DescriptorMapUpdateResult::Fail();
     }
     
     // Make some types for our arguments
@@ -1284,7 +1293,7 @@ AppleObjCRuntimeV2::UpdateISAToDescripto
     if (m_get_shared_cache_class_info_code.get())
         function_address.SetOffset(m_get_shared_cache_class_info_code->StartAddress());
     else
-        return false;
+        return DescriptorMapUpdateResult::Fail();
     
     ValueList arguments;
     
@@ -1310,7 +1319,7 @@ AppleObjCRuntimeV2::UpdateISAToDescripto
                                                                         "objc-isa-to-descriptor-shared-cache"));
         
         if (m_get_shared_cache_class_info_function.get() == NULL)
-            return false;
+            return DescriptorMapUpdateResult::Fail();
         
         errors.Clear();
         
@@ -1319,7 +1328,7 @@ AppleObjCRuntimeV2::UpdateISAToDescripto
         {
             if (log)
                 log->Printf ("Error compiling function: \"%s\".", errors.GetData());
-            return false;
+            return DescriptorMapUpdateResult::Fail();
         }
         
         errors.Clear();
@@ -1328,7 +1337,7 @@ AppleObjCRuntimeV2::UpdateISAToDescripto
         {
             if (log)
                 log->Printf ("Error Inserting function: \"%s\".", errors.GetData());
-            return false;
+            return DescriptorMapUpdateResult::Fail();
         }
     }
     else
@@ -1343,7 +1352,7 @@ AppleObjCRuntimeV2::UpdateISAToDescripto
                                                              err);
     
     if (class_infos_addr == LLDB_INVALID_ADDRESS)
-        return false;
+        return DescriptorMapUpdateResult::Fail();
     
     Mutex::Locker locker(m_get_shared_cache_class_info_args_mutex);
     
@@ -1353,6 +1362,7 @@ AppleObjCRuntimeV2::UpdateISAToDescripto
     arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size;
     
     bool success = false;
+    bool any_found = false;
     
     errors.Clear();
     
@@ -1418,8 +1428,8 @@ AppleObjCRuntimeV2::UpdateISAToDescripto
                                                     buffer.GetByteSize(),
                                                     process->GetByteOrder(),
                                                     addr_size);
-                    
-                    ParseClassInfoArray (class_infos_data, num_class_infos);
+
+                    any_found = (ParseClassInfoArray (class_infos_data, num_class_infos) > 0);
                 }
             }
             else
@@ -1442,7 +1452,7 @@ AppleObjCRuntimeV2::UpdateISAToDescripto
     // Deallocate the memory we allocated for the ClassInfo array
     process->DeallocateMemory(class_infos_addr);
     
-    return success;
+    return DescriptorMapUpdateResult(success, any_found);
 }
 
 
@@ -1546,7 +1556,12 @@ AppleObjCRuntimeV2::UpdateISAToDescripto
         // in the shared cache, but only once per process as this data never
         // changes
         if (!m_loaded_objc_opt)
-            UpdateISAToDescriptorMapSharedCache();
+        {
+            DescriptorMapUpdateResult shared_cache_update_result = UpdateISAToDescriptorMapSharedCache();
+            if (!shared_cache_update_result.any_found)
+                WarnIfNoClassesCached ();
+        }
+        
     }
     else
     {
@@ -1554,6 +1569,20 @@ AppleObjCRuntimeV2::UpdateISAToDescripto
     }
 }
 
+void
+AppleObjCRuntimeV2::WarnIfNoClassesCached ()
+{
+    if (m_noclasses_warning_emitted)
+        return;
+    
+    Debugger &debugger(GetProcess()->GetTarget().GetDebugger());
+    
+    if (debugger.GetAsyncOutputStream())
+    {
+        debugger.GetAsyncOutputStream()->PutCString("warning: could not load any Objective-C class information from the dyld shared cache. This will signficantly reduce the quality of type information available.\n");
+        m_noclasses_warning_emitted = true;
+    }
+}
 
 // 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?

Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h?rev=230299&r1=230298&r2=230299&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h Mon Feb 23 20:11:06 2015
@@ -240,6 +240,31 @@ private:
         DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorLegacy);
     };
     
+    struct DescriptorMapUpdateResult
+    {
+        bool update_ran;
+        bool any_found;
+        
+        DescriptorMapUpdateResult (bool ran,
+                                   bool found)
+        {
+            update_ran = ran;
+            any_found = found;
+        }
+        
+        static DescriptorMapUpdateResult
+        Fail ()
+        {
+            return {false, false};
+        }
+        
+        static DescriptorMapUpdateResult
+        Success ()
+        {
+            return {true, true};
+        }
+    };
+    
     AppleObjCRuntimeV2 (Process *process,
                         const lldb::ModuleSP &objc_module_sp);
     
@@ -258,12 +283,15 @@ private:
     bool
     UpdateISAToDescriptorMapDynamic(RemoteNXMapTable &hash_table);
     
-    void
+    uint32_t
     ParseClassInfoArray (const lldb_private::DataExtractor &data,
                          uint32_t num_class_infos);
     
-    bool
+    DescriptorMapUpdateResult
     UpdateISAToDescriptorMapSharedCache ();
+    
+    void
+    WarnIfNoClassesCached ();
 
     lldb::addr_t
     GetSharedCacheReadOnlyAddress();
@@ -288,6 +316,7 @@ private:
     std::unique_ptr<NonPointerISACache>       m_non_pointer_isa_cache_ap;
     std::unique_ptr<TaggedPointerVendor>    m_tagged_pointer_vendor_ap;
     EncodingToTypeSP                        m_encoding_to_type_sp;
+    bool                                    m_noclasses_warning_emitted;
 };
     
 } // namespace lldb_private





More information about the lldb-commits mailing list