1""" 2Set breakpoints on objective-c class and instance methods in foundation. 3Also lookup objective-c data types and evaluate expressions. 4""" 5 6from __future__ import print_function 7 8 9import os 10import os.path 11import lldb 12from lldbsuite.test.decorators import * 13from lldbsuite.test.lldbtest import * 14from lldbsuite.test import lldbutil 15 16file_index = 0 17 18 19@skipUnlessDarwin 20class FoundationTestCase(TestBase): 21 22 mydir = TestBase.compute_mydir(__file__) 23 24 def setUp(self): 25 # Call super's setUp(). 26 TestBase.setUp(self) 27 # Find the line number to break inside main(). 28 self.main_source = "main.m" 29 self.line = line_number( 30 self.main_source, 31 '// Set break point at this line.') 32 33 def test_break(self): 34 """Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'.""" 35 self.build() 36 exe = self.getBuildArtifact("a.out") 37 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 38 39 # Stop at +[NSString stringWithFormat:]. 40 break_results = lldbutil.run_break_set_command( 41 self, "_regexp-break +[NSString stringWithFormat:]") 42 lldbutil.check_breakpoint_result( 43 self, 44 break_results, 45 symbol_name='+[NSString stringWithFormat:]', 46 num_locations=1) 47 48 # Stop at -[MyString initWithNSString:]. 49 lldbutil.run_break_set_by_symbol( 50 self, 51 '-[MyString initWithNSString:]', 52 num_expected_locations=1, 53 sym_exact=True) 54 55 # Stop at the "description" selector. 56 lldbutil.run_break_set_by_selector( 57 self, 58 'description', 59 num_expected_locations=1, 60 module_name='a.out') 61 62 # Stop at -[NSAutoreleasePool release]. 63 break_results = lldbutil.run_break_set_command( 64 self, "_regexp-break -[NSAutoreleasePool release]") 65 lldbutil.check_breakpoint_result( 66 self, 67 break_results, 68 symbol_name='-[NSAutoreleasePool release]', 69 num_locations=1) 70 71 self.runCmd("run", RUN_SUCCEEDED) 72 73 # First stop is +[NSString stringWithFormat:]. 74 self.expect( 75 "thread backtrace", 76 "Stop at +[NSString stringWithFormat:]", 77 substrs=["Foundation`+[NSString stringWithFormat:]"]) 78 79 self.runCmd("process continue") 80 81 # Second stop is still +[NSString stringWithFormat:]. 82 self.expect( 83 "thread backtrace", 84 "Stop at +[NSString stringWithFormat:]", 85 substrs=["Foundation`+[NSString stringWithFormat:]"]) 86 87 self.runCmd("process continue") 88 89 # Followed by a.out`-[MyString initWithNSString:]. 90 self.expect( 91 "thread backtrace", 92 "Stop at a.out`-[MyString initWithNSString:]", 93 substrs=["a.out`-[MyString initWithNSString:]"]) 94 95 self.runCmd("process continue") 96 97 # Followed by -[MyString description]. 98 self.expect("thread backtrace", "Stop at -[MyString description]", 99 substrs=["a.out`-[MyString description]"]) 100 101 self.runCmd("process continue") 102 103 # Followed by the same -[MyString description]. 104 self.expect("thread backtrace", "Stop at -[MyString description]", 105 substrs=["a.out`-[MyString description]"]) 106 107 self.runCmd("process continue") 108 109 # Followed by -[NSAutoreleasePool release]. 110 self.expect("thread backtrace", "Stop at -[NSAutoreleasePool release]", 111 substrs=["Foundation`-[NSAutoreleasePool release]"]) 112 113 # rdar://problem/8542091 114 # rdar://problem/8492646 115 def test_data_type_and_expr(self): 116 """Lookup objective-c data types and evaluate expressions.""" 117 self.build() 118 exe = self.getBuildArtifact("a.out") 119 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 120 121 # Stop at -[MyString description]. 122 lldbutil.run_break_set_by_symbol( 123 self, 124 '-[MyString description]', 125 num_expected_locations=1, 126 sym_exact=True) 127# self.expect("breakpoint set -n '-[MyString description]", BREAKPOINT_CREATED, 128# startstr = "Breakpoint created: 1: name = '-[MyString description]', 129# 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 'compiler_type = "@interface NSString']) 142 143 self.expect("image lookup -t MyString", DATA_TYPES_DISPLAYED_CORRECTLY, 144 substrs=['name = "MyString"', 145 'compiler_type = "@interface MyString', 146 'NSString * str;', 147 'NSDate * date;']) 148 149 self.expect( 150 "frame variable --show-types --scope", 151 VARIABLES_DISPLAYED_CORRECTLY, 152 substrs=["ARG: (MyString *) self"], 153 patterns=[ 154 "ARG: \(.*\) _cmd", 155 "(objc_selector *)|(SEL)"]) 156 157 # rdar://problem/8651752 158 # don't crash trying to ask clang how many children an empty record has 159 self.runCmd("frame variable *_cmd") 160 161 # rdar://problem/8492646 162 # test/foundation fails after updating to tot r115023 163 # self->str displays nothing as output 164 self.expect( 165 "frame variable --show-types self->str", 166 VARIABLES_DISPLAYED_CORRECTLY, 167 startstr="(NSString *) self->str") 168 169 # rdar://problem/8447030 170 # 'frame variable self->date' displays the wrong data member 171 self.expect( 172 "frame variable --show-types self->date", 173 VARIABLES_DISPLAYED_CORRECTLY, 174 startstr="(NSDate *) self->date") 175 176 # This should display the str and date member fields as well. 177 self.expect( 178 "frame variable --show-types *self", 179 VARIABLES_DISPLAYED_CORRECTLY, 180 substrs=[ 181 "(MyString) *self", 182 "(NSString *) str", 183 "(NSDate *) date"]) 184 185 # isa should be accessible. 186 self.expect("expression self->isa", VARIABLES_DISPLAYED_CORRECTLY, 187 substrs=["Class)"]) 188 189 # This should fail expectedly. 190 self.expect( 191 "expression self->non_existent_member", 192 COMMAND_FAILED_AS_EXPECTED, 193 error=True, 194 substrs=["error:", "'MyString' does not have a member named 'non_existent_member'"]) 195 196 # Use expression parser. 197 self.runCmd("expression self->str") 198 self.runCmd("expression self->date") 199 200 # (lldb) expression self->str 201 # error: instance variable 'str' is protected 202 # error: 1 errors parsing expression 203 # 204 # (lldb) expression self->date 205 # error: instance variable 'date' is protected 206 # error: 1 errors parsing expression 207 # 208 209 self.runCmd("breakpoint delete 1") 210 lldbutil.run_break_set_by_file_and_line( 211 self, "main.m", self.line, num_expected_locations=1, loc_exact=True) 212 213 self.runCmd("process continue") 214 215 # rdar://problem/8542091 216 # test/foundation: expr -o -- my not working? 217 # 218 # Test new feature with r115115: 219 # Add "-o" option to "expression" which prints the object description 220 # if available. 221 self.expect( 222 "expression --object-description -- my", 223 "Object description displayed correctly", 224 patterns=["Hello from.*a.out.*with timestamp: "]) 225 226 @add_test_categories(['pyapi']) 227 def test_print_ivars_correctly(self): 228 self.build() 229 # See: <rdar://problem/8717050> lldb needs to use the ObjC runtime symbols for ivar offsets 230 # Only fails for the ObjC 2.0 runtime. 231 exe = self.getBuildArtifact("a.out") 232 233 target = self.dbg.CreateTarget(exe) 234 self.assertTrue(target, VALID_TARGET) 235 236 break1 = target.BreakpointCreateByLocation(self.main_source, self.line) 237 self.assertTrue(break1, VALID_BREAKPOINT) 238 239 # Now launch the process, and do not stop at entry point. 240 process = target.LaunchSimple( 241 None, None, self.get_process_working_directory()) 242 243 self.assertTrue(process, PROCESS_IS_VALID) 244 245 # The stop reason of the thread should be breakpoint. 246 thread = process.GetThreadAtIndex(0) 247 if thread.GetStopReason() != lldb.eStopReasonBreakpoint: 248 from lldbsuite.test.lldbutil import stop_reason_to_str 249 self.fail(STOPPED_DUE_TO_BREAKPOINT_WITH_STOP_REASON_AS % 250 stop_reason_to_str(thread.GetStopReason())) 251 252 # Make sure we stopped at the first breakpoint. 253 254 cur_frame = thread.GetFrameAtIndex(0) 255 256 line_number = cur_frame.GetLineEntry().GetLine() 257 self.assertTrue(line_number == self.line, "Hit the first breakpoint.") 258 259 my_var = cur_frame.FindVariable("my") 260 self.assertTrue(my_var, "Made a variable object for my") 261 262 str_var = cur_frame.FindVariable("str") 263 self.assertTrue(str_var, "Made a variable object for str") 264 265 # Now make sure that the my->str == str: 266 267 my_str_var = my_var.GetChildMemberWithName("str") 268 self.assertTrue(my_str_var, "Found a str ivar in my") 269 270 str_value = int(str_var.GetValue(), 0) 271 272 my_str_value = int(my_str_var.GetValue(), 0) 273 274 self.assertTrue( 275 str_value == my_str_value, 276 "Got the correct value for my->str") 277 278 def test_expression_lookups_objc(self): 279 """Test running an expression detect spurious debug info lookups (DWARF).""" 280 self.build() 281 exe = self.getBuildArtifact("a.out") 282 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 283 284 # Stop at -[MyString initWithNSString:]. 285 lldbutil.run_break_set_by_symbol( 286 self, 287 '-[MyString initWithNSString:]', 288 num_expected_locations=1, 289 sym_exact=True) 290 291 self.runCmd("run", RUN_SUCCEEDED) 292 293 global file_index 294 # Log any DWARF lookups 295 ++file_index 296 logfile = os.path.join( 297 self.getBuildDir(), 298 "dwarf-lookups-" + 299 self.getArchitecture() + 300 "-" + 301 str(file_index) + 302 ".txt") 303 self.runCmd("log enable -f %s dwarf lookups" % (logfile)) 304 self.runCmd("expr self") 305 self.runCmd("log disable dwarf lookups") 306 307 def cleanup(): 308 if os.path.exists(logfile): 309 os.unlink(logfile) 310 311 self.addTearDownHook(cleanup) 312 313 if os.path.exists(logfile): 314 f = open(logfile) 315 lines = f.readlines() 316 num_errors = 0 317 for line in lines: 318 if "$__lldb" in line: 319 if num_errors == 0: 320 print( 321 "error: found spurious name lookups when evaluating an expression:") 322 num_errors += 1 323 print(line, end='') 324 self.assertTrue(num_errors == 0, "Spurious lookups detected") 325 f.close() 326