1from __future__ import print_function 2 3# lldb test suite imports 4from lldbsuite.test.decorators import * 5from lldbsuite.test.lldbtest import TestBase 6 7# gdb-remote-specific imports 8import lldbgdbserverutils 9from gdbremote_testcase import GdbRemoteTestCaseBase 10 11import binascii 12import os 13import stat 14import struct 15import typing 16 17 18class GDBStat(typing.NamedTuple): 19 st_dev: int 20 st_ino: int 21 st_mode: int 22 st_nlink: int 23 st_uid: int 24 st_gid: int 25 st_rdev: int 26 st_size: int 27 st_blksize: int 28 st_blocks: int 29 st_atime: int 30 st_mtime: int 31 st_ctime: int 32 33 34def uint32_or_zero(x): 35 return x if x < 2**32 else 0 36 37 38def uint32_or_max(x): 39 return x if x < 2**32 else 2**32 - 1 40 41 42def uint32_trunc(x): 43 return x & (2**32 - 1) 44 45 46class TestGdbRemotePlatformFile(GdbRemoteTestCaseBase): 47 48 mydir = TestBase.compute_mydir(__file__) 49 50 @skipIfWindows 51 @add_test_categories(["llgs"]) 52 def test_platform_file_rdonly(self): 53 self.vFile_test(read=True) 54 55 @skipIfWindows 56 @add_test_categories(["llgs"]) 57 def test_platform_file_wronly(self): 58 self.vFile_test(write=True) 59 60 @skipIfWindows 61 @add_test_categories(["llgs"]) 62 def test_platform_file_rdwr(self): 63 self.vFile_test(read=True, write=True) 64 65 @skipIfWindows 66 @add_test_categories(["llgs"]) 67 def test_platform_file_wronly_append(self): 68 self.vFile_test(write=True, append=True) 69 70 @skipIfWindows 71 @add_test_categories(["llgs"]) 72 def test_platform_file_rdwr_append(self): 73 self.vFile_test(read=True, write=True, append=True) 74 75 @skipIfWindows 76 @add_test_categories(["llgs"]) 77 def test_platform_file_wronly_trunc(self): 78 self.vFile_test(write=True, trunc=True) 79 80 @skipIfWindows 81 @add_test_categories(["llgs"]) 82 def test_platform_file_rdwr_trunc(self): 83 self.vFile_test(read=True, write=True, trunc=True) 84 85 @skipIfWindows 86 @add_test_categories(["llgs"]) 87 def test_platform_file_wronly_creat(self): 88 self.vFile_test(write=True, creat=True) 89 90 @skipIfWindows 91 @add_test_categories(["llgs"]) 92 def test_platform_file_wronly_creat_excl(self): 93 self.vFile_test(write=True, creat=True, excl=True) 94 95 @skipIfWindows 96 @add_test_categories(["llgs"]) 97 def test_platform_file_wronly_fail(self): 98 server = self.connect_to_debug_monitor() 99 self.assertIsNotNone(server) 100 101 temp_path = self.getBuildArtifact("test") 102 self.assertFalse(os.path.exists(temp_path)) 103 104 # attempt to open the file without O_CREAT 105 self.do_handshake() 106 self.test_sequence.add_log_lines( 107 ["read packet: $vFile:open:%s,1,0#00" % ( 108 binascii.b2a_hex(temp_path.encode()).decode(),), 109 {"direction": "send", 110 "regex": r"^\$F-1,[0-9a-fA-F]+#[0-9a-fA-F]{2}$"}], 111 True) 112 self.expect_gdbremote_sequence() 113 114 @skipIfWindows 115 @add_test_categories(["llgs"]) 116 def test_platform_file_wronly_creat_excl_fail(self): 117 server = self.connect_to_debug_monitor() 118 self.assertIsNotNone(server) 119 120 temp_file = self.getBuildArtifact("test") 121 with open(temp_file, "wb"): 122 pass 123 124 # attempt to open the file with O_CREAT|O_EXCL 125 self.do_handshake() 126 self.test_sequence.add_log_lines( 127 ["read packet: $vFile:open:%s,a01,0#00" % ( 128 binascii.b2a_hex(temp_file.encode()).decode(),), 129 {"direction": "send", 130 "regex": r"^\$F-1,[0-9a-fA-F]+#[0-9a-fA-F]{2}$"}], 131 True) 132 self.expect_gdbremote_sequence() 133 134 @skipIfWindows 135 @add_test_categories(["llgs"]) 136 def test_platform_file_size(self): 137 server = self.connect_to_debug_monitor() 138 self.assertIsNotNone(server) 139 140 temp_path = self.getBuildArtifact("test") 141 test_data = b"test data of some length" 142 with open(temp_path, "wb") as temp_file: 143 temp_file.write(test_data) 144 145 self.do_handshake() 146 self.test_sequence.add_log_lines( 147 ["read packet: $vFile:size:%s#00" % ( 148 binascii.b2a_hex(temp_path.encode()).decode(),), 149 {"direction": "send", 150 "regex": r"^\$F([0-9a-fA-F]+)+#[0-9a-fA-F]{2}$", 151 "capture": {1: "size"}}], 152 True) 153 context = self.expect_gdbremote_sequence() 154 self.assertEqual(int(context["size"], 16), len(test_data)) 155 156 @skipIfWindows 157 @add_test_categories(["llgs"]) 158 def test_platform_file_mode(self): 159 server = self.connect_to_debug_monitor() 160 self.assertIsNotNone(server) 161 162 temp_path = self.getBuildArtifact("test") 163 test_mode = 0o751 164 165 with open(temp_path, "wb") as temp_file: 166 os.chmod(temp_file.fileno(), test_mode) 167 168 self.do_handshake() 169 self.test_sequence.add_log_lines( 170 ["read packet: $vFile:mode:%s#00" % ( 171 binascii.b2a_hex(temp_path.encode()).decode(),), 172 {"direction": "send", 173 "regex": r"^\$F([0-9a-fA-F]+)+#[0-9a-fA-F]{2}$", 174 "capture": {1: "mode"}}], 175 True) 176 context = self.expect_gdbremote_sequence() 177 self.assertEqual(int(context["mode"], 16), test_mode) 178 179 @skipIfWindows 180 @add_test_categories(["llgs"]) 181 def test_platform_file_exists(self): 182 server = self.connect_to_debug_monitor() 183 self.assertIsNotNone(server) 184 185 temp_path = self.getBuildArtifact("test") 186 with open(temp_path, "wb"): 187 pass 188 189 self.do_handshake() 190 self.test_sequence.add_log_lines( 191 ["read packet: $vFile:exists:%s#00" % ( 192 binascii.b2a_hex(temp_path.encode()).decode(),), 193 "send packet: $F,1#00"], 194 True) 195 self.expect_gdbremote_sequence() 196 197 @skipIfWindows 198 @add_test_categories(["llgs"]) 199 def test_platform_file_exists_not(self): 200 server = self.connect_to_debug_monitor() 201 self.assertIsNotNone(server) 202 203 test_path = self.getBuildArtifact("nonexist") 204 self.do_handshake() 205 self.test_sequence.add_log_lines( 206 ["read packet: $vFile:exists:%s#00" % ( 207 binascii.b2a_hex(test_path.encode()).decode(),), 208 "send packet: $F,0#00"], 209 True) 210 self.expect_gdbremote_sequence() 211 212 @skipIfWindows 213 @add_test_categories(["llgs"]) 214 def test_platform_file_fstat(self): 215 server = self.connect_to_debug_monitor() 216 self.assertIsNotNone(server) 217 218 with tempfile.NamedTemporaryFile() as temp_file: 219 temp_file.write(b"some test data for stat") 220 temp_file.flush() 221 222 self.do_handshake() 223 self.test_sequence.add_log_lines( 224 ["read packet: $vFile:open:%s,0,0#00" % ( 225 binascii.b2a_hex(temp_file.name.encode()).decode(),), 226 {"direction": "send", 227 "regex": r"^\$F([0-9a-fA-F]+)#[0-9a-fA-F]{2}$", 228 "capture": {1: "fd"}}], 229 True) 230 231 context = self.expect_gdbremote_sequence() 232 self.assertIsNotNone(context) 233 fd = int(context["fd"], 16) 234 235 self.reset_test_sequence() 236 self.test_sequence.add_log_lines( 237 ["read packet: $vFile:fstat:%x#00" % (fd,), 238 {"direction": "send", 239 "regex": r"^\$F([0-9a-fA-F]+);(.*)#[0-9a-fA-F]{2}$", 240 "capture": {1: "size", 2: "data"}}], 241 True) 242 context = self.expect_gdbremote_sequence() 243 self.assertEqual(int(context["size"], 16), 64) 244 # NB: we're using .encode() as a hack because the test suite 245 # is wrongly using (unicode) str instead of bytes 246 gdb_stat = GDBStat( 247 *struct.unpack(">IIIIIIIQQQIII", 248 self.decode_gdbremote_binary(context["data"]) 249 .encode("iso-8859-1"))) 250 sys_stat = os.fstat(temp_file.fileno()) 251 252 self.assertEqual(gdb_stat.st_dev, uint32_or_zero(sys_stat.st_dev)) 253 self.assertEqual(gdb_stat.st_ino, uint32_or_zero(sys_stat.st_ino)) 254 self.assertEqual(gdb_stat.st_mode, uint32_trunc(sys_stat.st_mode)) 255 self.assertEqual(gdb_stat.st_nlink, uint32_or_max(sys_stat.st_nlink)) 256 self.assertEqual(gdb_stat.st_uid, uint32_or_zero(sys_stat.st_uid)) 257 self.assertEqual(gdb_stat.st_gid, uint32_or_zero(sys_stat.st_gid)) 258 self.assertEqual(gdb_stat.st_rdev, uint32_or_zero(sys_stat.st_rdev)) 259 self.assertEqual(gdb_stat.st_size, sys_stat.st_size) 260 self.assertEqual(gdb_stat.st_blksize, sys_stat.st_blksize) 261 self.assertEqual(gdb_stat.st_blocks, sys_stat.st_blocks) 262 self.assertEqual(gdb_stat.st_atime, 263 uint32_or_zero(int(sys_stat.st_atime))) 264 self.assertEqual(gdb_stat.st_mtime, 265 uint32_or_zero(int(sys_stat.st_mtime))) 266 self.assertEqual(gdb_stat.st_ctime, 267 uint32_or_zero(int(sys_stat.st_ctime))) 268 269 self.reset_test_sequence() 270 self.test_sequence.add_log_lines( 271 ["read packet: $vFile:close:%x#00" % (fd,), 272 "send packet: $F0#00"], 273 True) 274 self.expect_gdbremote_sequence() 275 276 def expect_error(self): 277 self.test_sequence.add_log_lines( 278 [{"direction": "send", 279 "regex": r"^\$F-1,[0-9a-fA-F]+#[0-9a-fA-F]{2}$"}], 280 True) 281 self.expect_gdbremote_sequence() 282 283 def vFile_test(self, read=False, write=False, append=False, trunc=False, 284 creat=False, excl=False): 285 if read and write: 286 mode = 2 287 elif write: 288 mode = 1 289 else: # read 290 mode = 0 291 if append: 292 mode |= 8 293 if creat: 294 mode |= 0x200 295 if trunc: 296 mode |= 0x400 297 if excl: 298 mode |= 0x800 299 300 old_umask = os.umask(0o22) 301 try: 302 server = self.connect_to_debug_monitor() 303 finally: 304 os.umask(old_umask) 305 self.assertIsNotNone(server) 306 307 # create a temporary file with some data 308 temp_path = self.getBuildArtifact("test") 309 test_data = 'some test data longer than 16 bytes\n' 310 311 if creat: 312 self.assertFalse(os.path.exists(temp_path)) 313 else: 314 with open(temp_path, "wb") as temp_file: 315 temp_file.write(test_data.encode()) 316 317 # open the file for reading 318 self.do_handshake() 319 self.test_sequence.add_log_lines( 320 ["read packet: $vFile:open:%s,%x,1a0#00" % ( 321 binascii.b2a_hex(temp_path.encode()).decode(), 322 mode), 323 {"direction": "send", 324 "regex": r"^\$F([0-9a-fA-F]+)#[0-9a-fA-F]{2}$", 325 "capture": {1: "fd"}}], 326 True) 327 328 context = self.expect_gdbremote_sequence() 329 self.assertIsNotNone(context) 330 fd = int(context["fd"], 16) 331 332 # read data from the file 333 self.reset_test_sequence() 334 self.test_sequence.add_log_lines( 335 ["read packet: $vFile:pread:%x,11,10#00" % (fd,)], 336 True) 337 if read: 338 self.test_sequence.add_log_lines( 339 [{"direction": "send", 340 "regex": r"^\$F([0-9a-fA-F]+);(.*)#[0-9a-fA-F]{2}$", 341 "capture": {1: "size", 2: "data"}}], 342 True) 343 context = self.expect_gdbremote_sequence() 344 self.assertIsNotNone(context) 345 if trunc: 346 self.assertEqual(context["size"], "0") 347 self.assertEqual(context["data"], "") 348 else: 349 self.assertEqual(context["size"], "11") # hex 350 self.assertEqual(context["data"], test_data[0x10:0x10 + 0x11]) 351 else: 352 self.expect_error() 353 354 # another offset 355 if read and not trunc: 356 self.reset_test_sequence() 357 self.test_sequence.add_log_lines( 358 ["read packet: $vFile:pread:%x,6,3#00" % (fd,), 359 {"direction": "send", 360 "regex": r"^\$F([0-9a-fA-F]+);(.+)#[0-9a-fA-F]{2}$", 361 "capture": {1: "size", 2: "data"}}], 362 True) 363 context = self.expect_gdbremote_sequence() 364 self.assertIsNotNone(context) 365 self.assertEqual(context["size"], "6") # hex 366 self.assertEqual(context["data"], test_data[3:3 + 6]) 367 368 # write data to the file 369 self.reset_test_sequence() 370 self.test_sequence.add_log_lines( 371 ["read packet: $vFile:pwrite:%x,6,somedata#00" % (fd,)], 372 True) 373 if write: 374 self.test_sequence.add_log_lines( 375 ["send packet: $F8#00"], 376 True) 377 self.expect_gdbremote_sequence() 378 else: 379 self.expect_error() 380 381 # close the file 382 self.reset_test_sequence() 383 self.test_sequence.add_log_lines( 384 ["read packet: $vFile:close:%x#00" % (fd,), 385 "send packet: $F0#00"], 386 True) 387 self.expect_gdbremote_sequence() 388 389 if write: 390 # check if the data was actually written 391 with open(temp_path, "rb") as temp_file: 392 if creat: 393 self.assertEqual(os.fstat(temp_file.fileno()).st_mode & 0o7777, 394 0o640) 395 data = test_data.encode() 396 if trunc or creat: 397 data = b"\0" * 6 + b"somedata" 398 elif append: 399 data += b"somedata" 400 else: 401 data = data[:6] + b"somedata" + data[6 + 8:] 402 self.assertEqual(temp_file.read(), data) 403