1"""
2Test that objective-c constant strings are generated correctly by the expression
3parser.
4"""
5
6
7
8import shutil
9import subprocess
10import lldb
11from lldbsuite.test.decorators import *
12from lldbsuite.test.lldbtest import *
13from lldbsuite.test import lldbutil
14
15
16class TestObjCBreakpoints(TestBase):
17
18    mydir = TestBase.compute_mydir(__file__)
19
20    @add_test_categories(["objc"])
21    def test_break(self):
22        """Test setting Objective-C specific breakpoints (DWARF in .o files)."""
23        self.build()
24        self.setTearDownCleanup()
25        self.check_objc_breakpoints(False)
26
27    def setUp(self):
28        # Call super's setUp().
29        TestBase.setUp(self)
30        # Find the line number to break inside main().
31        self.main_source = "main.m"
32        self.line = line_number(self.main_source, '// Set breakpoint here')
33
34    def check_category_breakpoints(self):
35        name_bp = self.target.BreakpointCreateByName("myCategoryFunction")
36        selector_bp = self.target.BreakpointCreateByName(
37            "myCategoryFunction",
38            lldb.eFunctionNameTypeSelector,
39            lldb.SBFileSpecList(),
40            lldb.SBFileSpecList())
41        self.assertEqual(
42            name_bp.GetNumLocations(), selector_bp.GetNumLocations(),
43            'Make sure setting a breakpoint by name "myCategoryFunction" sets a breakpoint even though it is in a category')
44        for bp_loc in selector_bp:
45            function_name = bp_loc.GetAddress().GetSymbol().GetName()
46            self.assertTrue(
47                " myCategoryFunction]" in function_name,
48                'Make sure all function names have " myCategoryFunction]" in their names')
49
50        category_bp = self.target.BreakpointCreateByName(
51            "-[MyClass(MyCategory) myCategoryFunction]")
52        stripped_bp = self.target.BreakpointCreateByName(
53            "-[MyClass myCategoryFunction]")
54        stripped2_bp = self.target.BreakpointCreateByName(
55            "[MyClass myCategoryFunction]")
56        self.assertEqual(
57            category_bp.GetNumLocations(), 1,
58            "Make sure we can set a breakpoint using a full objective C function name with the category included (-[MyClass(MyCategory) myCategoryFunction])")
59        self.assertEqual(
60            stripped_bp.GetNumLocations(), 1,
61            "Make sure we can set a breakpoint using a full objective C function name without the category included (-[MyClass myCategoryFunction])")
62        self.assertEqual(
63            stripped2_bp.GetNumLocations(), 1,
64            "Make sure we can set a breakpoint using a full objective C function name without the category included ([MyClass myCategoryFunction])")
65
66    def check_objc_breakpoints(self, have_dsym):
67        """Test constant string generation amd comparison by the expression parser."""
68
69        # Set debugger into synchronous mode
70        self.dbg.SetAsync(False)
71
72        # Create a target by the debugger.
73        exe = self.getBuildArtifact("a.out")
74        self.target = self.dbg.CreateTarget(exe)
75        self.assertTrue(self.target, VALID_TARGET)
76
77        #----------------------------------------------------------------------
78        # Set breakpoints on all selectors whose name is "count". This should
79        # catch breakpoints that are both C functions _and_ anything whose
80        # selector is "count" because just looking at "count" we can't tell
81        # definitively if the name is a selector or a C function
82        #----------------------------------------------------------------------
83        name_bp = self.target.BreakpointCreateByName("count")
84        selector_bp = self.target.BreakpointCreateByName(
85            "count",
86            lldb.eFunctionNameTypeSelector,
87            lldb.SBFileSpecList(),
88            lldb.SBFileSpecList())
89        self.assertGreaterEqual(
90            name_bp.GetNumLocations(), selector_bp.GetNumLocations(),
91            'Make sure we get at least the same amount of breakpoints if not more when setting by name "count"')
92        self.assertGreater(
93            selector_bp.GetNumLocations(), 50,
94            'Make sure we find a lot of "count" selectors')  # There are 93 on the latest MacOSX
95        for bp_loc in selector_bp:
96            function_name = bp_loc.GetAddress().GetSymbol().GetName()
97            self.assertTrue(
98                " count]" in function_name,
99                'Make sure all function names have " count]" in their names')
100
101        #----------------------------------------------------------------------
102        # Set breakpoints on all selectors whose name is "isEqual:". This should
103        # catch breakpoints that are only ObjC selectors because no C function
104        # can end with a :
105        #----------------------------------------------------------------------
106        name_bp = self.target.BreakpointCreateByName("isEqual:")
107        selector_bp = self.target.BreakpointCreateByName(
108            "isEqual:",
109            lldb.eFunctionNameTypeSelector,
110            lldb.SBFileSpecList(),
111            lldb.SBFileSpecList())
112        self.assertEqual(
113            name_bp.GetNumLocations(), selector_bp.GetNumLocations(),
114            'Make sure setting a breakpoint by name "isEqual:" only sets selector breakpoints')
115        for bp_loc in selector_bp:
116            function_name = bp_loc.GetAddress().GetSymbol().GetName()
117            self.assertTrue(
118                " isEqual:]" in function_name,
119                'Make sure all function names have " isEqual:]" in their names')
120
121        self.check_category_breakpoints()
122
123        # Stop here for reproducers. They don't capture file system changes.
124        if configuration.is_reproducer():
125            return
126
127        if have_dsym:
128            shutil.rmtree(exe + ".dSYM")
129        self.assertEqual(subprocess.call(
130            ['/usr/bin/strip', '-Sx', exe]), 0, 'stripping dylib succeeded')
131
132        # Check breakpoints again, this time using the symbol table only
133        self.check_category_breakpoints()
134