xref: /llvm-project/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemotePlatformFile.py (revision fc1df55bcf9b6cc2dec157bcd188b471bc91b945)
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