1""" 2Test lldb-vscode setBreakpoints request 3""" 4 5 6import unittest2 7import vscode 8from lldbsuite.test.decorators import * 9from lldbsuite.test.lldbtest import * 10from lldbsuite.test import lldbutil 11import lldbvscode_testcase 12import os 13import shutil 14import subprocess 15import tempfile 16import threading 17import time 18 19 20def spawn_and_wait(program, delay): 21 if delay: 22 time.sleep(delay) 23 process = subprocess.Popen([program], 24 stdin=subprocess.PIPE, 25 stdout=subprocess.PIPE, 26 stderr=subprocess.PIPE) 27 process.wait() 28 29 30class TestVSCode_attach(lldbvscode_testcase.VSCodeTestCaseBase): 31 32 def set_and_hit_breakpoint(self, continueToExit=True): 33 source = 'main.c' 34 breakpoint1_line = line_number(source, '// breakpoint 1') 35 lines = [breakpoint1_line] 36 # Set breakpoint in the thread function so we can step the threads 37 breakpoint_ids = self.set_source_breakpoints(source, lines) 38 self.assertEqual(len(breakpoint_ids), len(lines), 39 "expect correct number of breakpoints") 40 self.continue_to_breakpoints(breakpoint_ids) 41 if continueToExit: 42 self.continue_to_exit() 43 44 @skipIfWindows 45 @skipIfNetBSD # Hangs on NetBSD as well 46 @skipIfRemote 47 def test_by_pid(self): 48 ''' 49 Tests attaching to a process by process ID. 50 ''' 51 self.build_and_create_debug_adaptor() 52 program = self.getBuildArtifact("a.out") 53 self.process = subprocess.Popen([program], 54 stdin=subprocess.PIPE, 55 stdout=subprocess.PIPE, 56 stderr=subprocess.PIPE) 57 self.attach(pid=self.process.pid) 58 self.set_and_hit_breakpoint(continueToExit=True) 59 60 @skipIfWindows 61 @skipIfNetBSD # Hangs on NetBSD as well 62 @skipIfRemote 63 def test_by_name(self): 64 ''' 65 Tests attaching to a process by process name. 66 ''' 67 self.build_and_create_debug_adaptor() 68 orig_program = self.getBuildArtifact("a.out") 69 # Since we are going to attach by process name, we need a unique 70 # process name that has minimal chance to match a process that is 71 # already running. To do this we use tempfile.mktemp() to give us a 72 # full path to a location where we can copy our executable. We then 73 # run this copy to ensure we don't get the error "more that one 74 # process matches 'a.out'". 75 program = tempfile.mktemp() 76 shutil.copyfile(orig_program, program) 77 shutil.copymode(orig_program, program) 78 79 # Use a file as a synchronization point between test and inferior. 80 pid_file_path = lldbutil.append_to_process_working_directory(self, 81 "pid_file_%d" % (int(time.time()))) 82 83 def cleanup(): 84 if os.path.exists(program): 85 os.unlink(program) 86 self.run_platform_command("rm %s" % (pid_file_path)) 87 # Execute the cleanup function during test case tear down. 88 self.addTearDownHook(cleanup) 89 90 popen = self.spawnSubprocess(program, [pid_file_path]) 91 92 pid = lldbutil.wait_for_file_on_target(self, pid_file_path) 93 94 self.attach(program=program) 95 self.set_and_hit_breakpoint(continueToExit=True) 96 97 @skipUnlessDarwin 98 @skipIfDarwin 99 @skipIfNetBSD # Hangs on NetBSD as well 100 def test_by_name_waitFor(self): 101 ''' 102 Tests attaching to a process by process name and waiting for the 103 next instance of a process to be launched, ingoring all current 104 ones. 105 ''' 106 self.build_and_create_debug_adaptor() 107 program = self.getBuildArtifact("a.out") 108 self.spawn_thread = threading.Thread(target=spawn_and_wait, 109 args=(program, 1.0,)) 110 self.spawn_thread.start() 111 self.attach(program=program, waitFor=True) 112 self.set_and_hit_breakpoint(continueToExit=True) 113 114 @skipIfWindows 115 @skipIfDarwin 116 @skipIfNetBSD # Hangs on NetBSD as well 117 @skipIf(archs=["arm", "aarch64"]) # Example of a flaky run http://lab.llvm.org:8011/builders/lldb-aarch64-ubuntu/builds/5527/steps/test/logs/stdio 118 def test_commands(self): 119 ''' 120 Tests the "initCommands", "preRunCommands", "stopCommands", 121 "exitCommands", "terminateCommands" and "attachCommands" 122 that can be passed during attach. 123 124 "initCommands" are a list of LLDB commands that get executed 125 before the targt is created. 126 "preRunCommands" are a list of LLDB commands that get executed 127 after the target has been created and before the launch. 128 "stopCommands" are a list of LLDB commands that get executed each 129 time the program stops. 130 "exitCommands" are a list of LLDB commands that get executed when 131 the process exits 132 "attachCommands" are a list of LLDB commands that get executed and 133 must have a valid process in the selected target in LLDB after 134 they are done executing. This allows custom commands to create any 135 kind of debug session. 136 "terminateCommands" are a list of LLDB commands that get executed when 137 the debugger session terminates. 138 ''' 139 self.build_and_create_debug_adaptor() 140 program = self.getBuildArtifact("a.out") 141 # Here we just create a target and launch the process as a way to test 142 # if we are able to use attach commands to create any kind of a target 143 # and use it for debugging 144 attachCommands = [ 145 'target create -d "%s"' % (program), 146 'process launch --stop-at-entry' 147 ] 148 initCommands = ['target list', 'platform list'] 149 preRunCommands = ['image list a.out', 'image dump sections a.out'] 150 postRunCommands = ['help trace', 'help process trace'] 151 stopCommands = ['frame variable', 'bt'] 152 exitCommands = ['expr 2+3', 'expr 3+4'] 153 terminateCommands = ['expr 4+2'] 154 self.attach(program=program, 155 attachCommands=attachCommands, 156 initCommands=initCommands, 157 preRunCommands=preRunCommands, 158 stopCommands=stopCommands, 159 exitCommands=exitCommands, 160 terminateCommands=terminateCommands, 161 postRunCommands=postRunCommands) 162 # Get output from the console. This should contain both the 163 # "initCommands" and the "preRunCommands". 164 output = self.get_console() 165 # Verify all "initCommands" were found in console output 166 self.verify_commands('initCommands', output, initCommands) 167 # Verify all "preRunCommands" were found in console output 168 self.verify_commands('preRunCommands', output, preRunCommands) 169 # Verify all "postRunCommands" were found in console output 170 self.verify_commands('postRunCommands', output, postRunCommands) 171 172 functions = ['main'] 173 breakpoint_ids = self.set_function_breakpoints(functions) 174 self.assertEquals(len(breakpoint_ids), len(functions), 175 "expect one breakpoint") 176 self.continue_to_breakpoints(breakpoint_ids) 177 output = self.get_console(timeout=1.0) 178 self.verify_commands('stopCommands', output, stopCommands) 179 180 # Continue after launch and hit the "pause()" call and stop the target. 181 # Get output from the console. This should contain both the 182 # "stopCommands" that were run after we stop. 183 self.vscode.request_continue() 184 time.sleep(0.5) 185 self.vscode.request_pause() 186 self.vscode.wait_for_stopped() 187 output = self.get_console(timeout=1.0) 188 self.verify_commands('stopCommands', output, stopCommands) 189 190 # Continue until the program exits 191 self.continue_to_exit() 192 # Get output from the console. This should contain both the 193 # "exitCommands" that were run after the second breakpoint was hit 194 # and the "terminateCommands" due to the debugging session ending 195 output = self.collect_console(duration=1.0) 196 self.verify_commands('exitCommands', output, exitCommands) 197 self.verify_commands('terminateCommands', output, terminateCommands) 198 199 @skipIfWindows 200 @skipIfDarwin 201 @skipIfNetBSD # Hangs on NetBSD as well 202 @skipIf(archs=["arm", "aarch64"]) # Example of a flaky run http://lab.llvm.org:8011/builders/lldb-aarch64-ubuntu/builds/5517/steps/test/logs/stdio 203 def test_terminate_commands(self): 204 ''' 205 Tests that the "terminateCommands", that can be passed during 206 attach, are run when the debugger is disconnected. 207 ''' 208 self.build_and_create_debug_adaptor() 209 program = self.getBuildArtifact("a.out") 210 # Here we just create a target and launch the process as a way to test 211 # if we are able to use attach commands to create any kind of a target 212 # and use it for debugging 213 attachCommands = [ 214 'target create -d "%s"' % (program), 215 'process launch --stop-at-entry' 216 ] 217 terminateCommands = ['expr 4+2'] 218 self.attach(program=program, 219 attachCommands=attachCommands, 220 terminateCommands=terminateCommands, 221 disconnectAutomatically=False) 222 self.get_console() 223 # Once it's disconnected the console should contain the 224 # "terminateCommands" 225 self.vscode.request_disconnect(terminateDebuggee=True) 226 output = self.collect_console(duration=1.0) 227 self.verify_commands('terminateCommands', output, terminateCommands) 228