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_mode_fail(self): 182 server = self.connect_to_debug_monitor() 183 self.assertIsNotNone(server) 184 185 temp_path = self.getBuildArtifact("nonexist") 186 187 self.do_handshake() 188 self.test_sequence.add_log_lines( 189 ["read packet: $vFile:mode:%s#00" % ( 190 binascii.b2a_hex(temp_path.encode()).decode(),), 191 {"direction": "send", 192 "regex": r"^\$F-1,0*2+#[0-9a-fA-F]{2}$"}], 193 True) 194 self.expect_gdbremote_sequence() 195 196 @skipIfWindows 197 @add_test_categories(["llgs"]) 198 def test_platform_file_exists(self): 199 server = self.connect_to_debug_monitor() 200 self.assertIsNotNone(server) 201 202 temp_path = self.getBuildArtifact("test") 203 with open(temp_path, "wb"): 204 pass 205 206 self.do_handshake() 207 self.test_sequence.add_log_lines( 208 ["read packet: $vFile:exists:%s#00" % ( 209 binascii.b2a_hex(temp_path.encode()).decode(),), 210 "send packet: $F,1#00"], 211 True) 212 self.expect_gdbremote_sequence() 213 214 @skipIfWindows 215 @add_test_categories(["llgs"]) 216 def test_platform_file_exists_not(self): 217 server = self.connect_to_debug_monitor() 218 self.assertIsNotNone(server) 219 220 test_path = self.getBuildArtifact("nonexist") 221 self.do_handshake() 222 self.test_sequence.add_log_lines( 223 ["read packet: $vFile:exists:%s#00" % ( 224 binascii.b2a_hex(test_path.encode()).decode(),), 225 "send packet: $F,0#00"], 226 True) 227 self.expect_gdbremote_sequence() 228 229 @skipIfWindows 230 @add_test_categories(["llgs"]) 231 def test_platform_file_fstat(self): 232 server = self.connect_to_debug_monitor() 233 self.assertIsNotNone(server) 234 235 with tempfile.NamedTemporaryFile() as temp_file: 236 temp_file.write(b"some test data for stat") 237 temp_file.flush() 238 239 self.do_handshake() 240 self.test_sequence.add_log_lines( 241 ["read packet: $vFile:open:%s,0,0#00" % ( 242 binascii.b2a_hex(temp_file.name.encode()).decode(),), 243 {"direction": "send", 244 "regex": r"^\$F([0-9a-fA-F]+)#[0-9a-fA-F]{2}$", 245 "capture": {1: "fd"}}], 246 True) 247 248 context = self.expect_gdbremote_sequence() 249 self.assertIsNotNone(context) 250 fd = int(context["fd"], 16) 251 252 self.reset_test_sequence() 253 self.test_sequence.add_log_lines( 254 ["read packet: $vFile:fstat:%x#00" % (fd,), 255 {"direction": "send", 256 "regex": r"^\$F([0-9a-fA-F]+);(.*)#[0-9a-fA-F]{2}$", 257 "capture": {1: "size", 2: "data"}}], 258 True) 259 context = self.expect_gdbremote_sequence() 260 self.assertEqual(int(context["size"], 16), 64) 261 # NB: we're using .encode() as a hack because the test suite 262 # is wrongly using (unicode) str instead of bytes 263 gdb_stat = GDBStat( 264 *struct.unpack(">IIIIIIIQQQIII", 265 self.decode_gdbremote_binary(context["data"]) 266 .encode("iso-8859-1"))) 267 sys_stat = os.fstat(temp_file.fileno()) 268 269 self.assertEqual(gdb_stat.st_dev, uint32_or_zero(sys_stat.st_dev)) 270 self.assertEqual(gdb_stat.st_ino, uint32_or_zero(sys_stat.st_ino)) 271 self.assertEqual(gdb_stat.st_mode, uint32_trunc(sys_stat.st_mode)) 272 self.assertEqual(gdb_stat.st_nlink, uint32_or_max(sys_stat.st_nlink)) 273 self.assertEqual(gdb_stat.st_uid, uint32_or_zero(sys_stat.st_uid)) 274 self.assertEqual(gdb_stat.st_gid, uint32_or_zero(sys_stat.st_gid)) 275 self.assertEqual(gdb_stat.st_rdev, uint32_or_zero(sys_stat.st_rdev)) 276 self.assertEqual(gdb_stat.st_size, sys_stat.st_size) 277 self.assertEqual(gdb_stat.st_blksize, sys_stat.st_blksize) 278 self.assertEqual(gdb_stat.st_blocks, sys_stat.st_blocks) 279 self.assertEqual(gdb_stat.st_atime, 280 uint32_or_zero(int(sys_stat.st_atime))) 281 self.assertEqual(gdb_stat.st_mtime, 282 uint32_or_zero(int(sys_stat.st_mtime))) 283 self.assertEqual(gdb_stat.st_ctime, 284 uint32_or_zero(int(sys_stat.st_ctime))) 285 286 self.reset_test_sequence() 287 self.test_sequence.add_log_lines( 288 ["read packet: $vFile:close:%x#00" % (fd,), 289 "send packet: $F0#00"], 290 True) 291 self.expect_gdbremote_sequence() 292 293 def expect_error(self): 294 self.test_sequence.add_log_lines( 295 [{"direction": "send", 296 "regex": r"^\$F-1,[0-9a-fA-F]+#[0-9a-fA-F]{2}$"}], 297 True) 298 self.expect_gdbremote_sequence() 299 300 def vFile_test(self, read=False, write=False, append=False, trunc=False, 301 creat=False, excl=False): 302 if read and write: 303 mode = 2 304 elif write: 305 mode = 1 306 else: # read 307 mode = 0 308 if append: 309 mode |= 8 310 if creat: 311 mode |= 0x200 312 if trunc: 313 mode |= 0x400 314 if excl: 315 mode |= 0x800 316 317 old_umask = os.umask(0o22) 318 try: 319 server = self.connect_to_debug_monitor() 320 finally: 321 os.umask(old_umask) 322 self.assertIsNotNone(server) 323 324 # create a temporary file with some data 325 temp_path = self.getBuildArtifact("test") 326 test_data = 'some test data longer than 16 bytes\n' 327 328 if creat: 329 self.assertFalse(os.path.exists(temp_path)) 330 else: 331 with open(temp_path, "wb") as temp_file: 332 temp_file.write(test_data.encode()) 333 334 # open the file for reading 335 self.do_handshake() 336 self.test_sequence.add_log_lines( 337 ["read packet: $vFile:open:%s,%x,1a0#00" % ( 338 binascii.b2a_hex(temp_path.encode()).decode(), 339 mode), 340 {"direction": "send", 341 "regex": r"^\$F([0-9a-fA-F]+)#[0-9a-fA-F]{2}$", 342 "capture": {1: "fd"}}], 343 True) 344 345 context = self.expect_gdbremote_sequence() 346 self.assertIsNotNone(context) 347 fd = int(context["fd"], 16) 348 349 # read data from the file 350 self.reset_test_sequence() 351 self.test_sequence.add_log_lines( 352 ["read packet: $vFile:pread:%x,11,10#00" % (fd,)], 353 True) 354 if read: 355 self.test_sequence.add_log_lines( 356 [{"direction": "send", 357 "regex": r"^\$F([0-9a-fA-F]+);(.*)#[0-9a-fA-F]{2}$", 358 "capture": {1: "size", 2: "data"}}], 359 True) 360 context = self.expect_gdbremote_sequence() 361 self.assertIsNotNone(context) 362 if trunc: 363 self.assertEqual(context["size"], "0") 364 self.assertEqual(context["data"], "") 365 else: 366 self.assertEqual(context["size"], "11") # hex 367 self.assertEqual(context["data"], test_data[0x10:0x10 + 0x11]) 368 else: 369 self.expect_error() 370 371 # another offset 372 if read and not trunc: 373 self.reset_test_sequence() 374 self.test_sequence.add_log_lines( 375 ["read packet: $vFile:pread:%x,6,3#00" % (fd,), 376 {"direction": "send", 377 "regex": r"^\$F([0-9a-fA-F]+);(.+)#[0-9a-fA-F]{2}$", 378 "capture": {1: "size", 2: "data"}}], 379 True) 380 context = self.expect_gdbremote_sequence() 381 self.assertIsNotNone(context) 382 self.assertEqual(context["size"], "6") # hex 383 self.assertEqual(context["data"], test_data[3:3 + 6]) 384 385 # write data to the file 386 self.reset_test_sequence() 387 self.test_sequence.add_log_lines( 388 ["read packet: $vFile:pwrite:%x,6,somedata#00" % (fd,)], 389 True) 390 if write: 391 self.test_sequence.add_log_lines( 392 ["send packet: $F8#00"], 393 True) 394 self.expect_gdbremote_sequence() 395 else: 396 self.expect_error() 397 398 # close the file 399 self.reset_test_sequence() 400 self.test_sequence.add_log_lines( 401 ["read packet: $vFile:close:%x#00" % (fd,), 402 "send packet: $F0#00"], 403 True) 404 self.expect_gdbremote_sequence() 405 406 if write: 407 # check if the data was actually written 408 with open(temp_path, "rb") as temp_file: 409 if creat: 410 self.assertEqual(os.fstat(temp_file.fileno()).st_mode & 0o7777, 411 0o640) 412 data = test_data.encode() 413 if trunc or creat: 414 data = b"\0" * 6 + b"somedata" 415 elif append: 416 data += b"somedata" 417 else: 418 data = data[:6] + b"somedata" + data[6 + 8:] 419 self.assertEqual(temp_file.read(), data) 420