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