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