1""" 2Test lldb-dap setBreakpoints request 3""" 4 5import dap_server 6import lldbdap_testcase 7from lldbsuite.test import lldbutil 8from lldbsuite.test.decorators import * 9from lldbsuite.test.lldbtest import * 10 11 12def get_subprocess(root_process, process_name): 13 queue = [root_process] 14 while queue: 15 process = queue.pop() 16 if process.name() == process_name: 17 return process 18 queue.extend(process.children()) 19 20 self.assertTrue(False, "No subprocess with name %s found" % process_name) 21 22class TestDAP_console(lldbdap_testcase.DAPTestCaseBase): 23 def check_lldb_command( 24 self, lldb_command, contains_string, assert_msg, command_escape_prefix="`" 25 ): 26 response = self.dap_server.request_evaluate( 27 f"{command_escape_prefix}{lldb_command}", context="repl" 28 ) 29 output = response["body"]["result"] 30 self.assertIn( 31 contains_string, 32 output, 33 ( 34 """Verify %s by checking the command output:\n""" 35 """'''\n%s'''\nfor the string: "%s" """ 36 % (assert_msg, output, contains_string) 37 ), 38 ) 39 40 def test_scopes_variables_setVariable_evaluate(self): 41 """ 42 Tests that the "scopes" request causes the currently selected 43 thread and frame to be updated. There are no DAP packets that tell 44 lldb-dap which thread and frame are selected other than the 45 "scopes" request. lldb-dap will now select the thread and frame 46 for the latest "scopes" request that it receives. 47 48 The LLDB command interpreter needs to have the right thread and 49 frame selected so that commands executed in the debug console act 50 on the right scope. This applies both to the expressions that are 51 evaluated and the lldb commands that start with the backtick 52 character. 53 """ 54 program = self.getBuildArtifact("a.out") 55 self.build_and_launch(program) 56 source = "main.cpp" 57 breakpoint1_line = line_number(source, "// breakpoint 1") 58 lines = [breakpoint1_line] 59 # Set breakpoint in the thread function so we can step the threads 60 breakpoint_ids = self.set_source_breakpoints(source, lines) 61 self.assertEqual( 62 len(breakpoint_ids), len(lines), "expect correct number of breakpoints" 63 ) 64 self.continue_to_breakpoints(breakpoint_ids) 65 # Cause a "scopes" to be sent for frame zero which should update the 66 # selected thread and frame to frame 0. 67 self.dap_server.get_local_variables(frameIndex=0) 68 # Verify frame #0 is selected in the command interpreter by running 69 # the "frame select" command with no frame index which will print the 70 # currently selected frame. 71 self.check_lldb_command("frame select", "frame #0", "frame 0 is selected") 72 73 # Cause a "scopes" to be sent for frame one which should update the 74 # selected thread and frame to frame 1. 75 self.dap_server.get_local_variables(frameIndex=1) 76 # Verify frame #1 is selected in the command interpreter by running 77 # the "frame select" command with no frame index which will print the 78 # currently selected frame. 79 80 self.check_lldb_command("frame select", "frame #1", "frame 1 is selected") 81 82 def test_custom_escape_prefix(self): 83 program = self.getBuildArtifact("a.out") 84 self.build_and_launch(program, commandEscapePrefix="::") 85 source = "main.cpp" 86 breakpoint1_line = line_number(source, "// breakpoint 1") 87 breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line]) 88 self.continue_to_breakpoints(breakpoint_ids) 89 90 self.check_lldb_command( 91 "help", 92 "For more information on any command", 93 "Help can be invoked", 94 command_escape_prefix="::", 95 ) 96 97 def test_empty_escape_prefix(self): 98 program = self.getBuildArtifact("a.out") 99 self.build_and_launch(program, commandEscapePrefix="") 100 source = "main.cpp" 101 breakpoint1_line = line_number(source, "// breakpoint 1") 102 breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line]) 103 self.continue_to_breakpoints(breakpoint_ids) 104 105 self.check_lldb_command( 106 "help", 107 "For more information on any command", 108 "Help can be invoked", 109 command_escape_prefix="", 110 ) 111 112 @skipIfWindows 113 def test_exit_status_message_sigterm(self): 114 source = "main.cpp" 115 program = self.getBuildArtifact("a.out") 116 self.build_and_launch(program, commandEscapePrefix="") 117 breakpoint1_line = line_number(source, "// breakpoint 1") 118 breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line]) 119 self.continue_to_breakpoints(breakpoint_ids) 120 121 # Kill lldb-server process. 122 process_name = ( 123 "debugserver" if platform.system() in ["Darwin"] else "lldb-server" 124 ) 125 126 try: 127 import psutil 128 except ImportError: 129 print( 130 "psutil not installed, please install using 'pip install psutil'. " 131 "Skipping test_exit_status_message_sigterm test.", 132 file=sys.stderr, 133 ) 134 return 135 process = get_subprocess(psutil.Process(os.getpid()), process_name) 136 process.terminate() 137 process.wait() 138 139 # Get the console output 140 console_output = self.collect_console( 141 timeout_secs=10.0, pattern="exited with status" 142 ) 143 144 # Verify the exit status message is printed. 145 self.assertIn( 146 "exited with status = -1 (0xffffffff) debugserver died with signal SIGTERM", 147 console_output, 148 "Exit status does not contain message 'exited with status'", 149 ) 150 151 def test_exit_status_message_ok(self): 152 program = self.getBuildArtifact("a.out") 153 self.build_and_launch(program, commandEscapePrefix="") 154 self.continue_to_exit() 155 156 # Get the console output 157 console_output = self.collect_console( 158 timeout_secs=10.0, pattern="exited with status" 159 ) 160 161 # Verify the exit status message is printed. 162 self.assertIn( 163 "exited with status = 0 (0x00000000)", 164 console_output, 165 "Exit status does not contain message 'exited with status'", 166 ) 167