498 lines · python
1# lldb test suite imports2from lldbsuite.test.decorators import *3from lldbsuite.test.lldbtest import TestBase4from lldbsuite.test import lldbutil5 6# gdb-remote-specific imports7import lldbgdbserverutils8from gdbremote_testcase import GdbRemoteTestCaseBase9 10import binascii11import os12import stat13import struct14import typing15 16 17class GDBStat(typing.NamedTuple):18 st_dev: int19 st_ino: int20 st_mode: int21 st_nlink: int22 st_uid: int23 st_gid: int24 st_rdev: int25 st_size: int26 st_blksize: int27 st_blocks: int28 st_atime: int29 st_mtime: int30 st_ctime: int31 32 33def uint32_or_zero(x):34 return x if x < 2**32 and x >= 0 else 035 36 37def uint32_or_max(x):38 return x if x < 2**32 and x >= 0 else 2**32 - 139 40 41def uint32_trunc(x):42 return x & (2**32 - 1)43 44 45class TestGdbRemotePlatformFile(GdbRemoteTestCaseBase):46 @skipIfWindows47 @add_test_categories(["llgs"])48 def test_platform_file_rdonly(self):49 self.vFile_test(read=True)50 51 @skipIfWindows52 @add_test_categories(["llgs"])53 def test_platform_file_wronly(self):54 self.vFile_test(write=True)55 56 @skipIfWindows57 @add_test_categories(["llgs"])58 def test_platform_file_rdwr(self):59 self.vFile_test(read=True, write=True)60 61 @skipIfWindows62 @add_test_categories(["llgs"])63 def test_platform_file_wronly_append(self):64 self.vFile_test(write=True, append=True)65 66 @skipIfWindows67 @add_test_categories(["llgs"])68 def test_platform_file_rdwr_append(self):69 self.vFile_test(read=True, write=True, append=True)70 71 @skipIfWindows72 @add_test_categories(["llgs"])73 def test_platform_file_wronly_trunc(self):74 self.vFile_test(write=True, trunc=True)75 76 @skipIfWindows77 @add_test_categories(["llgs"])78 def test_platform_file_rdwr_trunc(self):79 self.vFile_test(read=True, write=True, trunc=True)80 81 @skipIfWindows82 @add_test_categories(["llgs"])83 def test_platform_file_wronly_creat(self):84 self.vFile_test(write=True, creat=True)85 86 @skipIfWindows87 @add_test_categories(["llgs"])88 def test_platform_file_wronly_creat_excl(self):89 self.vFile_test(write=True, creat=True, excl=True)90 91 @skipIfWindows92 @add_test_categories(["llgs"])93 def test_platform_file_wronly_fail(self):94 server = self.connect_to_debug_monitor()95 self.assertIsNotNone(server)96 97 temp_path = self.getBuildArtifact("test")98 self.assertFalse(os.path.exists(temp_path))99 100 # attempt to open the file without O_CREAT101 self.do_handshake()102 self.test_sequence.add_log_lines(103 [104 "read packet: $vFile:open:%s,1,0#00"105 % (binascii.b2a_hex(temp_path.encode()).decode(),),106 {"direction": "send", "regex": r"^\$F-1,[0-9a-fA-F]+#[0-9a-fA-F]{2}$"},107 ],108 True,109 )110 self.expect_gdbremote_sequence()111 112 @skipIfWindows113 @add_test_categories(["llgs"])114 def test_platform_file_wronly_creat_excl_fail(self):115 server = self.connect_to_debug_monitor()116 self.assertIsNotNone(server)117 118 temp_file = self.getBuildArtifact("test")119 with open(temp_file, "wb"):120 pass121 temp_file = lldbutil.install_to_target(self, temp_file)122 123 # attempt to open the file with O_CREAT|O_EXCL124 self.do_handshake()125 self.test_sequence.add_log_lines(126 [127 "read packet: $vFile:open:%s,a01,0#00"128 % (binascii.b2a_hex(temp_file.encode()).decode(),),129 {"direction": "send", "regex": r"^\$F-1,[0-9a-fA-F]+#[0-9a-fA-F]{2}$"},130 ],131 True,132 )133 self.expect_gdbremote_sequence()134 135 @skipIfWindows136 @add_test_categories(["llgs"])137 def test_platform_file_size(self):138 server = self.connect_to_debug_monitor()139 self.assertIsNotNone(server)140 141 temp_path = self.getBuildArtifact("test")142 test_data = b"test data of some length"143 with open(temp_path, "wb") as temp_file:144 temp_file.write(test_data)145 temp_path = lldbutil.install_to_target(self, temp_path)146 147 self.do_handshake()148 self.test_sequence.add_log_lines(149 [150 "read packet: $vFile:size:%s#00"151 % (binascii.b2a_hex(temp_path.encode()).decode(),),152 {153 "direction": "send",154 "regex": r"^\$F([0-9a-fA-F]+)+#[0-9a-fA-F]{2}$",155 "capture": {1: "size"},156 },157 ],158 True,159 )160 context = self.expect_gdbremote_sequence()161 self.assertEqual(int(context["size"], 16), len(test_data))162 163 @skipIfWindows164 @add_test_categories(["llgs"])165 def test_platform_file_mode(self):166 server = self.connect_to_debug_monitor()167 self.assertIsNotNone(server)168 169 temp_path = self.getBuildArtifact("test")170 test_mode = 0o751171 172 with open(temp_path, "wb") as temp_file:173 if lldbplatformutil.getHostPlatform() == "windows":174 test_mode = 0o700175 else:176 os.chmod(temp_file.fileno(), test_mode)177 temp_path = lldbutil.install_to_target(self, temp_path)178 179 self.do_handshake()180 self.test_sequence.add_log_lines(181 [182 "read packet: $vFile:mode:%s#00"183 % (binascii.b2a_hex(temp_path.encode()).decode(),),184 {185 "direction": "send",186 "regex": r"^\$F([0-9a-fA-F]+)+#[0-9a-fA-F]{2}$",187 "capture": {1: "mode"},188 },189 ],190 True,191 )192 context = self.expect_gdbremote_sequence()193 self.assertEqual(int(context["mode"], 16), test_mode)194 195 @skipIfWindows196 @add_test_categories(["llgs"])197 def test_platform_file_mode_fail(self):198 server = self.connect_to_debug_monitor()199 self.assertIsNotNone(server)200 201 temp_path = self.getBuildArtifact("nonexist")202 203 self.do_handshake()204 self.test_sequence.add_log_lines(205 [206 "read packet: $vFile:mode:%s#00"207 % (binascii.b2a_hex(temp_path.encode()).decode(),),208 {"direction": "send", "regex": r"^\$F-1,0*2+#[0-9a-fA-F]{2}$"},209 ],210 True,211 )212 self.expect_gdbremote_sequence()213 214 @skipIfWindows215 @add_test_categories(["llgs"])216 def test_platform_file_exists(self):217 server = self.connect_to_debug_monitor()218 self.assertIsNotNone(server)219 220 temp_path = self.getBuildArtifact("test")221 with open(temp_path, "wb"):222 pass223 temp_path = lldbutil.install_to_target(self, temp_path)224 225 self.do_handshake()226 self.test_sequence.add_log_lines(227 [228 "read packet: $vFile:exists:%s#00"229 % (binascii.b2a_hex(temp_path.encode()).decode(),),230 "send packet: $F,1#00",231 ],232 True,233 )234 self.expect_gdbremote_sequence()235 236 @skipIfWindows237 @add_test_categories(["llgs"])238 def test_platform_file_exists_not(self):239 server = self.connect_to_debug_monitor()240 self.assertIsNotNone(server)241 242 test_path = self.getBuildArtifact("nonexist")243 self.do_handshake()244 self.test_sequence.add_log_lines(245 [246 "read packet: $vFile:exists:%s#00"247 % (binascii.b2a_hex(test_path.encode()).decode(),),248 "send packet: $F,0#00",249 ],250 True,251 )252 self.expect_gdbremote_sequence()253 254 @skipIfWindows255 # FIXME: lldb.remote_platform.Install() cannot copy opened temp file on Windows.256 # It is possible to use tempfile.NamedTemporaryFile(..., delete=False) and257 # delete the temp file manually at the end.258 @skipIf(hostoslist=["windows"])259 @add_test_categories(["llgs"])260 def test_platform_file_fstat(self):261 server = self.connect_to_debug_monitor()262 self.assertIsNotNone(server)263 264 with tempfile.NamedTemporaryFile() as temp_file:265 temp_file.write(b"some test data for stat")266 temp_file.flush()267 temp_path = lldbutil.install_to_target(self, temp_file.name)268 269 self.do_handshake()270 self.test_sequence.add_log_lines(271 [272 "read packet: $vFile:open:%s,0,0#00"273 % (binascii.b2a_hex(temp_path.encode()).decode(),),274 {275 "direction": "send",276 "regex": r"^\$F([0-9a-fA-F]+)#[0-9a-fA-F]{2}$",277 "capture": {1: "fd"},278 },279 ],280 True,281 )282 283 context = self.expect_gdbremote_sequence()284 self.assertIsNotNone(context)285 fd = int(context["fd"], 16)286 287 self.reset_test_sequence()288 self.test_sequence.add_log_lines(289 [290 "read packet: $vFile:fstat:%x#00" % (fd,),291 {292 "direction": "send",293 "regex": r"^\$F([0-9a-fA-F]+);(.*)#[0-9a-fA-F]{2}$",294 "capture": {1: "size", 2: "data"},295 },296 ],297 True,298 )299 context = self.expect_gdbremote_sequence()300 self.assertEqual(int(context["size"], 16), 64)301 # NB: we're using .encode() as a hack because the test suite302 # is wrongly using (unicode) str instead of bytes303 gdb_stat = GDBStat(304 *struct.unpack(305 ">IIIIIIIQQQIII",306 self.decode_gdbremote_binary(context["data"]).encode("iso-8859-1"),307 )308 )309 sys_stat = os.fstat(temp_file.fileno())310 311 self.assertEqual(gdb_stat.st_mode, uint32_trunc(sys_stat.st_mode))312 self.assertEqual(gdb_stat.st_nlink, uint32_or_max(sys_stat.st_nlink))313 self.assertEqual(gdb_stat.st_rdev, uint32_or_zero(sys_stat.st_rdev))314 self.assertEqual(gdb_stat.st_size, sys_stat.st_size)315 if not lldb.remote_platform:316 self.assertEqual(gdb_stat.st_dev, uint32_or_zero(sys_stat.st_dev))317 self.assertEqual(gdb_stat.st_ino, uint32_or_zero(sys_stat.st_ino))318 self.assertEqual(gdb_stat.st_uid, uint32_or_zero(sys_stat.st_uid))319 self.assertEqual(gdb_stat.st_gid, uint32_or_zero(sys_stat.st_gid))320 self.assertEqual(gdb_stat.st_blksize, sys_stat.st_blksize)321 self.assertEqual(gdb_stat.st_blocks, sys_stat.st_blocks)322 self.assertEqual(323 gdb_stat.st_atime, uint32_or_zero(int(sys_stat.st_atime))324 )325 self.assertEqual(326 gdb_stat.st_mtime, uint32_or_zero(int(sys_stat.st_mtime))327 )328 self.assertEqual(329 gdb_stat.st_ctime, uint32_or_zero(int(sys_stat.st_ctime))330 )331 332 self.reset_test_sequence()333 self.test_sequence.add_log_lines(334 ["read packet: $vFile:close:%x#00" % (fd,), "send packet: $F0#00"], True335 )336 self.expect_gdbremote_sequence()337 338 def expect_error(self):339 self.test_sequence.add_log_lines(340 [{"direction": "send", "regex": r"^\$F-1,[0-9a-fA-F]+#[0-9a-fA-F]{2}$"}],341 True,342 )343 self.expect_gdbremote_sequence()344 345 def vFile_test(346 self,347 read=False,348 write=False,349 append=False,350 trunc=False,351 creat=False,352 excl=False,353 ):354 if read and write:355 mode = 2356 elif write:357 mode = 1358 else: # read359 mode = 0360 if append:361 mode |= 8362 if creat:363 mode |= 0x200364 if trunc:365 mode |= 0x400366 if excl:367 mode |= 0x800368 369 old_umask = os.umask(0o22)370 try:371 server = self.connect_to_debug_monitor()372 finally:373 os.umask(old_umask)374 self.assertIsNotNone(server)375 376 # create a temporary file with some data377 temp_path = self.getBuildArtifact("test")378 test_data = "some test data longer than 16 bytes\n"379 380 if creat:381 self.assertFalse(os.path.exists(temp_path))382 if lldb.remote_platform:383 temp_path = lldbutil.append_to_process_working_directory(self, "test")384 else:385 with open(temp_path, "wb") as temp_file:386 temp_file.write(test_data.encode())387 temp_path = lldbutil.install_to_target(self, temp_path)388 389 # open the file for reading390 self.do_handshake()391 self.test_sequence.add_log_lines(392 [393 "read packet: $vFile:open:%s,%x,1a0#00"394 % (binascii.b2a_hex(temp_path.encode()).decode(), mode),395 {396 "direction": "send",397 "regex": r"^\$F([0-9a-fA-F]+)#[0-9a-fA-F]{2}$",398 "capture": {1: "fd"},399 },400 ],401 True,402 )403 404 context = self.expect_gdbremote_sequence()405 self.assertIsNotNone(context)406 fd = int(context["fd"], 16)407 408 # read data from the file409 self.reset_test_sequence()410 self.test_sequence.add_log_lines(411 ["read packet: $vFile:pread:%x,11,10#00" % (fd,)], True412 )413 if read:414 self.test_sequence.add_log_lines(415 [416 {417 "direction": "send",418 "regex": r"^\$F([0-9a-fA-F]+);(.*)#[0-9a-fA-F]{2}$",419 "capture": {1: "size", 2: "data"},420 }421 ],422 True,423 )424 context = self.expect_gdbremote_sequence()425 self.assertIsNotNone(context)426 if trunc:427 self.assertEqual(context["size"], "0")428 self.assertEqual(context["data"], "")429 else:430 self.assertEqual(context["size"], "11") # hex431 self.assertEqual(context["data"], test_data[0x10 : 0x10 + 0x11])432 else:433 self.expect_error()434 435 # another offset436 if read and not trunc:437 self.reset_test_sequence()438 self.test_sequence.add_log_lines(439 [440 "read packet: $vFile:pread:%x,6,3#00" % (fd,),441 {442 "direction": "send",443 "regex": r"^\$F([0-9a-fA-F]+);(.+)#[0-9a-fA-F]{2}$",444 "capture": {1: "size", 2: "data"},445 },446 ],447 True,448 )449 context = self.expect_gdbremote_sequence()450 self.assertIsNotNone(context)451 self.assertEqual(context["size"], "6") # hex452 self.assertEqual(context["data"], test_data[3 : 3 + 6])453 454 # write data to the file455 self.reset_test_sequence()456 self.test_sequence.add_log_lines(457 ["read packet: $vFile:pwrite:%x,6,somedata#00" % (fd,)], True458 )459 if write:460 self.test_sequence.add_log_lines(["send packet: $F8#00"], True)461 self.expect_gdbremote_sequence()462 else:463 self.expect_error()464 465 # close the file466 self.reset_test_sequence()467 self.test_sequence.add_log_lines(468 ["read packet: $vFile:close:%x#00" % (fd,), "send packet: $F0#00"], True469 )470 self.expect_gdbremote_sequence()471 472 if write:473 # check if the data was actually written474 if lldb.remote_platform:475 local_path = self.getBuildArtifact("file_from_target")476 error = lldb.remote_platform.Get(477 lldb.SBFileSpec(temp_path, False), lldb.SBFileSpec(local_path, True)478 )479 self.assertTrue(480 error.Success(),481 "Reading file {0} failed: {1}".format(temp_path, error),482 )483 temp_path = local_path484 485 with open(temp_path, "rb") as temp_file:486 if creat and lldbplatformutil.getHostPlatform() != "windows":487 self.assertEqual(488 os.fstat(temp_file.fileno()).st_mode & 0o7777, 0o640489 )490 data = test_data.encode()491 if trunc or creat:492 data = b"\0" * 6 + b"somedata"493 elif append:494 data += b"somedata"495 else:496 data = data[:6] + b"somedata" + data[6 + 8 :]497 self.assertEqual(temp_file.read(), data)498