[Lldb-commits] [lldb] r224306 - If a binary was stripped we sometimes didn't show the ivars of an Objective C class correctly. Now we do as we consult the runtime data for the class so we don't have to have a symbol in the symbol table.

Greg Clayton gclayton at apple.com
Mon Dec 15 17:33:17 PST 2014


Author: gclayton
Date: Mon Dec 15 19:33:17 2014
New Revision: 224306

URL: http://llvm.org/viewvc/llvm-project?rev=224306&view=rev
Log:
If a binary was stripped we sometimes didn't show the ivars of an Objective C class correctly. Now we do as we consult the runtime data for the class so we don't have to have a symbol in the symbol table.

Fixed:
1 - try the symbol table symbol for an ObjC ivar and use it if available
2 - fall back to using the runtime data since it is slower to gather via memory read
3 - Fixed our hidden ivars test case to test this to ensure we don't regress
4 - split out a test case in the hidden ivars to cover only the part that was failing so we don't have an expected failure for all of the other content in the test.

<rdar://problem/18882687>


Modified:
    lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
    lldb/trunk/test/lang/objc/hidden-ivars/TestHiddenIvars.py
    lldb/trunk/test/lang/objc/hidden-ivars/main.m

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=224306&r1=224305&r2=224306&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp Mon Dec 15 19:33:17 2014
@@ -554,36 +554,52 @@ AppleObjCRuntimeV2::CreateObjectChecker(
 size_t
 AppleObjCRuntimeV2::GetByteOffsetForIvar (ClangASTType &parent_ast_type, const char *ivar_name)
 {
+    uint32_t ivar_offset = LLDB_INVALID_IVAR_OFFSET;
+
     const char *class_name = parent_ast_type.GetConstTypeName().AsCString();
+    if (class_name && class_name[0] && ivar_name && ivar_name[0])
+    {
+        //----------------------------------------------------------------------
+        // Make the objective C V2 mangled name for the ivar offset from the
+        // class name and ivar name
+        //----------------------------------------------------------------------
+        std::string buffer("OBJC_IVAR_$_");
+        buffer.append (class_name);
+        buffer.push_back ('.');
+        buffer.append (ivar_name);
+        ConstString ivar_const_str (buffer.c_str());
+        
+        //----------------------------------------------------------------------
+        // Try to get the ivar offset address from the symbol table first using
+        // the name we created above
+        //----------------------------------------------------------------------
+        SymbolContextList sc_list;
+        Target &target = m_process->GetTarget();
+        target.GetImages().FindSymbolsWithNameAndType(ivar_const_str, eSymbolTypeObjCIVar, sc_list);
+
+        addr_t ivar_offset_address = LLDB_INVALID_ADDRESS;
+
+        Error error;
+        SymbolContext ivar_offset_symbol;
+        if (sc_list.GetSize() == 1 && sc_list.GetContextAtIndex(0, ivar_offset_symbol))
+        {
+            if (ivar_offset_symbol.symbol)
+                ivar_offset_address = ivar_offset_symbol.symbol->GetAddress().GetLoadAddress (&target);
+        }
+
+        //----------------------------------------------------------------------
+        // If we didn't get the ivar offset address from the symbol table, fall
+        // back to getting it from the runtime
+        //----------------------------------------------------------------------
+        if (ivar_offset_address == LLDB_INVALID_ADDRESS)
+            ivar_offset_address = LookupRuntimeSymbol(ivar_const_str);
 
-    if (!class_name || *class_name == '\0' || !ivar_name || *ivar_name == '\0')
-        return LLDB_INVALID_IVAR_OFFSET;
-    
-    std::string buffer("OBJC_IVAR_$_");
-    buffer.append (class_name);
-    buffer.push_back ('.');
-    buffer.append (ivar_name);
-    ConstString ivar_const_str (buffer.c_str());
-    
-    SymbolContextList sc_list;
-    Target &target = m_process->GetTarget();
-    
-    target.GetImages().FindSymbolsWithNameAndType(ivar_const_str, eSymbolTypeObjCIVar, sc_list);
-
-    SymbolContext ivar_offset_symbol;
-    if (sc_list.GetSize() != 1 
-        || !sc_list.GetContextAtIndex(0, ivar_offset_symbol) 
-        || ivar_offset_symbol.symbol == NULL)
-        return LLDB_INVALID_IVAR_OFFSET;
-    
-    addr_t ivar_offset_address = ivar_offset_symbol.symbol->GetAddress().GetLoadAddress (&target);
-    
-    Error error;
-    
-    uint32_t ivar_offset = m_process->ReadUnsignedIntegerFromMemory (ivar_offset_address, 
-                                                                     4, 
-                                                                     LLDB_INVALID_IVAR_OFFSET, 
-                                                                     error);
+        if (ivar_offset_address != LLDB_INVALID_ADDRESS)
+            ivar_offset = m_process->ReadUnsignedIntegerFromMemory (ivar_offset_address,
+                                                                    4,
+                                                                    LLDB_INVALID_IVAR_OFFSET,
+                                                                    error);
+    }
     return ivar_offset;
 }
 

Modified: lldb/trunk/test/lang/objc/hidden-ivars/TestHiddenIvars.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/objc/hidden-ivars/TestHiddenIvars.py?rev=224306&r1=224305&r2=224306&view=diff
==============================================================================
--- lldb/trunk/test/lang/objc/hidden-ivars/TestHiddenIvars.py (original)
+++ lldb/trunk/test/lang/objc/hidden-ivars/TestHiddenIvars.py Mon Dec 15 19:33:17 2014
@@ -5,6 +5,7 @@ import unittest2
 import lldb
 from lldbtest import *
 import lldbutil
+import subprocess
 
 class HiddenIvarsTestCase(TestBase):
 
@@ -15,34 +16,74 @@ class HiddenIvarsTestCase(TestBase):
     def test_expr_with_dsym(self):
         if self.getArchitecture() == 'i386':
             self.skipTest("requires modern objc runtime")
-        self.buildDsym()
-        self.expr()
+        else:
+            self.buildDsym()
+            self.expr(False)
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @dsym_test
+    def test_expr_stripped_with_dsym(self):
+        if self.getArchitecture() == 'i386':
+            self.skipTest("requires modern objc runtime")
+        else:
+            self.buildDsym()
+            self.expr(True)
 
     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     @dwarf_test
     def test_expr_with_dwarf(self):
         if self.getArchitecture() == 'i386':
             self.skipTest("requires modern objc runtime")
-        self.buildDwarf()
-        self.expr()
+        else:
+            self.buildDwarf()
+            self.expr(False)
 
-    @unittest2.expectedFailure("rdar://18683637")
     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     @dsym_test
     def test_frame_variable_with_dsym(self):
         if self.getArchitecture() == 'i386':
             self.skipTest("requires modern objc runtime")
-        self.buildDsym()
-        self.frame_var()
+        else:
+            self.buildDsym()
+            self.frame_var(False)
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @dsym_test
+    def test_frame_variable_stripped_with_dsym(self):
+        if self.getArchitecture() == 'i386':
+            self.skipTest("requires modern objc runtime")
+        else:
+            self.buildDsym()
+            self.frame_var(True)
 
-    @unittest2.expectedFailure("rdar://18683637")
     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     @dwarf_test
     def test_frame_variable_with_dwarf(self):
         if self.getArchitecture() == 'i386':
             self.skipTest("requires modern objc runtime")
-        self.buildDwarf()
-        self.frame_var()
+        else:
+            self.buildDwarf()
+            self.frame_var(False)
+
+    @unittest2.expectedFailure("rdar://18683637")
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @dsym_test
+    def test_frame_variable_across_modules_with_dsym(self):
+        if self.getArchitecture() == 'i386':
+            self.skipTest("requires modern objc runtime")
+        else:
+            self.buildDsym()
+            self.frame_var_type_access_across_module()
+
+    @unittest2.expectedFailure("rdar://18683637")
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @dwarf_test
+    def test_frame_variable_across_modules_with_dwarf(self):
+        if self.getArchitecture() == 'i386':
+            self.skipTest("requires modern objc runtime")
+        else:
+            self.buildDwarf()
+            self.frame_var_type_access_across_module()
 
     def setUp(self):
         # Call super's setUp().
@@ -54,8 +95,12 @@ class HiddenIvarsTestCase(TestBase):
         # The names should have no loading "lib" or extension as they will be localized
         self.shlib_names = ["InternalDefiner"]
         
-    def common_setup(self):
+    def common_setup(self, strip):
         
+        if strip:
+            self.assertTrue(subprocess.call(['/usr/bin/strip', '-Sx', 'libInternalDefiner.dylib']) == 0, 'stripping dylib succeeded')
+            self.assertTrue(subprocess.call(['/bin/rm', '-rf', 'libInternalDefiner.dylib.dSYM']) == 0, 'remove dylib dSYM file succeeded')
+            self.assertTrue(subprocess.call(['/usr/bin/strip', '-Sx', 'a.out']) == 0, 'stripping a.out succeeded')
         # Create a target by the debugger.
         target = self.dbg.CreateTarget("a.out")
         self.assertTrue(target, VALID_TARGET)
@@ -88,8 +133,8 @@ class HiddenIvarsTestCase(TestBase):
         self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE,
             substrs = [' resolved, hit count = 1'])
 
-    def expr(self):
-        self.common_setup()
+    def expr(self, strip):
+        self.common_setup(strip)
 
         # This should display correctly.
         self.expect("expression (j->_definer->foo)", VARIABLES_DISPLAYED_CORRECTLY,
@@ -97,9 +142,13 @@ class HiddenIvarsTestCase(TestBase):
 
         self.expect("expression (j->_definer->bar)", VARIABLES_DISPLAYED_CORRECTLY,
             substrs = ["= 5"])
-            
-        self.expect("expression *(j->_definer)", VARIABLES_DISPLAYED_CORRECTLY,
-            substrs = ["foo = 4", "bar = 5"])
+
+        if strip:
+            self.expect("expression *(j->_definer)", VARIABLES_DISPLAYED_CORRECTLY,
+                substrs = ["foo = 4"])
+        else:
+            self.expect("expression *(j->_definer)", VARIABLES_DISPLAYED_CORRECTLY,
+                substrs = ["foo = 4", "bar = 5"])
 
         self.expect("expression (k->foo)", VARIABLES_DISPLAYED_CORRECTLY,
             substrs = ["= 2"])
@@ -107,30 +156,52 @@ class HiddenIvarsTestCase(TestBase):
         self.expect("expression (k->bar)", VARIABLES_DISPLAYED_CORRECTLY,
             substrs = ["= 3"])
 
-        self.expect("expression *(k)", VARIABLES_DISPLAYED_CORRECTLY,
-            substrs = ["foo = 2", "bar = 3"])
+        self.expect("expression k.filteredDataSource", VARIABLES_DISPLAYED_CORRECTLY,
+            substrs = [' = 0x', '"2 objects"'])
 
-    def frame_var(self):
-        self.common_setup()
+        if strip:
+            self.expect("expression *(k)", VARIABLES_DISPLAYED_CORRECTLY,
+                substrs = ["foo = 2", ' = 0x', '"2 objects"'])
+        else:            
+            self.expect("expression *(k)", VARIABLES_DISPLAYED_CORRECTLY,
+                substrs = ["foo = 2", "bar = 3", '_filteredDataSource = 0x', '"2 objects"'])
+
+    def frame_var(self, strip):
+        self.common_setup(strip)
 
         # This should display correctly.
         self.expect("frame variable j->_definer->foo", VARIABLES_DISPLAYED_CORRECTLY,
             substrs = ["= 4"])
 
-        self.expect("frame variable j->_definer->bar", VARIABLES_DISPLAYED_CORRECTLY,
-            substrs = ["= 5"])
+        if not strip:
+            self.expect("frame variable j->_definer->bar", VARIABLES_DISPLAYED_CORRECTLY,
+                substrs = ["= 5"])
             
-        self.expect("frame variable *j->_definer", VARIABLES_DISPLAYED_CORRECTLY,
-            substrs = ["foo = 4", "bar = 5"])
+        if strip:
+            self.expect("frame variable *j->_definer", VARIABLES_DISPLAYED_CORRECTLY,
+                substrs = ["foo = 4"])
+        else:
+            self.expect("frame variable *j->_definer", VARIABLES_DISPLAYED_CORRECTLY,
+                substrs = ["foo = 4", "bar = 5"])
 
         self.expect("frame variable k->foo", VARIABLES_DISPLAYED_CORRECTLY,
             substrs = ["= 2"])
 
-        self.expect("frame variable k->bar", VARIABLES_DISPLAYED_CORRECTLY,
-            substrs = ["= 3"])
+        self.expect("frame variable k->_filteredDataSource", VARIABLES_DISPLAYED_CORRECTLY,
+            substrs = [' = 0x', '"2 objects"'])
+
+        if strip:
+            self.expect("frame variable *k", VARIABLES_DISPLAYED_CORRECTLY,
+                substrs = ["foo = 2", '_filteredDataSource = 0x', '"2 objects"'])
+        else:
+            self.expect("frame variable *k", VARIABLES_DISPLAYED_CORRECTLY,
+                substrs = ["foo = 2", "bar = 3", '_filteredDataSource = 0x', '"2 objects"'])
+        
+    def frame_var_type_access_across_module(self):
+        self.common_setup(False)
+
+        self.expect("frame variable k->bar", VARIABLES_DISPLAYED_CORRECTLY, substrs = ["= 3"])
 
-        self.expect("frame variable *k", VARIABLES_DISPLAYED_CORRECTLY,
-            substrs = ["foo = 2", "bar = 3"])
                        
 if __name__ == '__main__':
     import atexit

Modified: lldb/trunk/test/lang/objc/hidden-ivars/main.m
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/objc/hidden-ivars/main.m?rev=224306&r1=224305&r2=224306&view=diff
==============================================================================
--- lldb/trunk/test/lang/objc/hidden-ivars/main.m (original)
+++ lldb/trunk/test/lang/objc/hidden-ivars/main.m Mon Dec 15 19:33:17 2014
@@ -23,9 +23,7 @@
 @end
 
 @interface InheritContainer : InternalDefiner 
-{
-}
-
+ at property (nonatomic, strong) NSMutableArray *filteredDataSource;
 -(id)init;
 @end
 
@@ -35,6 +33,7 @@
 {
     if (self = [super initWithFoo:2 andBar:3])
     {
+        self.filteredDataSource = [NSMutableArray arrayWithObjects:@"hello", @"world", nil];
     }
     return self;
 }





More information about the lldb-commits mailing list