1from lldbsuite.test.gdbclientutils import * 2from lldbsuite.test.decorators import * 3from lldbsuite.test.lldbgdbclient import GDBPlatformClientTestBase 4 5 6class TestGDBRemotePlatformFile(GDBPlatformClientTestBase): 7 def test_file(self): 8 """Test mock operations on a remote file""" 9 10 class Responder(MockGDBServerResponder): 11 def vFile(self, packet): 12 if packet.startswith("vFile:open:"): 13 return "F10" 14 elif packet.startswith("vFile:pread:"): 15 return "Fd;frobnicator" 16 elif packet.startswith("vFile:pwrite:"): 17 return "Fa" 18 elif packet.startswith("vFile:close:"): 19 return "F0" 20 return "F-1,58" 21 22 self.server.responder = Responder() 23 24 self.match( 25 "platform file open /some/file.txt -v 0755", [r"File Descriptor = 16"] 26 ) 27 self.match( 28 "platform file read 16 -o 11 -c 13", 29 [r"Return = 11\nData = \"frobnicator\""], 30 ) 31 self.match("platform file write 16 -o 11 -d teststring", [r"Return = 10"]) 32 self.match("platform file close 16", [r"file 16 closed."]) 33 self.assertPacketLogContains( 34 [ 35 "vFile:open:2f736f6d652f66696c652e747874,00000202,000001ed", 36 "vFile:pread:10,d,b", 37 "vFile:pwrite:10,b,teststring", 38 "vFile:close:10", 39 ] 40 ) 41 42 def test_file_fail(self): 43 """Test mocked failures of remote operations""" 44 45 class Responder(MockGDBServerResponder): 46 def vFile(self, packet): 47 # use ENOSYS as this constant differs between GDB Remote 48 # Protocol and Linux, so we can test the translation 49 return "F-1,58" 50 51 self.server.responder = Responder() 52 enosys_regex = r"error: (Function not implemented|function not supported)" 53 self.match( 54 "platform file open /some/file.txt -v 0755", 55 [enosys_regex], 56 error=True, 57 ) 58 self.match( 59 "platform file read 16 -o 11 -c 13", 60 [enosys_regex], 61 error=True, 62 ) 63 self.match( 64 "platform file write 16 -o 11 -d teststring", 65 [enosys_regex], 66 error=True, 67 ) 68 self.match("platform file close 16", [enosys_regex], error=True) 69 self.assertPacketLogContains( 70 [ 71 "vFile:open:2f736f6d652f66696c652e747874,00000202,000001ed", 72 "vFile:pread:10,d,b", 73 "vFile:pwrite:10,b,teststring", 74 "vFile:close:10", 75 ] 76 ) 77 78 def test_file_size(self): 79 """Test 'platform get-size'""" 80 81 class Responder(MockGDBServerResponder): 82 def vFile(self, packet): 83 return "F1000" 84 85 self.server.responder = Responder() 86 87 self.match( 88 "platform get-size /some/file.txt", 89 [r"File size of /some/file\.txt \(remote\): 4096"], 90 ) 91 self.assertPacketLogContains( 92 [ 93 "vFile:size:2f736f6d652f66696c652e747874", 94 ] 95 ) 96 97 def test_file_size_fallback(self): 98 """Test 'platform get-size fallback to vFile:fstat'""" 99 100 class Responder(MockGDBServerResponder): 101 def vFile(self, packet): 102 if packet.startswith("vFile:open:"): 103 return "F5" 104 elif packet.startswith("vFile:fstat:"): 105 return "F40;" + 28 * "\0" + "\0\0\0\0\0\1\2\3" + 28 * "\0" 106 if packet.startswith("vFile:close:"): 107 return "F0" 108 return "" 109 110 self.server.responder = Responder() 111 112 self.match( 113 "platform get-size /some/file.txt", 114 [r"File size of /some/file\.txt \(remote\): 66051"], 115 ) 116 self.assertPacketLogContains( 117 [ 118 "vFile:size:2f736f6d652f66696c652e747874", 119 "vFile:open:2f736f6d652f66696c652e747874,00000000,00000000", 120 "vFile:fstat:5", 121 "vFile:close:5", 122 ] 123 ) 124 125 self.runCmd("platform disconnect") 126 127 # For a new onnection, we should attempt vFile:size once again. 128 server2 = MockGDBServer(self.server_socket_class()) 129 server2.responder = Responder() 130 server2.start() 131 self.addTearDownHook(lambda: server2.stop()) 132 self.runCmd("platform connect " + server2.get_connect_url()) 133 self.match( 134 "platform get-size /other/file.txt", 135 [r"File size of /other/file\.txt \(remote\): 66051"], 136 ) 137 138 self.assertPacketLogContains( 139 [ 140 "vFile:size:2f6f746865722f66696c652e747874", 141 "vFile:open:2f6f746865722f66696c652e747874,00000000,00000000", 142 "vFile:fstat:5", 143 "vFile:close:5", 144 ], 145 log=server2.responder.packetLog, 146 ) 147 148 @expectedFailureAll( 149 hostoslist=["windows"], bugnumber="github.com/llvm/llvm-project/issues/92255" 150 ) 151 def test_file_permissions(self): 152 """Test 'platform get-permissions'""" 153 154 class Responder(MockGDBServerResponder): 155 def vFile(self, packet): 156 return "F1a4" 157 158 self.server.responder = Responder() 159 160 self.match( 161 "platform get-permissions /some/file.txt", 162 [r"File permissions of /some/file\.txt \(remote\): 0o0644"], 163 ) 164 self.assertPacketLogContains( 165 [ 166 "vFile:mode:2f736f6d652f66696c652e747874", 167 ] 168 ) 169 170 @expectedFailureAll( 171 hostoslist=["windows"], bugnumber="github.com/llvm/llvm-project/issues/92255" 172 ) 173 def test_file_permissions_fallback(self): 174 """Test 'platform get-permissions' fallback to fstat""" 175 176 class Responder(MockGDBServerResponder): 177 def vFile(self, packet): 178 if packet.startswith("vFile:open:"): 179 return "F5" 180 elif packet.startswith("vFile:fstat:"): 181 return "F40;" + 8 * "\0" + "\0\0\1\xA4" + 52 * "\0" 182 if packet.startswith("vFile:close:"): 183 return "F0" 184 return "" 185 186 self.server.responder = Responder() 187 188 try: 189 self.match( 190 "platform get-permissions /some/file.txt", 191 [r"File permissions of /some/file\.txt \(remote\): 0o0644"], 192 ) 193 self.assertPacketLogContains( 194 [ 195 "vFile:mode:2f736f6d652f66696c652e747874", 196 "vFile:open:2f736f6d652f66696c652e747874,00000000,00000000", 197 "vFile:fstat:5", 198 "vFile:close:5", 199 ] 200 ) 201 finally: 202 self.dbg.GetSelectedPlatform().DisconnectRemote() 203 204 def test_file_exists(self): 205 """Test 'platform file-exists'""" 206 207 class Responder(MockGDBServerResponder): 208 def vFile(self, packet): 209 return "F,1" 210 211 self.server.responder = Responder() 212 213 self.match( 214 "platform file-exists /some/file.txt", 215 [r"File /some/file\.txt \(remote\) exists"], 216 ) 217 self.assertPacketLogContains( 218 [ 219 "vFile:exists:2f736f6d652f66696c652e747874", 220 ] 221 ) 222 223 def test_file_exists_not(self): 224 """Test 'platform file-exists' with non-existing file""" 225 226 class Responder(MockGDBServerResponder): 227 def vFile(self, packet): 228 return "F,0" 229 230 self.server.responder = Responder() 231 232 self.match( 233 "platform file-exists /some/file.txt", 234 [r"File /some/file\.txt \(remote\) does not exist"], 235 ) 236 self.assertPacketLogContains( 237 [ 238 "vFile:exists:2f736f6d652f66696c652e747874", 239 ] 240 ) 241 242 def test_file_exists_fallback(self): 243 """Test 'platform file-exists' fallback to open""" 244 245 class Responder(MockGDBServerResponder): 246 def vFile(self, packet): 247 if packet.startswith("vFile:open:"): 248 return "F5" 249 if packet.startswith("vFile:close:"): 250 return "F0" 251 return "" 252 253 self.server.responder = Responder() 254 255 self.match( 256 "platform file-exists /some/file.txt", 257 [r"File /some/file\.txt \(remote\) exists"], 258 ) 259 self.assertPacketLogContains( 260 [ 261 "vFile:exists:2f736f6d652f66696c652e747874", 262 "vFile:open:2f736f6d652f66696c652e747874,00000000,00000000", 263 "vFile:close:5", 264 ] 265 ) 266 267 def test_file_exists_not_fallback(self): 268 """Test 'platform file-exists' fallback to open with non-existing file""" 269 270 class Responder(MockGDBServerResponder): 271 def vFile(self, packet): 272 if packet.startswith("vFile:open:"): 273 return "F-1,2" 274 return "" 275 276 self.server.responder = Responder() 277 278 self.match( 279 "platform file-exists /some/file.txt", 280 [r"File /some/file\.txt \(remote\) does not exist"], 281 ) 282 self.assertPacketLogContains( 283 [ 284 "vFile:exists:2f736f6d652f66696c652e747874", 285 "vFile:open:2f736f6d652f66696c652e747874,00000000,00000000", 286 ] 287 ) 288