diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index 9522dd58cad3..87c564aea56a 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -554,36 +554,52 @@ AppleObjCRuntimeV2::CreateObjectChecker(const char *name) 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); - 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); + addr_t ivar_offset_address = LLDB_INVALID_ADDRESS; - 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); + 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 (ivar_offset_address != LLDB_INVALID_ADDRESS) + ivar_offset = m_process->ReadUnsignedIntegerFromMemory (ivar_offset_address, + 4, + LLDB_INVALID_IVAR_OFFSET, + error); + } return ivar_offset; } diff --git a/lldb/test/lang/objc/hidden-ivars/TestHiddenIvars.py b/lldb/test/lang/objc/hidden-ivars/TestHiddenIvars.py index f657cc59f45d..136467f7353a 100644 --- a/lldb/test/lang/objc/hidden-ivars/TestHiddenIvars.py +++ b/lldb/test/lang/objc/hidden-ivars/TestHiddenIvars.py @@ -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 diff --git a/lldb/test/lang/objc/hidden-ivars/main.m b/lldb/test/lang/objc/hidden-ivars/main.m index 18b78f1f44bc..1795d56e7d8a 100644 --- a/lldb/test/lang/objc/hidden-ivars/main.m +++ b/lldb/test/lang/objc/hidden-ivars/main.m @@ -23,9 +23,7 @@ @end @interface InheritContainer : InternalDefiner -{ -} - +@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; }