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 mydir = TestBase.compute_mydir(__file__) 33 34 def set_and_hit_breakpoint(self, continueToExit=True): 35 source = 'main.c' 36 breakpoint1_line = line_number(source, '// breakpoint 1') 37 lines = [breakpoint1_line] 38 # Set breakpoint in the thread function so we can step the threads 39 breakpoint_ids = self.set_source_breakpoints(source, lines) 40 self.assertEqual(len(breakpoint_ids), len(lines), 41 "expect correct number of breakpoints") 42 self.continue_to_breakpoints(breakpoint_ids) 43 if continueToExit: 44 self.continue_to_exit() 45 46 47 @skipIfWindows 48 @skipIfNetBSD # Hangs on NetBSD as well 49 @skipIfRemote 50 def test_by_pid(self): 51 ''' 52 Tests attaching to a process by process ID. 53 ''' 54 self.build_and_create_debug_adaptor() 55 program = self.getBuildArtifact("a.out") 56 self.process = subprocess.Popen([program], 57 stdin=subprocess.PIPE, 58 stdout=subprocess.PIPE, 59 stderr=subprocess.PIPE) 60 self.attach(pid=self.process.pid) 61 self.set_and_hit_breakpoint(continueToExit=True) 62 63 @skipIfWindows 64 @skipIfNetBSD # Hangs on NetBSD as well 65 @skipIfRemote 66 def test_by_name(self): 67 ''' 68 Tests attaching to a process by process name. 69 ''' 70 self.build_and_create_debug_adaptor() 71 orig_program = self.getBuildArtifact("a.out") 72 # Since we are going to attach by process name, we need a unique 73 # process name that has minimal chance to match a process that is 74 # already running. To do this we use tempfile.mktemp() to give us a 75 # full path to a location where we can copy our executable. We then 76 # run this copy to ensure we don't get the error "more that one 77 # process matches 'a.out'". 78 program = tempfile.mktemp() 79 shutil.copyfile(orig_program, program) 80 shutil.copymode(orig_program, program) 81 82 # Use a file as a synchronization point between test and inferior. 83 pid_file_path = lldbutil.append_to_process_working_directory(self, 84 "pid_file_%d" % (int(time.time()))) 85 86 def cleanup(): 87 if os.path.exists(program): 88 os.unlink(program) 89 self.run_platform_command("rm %s" % (pid_file_path)) 90 # Execute the cleanup function during test case tear down. 91 self.addTearDownHook(cleanup) 92 93 popen = self.spawnSubprocess(program, [pid_file_path]) 94 self.addTearDownHook(self.cleanupSubprocesses) 95 96 pid = lldbutil.wait_for_file_on_target(self, pid_file_path) 97 98 self.attach(program=program) 99 self.set_and_hit_breakpoint(continueToExit=True) 100 101 @skipUnlessDarwin 102 @skipIfDarwin 103 @skipIfNetBSD # Hangs on NetBSD as well 104 def test_by_name_waitFor(self): 105 ''' 106 Tests attaching to a process by process name and waiting for the 107 next instance of a process to be launched, ingoring all current 108 ones. 109 ''' 110 self.build_and_create_debug_adaptor() 111 program = self.getBuildArtifact("a.out") 112 self.spawn_thread = threading.Thread(target=spawn_and_wait, 113 args=(program, 1.0,)) 114 self.spawn_thread.start() 115 self.attach(program=program, waitFor=True) 116 self.set_and_hit_breakpoint(continueToExit=True) 117 118 @skipIfWindows 119 @skipIfDarwin 120 @skipIfNetBSD # Hangs on NetBSD as well 121 def test_commands(self): 122 ''' 123 Tests the "initCommands", "preRunCommands", "stopCommands", 124 "exitCommands", and "attachCommands" that can be passed during 125 attach. 126 127 "initCommands" are a list of LLDB commands that get executed 128 before the targt is created. 129 "preRunCommands" are a list of LLDB commands that get executed 130 after the target has been created and before the launch. 131 "stopCommands" are a list of LLDB commands that get executed each 132 time the program stops. 133 "exitCommands" are a list of LLDB commands that get executed when 134 the process exits 135 "attachCommands" are a list of LLDB commands that get executed and 136 must have a valid process in the selected target in LLDB after 137 they are done executing. This allows custom commands to create any 138 kind of debug session. 139 ''' 140 self.build_and_create_debug_adaptor() 141 program = self.getBuildArtifact("a.out") 142 # Here we just create a target and launch the process as a way to test 143 # if we are able to use attach commands to create any kind of a target 144 # and use it for debugging 145 attachCommands = [ 146 'target create -d "%s"' % (program), 147 'process launch' 148 ] 149 initCommands = ['target list', 'platform list'] 150 preRunCommands = ['image list a.out', 'image dump sections a.out'] 151 stopCommands = ['frame variable', 'bt'] 152 exitCommands = ['expr 2+3', 'expr 3+4'] 153 self.attach(program=program, 154 attachCommands=attachCommands, 155 initCommands=initCommands, 156 preRunCommands=preRunCommands, 157 stopCommands=stopCommands, 158 exitCommands=exitCommands) 159 160 # Get output from the console. This should contain both the 161 # "initCommands" and the "preRunCommands". 162 output = self.get_console() 163 # Verify all "initCommands" were found in console output 164 self.verify_commands('initCommands', output, initCommands) 165 # Verify all "preRunCommands" were found in console output 166 self.verify_commands('preRunCommands', output, preRunCommands) 167 168 functions = ['main'] 169 breakpoint_ids = self.set_function_breakpoints(functions) 170 self.assertEquals(len(breakpoint_ids), len(functions), 171 "expect one breakpoint") 172 self.continue_to_breakpoints(breakpoint_ids) 173 output = self.get_console(timeout=1.0) 174 self.verify_commands('stopCommands', output, stopCommands) 175 176 # Continue after launch and hit the "pause()" call and stop the target. 177 # Get output from the console. This should contain both the 178 # "stopCommands" that were run after we stop. 179 self.vscode.request_continue() 180 time.sleep(0.5) 181 self.vscode.request_pause() 182 self.vscode.wait_for_stopped() 183 output = self.get_console(timeout=1.0) 184 self.verify_commands('stopCommands', output, stopCommands) 185 186 # Continue until the program exits 187 self.continue_to_exit() 188 # Get output from the console. This should contain both the 189 # "exitCommands" that were run after the second breakpoint was hit 190 output = self.get_console(timeout=1.0) 191 self.verify_commands('exitCommands', output, exitCommands) 192