1"""Test that hidden ivars in a shared library are visible from the main executable."""
2
3
4
5import unittest2
6import subprocess
7
8import lldb
9from lldbsuite.test.decorators import *
10from lldbsuite.test.lldbtest import *
11from lldbsuite.test import lldbutil
12
13
14class HiddenIvarsTestCase(TestBase):
15
16    mydir = TestBase.compute_mydir(__file__)
17
18    def setUp(self):
19        # Call super's setUp().
20        TestBase.setUp(self)
21        # Find the line number to break inside main().
22        self.source = 'main.m'
23        self.line = line_number(self.source, '// breakpoint1')
24        # The makefile names of the shared libraries as they appear in DYLIB_NAME.
25        # The names should have no loading "lib" or extension as they will be
26        # localized
27        self.shlib_names = ["InternalDefiner"]
28
29    @skipIf(
30        debug_info=no_match("dsym"),
31        bugnumber="This test requires a stripped binary and a dSYM")
32    @skipIfReproducer # FIXME: Unexpected packet during (passive) replay
33    def test_expr_stripped(self):
34        if self.getArchitecture() == 'i386':
35            self.skipTest("requires modern objc runtime")
36        else:
37            self.build()
38            self.expr(True)
39
40    @skipIfReproducer # FIXME: Unexpected packet during (passive) replay
41    def test_expr(self):
42        if self.getArchitecture() == 'i386':
43            self.skipTest("requires modern objc runtime")
44        else:
45            self.build()
46            self.expr(False)
47
48    @skipIf(
49        debug_info=no_match("dsym"),
50        bugnumber="This test requires a stripped binary and a dSYM")
51    def test_frame_variable_stripped(self):
52        if self.getArchitecture() == 'i386':
53            self.skipTest("requires modern objc runtime")
54        else:
55            self.build()
56            self.frame_var(True)
57
58    def test_frame_variable(self):
59        if self.getArchitecture() == 'i386':
60            self.skipTest("requires modern objc runtime")
61        else:
62            self.build()
63            self.frame_var(False)
64
65    @expectedFailure("rdar://18683637")
66    def test_frame_variable_across_modules(self):
67        if self.getArchitecture() == 'i386':
68            self.skipTest("requires modern objc runtime")
69        else:
70            self.build()
71            self.common_setup(False)
72            self.expect(
73                "frame variable k->bar",
74                VARIABLES_DISPLAYED_CORRECTLY,
75                substrs=["= 3"])
76
77    def common_setup(self, strip):
78
79        if strip:
80            exe = self.getBuildArtifact("stripped/a.out")
81        else:
82            exe = self.getBuildArtifact("a.out")
83        # Create a target by the debugger.
84        target = self.dbg.CreateTarget(exe)
85        self.assertTrue(target, VALID_TARGET)
86
87        # Create the breakpoint inside function 'main'.
88        breakpoint = target.BreakpointCreateByLocation(self.source, self.line)
89        self.assertTrue(breakpoint, VALID_BREAKPOINT)
90
91        # Register our shared libraries for remote targets so they get
92        # automatically uploaded
93        environment = self.registerSharedLibrariesWithTarget(
94            target, self.shlib_names)
95
96        # Now launch the process, and do not stop at entry point.
97        process = target.LaunchSimple(
98            None, environment, self.get_process_working_directory())
99        self.assertTrue(process, PROCESS_IS_VALID)
100
101        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
102
103        # Break inside the foo function which takes a bar_ptr argument.
104        lldbutil.run_break_set_by_file_and_line(
105            self, "main.m", self.line, num_expected_locations=1, loc_exact=True)
106
107        self.runCmd("run", RUN_SUCCEEDED)
108
109        # The stop reason of the thread should be breakpoint.
110        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
111                    substrs=['stopped',
112                             'stop reason = breakpoint'])
113
114        # The breakpoint should have a hit count of 1.
115        self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE,
116                    substrs=[' resolved, hit count = 1'])
117
118    def expr(self, strip):
119        self.common_setup(strip)
120
121        # This should display correctly.
122        self.expect(
123            "expression (j->_definer->foo)",
124            VARIABLES_DISPLAYED_CORRECTLY,
125            substrs=["= 4"])
126
127        self.expect(
128            "expression (j->_definer->bar)",
129            VARIABLES_DISPLAYED_CORRECTLY,
130            substrs=["= 5"])
131
132        if strip:
133            self.expect(
134                "expression *(j->_definer)",
135                VARIABLES_DISPLAYED_CORRECTLY,
136                substrs=["foo = 4"])
137        else:
138            self.expect(
139                "expression *(j->_definer)",
140                VARIABLES_DISPLAYED_CORRECTLY,
141                substrs=[
142                    "foo = 4",
143                    "bar = 5"])
144
145        self.expect("expression (k->foo)", VARIABLES_DISPLAYED_CORRECTLY,
146                    substrs=["= 2"])
147
148        self.expect("expression (k->bar)", VARIABLES_DISPLAYED_CORRECTLY,
149                    substrs=["= 3"])
150
151        self.expect(
152            "expression k.filteredDataSource",
153            VARIABLES_DISPLAYED_CORRECTLY,
154            substrs=[
155                ' = 0x',
156                '"2 elements"'])
157
158        if strip:
159            self.expect("expression *(k)", VARIABLES_DISPLAYED_CORRECTLY,
160                        substrs=["foo = 2", ' = 0x', '"2 elements"'])
161        else:
162            self.expect(
163                "expression *(k)",
164                VARIABLES_DISPLAYED_CORRECTLY,
165                substrs=[
166                    "foo = 2",
167                    "bar = 3",
168                    '_filteredDataSource = 0x',
169                    '"2 elements"'])
170
171    def frame_var(self, strip):
172        self.common_setup(strip)
173
174        # This should display correctly.
175        self.expect(
176            "frame variable j->_definer->foo",
177            VARIABLES_DISPLAYED_CORRECTLY,
178            substrs=["= 4"])
179
180        if not strip:
181            self.expect(
182                "frame variable j->_definer->bar",
183                VARIABLES_DISPLAYED_CORRECTLY,
184                substrs=["= 5"])
185
186        if strip:
187            self.expect(
188                "frame variable *j->_definer",
189                VARIABLES_DISPLAYED_CORRECTLY,
190                substrs=["foo = 4"])
191        else:
192            self.expect(
193                "frame variable *j->_definer",
194                VARIABLES_DISPLAYED_CORRECTLY,
195                substrs=[
196                    "foo = 4",
197                    "bar = 5"])
198
199        self.expect("frame variable k->foo", VARIABLES_DISPLAYED_CORRECTLY,
200                    substrs=["= 2"])
201
202        self.expect(
203            "frame variable k->_filteredDataSource",
204            VARIABLES_DISPLAYED_CORRECTLY,
205            substrs=[
206                ' = 0x',
207                '"2 elements"'])
208
209        if strip:
210            self.expect(
211                "frame variable *k",
212                VARIABLES_DISPLAYED_CORRECTLY,
213                substrs=[
214                    "foo = 2",
215                    '_filteredDataSource = 0x',
216                    '"2 elements"'])
217        else:
218            self.expect(
219                "frame variable *k",
220                VARIABLES_DISPLAYED_CORRECTLY,
221                substrs=[
222                    "foo = 2",
223                    "bar = 3",
224                    '_filteredDataSource = 0x',
225                    '"2 elements"'])
226