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