Home | History | Annotate | Download | only in foundation
      1 """
      2 Set breakpoints on objective-c class and instance methods in foundation.
      3 Also lookup objective-c data types and evaluate expressions.
      4 """
      5 
      6 import os, time
      7 import unittest2
      8 import lldb
      9 from lldbtest import *
     10 import lldbutil
     11 
     12 @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     13 class 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         
    257 if __name__ == '__main__':
    258     import atexit
    259     lldb.SBDebugger.Initialize()
    260     atexit.register(lambda: lldb.SBDebugger.Terminate())
    261     unittest2.main()
    262