1"""
2Set breakpoints on objective-c class and instance methods in foundation.
3Also lookup objective-c data types and evaluate expressions.
4"""
5
6import os, time
7import unittest2
8import lldb
9from lldbtest import *
10import lldbutil
11
12@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
13class FoundationTestCase(TestBase):
14
15    mydir = os.path.join("lang", "objc", "foundation")
16
17    @dsym_test
18    def test_break_with_dsym(self):
19        """Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'."""
20        self.buildDsym()
21        self.break_on_objc_methods()
22
23    @dwarf_test
24    def test_break_with_dwarf(self):
25        """Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'."""
26        self.buildDwarf()
27        self.break_on_objc_methods()
28
29    #@unittest2.expectedFailure
30    # rdar://problem/8542091
31    # rdar://problem/8492646
32    @dsym_test
33    def test_data_type_and_expr_with_dsym(self):
34        """Lookup objective-c data types and evaluate expressions."""
35        self.buildDsym()
36        self.data_type_and_expr_objc()
37
38    #@unittest2.expectedFailure
39    # rdar://problem/8542091
40    # rdar://problem/8492646
41    @dwarf_test
42    def test_data_type_and_expr_with_dwarf(self):
43        """Lookup objective-c data types and evaluate expressions."""
44        self.buildDwarf()
45        self.data_type_and_expr_objc()
46
47    @python_api_test
48    @dsym_test
49    def test_print_ivars_correctly_with_dsym (self):
50        self.buildDsym()
51        self.print_ivars_correctly()
52
53    @python_api_test
54    @dwarf_test
55    def test_print_ivars_correctly_with_dwarf (self):
56        self.buildDwarf()
57        self.print_ivars_correctly()
58
59    def break_on_objc_methods(self):
60        """Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'."""
61        exe = os.path.join(os.getcwd(), "a.out")
62        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
63
64        # Stop at +[NSString stringWithFormat:].
65        break_results = lldbutil.run_break_set_command(self, "_regexp-break +[NSString stringWithFormat:]")
66        lldbutil.check_breakpoint_result (self, break_results, symbol_name='+[NSString stringWithFormat:]', num_locations=1)
67
68        # Stop at -[MyString initWithNSString:].
69        lldbutil.run_break_set_by_symbol (self, '-[MyString initWithNSString:]', num_expected_locations=1, sym_exact=True)
70
71        # Stop at the "description" selector.
72        lldbutil.run_break_set_by_selector (self, 'description', num_expected_locations=1, module_name='a.out')
73
74        # Stop at -[NSAutoreleasePool release].
75        break_results = lldbutil.run_break_set_command(self, "_regexp-break -[NSAutoreleasePool release]")
76        lldbutil.check_breakpoint_result (self, break_results, symbol_name='-[NSAutoreleasePool release]', num_locations=1)
77
78        self.runCmd("run", RUN_SUCCEEDED)
79
80        # First stop is +[NSString stringWithFormat:].
81        self.expect("thread backtrace", "Stop at +[NSString stringWithFormat:]",
82            substrs = ["Foundation`+[NSString stringWithFormat:]"])
83
84        self.runCmd("process continue")
85
86        # Second stop is still +[NSString stringWithFormat:].
87        self.expect("thread backtrace", "Stop at +[NSString stringWithFormat:]",
88            substrs = ["Foundation`+[NSString stringWithFormat:]"])
89
90        self.runCmd("process continue")
91
92        # Followed by a.out`-[MyString initWithNSString:].
93        self.expect("thread backtrace", "Stop at a.out`-[MyString initWithNSString:]",
94            substrs = ["a.out`-[MyString initWithNSString:]"])
95
96        self.runCmd("process continue")
97
98        # Followed by -[MyString description].
99        self.expect("thread backtrace", "Stop at -[MyString description]",
100            substrs = ["a.out`-[MyString description]"])
101
102        self.runCmd("process continue")
103
104        # Followed by the same -[MyString description].
105        self.expect("thread backtrace", "Stop at -[MyString description]",
106            substrs = ["a.out`-[MyString description]"])
107
108        self.runCmd("process continue")
109
110        # Followed by -[NSAutoreleasePool release].
111        self.expect("thread backtrace", "Stop at -[NSAutoreleasePool release]",
112            substrs = ["Foundation`-[NSAutoreleasePool release]"])
113
114    def setUp(self):
115        # Call super's setUp().
116        TestBase.setUp(self)
117        # Find the line number to break inside main().
118        self.main_source = "main.m"
119        self.line = line_number(self.main_source, '// Set break point at this line.')
120
121    def data_type_and_expr_objc(self):
122        """Lookup objective-c data types and evaluate expressions."""
123        exe = os.path.join(os.getcwd(), "a.out")
124        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
125
126        # Stop at -[MyString description].
127        lldbutil.run_break_set_by_symbol (self, '-[MyString description]', num_expected_locations=1, sym_exact=True)
128#        self.expect("breakpoint set -n '-[MyString description]", BREAKPOINT_CREATED,
129#            startstr = "Breakpoint created: 1: name = '-[MyString description]', locations = 1")
130
131        self.runCmd("run", RUN_SUCCEEDED)
132
133        # The backtrace should show we stop at -[MyString description].
134        self.expect("thread backtrace", "Stop at -[MyString description]",
135            substrs = ["a.out`-[MyString description]"])
136
137        # Lookup objc data type MyString and evaluate some expressions.
138
139        self.expect("image lookup -t NSString", DATA_TYPES_DISPLAYED_CORRECTLY,
140            substrs = ['name = "NSString"',
141                       'clang_type = "@interface NSString'])
142
143        self.expect("image lookup -t MyString", DATA_TYPES_DISPLAYED_CORRECTLY,
144            substrs = ['name = "MyString"',
145                       'clang_type = "@interface MyString',
146                       'NSString * str;',
147                       'NSDate * date;'])
148
149        self.expect("frame variable --show-types --scope", VARIABLES_DISPLAYED_CORRECTLY,
150            substrs = ["ARG: (MyString *) self"],
151            patterns = ["ARG: \(.*\) _cmd",
152                        "(objc_selector *)|(SEL)"])
153
154        # rdar://problem/8651752
155        # don't crash trying to ask clang how many children an empty record has
156        self.runCmd("frame variable *_cmd")
157
158        # rdar://problem/8492646
159        # test/foundation fails after updating to tot r115023
160        # self->str displays nothing as output
161        self.expect("frame variable --show-types self->str", VARIABLES_DISPLAYED_CORRECTLY,
162            startstr = "(NSString *) self->str")
163
164        # rdar://problem/8447030
165        # 'frame variable self->date' displays the wrong data member
166        self.expect("frame variable --show-types self->date", VARIABLES_DISPLAYED_CORRECTLY,
167            startstr = "(NSDate *) self->date")
168
169        # This should display the str and date member fields as well.
170        self.expect("frame variable --show-types *self", VARIABLES_DISPLAYED_CORRECTLY,
171            substrs = ["(MyString) *self",
172                       "(NSString *) str",
173                       "(NSDate *) date"])
174
175        # isa should be accessible.
176        self.expect("expression self->isa", VARIABLES_DISPLAYED_CORRECTLY,
177            substrs = ["(Class)"])
178
179        # This should fail expectedly.
180        self.expect("expression self->non_existent_member",
181                    COMMAND_FAILED_AS_EXPECTED, error=True,
182            startstr = "error: 'MyString' does not have a member named 'non_existent_member'")
183
184        # Use expression parser.
185        self.runCmd("expression self->str")
186        self.runCmd("expression self->date")
187
188        # (lldb) expression self->str
189        # error: instance variable 'str' is protected
190        # error: 1 errors parsing expression
191        #
192        # (lldb) expression self->date
193        # error: instance variable 'date' is protected
194        # error: 1 errors parsing expression
195        #
196
197        self.runCmd("breakpoint delete 1")
198        lldbutil.run_break_set_by_file_and_line (self, "main.m", self.line, num_expected_locations=1, loc_exact=True)
199
200        self.runCmd("process continue")
201
202        # rdar://problem/8542091
203        # test/foundation: expr -o -- my not working?
204        #
205        # Test new feature with r115115:
206        # Add "-o" option to "expression" which prints the object description if available.
207        self.expect("expression --object-description -- my", "Object description displayed correctly",
208            patterns = ["Hello from.*a.out.*with timestamp: "])
209
210    # See: <rdar://problem/8717050> lldb needs to use the ObjC runtime symbols for ivar offsets
211    # Only fails for the ObjC 2.0 runtime.
212    def print_ivars_correctly(self) :
213        exe = os.path.join(os.getcwd(), "a.out")
214
215        target = self.dbg.CreateTarget(exe)
216        self.assertTrue(target, VALID_TARGET)
217
218        break1 = target.BreakpointCreateByLocation(self.main_source, self.line)
219        self.assertTrue(break1, VALID_BREAKPOINT)
220
221        # Now launch the process, and do not stop at entry point.
222        process = target.LaunchSimple(None, None, os.getcwd())
223
224        self.assertTrue(process, PROCESS_IS_VALID)
225
226        # The stop reason of the thread should be breakpoint.
227        thread = process.GetThreadAtIndex(0)
228        if thread.GetStopReason() != lldb.eStopReasonBreakpoint:
229            from lldbutil import stop_reason_to_str
230            self.fail(STOPPED_DUE_TO_BREAKPOINT_WITH_STOP_REASON_AS %
231                      stop_reason_to_str(thread.GetStopReason()))
232
233        # Make sure we stopped at the first breakpoint.
234
235        cur_frame = thread.GetFrameAtIndex(0)
236
237        line_number = cur_frame.GetLineEntry().GetLine()
238        self.assertTrue (line_number == self.line, "Hit the first breakpoint.")
239
240        my_var = cur_frame.FindVariable("my")
241        self.assertTrue(my_var, "Made a variable object for my")
242
243        str_var = cur_frame.FindVariable("str")
244        self.assertTrue(str_var, "Made a variable object for str")
245
246        # Now make sure that the my->str == str:
247
248        my_str_var = my_var.GetChildMemberWithName("str")
249        self.assertTrue(my_str_var, "Found a str ivar in my")
250
251        str_value = int(str_var.GetValue(), 0)
252
253        my_str_value = int(my_str_var.GetValue(), 0)
254
255        self.assertTrue(str_value == my_str_value, "Got the correct value for my->str")
256
257if __name__ == '__main__':
258    import atexit
259    lldb.SBDebugger.Initialize()
260    atexit.register(lambda: lldb.SBDebugger.Terminate())
261    unittest2.main()
262