199451b44SJordan Rupprecht""" 299451b44SJordan RupprechtTest lldb-vscode setBreakpoints request 399451b44SJordan Rupprecht""" 499451b44SJordan Rupprecht 599451b44SJordan Rupprecht 699451b44SJordan Rupprechtimport unittest2 799451b44SJordan Rupprechtimport vscode 899451b44SJordan Rupprechtfrom lldbsuite.test.decorators import * 999451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import * 1099451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil 1199451b44SJordan Rupprechtimport lldbvscode_testcase 1299451b44SJordan Rupprechtimport os 1399451b44SJordan Rupprechtimport shutil 1499451b44SJordan Rupprechtimport subprocess 1599451b44SJordan Rupprechtimport tempfile 1699451b44SJordan Rupprechtimport threading 1799451b44SJordan Rupprechtimport time 1899451b44SJordan Rupprecht 1999451b44SJordan Rupprecht 2099451b44SJordan Rupprechtdef spawn_and_wait(program, delay): 2199451b44SJordan Rupprecht if delay: 2299451b44SJordan Rupprecht time.sleep(delay) 2399451b44SJordan Rupprecht process = subprocess.Popen([program], 2499451b44SJordan Rupprecht stdin=subprocess.PIPE, 2599451b44SJordan Rupprecht stdout=subprocess.PIPE, 2699451b44SJordan Rupprecht stderr=subprocess.PIPE) 2799451b44SJordan Rupprecht process.wait() 2899451b44SJordan Rupprecht 2999451b44SJordan Rupprecht 3099451b44SJordan Rupprechtclass TestVSCode_attach(lldbvscode_testcase.VSCodeTestCaseBase): 3199451b44SJordan Rupprecht 3299451b44SJordan Rupprecht def set_and_hit_breakpoint(self, continueToExit=True): 3399451b44SJordan Rupprecht source = 'main.c' 3499451b44SJordan Rupprecht breakpoint1_line = line_number(source, '// breakpoint 1') 3599451b44SJordan Rupprecht lines = [breakpoint1_line] 36e9264b74SKazuaki Ishizaki # Set breakpoint in the thread function so we can step the threads 3799451b44SJordan Rupprecht breakpoint_ids = self.set_source_breakpoints(source, lines) 3899451b44SJordan Rupprecht self.assertEqual(len(breakpoint_ids), len(lines), 3999451b44SJordan Rupprecht "expect correct number of breakpoints") 4099451b44SJordan Rupprecht self.continue_to_breakpoints(breakpoint_ids) 4199451b44SJordan Rupprecht if continueToExit: 4299451b44SJordan Rupprecht self.continue_to_exit() 4399451b44SJordan Rupprecht 4499451b44SJordan Rupprecht @skipIfWindows 4599451b44SJordan Rupprecht @skipIfNetBSD # Hangs on NetBSD as well 4614fb3179SJonas Devlieghere @skipIfRemote 4799451b44SJordan Rupprecht def test_by_pid(self): 4899451b44SJordan Rupprecht ''' 4999451b44SJordan Rupprecht Tests attaching to a process by process ID. 5099451b44SJordan Rupprecht ''' 5199451b44SJordan Rupprecht self.build_and_create_debug_adaptor() 5299451b44SJordan Rupprecht program = self.getBuildArtifact("a.out") 5399451b44SJordan Rupprecht self.process = subprocess.Popen([program], 5499451b44SJordan Rupprecht stdin=subprocess.PIPE, 5599451b44SJordan Rupprecht stdout=subprocess.PIPE, 5699451b44SJordan Rupprecht stderr=subprocess.PIPE) 5799451b44SJordan Rupprecht self.attach(pid=self.process.pid) 5899451b44SJordan Rupprecht self.set_and_hit_breakpoint(continueToExit=True) 5999451b44SJordan Rupprecht 6099451b44SJordan Rupprecht @skipIfWindows 6199451b44SJordan Rupprecht @skipIfNetBSD # Hangs on NetBSD as well 6214fb3179SJonas Devlieghere @skipIfRemote 6399451b44SJordan Rupprecht def test_by_name(self): 6499451b44SJordan Rupprecht ''' 6599451b44SJordan Rupprecht Tests attaching to a process by process name. 6699451b44SJordan Rupprecht ''' 6799451b44SJordan Rupprecht self.build_and_create_debug_adaptor() 6899451b44SJordan Rupprecht orig_program = self.getBuildArtifact("a.out") 6999451b44SJordan Rupprecht # Since we are going to attach by process name, we need a unique 7099451b44SJordan Rupprecht # process name that has minimal chance to match a process that is 7199451b44SJordan Rupprecht # already running. To do this we use tempfile.mktemp() to give us a 7299451b44SJordan Rupprecht # full path to a location where we can copy our executable. We then 7399451b44SJordan Rupprecht # run this copy to ensure we don't get the error "more that one 7499451b44SJordan Rupprecht # process matches 'a.out'". 7599451b44SJordan Rupprecht program = tempfile.mktemp() 7699451b44SJordan Rupprecht shutil.copyfile(orig_program, program) 7799451b44SJordan Rupprecht shutil.copymode(orig_program, program) 7899451b44SJordan Rupprecht 7999451b44SJordan Rupprecht # Use a file as a synchronization point between test and inferior. 8099451b44SJordan Rupprecht pid_file_path = lldbutil.append_to_process_working_directory(self, 8199451b44SJordan Rupprecht "pid_file_%d" % (int(time.time()))) 8299451b44SJordan Rupprecht 8399451b44SJordan Rupprecht def cleanup(): 8499451b44SJordan Rupprecht if os.path.exists(program): 8599451b44SJordan Rupprecht os.unlink(program) 8699451b44SJordan Rupprecht self.run_platform_command("rm %s" % (pid_file_path)) 8799451b44SJordan Rupprecht # Execute the cleanup function during test case tear down. 8899451b44SJordan Rupprecht self.addTearDownHook(cleanup) 8999451b44SJordan Rupprecht 9099451b44SJordan Rupprecht popen = self.spawnSubprocess(program, [pid_file_path]) 9199451b44SJordan Rupprecht 9299451b44SJordan Rupprecht pid = lldbutil.wait_for_file_on_target(self, pid_file_path) 9399451b44SJordan Rupprecht 9499451b44SJordan Rupprecht self.attach(program=program) 9599451b44SJordan Rupprecht self.set_and_hit_breakpoint(continueToExit=True) 9699451b44SJordan Rupprecht 9799451b44SJordan Rupprecht @skipUnlessDarwin 9899451b44SJordan Rupprecht @skipIfDarwin 9999451b44SJordan Rupprecht @skipIfNetBSD # Hangs on NetBSD as well 10099451b44SJordan Rupprecht def test_by_name_waitFor(self): 10199451b44SJordan Rupprecht ''' 10299451b44SJordan Rupprecht Tests attaching to a process by process name and waiting for the 10399451b44SJordan Rupprecht next instance of a process to be launched, ingoring all current 10499451b44SJordan Rupprecht ones. 10599451b44SJordan Rupprecht ''' 10699451b44SJordan Rupprecht self.build_and_create_debug_adaptor() 10799451b44SJordan Rupprecht program = self.getBuildArtifact("a.out") 10899451b44SJordan Rupprecht self.spawn_thread = threading.Thread(target=spawn_and_wait, 10999451b44SJordan Rupprecht args=(program, 1.0,)) 11099451b44SJordan Rupprecht self.spawn_thread.start() 11199451b44SJordan Rupprecht self.attach(program=program, waitFor=True) 11299451b44SJordan Rupprecht self.set_and_hit_breakpoint(continueToExit=True) 11399451b44SJordan Rupprecht 11499451b44SJordan Rupprecht @skipIfWindows 11599451b44SJordan Rupprecht @skipIfDarwin 11699451b44SJordan Rupprecht @skipIfNetBSD # Hangs on NetBSD as well 1171f780c99SMuhammad Omair Javaid @skipIf(archs=["arm", "aarch64"]) # Example of a flaky run http://lab.llvm.org:8011/builders/lldb-aarch64-ubuntu/builds/5527/steps/test/logs/stdio 11899451b44SJordan Rupprecht def test_commands(self): 11999451b44SJordan Rupprecht ''' 12099451b44SJordan Rupprecht Tests the "initCommands", "preRunCommands", "stopCommands", 12174ab1da0SWalter Erquinigo "exitCommands", "terminateCommands" and "attachCommands" 12274ab1da0SWalter Erquinigo that can be passed during attach. 12399451b44SJordan Rupprecht 12499451b44SJordan Rupprecht "initCommands" are a list of LLDB commands that get executed 12599451b44SJordan Rupprecht before the targt is created. 12699451b44SJordan Rupprecht "preRunCommands" are a list of LLDB commands that get executed 12799451b44SJordan Rupprecht after the target has been created and before the launch. 12899451b44SJordan Rupprecht "stopCommands" are a list of LLDB commands that get executed each 12999451b44SJordan Rupprecht time the program stops. 13099451b44SJordan Rupprecht "exitCommands" are a list of LLDB commands that get executed when 13199451b44SJordan Rupprecht the process exits 13299451b44SJordan Rupprecht "attachCommands" are a list of LLDB commands that get executed and 13399451b44SJordan Rupprecht must have a valid process in the selected target in LLDB after 13499451b44SJordan Rupprecht they are done executing. This allows custom commands to create any 13599451b44SJordan Rupprecht kind of debug session. 13674ab1da0SWalter Erquinigo "terminateCommands" are a list of LLDB commands that get executed when 13774ab1da0SWalter Erquinigo the debugger session terminates. 13899451b44SJordan Rupprecht ''' 13999451b44SJordan Rupprecht self.build_and_create_debug_adaptor() 14099451b44SJordan Rupprecht program = self.getBuildArtifact("a.out") 14199451b44SJordan Rupprecht # Here we just create a target and launch the process as a way to test 14299451b44SJordan Rupprecht # if we are able to use attach commands to create any kind of a target 14399451b44SJordan Rupprecht # and use it for debugging 14499451b44SJordan Rupprecht attachCommands = [ 14599451b44SJordan Rupprecht 'target create -d "%s"' % (program), 146e7a3c4c1SPavel Labath 'process launch --stop-at-entry' 14799451b44SJordan Rupprecht ] 14899451b44SJordan Rupprecht initCommands = ['target list', 'platform list'] 14999451b44SJordan Rupprecht preRunCommands = ['image list a.out', 'image dump sections a.out'] 15079fbbeb4SWalter Erquinigo postRunCommands = ['help trace', 'help process trace'] 15199451b44SJordan Rupprecht stopCommands = ['frame variable', 'bt'] 15299451b44SJordan Rupprecht exitCommands = ['expr 2+3', 'expr 3+4'] 15374ab1da0SWalter Erquinigo terminateCommands = ['expr 4+2'] 15499451b44SJordan Rupprecht self.attach(program=program, 15599451b44SJordan Rupprecht attachCommands=attachCommands, 15699451b44SJordan Rupprecht initCommands=initCommands, 15799451b44SJordan Rupprecht preRunCommands=preRunCommands, 15899451b44SJordan Rupprecht stopCommands=stopCommands, 15974ab1da0SWalter Erquinigo exitCommands=exitCommands, 16079fbbeb4SWalter Erquinigo terminateCommands=terminateCommands, 16179fbbeb4SWalter Erquinigo postRunCommands=postRunCommands) 16299451b44SJordan Rupprecht # Get output from the console. This should contain both the 16399451b44SJordan Rupprecht # "initCommands" and the "preRunCommands". 16499451b44SJordan Rupprecht output = self.get_console() 16599451b44SJordan Rupprecht # Verify all "initCommands" were found in console output 16699451b44SJordan Rupprecht self.verify_commands('initCommands', output, initCommands) 16799451b44SJordan Rupprecht # Verify all "preRunCommands" were found in console output 16899451b44SJordan Rupprecht self.verify_commands('preRunCommands', output, preRunCommands) 16979fbbeb4SWalter Erquinigo # Verify all "postRunCommands" were found in console output 17079fbbeb4SWalter Erquinigo self.verify_commands('postRunCommands', output, postRunCommands) 17199451b44SJordan Rupprecht 17299451b44SJordan Rupprecht functions = ['main'] 17399451b44SJordan Rupprecht breakpoint_ids = self.set_function_breakpoints(functions) 174b3a0c4d7SRaphael Isemann self.assertEquals(len(breakpoint_ids), len(functions), 17599451b44SJordan Rupprecht "expect one breakpoint") 17699451b44SJordan Rupprecht self.continue_to_breakpoints(breakpoint_ids) 17799451b44SJordan Rupprecht output = self.get_console(timeout=1.0) 17899451b44SJordan Rupprecht self.verify_commands('stopCommands', output, stopCommands) 17999451b44SJordan Rupprecht 18099451b44SJordan Rupprecht # Continue after launch and hit the "pause()" call and stop the target. 18199451b44SJordan Rupprecht # Get output from the console. This should contain both the 18299451b44SJordan Rupprecht # "stopCommands" that were run after we stop. 18399451b44SJordan Rupprecht self.vscode.request_continue() 18499451b44SJordan Rupprecht time.sleep(0.5) 18599451b44SJordan Rupprecht self.vscode.request_pause() 18699451b44SJordan Rupprecht self.vscode.wait_for_stopped() 18799451b44SJordan Rupprecht output = self.get_console(timeout=1.0) 18899451b44SJordan Rupprecht self.verify_commands('stopCommands', output, stopCommands) 18999451b44SJordan Rupprecht 19099451b44SJordan Rupprecht # Continue until the program exits 19199451b44SJordan Rupprecht self.continue_to_exit() 19299451b44SJordan Rupprecht # Get output from the console. This should contain both the 19399451b44SJordan Rupprecht # "exitCommands" that were run after the second breakpoint was hit 19474ab1da0SWalter Erquinigo # and the "terminateCommands" due to the debugging session ending 19574ab1da0SWalter Erquinigo output = self.collect_console(duration=1.0) 19699451b44SJordan Rupprecht self.verify_commands('exitCommands', output, exitCommands) 19774ab1da0SWalter Erquinigo self.verify_commands('terminateCommands', output, terminateCommands) 19874ab1da0SWalter Erquinigo 19974ab1da0SWalter Erquinigo @skipIfWindows 2008e084223SWalter Erquinigo @skipIfDarwin 20174ab1da0SWalter Erquinigo @skipIfNetBSD # Hangs on NetBSD as well 2021f780c99SMuhammad Omair Javaid @skipIf(archs=["arm", "aarch64"]) # Example of a flaky run http://lab.llvm.org:8011/builders/lldb-aarch64-ubuntu/builds/5517/steps/test/logs/stdio 20374ab1da0SWalter Erquinigo def test_terminate_commands(self): 20474ab1da0SWalter Erquinigo ''' 20574ab1da0SWalter Erquinigo Tests that the "terminateCommands", that can be passed during 20674ab1da0SWalter Erquinigo attach, are run when the debugger is disconnected. 20774ab1da0SWalter Erquinigo ''' 20874ab1da0SWalter Erquinigo self.build_and_create_debug_adaptor() 20974ab1da0SWalter Erquinigo program = self.getBuildArtifact("a.out") 21074ab1da0SWalter Erquinigo # Here we just create a target and launch the process as a way to test 21174ab1da0SWalter Erquinigo # if we are able to use attach commands to create any kind of a target 21274ab1da0SWalter Erquinigo # and use it for debugging 21374ab1da0SWalter Erquinigo attachCommands = [ 21474ab1da0SWalter Erquinigo 'target create -d "%s"' % (program), 215*c41c5746SGreg Clayton 'process launch --stop-at-entry' 21674ab1da0SWalter Erquinigo ] 21774ab1da0SWalter Erquinigo terminateCommands = ['expr 4+2'] 21874ab1da0SWalter Erquinigo self.attach(program=program, 21974ab1da0SWalter Erquinigo attachCommands=attachCommands, 22074ab1da0SWalter Erquinigo terminateCommands=terminateCommands, 22174ab1da0SWalter Erquinigo disconnectAutomatically=False) 22274ab1da0SWalter Erquinigo self.get_console() 22374ab1da0SWalter Erquinigo # Once it's disconnected the console should contain the 22474ab1da0SWalter Erquinigo # "terminateCommands" 22574ab1da0SWalter Erquinigo self.vscode.request_disconnect(terminateDebuggee=True) 22674ab1da0SWalter Erquinigo output = self.collect_console(duration=1.0) 22774ab1da0SWalter Erquinigo self.verify_commands('terminateCommands', output, terminateCommands) 228