from lldbsuite.test.gdbclientutils import * from lldbsuite.test.decorators import * from lldbsuite.test.lldbgdbclient import GDBPlatformClientTestBase class TestGDBRemotePlatformFile(GDBPlatformClientTestBase): def test_file(self): """Test mock operations on a remote file""" class Responder(MockGDBServerResponder): def vFile(self, packet): if packet.startswith("vFile:open:"): return "F10" elif packet.startswith("vFile:pread:"): return "Fd;frobnicator" elif packet.startswith("vFile:pwrite:"): return "Fa" elif packet.startswith("vFile:close:"): return "F0" return "F-1,58" self.server.responder = Responder() self.match( "platform file open /some/file.txt -v 0755", [r"File Descriptor = 16"] ) self.match( "platform file read 16 -o 11 -c 13", [r"Return = 11\nData = \"frobnicator\""], ) self.match("platform file write 16 -o 11 -d teststring", [r"Return = 10"]) self.match("platform file close 16", [r"file 16 closed."]) self.assertPacketLogContains( [ "vFile:open:2f736f6d652f66696c652e747874,00000202,000001ed", "vFile:pread:10,d,b", "vFile:pwrite:10,b,teststring", "vFile:close:10", ] ) def test_file_fail(self): """Test mocked failures of remote operations""" class Responder(MockGDBServerResponder): def vFile(self, packet): # use ENOSYS as this constant differs between GDB Remote # Protocol and Linux, so we can test the translation return "F-1,58" self.server.responder = Responder() enosys_regex = r"error: (Function not implemented|function not supported)" self.match( "platform file open /some/file.txt -v 0755", [enosys_regex], error=True, ) self.match( "platform file read 16 -o 11 -c 13", [enosys_regex], error=True, ) self.match( "platform file write 16 -o 11 -d teststring", [enosys_regex], error=True, ) self.match("platform file close 16", [enosys_regex], error=True) self.assertPacketLogContains( [ "vFile:open:2f736f6d652f66696c652e747874,00000202,000001ed", "vFile:pread:10,d,b", "vFile:pwrite:10,b,teststring", "vFile:close:10", ] ) def test_file_size(self): """Test 'platform get-size'""" class Responder(MockGDBServerResponder): def vFile(self, packet): return "F1000" self.server.responder = Responder() self.match( "platform get-size /some/file.txt", [r"File size of /some/file\.txt \(remote\): 4096"], ) self.assertPacketLogContains( [ "vFile:size:2f736f6d652f66696c652e747874", ] ) def test_file_size_fallback(self): """Test 'platform get-size fallback to vFile:fstat'""" class Responder(MockGDBServerResponder): def vFile(self, packet): if packet.startswith("vFile:open:"): return "F5" elif packet.startswith("vFile:fstat:"): return "F40;" + 28 * "\0" + "\0\0\0\0\0\1\2\3" + 28 * "\0" if packet.startswith("vFile:close:"): return "F0" return "" self.server.responder = Responder() self.match( "platform get-size /some/file.txt", [r"File size of /some/file\.txt \(remote\): 66051"], ) self.assertPacketLogContains( [ "vFile:size:2f736f6d652f66696c652e747874", "vFile:open:2f736f6d652f66696c652e747874,00000000,00000000", "vFile:fstat:5", "vFile:close:5", ] ) self.runCmd("platform disconnect") # For a new onnection, we should attempt vFile:size once again. server2 = MockGDBServer(self.server_socket_class()) server2.responder = Responder() server2.start() self.addTearDownHook(lambda: server2.stop()) self.runCmd("platform connect " + server2.get_connect_url()) self.match( "platform get-size /other/file.txt", [r"File size of /other/file\.txt \(remote\): 66051"], ) self.assertPacketLogContains( [ "vFile:size:2f6f746865722f66696c652e747874", "vFile:open:2f6f746865722f66696c652e747874,00000000,00000000", "vFile:fstat:5", "vFile:close:5", ], log=server2.responder.packetLog, ) @expectedFailureAll( hostoslist=["windows"], bugnumber="github.com/llvm/llvm-project/issues/92255" ) def test_file_permissions(self): """Test 'platform get-permissions'""" class Responder(MockGDBServerResponder): def vFile(self, packet): return "F1a4" self.server.responder = Responder() self.match( "platform get-permissions /some/file.txt", [r"File permissions of /some/file\.txt \(remote\): 0o0644"], ) self.assertPacketLogContains( [ "vFile:mode:2f736f6d652f66696c652e747874", ] ) @expectedFailureAll( hostoslist=["windows"], bugnumber="github.com/llvm/llvm-project/issues/92255" ) def test_file_permissions_fallback(self): """Test 'platform get-permissions' fallback to fstat""" class Responder(MockGDBServerResponder): def vFile(self, packet): if packet.startswith("vFile:open:"): return "F5" elif packet.startswith("vFile:fstat:"): return "F40;" + 8 * "\0" + "\0\0\1\xA4" + 52 * "\0" if packet.startswith("vFile:close:"): return "F0" return "" self.server.responder = Responder() try: self.match( "platform get-permissions /some/file.txt", [r"File permissions of /some/file\.txt \(remote\): 0o0644"], ) self.assertPacketLogContains( [ "vFile:mode:2f736f6d652f66696c652e747874", "vFile:open:2f736f6d652f66696c652e747874,00000000,00000000", "vFile:fstat:5", "vFile:close:5", ] ) finally: self.dbg.GetSelectedPlatform().DisconnectRemote() def test_file_exists(self): """Test 'platform file-exists'""" class Responder(MockGDBServerResponder): def vFile(self, packet): return "F,1" self.server.responder = Responder() self.match( "platform file-exists /some/file.txt", [r"File /some/file\.txt \(remote\) exists"], ) self.assertPacketLogContains( [ "vFile:exists:2f736f6d652f66696c652e747874", ] ) def test_file_exists_not(self): """Test 'platform file-exists' with non-existing file""" class Responder(MockGDBServerResponder): def vFile(self, packet): return "F,0" self.server.responder = Responder() self.match( "platform file-exists /some/file.txt", [r"File /some/file\.txt \(remote\) does not exist"], ) self.assertPacketLogContains( [ "vFile:exists:2f736f6d652f66696c652e747874", ] ) def test_file_exists_fallback(self): """Test 'platform file-exists' fallback to open""" class Responder(MockGDBServerResponder): def vFile(self, packet): if packet.startswith("vFile:open:"): return "F5" if packet.startswith("vFile:close:"): return "F0" return "" self.server.responder = Responder() self.match( "platform file-exists /some/file.txt", [r"File /some/file\.txt \(remote\) exists"], ) self.assertPacketLogContains( [ "vFile:exists:2f736f6d652f66696c652e747874", "vFile:open:2f736f6d652f66696c652e747874,00000000,00000000", "vFile:close:5", ] ) def test_file_exists_not_fallback(self): """Test 'platform file-exists' fallback to open with non-existing file""" class Responder(MockGDBServerResponder): def vFile(self, packet): if packet.startswith("vFile:open:"): return "F-1,2" return "" self.server.responder = Responder() self.match( "platform file-exists /some/file.txt", [r"File /some/file\.txt \(remote\) does not exist"], ) self.assertPacketLogContains( [ "vFile:exists:2f736f6d652f66696c652e747874", "vFile:open:2f736f6d652f66696c652e747874,00000000,00000000", ] )