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