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