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