xref: /llvm-project/lldb/test/API/lang/objc/foundation/TestObjCMethods.py (revision 2238dcc39358353cac21df75c3c3286ab20b8f53)
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 Rupprechtimport os
799451b44SJordan Rupprechtimport os.path
899451b44SJordan Rupprechtimport lldb
999451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
1099451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
1199451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil
1299451b44SJordan Rupprecht
1399451b44SJordan Rupprechtfile_index = 0
1499451b44SJordan Rupprecht
1599451b44SJordan Rupprecht
1699451b44SJordan Rupprechtclass FoundationTestCase(TestBase):
1799451b44SJordan Rupprecht    def setUp(self):
1899451b44SJordan Rupprecht        # Call super's setUp().
1999451b44SJordan Rupprecht        TestBase.setUp(self)
2099451b44SJordan Rupprecht        # Find the line number to break inside main().
2199451b44SJordan Rupprecht        self.main_source = "main.m"
22*2238dcc3SJonas Devlieghere        self.line = line_number(self.main_source, "// Set break point at this line.")
2399451b44SJordan Rupprecht
2499451b44SJordan Rupprecht    def test_break(self):
2599451b44SJordan Rupprecht        """Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'."""
2699451b44SJordan Rupprecht        self.build()
2799451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
2899451b44SJordan Rupprecht        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
2999451b44SJordan Rupprecht
3099451b44SJordan Rupprecht        # Stop at +[NSString stringWithFormat:].
3199451b44SJordan Rupprecht        break_results = lldbutil.run_break_set_command(
32*2238dcc3SJonas Devlieghere            self, "_regexp-break +[NSString stringWithFormat:]"
33*2238dcc3SJonas Devlieghere        )
3499451b44SJordan Rupprecht        lldbutil.check_breakpoint_result(
3599451b44SJordan Rupprecht            self,
3699451b44SJordan Rupprecht            break_results,
37*2238dcc3SJonas Devlieghere            symbol_name="+[NSString stringWithFormat:]",
38*2238dcc3SJonas Devlieghere            num_locations=1,
39*2238dcc3SJonas Devlieghere        )
4099451b44SJordan Rupprecht
4199451b44SJordan Rupprecht        # Stop at -[MyString initWithNSString:].
4299451b44SJordan Rupprecht        lldbutil.run_break_set_by_symbol(
4399451b44SJordan Rupprecht            self,
44*2238dcc3SJonas Devlieghere            "-[MyString initWithNSString:]",
4599451b44SJordan Rupprecht            num_expected_locations=1,
46*2238dcc3SJonas Devlieghere            sym_exact=True,
47*2238dcc3SJonas Devlieghere        )
4899451b44SJordan Rupprecht
4999451b44SJordan Rupprecht        # Stop at the "description" selector.
5099451b44SJordan Rupprecht        lldbutil.run_break_set_by_selector(
51*2238dcc3SJonas Devlieghere            self, "description", num_expected_locations=1, module_name="a.out"
52*2238dcc3SJonas Devlieghere        )
5399451b44SJordan Rupprecht
5499451b44SJordan Rupprecht        # Stop at -[NSAutoreleasePool release].
5599451b44SJordan Rupprecht        break_results = lldbutil.run_break_set_command(
56*2238dcc3SJonas Devlieghere            self, "_regexp-break -[NSAutoreleasePool release]"
57*2238dcc3SJonas Devlieghere        )
5899451b44SJordan Rupprecht        lldbutil.check_breakpoint_result(
5999451b44SJordan Rupprecht            self,
6099451b44SJordan Rupprecht            break_results,
61*2238dcc3SJonas Devlieghere            symbol_name="-[NSAutoreleasePool release]",
62*2238dcc3SJonas Devlieghere            num_locations=1,
63*2238dcc3SJonas Devlieghere        )
6499451b44SJordan Rupprecht
6599451b44SJordan Rupprecht        self.runCmd("run", RUN_SUCCEEDED)
6699451b44SJordan Rupprecht
6799451b44SJordan Rupprecht        # First stop is +[NSString stringWithFormat:].
6899451b44SJordan Rupprecht        self.expect(
6999451b44SJordan Rupprecht            "thread backtrace",
7099451b44SJordan Rupprecht            "Stop at +[NSString stringWithFormat:]",
71*2238dcc3SJonas Devlieghere            substrs=["Foundation`+[NSString stringWithFormat:]"],
72*2238dcc3SJonas Devlieghere        )
7399451b44SJordan Rupprecht
7499451b44SJordan Rupprecht        self.runCmd("process continue")
7599451b44SJordan Rupprecht
7699451b44SJordan Rupprecht        # Second stop is still +[NSString stringWithFormat:].
7799451b44SJordan Rupprecht        self.expect(
7899451b44SJordan Rupprecht            "thread backtrace",
7999451b44SJordan Rupprecht            "Stop at +[NSString stringWithFormat:]",
80*2238dcc3SJonas Devlieghere            substrs=["Foundation`+[NSString stringWithFormat:]"],
81*2238dcc3SJonas Devlieghere        )
8299451b44SJordan Rupprecht
8399451b44SJordan Rupprecht        self.runCmd("process continue")
8499451b44SJordan Rupprecht
8599451b44SJordan Rupprecht        # Followed by a.out`-[MyString initWithNSString:].
8699451b44SJordan Rupprecht        self.expect(
8799451b44SJordan Rupprecht            "thread backtrace",
8899451b44SJordan Rupprecht            "Stop at a.out`-[MyString initWithNSString:]",
89*2238dcc3SJonas Devlieghere            substrs=["a.out`-[MyString initWithNSString:]"],
90*2238dcc3SJonas Devlieghere        )
9199451b44SJordan Rupprecht
9299451b44SJordan Rupprecht        self.runCmd("process continue")
9399451b44SJordan Rupprecht
9499451b44SJordan Rupprecht        # Followed by -[MyString description].
95*2238dcc3SJonas Devlieghere        self.expect(
96*2238dcc3SJonas Devlieghere            "thread backtrace",
97*2238dcc3SJonas Devlieghere            "Stop at -[MyString description]",
98*2238dcc3SJonas Devlieghere            substrs=["a.out`-[MyString description]"],
99*2238dcc3SJonas Devlieghere        )
10099451b44SJordan Rupprecht
10199451b44SJordan Rupprecht        self.runCmd("process continue")
10299451b44SJordan Rupprecht
10399451b44SJordan Rupprecht        # Followed by the same -[MyString description].
104*2238dcc3SJonas Devlieghere        self.expect(
105*2238dcc3SJonas Devlieghere            "thread backtrace",
106*2238dcc3SJonas Devlieghere            "Stop at -[MyString description]",
107*2238dcc3SJonas Devlieghere            substrs=["a.out`-[MyString description]"],
108*2238dcc3SJonas Devlieghere        )
10999451b44SJordan Rupprecht
11099451b44SJordan Rupprecht        self.runCmd("process continue")
11199451b44SJordan Rupprecht
11299451b44SJordan Rupprecht        # Followed by -[NSAutoreleasePool release].
113*2238dcc3SJonas Devlieghere        self.expect(
114*2238dcc3SJonas Devlieghere            "thread backtrace",
115*2238dcc3SJonas Devlieghere            "Stop at -[NSAutoreleasePool release]",
116*2238dcc3SJonas Devlieghere            substrs=["Foundation`-[NSAutoreleasePool release]"],
117*2238dcc3SJonas Devlieghere        )
11899451b44SJordan Rupprecht
11999451b44SJordan Rupprecht    # rdar://problem/8542091
12099451b44SJordan Rupprecht    # rdar://problem/8492646
12199451b44SJordan Rupprecht    def test_data_type_and_expr(self):
12299451b44SJordan Rupprecht        """Lookup objective-c data types and evaluate expressions."""
12399451b44SJordan Rupprecht        self.build()
12499451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
12599451b44SJordan Rupprecht        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
12699451b44SJordan Rupprecht
12799451b44SJordan Rupprecht        # Stop at -[MyString description].
12899451b44SJordan Rupprecht        lldbutil.run_break_set_by_symbol(
129*2238dcc3SJonas Devlieghere            self, "-[MyString description]", num_expected_locations=1, sym_exact=True
130*2238dcc3SJonas Devlieghere        )
13199451b44SJordan Rupprecht        #        self.expect("breakpoint set -n '-[MyString description]", BREAKPOINT_CREATED,
13299451b44SJordan Rupprecht        # startstr = "Breakpoint created: 1: name = '-[MyString description]',
13399451b44SJordan Rupprecht        # locations = 1")
13499451b44SJordan Rupprecht
13599451b44SJordan Rupprecht        self.runCmd("run", RUN_SUCCEEDED)
13699451b44SJordan Rupprecht
137c21dfa9eSDave Lee        self.runCmd("settings set target.prefer-dynamic-value no-dynamic-values")
138c21dfa9eSDave Lee
13999451b44SJordan Rupprecht        # The backtrace should show we stop at -[MyString description].
140*2238dcc3SJonas Devlieghere        self.expect(
141*2238dcc3SJonas Devlieghere            "thread backtrace",
142*2238dcc3SJonas Devlieghere            "Stop at -[MyString description]",
143*2238dcc3SJonas Devlieghere            substrs=["a.out`-[MyString description]"],
144*2238dcc3SJonas Devlieghere        )
14599451b44SJordan Rupprecht
14699451b44SJordan Rupprecht        # Lookup objc data type MyString and evaluate some expressions.
14799451b44SJordan Rupprecht
148*2238dcc3SJonas Devlieghere        self.expect(
149*2238dcc3SJonas Devlieghere            "image lookup -t NSString",
150*2238dcc3SJonas Devlieghere            DATA_TYPES_DISPLAYED_CORRECTLY,
151*2238dcc3SJonas Devlieghere            substrs=['name = "NSString"', 'compiler_type = "@interface NSString'],
152*2238dcc3SJonas Devlieghere        )
15399451b44SJordan Rupprecht
154*2238dcc3SJonas Devlieghere        self.expect(
155*2238dcc3SJonas Devlieghere            "image lookup -t MyString",
156*2238dcc3SJonas Devlieghere            DATA_TYPES_DISPLAYED_CORRECTLY,
157*2238dcc3SJonas Devlieghere            substrs=[
158*2238dcc3SJonas Devlieghere                'name = "MyString"',
15999451b44SJordan Rupprecht                'compiler_type = "@interface MyString',
160*2238dcc3SJonas Devlieghere                "NSString * str;",
161*2238dcc3SJonas Devlieghere                "NSDate * date;",
162*2238dcc3SJonas Devlieghere            ],
163*2238dcc3SJonas Devlieghere        )
16499451b44SJordan Rupprecht
16599451b44SJordan Rupprecht        self.expect(
16699451b44SJordan Rupprecht            "frame variable --show-types --scope",
16799451b44SJordan Rupprecht            VARIABLES_DISPLAYED_CORRECTLY,
16899451b44SJordan Rupprecht            substrs=["ARG: (MyString *) self"],
169*2238dcc3SJonas Devlieghere            patterns=["ARG: \(.*\) _cmd", "(objc_selector *)|(SEL)"],
170*2238dcc3SJonas Devlieghere        )
17199451b44SJordan Rupprecht
17299451b44SJordan Rupprecht        # rdar://problem/8651752
17399451b44SJordan Rupprecht        # don't crash trying to ask clang how many children an empty record has
17499451b44SJordan Rupprecht        self.runCmd("frame variable *_cmd")
17599451b44SJordan Rupprecht
17699451b44SJordan Rupprecht        # rdar://problem/8492646
17799451b44SJordan Rupprecht        # test/foundation fails after updating to tot r115023
17899451b44SJordan Rupprecht        # self->str displays nothing as output
17999451b44SJordan Rupprecht        self.expect(
18099451b44SJordan Rupprecht            "frame variable --show-types self->str",
18199451b44SJordan Rupprecht            VARIABLES_DISPLAYED_CORRECTLY,
182*2238dcc3SJonas Devlieghere            startstr="(NSString *) self->str",
183*2238dcc3SJonas Devlieghere        )
18499451b44SJordan Rupprecht
18599451b44SJordan Rupprecht        # rdar://problem/8447030
18699451b44SJordan Rupprecht        # 'frame variable self->date' displays the wrong data member
18799451b44SJordan Rupprecht        self.expect(
18899451b44SJordan Rupprecht            "frame variable --show-types self->date",
18999451b44SJordan Rupprecht            VARIABLES_DISPLAYED_CORRECTLY,
190*2238dcc3SJonas Devlieghere            startstr="(NSDate *) self->date",
191*2238dcc3SJonas Devlieghere        )
19299451b44SJordan Rupprecht
19399451b44SJordan Rupprecht        # This should display the str and date member fields as well.
19499451b44SJordan Rupprecht        self.expect(
19599451b44SJordan Rupprecht            "frame variable --show-types *self",
19699451b44SJordan Rupprecht            VARIABLES_DISPLAYED_CORRECTLY,
197*2238dcc3SJonas Devlieghere            substrs=["(MyString) *self", "(NSString *) str", "(NSDate *) date"],
198*2238dcc3SJonas Devlieghere        )
19999451b44SJordan Rupprecht
20099451b44SJordan Rupprecht        # isa should be accessible.
201*2238dcc3SJonas Devlieghere        self.expect(
202*2238dcc3SJonas Devlieghere            "expression self->isa", VARIABLES_DISPLAYED_CORRECTLY, substrs=["Class)"]
203*2238dcc3SJonas Devlieghere        )
20499451b44SJordan Rupprecht
20599451b44SJordan Rupprecht        # This should fail expectedly.
20699451b44SJordan Rupprecht        self.expect(
20799451b44SJordan Rupprecht            "expression self->non_existent_member",
20899451b44SJordan Rupprecht            COMMAND_FAILED_AS_EXPECTED,
20999451b44SJordan Rupprecht            error=True,
210*2238dcc3SJonas Devlieghere            substrs=[
211*2238dcc3SJonas Devlieghere                "error:",
212*2238dcc3SJonas Devlieghere                "'MyString' does not have a member named 'non_existent_member'",
213*2238dcc3SJonas Devlieghere            ],
214*2238dcc3SJonas Devlieghere        )
21599451b44SJordan Rupprecht
21699451b44SJordan Rupprecht        # Use expression parser.
21799451b44SJordan Rupprecht        self.runCmd("expression self->str")
21899451b44SJordan Rupprecht        self.runCmd("expression self->date")
21999451b44SJordan Rupprecht
22099451b44SJordan Rupprecht        # (lldb) expression self->str
22199451b44SJordan Rupprecht        # error: instance variable 'str' is protected
22299451b44SJordan Rupprecht        # error: 1 errors parsing expression
22399451b44SJordan Rupprecht        #
22499451b44SJordan Rupprecht        # (lldb) expression self->date
22599451b44SJordan Rupprecht        # error: instance variable 'date' is protected
22699451b44SJordan Rupprecht        # error: 1 errors parsing expression
22799451b44SJordan Rupprecht        #
22899451b44SJordan Rupprecht
22999451b44SJordan Rupprecht        self.runCmd("breakpoint delete 1")
23099451b44SJordan Rupprecht        lldbutil.run_break_set_by_file_and_line(
231*2238dcc3SJonas Devlieghere            self, "main.m", self.line, num_expected_locations=1, loc_exact=True
232*2238dcc3SJonas Devlieghere        )
23399451b44SJordan Rupprecht
23499451b44SJordan Rupprecht        self.runCmd("process continue")
23599451b44SJordan Rupprecht
23699451b44SJordan Rupprecht        # rdar://problem/8542091
23799451b44SJordan Rupprecht        # test/foundation: expr -o -- my not working?
23899451b44SJordan Rupprecht        #
23999451b44SJordan Rupprecht        # Test new feature with r115115:
24099451b44SJordan Rupprecht        # Add "-o" option to "expression" which prints the object description
24199451b44SJordan Rupprecht        # if available.
24299451b44SJordan Rupprecht        self.expect(
24399451b44SJordan Rupprecht            "expression --object-description -- my",
24499451b44SJordan Rupprecht            "Object description displayed correctly",
245*2238dcc3SJonas Devlieghere            patterns=["Hello from.*a.out.*with timestamp: "],
246*2238dcc3SJonas Devlieghere        )
24799451b44SJordan Rupprecht
248*2238dcc3SJonas Devlieghere    @add_test_categories(["pyapi"])
24999451b44SJordan Rupprecht    def test_print_ivars_correctly(self):
25099451b44SJordan Rupprecht        self.build()
25199451b44SJordan Rupprecht        # See: <rdar://problem/8717050> lldb needs to use the ObjC runtime symbols for ivar offsets
25299451b44SJordan Rupprecht        # Only fails for the ObjC 2.0 runtime.
25399451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
25499451b44SJordan Rupprecht
25599451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
25699451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
25799451b44SJordan Rupprecht
25899451b44SJordan Rupprecht        break1 = target.BreakpointCreateByLocation(self.main_source, self.line)
25999451b44SJordan Rupprecht        self.assertTrue(break1, VALID_BREAKPOINT)
26099451b44SJordan Rupprecht
26199451b44SJordan Rupprecht        # Now launch the process, and do not stop at entry point.
262*2238dcc3SJonas Devlieghere        process = target.LaunchSimple(None, None, self.get_process_working_directory())
26399451b44SJordan Rupprecht
26499451b44SJordan Rupprecht        self.assertTrue(process, PROCESS_IS_VALID)
26599451b44SJordan Rupprecht
26699451b44SJordan Rupprecht        # The stop reason of the thread should be breakpoint.
26799451b44SJordan Rupprecht        thread = process.GetThreadAtIndex(0)
26899451b44SJordan Rupprecht        if thread.GetStopReason() != lldb.eStopReasonBreakpoint:
26999451b44SJordan Rupprecht            from lldbsuite.test.lldbutil import stop_reason_to_str
270*2238dcc3SJonas Devlieghere
271*2238dcc3SJonas Devlieghere            self.fail(
272*2238dcc3SJonas Devlieghere                STOPPED_DUE_TO_BREAKPOINT_WITH_STOP_REASON_AS
273*2238dcc3SJonas Devlieghere                % stop_reason_to_str(thread.GetStopReason())
274*2238dcc3SJonas Devlieghere            )
27599451b44SJordan Rupprecht
27699451b44SJordan Rupprecht        # Make sure we stopped at the first breakpoint.
27799451b44SJordan Rupprecht
27899451b44SJordan Rupprecht        cur_frame = thread.GetFrameAtIndex(0)
27999451b44SJordan Rupprecht
28099451b44SJordan Rupprecht        line_number = cur_frame.GetLineEntry().GetLine()
281619e2e09SDave Lee        self.assertEqual(line_number, self.line, "Hit the first breakpoint.")
28299451b44SJordan Rupprecht
28399451b44SJordan Rupprecht        my_var = cur_frame.FindVariable("my")
28499451b44SJordan Rupprecht        self.assertTrue(my_var, "Made a variable object for my")
28599451b44SJordan Rupprecht
28699451b44SJordan Rupprecht        str_var = cur_frame.FindVariable("str")
28799451b44SJordan Rupprecht        self.assertTrue(str_var, "Made a variable object for str")
28899451b44SJordan Rupprecht
28999451b44SJordan Rupprecht        # Now make sure that the my->str == str:
29099451b44SJordan Rupprecht
29199451b44SJordan Rupprecht        my_str_var = my_var.GetChildMemberWithName("str")
29299451b44SJordan Rupprecht        self.assertTrue(my_str_var, "Found a str ivar in my")
29399451b44SJordan Rupprecht
29499451b44SJordan Rupprecht        str_value = int(str_var.GetValue(), 0)
29599451b44SJordan Rupprecht
29699451b44SJordan Rupprecht        my_str_value = int(my_str_var.GetValue(), 0)
29799451b44SJordan Rupprecht
298*2238dcc3SJonas Devlieghere        self.assertEqual(str_value, my_str_value, "Got the correct value for my->str")
29999451b44SJordan Rupprecht
30099451b44SJordan Rupprecht    def test_expression_lookups_objc(self):
30199451b44SJordan Rupprecht        """Test running an expression detect spurious debug info lookups (DWARF)."""
30299451b44SJordan Rupprecht        self.build()
30399451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
30499451b44SJordan Rupprecht        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
30599451b44SJordan Rupprecht
30699451b44SJordan Rupprecht        # Stop at -[MyString initWithNSString:].
30799451b44SJordan Rupprecht        lldbutil.run_break_set_by_symbol(
30899451b44SJordan Rupprecht            self,
309*2238dcc3SJonas Devlieghere            "-[MyString initWithNSString:]",
31099451b44SJordan Rupprecht            num_expected_locations=1,
311*2238dcc3SJonas Devlieghere            sym_exact=True,
312*2238dcc3SJonas Devlieghere        )
31399451b44SJordan Rupprecht
31499451b44SJordan Rupprecht        self.runCmd("run", RUN_SUCCEEDED)
31599451b44SJordan Rupprecht
31699451b44SJordan Rupprecht        global file_index
31799451b44SJordan Rupprecht        # Log any DWARF lookups
31899451b44SJordan Rupprecht        ++file_index
31999451b44SJordan Rupprecht        logfile = os.path.join(
32099451b44SJordan Rupprecht            self.getBuildDir(),
321*2238dcc3SJonas Devlieghere            "dwarf-lookups-" + self.getArchitecture() + "-" + str(file_index) + ".txt",
322*2238dcc3SJonas Devlieghere        )
32399451b44SJordan Rupprecht        self.runCmd("log enable -f %s dwarf lookups" % (logfile))
32499451b44SJordan Rupprecht        self.runCmd("expr self")
32599451b44SJordan Rupprecht        self.runCmd("log disable dwarf lookups")
32699451b44SJordan Rupprecht
32799451b44SJordan Rupprecht        def cleanup():
32899451b44SJordan Rupprecht            if os.path.exists(logfile):
32999451b44SJordan Rupprecht                os.unlink(logfile)
33099451b44SJordan Rupprecht
33199451b44SJordan Rupprecht        self.addTearDownHook(cleanup)
33299451b44SJordan Rupprecht
33399451b44SJordan Rupprecht        if os.path.exists(logfile):
33499451b44SJordan Rupprecht            f = open(logfile)
33599451b44SJordan Rupprecht            lines = f.readlines()
33699451b44SJordan Rupprecht            num_errors = 0
33799451b44SJordan Rupprecht            for line in lines:
33899451b44SJordan Rupprecht                if "$__lldb" in line:
33999451b44SJordan Rupprecht                    if num_errors == 0:
34099451b44SJordan Rupprecht                        print(
341*2238dcc3SJonas Devlieghere                            "error: found spurious name lookups when evaluating an expression:"
342*2238dcc3SJonas Devlieghere                        )
34399451b44SJordan Rupprecht                    num_errors += 1
344*2238dcc3SJonas Devlieghere                    print(line, end="")
345619e2e09SDave Lee            self.assertEqual(num_errors, 0, "Spurious lookups detected")
34699451b44SJordan Rupprecht            f.close()
347