1import lldb 2from lldbsuite.test.lldbtest import * 3from lldbsuite.test.decorators import * 4from lldbsuite.test.gdbclientutils import * 5from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase 6 7 8@skipIf(hostoslist=["windows"]) 9class TestPty(GDBRemoteTestBase): 10 server_socket_class = PtyServerSocket 11 12 def get_term_attrs(self): 13 import termios 14 15 return termios.tcgetattr(self._secondary_socket) 16 17 def setUp(self): 18 super().setUp() 19 # Duplicate the pty descriptors so we can inspect the pty state after 20 # they are closed 21 self._primary_socket = os.dup(self.server._socket._primary.name) 22 self._secondary_socket = os.dup(self.server._socket._secondary.name) 23 self.orig_attr = self.get_term_attrs() 24 25 def assert_raw_mode(self, current_attr): 26 import termios 27 28 self.assertEqual( 29 current_attr[0] 30 & ( 31 termios.BRKINT 32 | termios.PARMRK 33 | termios.ISTRIP 34 | termios.INLCR 35 | termios.IGNCR 36 | termios.ICRNL 37 | termios.IXON 38 ), 39 0, 40 ) 41 self.assertEqual(current_attr[1] & termios.OPOST, 0) 42 self.assertEqual(current_attr[2] & termios.CSIZE, termios.CS8) 43 self.assertEqual( 44 current_attr[3] 45 & (termios.ICANON | termios.ECHO | termios.ISIG | termios.IEXTEN), 46 0, 47 ) 48 self.assertEqual(current_attr[6][termios.VMIN], 1) 49 self.assertEqual(current_attr[6][termios.VTIME], 0) 50 51 def get_parity_flags(self, attr): 52 import termios 53 54 return attr[2] & (termios.PARENB | termios.PARODD) 55 56 def get_stop_bit_flags(self, attr): 57 import termios 58 59 return attr[2] & termios.CSTOPB 60 61 def test_process_connect_sync(self): 62 """Test the process connect command in synchronous mode""" 63 try: 64 self.dbg.SetAsync(False) 65 self.expect( 66 "platform select remote-gdb-server", 67 substrs=["Platform: remote-gdb-server", "Connected: no"], 68 ) 69 self.expect( 70 "process connect " + self.server.get_connect_url(), 71 substrs=["Process", "stopped"], 72 ) 73 74 current_attr = self.get_term_attrs() 75 # serial:// should set raw mode 76 self.assert_raw_mode(current_attr) 77 # other parameters should be unmodified 78 self.assertEqual(current_attr[4:6], self.orig_attr[4:6]) 79 self.assertEqual( 80 self.get_parity_flags(current_attr), 81 self.get_parity_flags(self.orig_attr), 82 ) 83 self.assertEqual( 84 self.get_stop_bit_flags(current_attr), 85 self.get_stop_bit_flags(self.orig_attr), 86 ) 87 finally: 88 self.dbg.GetSelectedTarget().GetProcess().Kill() 89 # original mode should be restored on exit 90 self.assertEqual(self.get_term_attrs(), self.orig_attr) 91 92 def test_process_connect_async(self): 93 """Test the process connect command in asynchronous mode""" 94 try: 95 self.dbg.SetAsync(True) 96 self.expect( 97 "platform select remote-gdb-server", 98 substrs=["Platform: remote-gdb-server", "Connected: no"], 99 ) 100 self.expect( 101 "process connect " + self.server.get_connect_url(), 102 matching=False, 103 substrs=["Process", "stopped"], 104 ) 105 lldbutil.expect_state_changes( 106 self, self.dbg.GetListener(), self.process(), [lldb.eStateStopped] 107 ) 108 109 current_attr = self.get_term_attrs() 110 # serial:// should set raw mode 111 self.assert_raw_mode(current_attr) 112 # other parameters should be unmodified 113 self.assertEqual(current_attr[4:6], self.orig_attr[4:6]) 114 self.assertEqual( 115 self.get_parity_flags(current_attr), 116 self.get_parity_flags(self.orig_attr), 117 ) 118 self.assertEqual( 119 self.get_stop_bit_flags(current_attr), 120 self.get_stop_bit_flags(self.orig_attr), 121 ) 122 finally: 123 self.dbg.GetSelectedTarget().GetProcess().Kill() 124 lldbutil.expect_state_changes( 125 self, self.dbg.GetListener(), self.process(), [lldb.eStateExited] 126 ) 127 # original mode should be restored on exit 128 self.assertEqual(self.get_term_attrs(), self.orig_attr) 129 130 def test_connect_via_file(self): 131 """Test connecting via the legacy file:// URL""" 132 import termios 133 134 try: 135 self.expect( 136 "platform select remote-gdb-server", 137 substrs=["Platform: remote-gdb-server", "Connected: no"], 138 ) 139 self.expect( 140 "process connect file://" + self.server.get_connect_address(), 141 substrs=["Process", "stopped"], 142 ) 143 144 # file:// sets baud rate and some raw-related flags 145 current_attr = self.get_term_attrs() 146 self.assertEqual( 147 current_attr[3] 148 & (termios.ICANON | termios.ECHO | termios.ECHOE | termios.ISIG), 149 0, 150 ) 151 self.assertEqual(current_attr[4], termios.B115200) 152 self.assertEqual(current_attr[5], termios.B115200) 153 self.assertEqual(current_attr[6][termios.VMIN], 1) 154 self.assertEqual(current_attr[6][termios.VTIME], 0) 155 finally: 156 self.dbg.GetSelectedTarget().GetProcess().Kill() 157 158 def test_process_connect_params(self): 159 """Test serial:// URL with parameters""" 160 import termios 161 162 try: 163 self.expect( 164 "platform select remote-gdb-server", 165 substrs=["Platform: remote-gdb-server", "Connected: no"], 166 ) 167 self.expect( 168 "process connect " 169 + self.server.get_connect_url() 170 + "?baud=115200&stop-bits=2", 171 substrs=["Process", "stopped"], 172 ) 173 174 current_attr = self.get_term_attrs() 175 self.assert_raw_mode(current_attr) 176 self.assertEqual(current_attr[4:6], 2 * [termios.B115200]) 177 self.assertEqual( 178 self.get_parity_flags(current_attr), 179 self.get_parity_flags(self.orig_attr), 180 ) 181 self.assertEqual(self.get_stop_bit_flags(current_attr), termios.CSTOPB) 182 finally: 183 self.dbg.GetSelectedTarget().GetProcess().Kill() 184 # original mode should be restored on exit 185 self.assertEqual(self.get_term_attrs(), self.orig_attr) 186