199451b44SJordan Rupprecht"""
299451b44SJordan RupprechtSet breakpoints on objective-c class and instance methods in foundation.
399451b44SJordan RupprechtAlso lookup objective-c data types and evaluate expressions.
499451b44SJordan Rupprecht"""
599451b44SJordan Rupprecht
699451b44SJordan Rupprechtfrom __future__ import print_function
799451b44SJordan Rupprecht
899451b44SJordan Rupprecht
999451b44SJordan Rupprechtimport os
1099451b44SJordan Rupprechtimport os.path
1199451b44SJordan Rupprechtimport lldb
1299451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
1399451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
1499451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil
1599451b44SJordan Rupprecht
1699451b44SJordan Rupprechtfile_index = 0
1799451b44SJordan Rupprecht
1899451b44SJordan Rupprecht
1999451b44SJordan Rupprechtclass FoundationTestCase(TestBase):
2099451b44SJordan Rupprecht
2199451b44SJordan Rupprecht    def setUp(self):
2299451b44SJordan Rupprecht        # Call super's setUp().
2399451b44SJordan Rupprecht        TestBase.setUp(self)
2499451b44SJordan Rupprecht        # Find the line number to break inside main().
2599451b44SJordan Rupprecht        self.main_source = "main.m"
2699451b44SJordan Rupprecht        self.line = line_number(
2799451b44SJordan Rupprecht            self.main_source,
2899451b44SJordan Rupprecht            '// Set break point at this line.')
2999451b44SJordan Rupprecht
3099451b44SJordan Rupprecht    def test_break(self):
3199451b44SJordan Rupprecht        """Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'."""
3299451b44SJordan Rupprecht        self.build()
3399451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
3499451b44SJordan Rupprecht        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
3599451b44SJordan Rupprecht
3699451b44SJordan Rupprecht        # Stop at +[NSString stringWithFormat:].
3799451b44SJordan Rupprecht        break_results = lldbutil.run_break_set_command(
3899451b44SJordan Rupprecht            self, "_regexp-break +[NSString stringWithFormat:]")
3999451b44SJordan Rupprecht        lldbutil.check_breakpoint_result(
4099451b44SJordan Rupprecht            self,
4199451b44SJordan Rupprecht            break_results,
4299451b44SJordan Rupprecht            symbol_name='+[NSString stringWithFormat:]',
4399451b44SJordan Rupprecht            num_locations=1)
4499451b44SJordan Rupprecht
4599451b44SJordan Rupprecht        # Stop at -[MyString initWithNSString:].
4699451b44SJordan Rupprecht        lldbutil.run_break_set_by_symbol(
4799451b44SJordan Rupprecht            self,
4899451b44SJordan Rupprecht            '-[MyString initWithNSString:]',
4999451b44SJordan Rupprecht            num_expected_locations=1,
5099451b44SJordan Rupprecht            sym_exact=True)
5199451b44SJordan Rupprecht
5299451b44SJordan Rupprecht        # Stop at the "description" selector.
5399451b44SJordan Rupprecht        lldbutil.run_break_set_by_selector(
5499451b44SJordan Rupprecht            self,
5599451b44SJordan Rupprecht            'description',
5699451b44SJordan Rupprecht            num_expected_locations=1,
5799451b44SJordan Rupprecht            module_name='a.out')
5899451b44SJordan Rupprecht
5999451b44SJordan Rupprecht        # Stop at -[NSAutoreleasePool release].
6099451b44SJordan Rupprecht        break_results = lldbutil.run_break_set_command(
6199451b44SJordan Rupprecht            self, "_regexp-break -[NSAutoreleasePool release]")
6299451b44SJordan Rupprecht        lldbutil.check_breakpoint_result(
6399451b44SJordan Rupprecht            self,
6499451b44SJordan Rupprecht            break_results,
6599451b44SJordan Rupprecht            symbol_name='-[NSAutoreleasePool release]',
6699451b44SJordan Rupprecht            num_locations=1)
6799451b44SJordan Rupprecht
6899451b44SJordan Rupprecht        self.runCmd("run", RUN_SUCCEEDED)
6999451b44SJordan Rupprecht
7099451b44SJordan Rupprecht        # First stop is +[NSString stringWithFormat:].
7199451b44SJordan Rupprecht        self.expect(
7299451b44SJordan Rupprecht            "thread backtrace",
7399451b44SJordan Rupprecht            "Stop at +[NSString stringWithFormat:]",
7499451b44SJordan Rupprecht            substrs=["Foundation`+[NSString stringWithFormat:]"])
7599451b44SJordan Rupprecht
7699451b44SJordan Rupprecht        self.runCmd("process continue")
7799451b44SJordan Rupprecht
7899451b44SJordan Rupprecht        # Second stop is still +[NSString stringWithFormat:].
7999451b44SJordan Rupprecht        self.expect(
8099451b44SJordan Rupprecht            "thread backtrace",
8199451b44SJordan Rupprecht            "Stop at +[NSString stringWithFormat:]",
8299451b44SJordan Rupprecht            substrs=["Foundation`+[NSString stringWithFormat:]"])
8399451b44SJordan Rupprecht
8499451b44SJordan Rupprecht        self.runCmd("process continue")
8599451b44SJordan Rupprecht
8699451b44SJordan Rupprecht        # Followed by a.out`-[MyString initWithNSString:].
8799451b44SJordan Rupprecht        self.expect(
8899451b44SJordan Rupprecht            "thread backtrace",
8999451b44SJordan Rupprecht            "Stop at a.out`-[MyString initWithNSString:]",
9099451b44SJordan Rupprecht            substrs=["a.out`-[MyString initWithNSString:]"])
9199451b44SJordan Rupprecht
9299451b44SJordan Rupprecht        self.runCmd("process continue")
9399451b44SJordan Rupprecht
9499451b44SJordan Rupprecht        # Followed by -[MyString description].
9599451b44SJordan Rupprecht        self.expect("thread backtrace", "Stop at -[MyString description]",
9699451b44SJordan Rupprecht                    substrs=["a.out`-[MyString description]"])
9799451b44SJordan Rupprecht
9899451b44SJordan Rupprecht        self.runCmd("process continue")
9999451b44SJordan Rupprecht
10099451b44SJordan Rupprecht        # Followed by the same -[MyString description].
10199451b44SJordan Rupprecht        self.expect("thread backtrace", "Stop at -[MyString description]",
10299451b44SJordan Rupprecht                    substrs=["a.out`-[MyString description]"])
10399451b44SJordan Rupprecht
10499451b44SJordan Rupprecht        self.runCmd("process continue")
10599451b44SJordan Rupprecht
10699451b44SJordan Rupprecht        # Followed by -[NSAutoreleasePool release].
10799451b44SJordan Rupprecht        self.expect("thread backtrace", "Stop at -[NSAutoreleasePool release]",
10899451b44SJordan Rupprecht                    substrs=["Foundation`-[NSAutoreleasePool release]"])
10999451b44SJordan Rupprecht
11099451b44SJordan Rupprecht    # rdar://problem/8542091
11199451b44SJordan Rupprecht    # rdar://problem/8492646
11299451b44SJordan Rupprecht    def test_data_type_and_expr(self):
11399451b44SJordan Rupprecht        """Lookup objective-c data types and evaluate expressions."""
11499451b44SJordan Rupprecht        self.build()
11599451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
11699451b44SJordan Rupprecht        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
11799451b44SJordan Rupprecht
11899451b44SJordan Rupprecht        # Stop at -[MyString description].
11999451b44SJordan Rupprecht        lldbutil.run_break_set_by_symbol(
12099451b44SJordan Rupprecht            self,
12199451b44SJordan Rupprecht            '-[MyString description]',
12299451b44SJordan Rupprecht            num_expected_locations=1,
12399451b44SJordan Rupprecht            sym_exact=True)
12499451b44SJordan Rupprecht#        self.expect("breakpoint set -n '-[MyString description]", BREAKPOINT_CREATED,
12599451b44SJordan Rupprecht# startstr = "Breakpoint created: 1: name = '-[MyString description]',
12699451b44SJordan Rupprecht# locations = 1")
12799451b44SJordan Rupprecht
12899451b44SJordan Rupprecht        self.runCmd("run", RUN_SUCCEEDED)
12999451b44SJordan Rupprecht
13099451b44SJordan Rupprecht        # The backtrace should show we stop at -[MyString description].
13199451b44SJordan Rupprecht        self.expect("thread backtrace", "Stop at -[MyString description]",
13299451b44SJordan Rupprecht                    substrs=["a.out`-[MyString description]"])
13399451b44SJordan Rupprecht
13499451b44SJordan Rupprecht        # Lookup objc data type MyString and evaluate some expressions.
13599451b44SJordan Rupprecht
13699451b44SJordan Rupprecht        self.expect("image lookup -t NSString", DATA_TYPES_DISPLAYED_CORRECTLY,
13799451b44SJordan Rupprecht                    substrs=['name = "NSString"',
13899451b44SJordan Rupprecht                             'compiler_type = "@interface NSString'])
13999451b44SJordan Rupprecht
14099451b44SJordan Rupprecht        self.expect("image lookup -t MyString", DATA_TYPES_DISPLAYED_CORRECTLY,
14199451b44SJordan Rupprecht                    substrs=['name = "MyString"',
14299451b44SJordan Rupprecht                             'compiler_type = "@interface MyString',
14399451b44SJordan Rupprecht                             'NSString * str;',
14499451b44SJordan Rupprecht                             'NSDate * date;'])
14599451b44SJordan Rupprecht
14699451b44SJordan Rupprecht        self.expect(
14799451b44SJordan Rupprecht            "frame variable --show-types --scope",
14899451b44SJordan Rupprecht            VARIABLES_DISPLAYED_CORRECTLY,
14999451b44SJordan Rupprecht            substrs=["ARG: (MyString *) self"],
15099451b44SJordan Rupprecht            patterns=[
15199451b44SJordan Rupprecht                "ARG: \(.*\) _cmd",
15299451b44SJordan Rupprecht                "(objc_selector *)|(SEL)"])
15399451b44SJordan Rupprecht
15499451b44SJordan Rupprecht        # rdar://problem/8651752
15599451b44SJordan Rupprecht        # don't crash trying to ask clang how many children an empty record has
15699451b44SJordan Rupprecht        self.runCmd("frame variable *_cmd")
15799451b44SJordan Rupprecht
15899451b44SJordan Rupprecht        # rdar://problem/8492646
15999451b44SJordan Rupprecht        # test/foundation fails after updating to tot r115023
16099451b44SJordan Rupprecht        # self->str displays nothing as output
16199451b44SJordan Rupprecht        self.expect(
16299451b44SJordan Rupprecht            "frame variable --show-types self->str",
16399451b44SJordan Rupprecht            VARIABLES_DISPLAYED_CORRECTLY,
16499451b44SJordan Rupprecht            startstr="(NSString *) self->str")
16599451b44SJordan Rupprecht
16699451b44SJordan Rupprecht        # rdar://problem/8447030
16799451b44SJordan Rupprecht        # 'frame variable self->date' displays the wrong data member
16899451b44SJordan Rupprecht        self.expect(
16999451b44SJordan Rupprecht            "frame variable --show-types self->date",
17099451b44SJordan Rupprecht            VARIABLES_DISPLAYED_CORRECTLY,
17199451b44SJordan Rupprecht            startstr="(NSDate *) self->date")
17299451b44SJordan Rupprecht
17399451b44SJordan Rupprecht        # This should display the str and date member fields as well.
17499451b44SJordan Rupprecht        self.expect(
17599451b44SJordan Rupprecht            "frame variable --show-types *self",
17699451b44SJordan Rupprecht            VARIABLES_DISPLAYED_CORRECTLY,
17799451b44SJordan Rupprecht            substrs=[
17899451b44SJordan Rupprecht                "(MyString) *self",
17999451b44SJordan Rupprecht                "(NSString *) str",
18099451b44SJordan Rupprecht                "(NSDate *) date"])
18199451b44SJordan Rupprecht
18299451b44SJordan Rupprecht        # isa should be accessible.
18399451b44SJordan Rupprecht        self.expect("expression self->isa", VARIABLES_DISPLAYED_CORRECTLY,
184d8fb631dSAdrian Prantl                    substrs=["Class)"])
18599451b44SJordan Rupprecht
18699451b44SJordan Rupprecht        # This should fail expectedly.
18799451b44SJordan Rupprecht        self.expect(
18899451b44SJordan Rupprecht            "expression self->non_existent_member",
18999451b44SJordan Rupprecht            COMMAND_FAILED_AS_EXPECTED,
19099451b44SJordan Rupprecht            error=True,
19199451b44SJordan Rupprecht            substrs=["error:", "'MyString' does not have a member named 'non_existent_member'"])
19299451b44SJordan Rupprecht
19399451b44SJordan Rupprecht        # Use expression parser.
19499451b44SJordan Rupprecht        self.runCmd("expression self->str")
19599451b44SJordan Rupprecht        self.runCmd("expression self->date")
19699451b44SJordan Rupprecht
19799451b44SJordan Rupprecht        # (lldb) expression self->str
19899451b44SJordan Rupprecht        # error: instance variable 'str' is protected
19999451b44SJordan Rupprecht        # error: 1 errors parsing expression
20099451b44SJordan Rupprecht        #
20199451b44SJordan Rupprecht        # (lldb) expression self->date
20299451b44SJordan Rupprecht        # error: instance variable 'date' is protected
20399451b44SJordan Rupprecht        # error: 1 errors parsing expression
20499451b44SJordan Rupprecht        #
20599451b44SJordan Rupprecht
20699451b44SJordan Rupprecht        self.runCmd("breakpoint delete 1")
20799451b44SJordan Rupprecht        lldbutil.run_break_set_by_file_and_line(
20899451b44SJordan Rupprecht            self, "main.m", self.line, num_expected_locations=1, loc_exact=True)
20999451b44SJordan Rupprecht
21099451b44SJordan Rupprecht        self.runCmd("process continue")
21199451b44SJordan Rupprecht
21299451b44SJordan Rupprecht        # rdar://problem/8542091
21399451b44SJordan Rupprecht        # test/foundation: expr -o -- my not working?
21499451b44SJordan Rupprecht        #
21599451b44SJordan Rupprecht        # Test new feature with r115115:
21699451b44SJordan Rupprecht        # Add "-o" option to "expression" which prints the object description
21799451b44SJordan Rupprecht        # if available.
21899451b44SJordan Rupprecht        self.expect(
21999451b44SJordan Rupprecht            "expression --object-description -- my",
22099451b44SJordan Rupprecht            "Object description displayed correctly",
22199451b44SJordan Rupprecht            patterns=["Hello from.*a.out.*with timestamp: "])
22299451b44SJordan Rupprecht
22399451b44SJordan Rupprecht    @add_test_categories(['pyapi'])
22499451b44SJordan Rupprecht    def test_print_ivars_correctly(self):
22599451b44SJordan Rupprecht        self.build()
22699451b44SJordan Rupprecht        # See: <rdar://problem/8717050> lldb needs to use the ObjC runtime symbols for ivar offsets
22799451b44SJordan Rupprecht        # Only fails for the ObjC 2.0 runtime.
22899451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
22999451b44SJordan Rupprecht
23099451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
23199451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
23299451b44SJordan Rupprecht
23399451b44SJordan Rupprecht        break1 = target.BreakpointCreateByLocation(self.main_source, self.line)
23499451b44SJordan Rupprecht        self.assertTrue(break1, VALID_BREAKPOINT)
23599451b44SJordan Rupprecht
23699451b44SJordan Rupprecht        # Now launch the process, and do not stop at entry point.
23799451b44SJordan Rupprecht        process = target.LaunchSimple(
23899451b44SJordan Rupprecht            None, None, self.get_process_working_directory())
23999451b44SJordan Rupprecht
24099451b44SJordan Rupprecht        self.assertTrue(process, PROCESS_IS_VALID)
24199451b44SJordan Rupprecht
24299451b44SJordan Rupprecht        # The stop reason of the thread should be breakpoint.
24399451b44SJordan Rupprecht        thread = process.GetThreadAtIndex(0)
24499451b44SJordan Rupprecht        if thread.GetStopReason() != lldb.eStopReasonBreakpoint:
24599451b44SJordan Rupprecht            from lldbsuite.test.lldbutil import stop_reason_to_str
24699451b44SJordan Rupprecht            self.fail(STOPPED_DUE_TO_BREAKPOINT_WITH_STOP_REASON_AS %
24799451b44SJordan Rupprecht                      stop_reason_to_str(thread.GetStopReason()))
24899451b44SJordan Rupprecht
24999451b44SJordan Rupprecht        # Make sure we stopped at the first breakpoint.
25099451b44SJordan Rupprecht
25199451b44SJordan Rupprecht        cur_frame = thread.GetFrameAtIndex(0)
25299451b44SJordan Rupprecht
25399451b44SJordan Rupprecht        line_number = cur_frame.GetLineEntry().GetLine()
254619e2e09SDave Lee        self.assertEqual(line_number, self.line, "Hit the first breakpoint.")
25599451b44SJordan Rupprecht
25699451b44SJordan Rupprecht        my_var = cur_frame.FindVariable("my")
25799451b44SJordan Rupprecht        self.assertTrue(my_var, "Made a variable object for my")
25899451b44SJordan Rupprecht
25999451b44SJordan Rupprecht        str_var = cur_frame.FindVariable("str")
26099451b44SJordan Rupprecht        self.assertTrue(str_var, "Made a variable object for str")
26199451b44SJordan Rupprecht
26299451b44SJordan Rupprecht        # Now make sure that the my->str == str:
26399451b44SJordan Rupprecht
26499451b44SJordan Rupprecht        my_str_var = my_var.GetChildMemberWithName("str")
26599451b44SJordan Rupprecht        self.assertTrue(my_str_var, "Found a str ivar in my")
26699451b44SJordan Rupprecht
26799451b44SJordan Rupprecht        str_value = int(str_var.GetValue(), 0)
26899451b44SJordan Rupprecht
26999451b44SJordan Rupprecht        my_str_value = int(my_str_var.GetValue(), 0)
27099451b44SJordan Rupprecht
271*0ed758b2SDave Lee        self.assertEqual(
272*0ed758b2SDave Lee            str_value, my_str_value,
27399451b44SJordan Rupprecht            "Got the correct value for my->str")
27499451b44SJordan Rupprecht
27599451b44SJordan Rupprecht    def test_expression_lookups_objc(self):
27699451b44SJordan Rupprecht        """Test running an expression detect spurious debug info lookups (DWARF)."""
27799451b44SJordan Rupprecht        self.build()
27899451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
27999451b44SJordan Rupprecht        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
28099451b44SJordan Rupprecht
28199451b44SJordan Rupprecht        # Stop at -[MyString initWithNSString:].
28299451b44SJordan Rupprecht        lldbutil.run_break_set_by_symbol(
28399451b44SJordan Rupprecht            self,
28499451b44SJordan Rupprecht            '-[MyString initWithNSString:]',
28599451b44SJordan Rupprecht            num_expected_locations=1,
28699451b44SJordan Rupprecht            sym_exact=True)
28799451b44SJordan Rupprecht
28899451b44SJordan Rupprecht        self.runCmd("run", RUN_SUCCEEDED)
28999451b44SJordan Rupprecht
29099451b44SJordan Rupprecht        global file_index
29199451b44SJordan Rupprecht        # Log any DWARF lookups
29299451b44SJordan Rupprecht        ++file_index
29399451b44SJordan Rupprecht        logfile = os.path.join(
29499451b44SJordan Rupprecht            self.getBuildDir(),
29599451b44SJordan Rupprecht            "dwarf-lookups-" +
29699451b44SJordan Rupprecht            self.getArchitecture() +
29799451b44SJordan Rupprecht            "-" +
29899451b44SJordan Rupprecht            str(file_index) +
29999451b44SJordan Rupprecht            ".txt")
30099451b44SJordan Rupprecht        self.runCmd("log enable -f %s dwarf lookups" % (logfile))
30199451b44SJordan Rupprecht        self.runCmd("expr self")
30299451b44SJordan Rupprecht        self.runCmd("log disable dwarf lookups")
30399451b44SJordan Rupprecht
30499451b44SJordan Rupprecht        def cleanup():
30599451b44SJordan Rupprecht            if os.path.exists(logfile):
30699451b44SJordan Rupprecht                os.unlink(logfile)
30799451b44SJordan Rupprecht
30899451b44SJordan Rupprecht        self.addTearDownHook(cleanup)
30999451b44SJordan Rupprecht
31099451b44SJordan Rupprecht        if os.path.exists(logfile):
31199451b44SJordan Rupprecht            f = open(logfile)
31299451b44SJordan Rupprecht            lines = f.readlines()
31399451b44SJordan Rupprecht            num_errors = 0
31499451b44SJordan Rupprecht            for line in lines:
31599451b44SJordan Rupprecht                if "$__lldb" in line:
31699451b44SJordan Rupprecht                    if num_errors == 0:
31799451b44SJordan Rupprecht                        print(
31899451b44SJordan Rupprecht                            "error: found spurious name lookups when evaluating an expression:")
31999451b44SJordan Rupprecht                    num_errors += 1
32099451b44SJordan Rupprecht                    print(line, end='')
321619e2e09SDave Lee            self.assertEqual(num_errors, 0, "Spurious lookups detected")
32299451b44SJordan Rupprecht            f.close()
323