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