19929cfbcSMichał Górnyfrom __future__ import print_function
29929cfbcSMichał Górny
39929cfbcSMichał Górny# lldb test suite imports
49929cfbcSMichał Górnyfrom lldbsuite.test.decorators import *
59929cfbcSMichał Górnyfrom lldbsuite.test.lldbtest import TestBase
69929cfbcSMichał Górny
79929cfbcSMichał Górny# gdb-remote-specific imports
89929cfbcSMichał Górnyimport lldbgdbserverutils
99929cfbcSMichał Górnyfrom gdbremote_testcase import GdbRemoteTestCaseBase
109929cfbcSMichał Górny
119929cfbcSMichał Górnyimport binascii
12a1097d31SMichał Górnyimport os
139929cfbcSMichał Górnyimport stat
14a1097d31SMichał Górnyimport struct
15a1097d31SMichał Górnyimport typing
16a1097d31SMichał Górny
17a1097d31SMichał Górny
18a1097d31SMichał Górnyclass GDBStat(typing.NamedTuple):
19a1097d31SMichał Górny    st_dev: int
20a1097d31SMichał Górny    st_ino: int
21a1097d31SMichał Górny    st_mode: int
22a1097d31SMichał Górny    st_nlink: int
23a1097d31SMichał Górny    st_uid: int
24a1097d31SMichał Górny    st_gid: int
25a1097d31SMichał Górny    st_rdev: int
26a1097d31SMichał Górny    st_size: int
27a1097d31SMichał Górny    st_blksize: int
28a1097d31SMichał Górny    st_blocks: int
29a1097d31SMichał Górny    st_atime: int
30a1097d31SMichał Górny    st_mtime: int
31a1097d31SMichał Górny    st_ctime: int
32a1097d31SMichał Górny
33a1097d31SMichał Górny
34a1097d31SMichał Górnydef uint32_or_zero(x):
35*d3292c4bSMichał Górny    return x if x < 2**32 and x >= 0 else 0
36a1097d31SMichał Górny
37a1097d31SMichał Górny
38a1097d31SMichał Górnydef uint32_or_max(x):
39*d3292c4bSMichał Górny    return x if x < 2**32 and x >= 0 else 2**32 - 1
40a1097d31SMichał Górny
41a1097d31SMichał Górny
42a1097d31SMichał Górnydef uint32_trunc(x):
43a1097d31SMichał Górny    return x & (2**32 - 1)
449929cfbcSMichał Górny
459929cfbcSMichał Górny
469929cfbcSMichał Górnyclass TestGdbRemotePlatformFile(GdbRemoteTestCaseBase):
479929cfbcSMichał Górny
4827b238afSMichał Górny    @skipIfWindows
4952d89d26SMichał Górny    @add_test_categories(["llgs"])
509929cfbcSMichał Górny    def test_platform_file_rdonly(self):
519929cfbcSMichał Górny        self.vFile_test(read=True)
529929cfbcSMichał Górny
5327b238afSMichał Górny    @skipIfWindows
5452d89d26SMichał Górny    @add_test_categories(["llgs"])
559929cfbcSMichał Górny    def test_platform_file_wronly(self):
569929cfbcSMichał Górny        self.vFile_test(write=True)
579929cfbcSMichał Górny
5827b238afSMichał Górny    @skipIfWindows
5952d89d26SMichał Górny    @add_test_categories(["llgs"])
609929cfbcSMichał Górny    def test_platform_file_rdwr(self):
619929cfbcSMichał Górny        self.vFile_test(read=True, write=True)
629929cfbcSMichał Górny
6327b238afSMichał Górny    @skipIfWindows
6452d89d26SMichał Górny    @add_test_categories(["llgs"])
659929cfbcSMichał Górny    def test_platform_file_wronly_append(self):
669929cfbcSMichał Górny        self.vFile_test(write=True, append=True)
679929cfbcSMichał Górny
6827b238afSMichał Górny    @skipIfWindows
6952d89d26SMichał Górny    @add_test_categories(["llgs"])
709929cfbcSMichał Górny    def test_platform_file_rdwr_append(self):
719929cfbcSMichał Górny        self.vFile_test(read=True, write=True, append=True)
729929cfbcSMichał Górny
7327b238afSMichał Górny    @skipIfWindows
7452d89d26SMichał Górny    @add_test_categories(["llgs"])
759929cfbcSMichał Górny    def test_platform_file_wronly_trunc(self):
769929cfbcSMichał Górny        self.vFile_test(write=True, trunc=True)
779929cfbcSMichał Górny
7827b238afSMichał Górny    @skipIfWindows
7952d89d26SMichał Górny    @add_test_categories(["llgs"])
809929cfbcSMichał Górny    def test_platform_file_rdwr_trunc(self):
819929cfbcSMichał Górny        self.vFile_test(read=True, write=True, trunc=True)
829929cfbcSMichał Górny
8327b238afSMichał Górny    @skipIfWindows
8452d89d26SMichał Górny    @add_test_categories(["llgs"])
859929cfbcSMichał Górny    def test_platform_file_wronly_creat(self):
869929cfbcSMichał Górny        self.vFile_test(write=True, creat=True)
879929cfbcSMichał Górny
8827b238afSMichał Górny    @skipIfWindows
8952d89d26SMichał Górny    @add_test_categories(["llgs"])
909929cfbcSMichał Górny    def test_platform_file_wronly_creat_excl(self):
919929cfbcSMichał Górny        self.vFile_test(write=True, creat=True, excl=True)
929929cfbcSMichał Górny
9327b238afSMichał Górny    @skipIfWindows
9452d89d26SMichał Górny    @add_test_categories(["llgs"])
959929cfbcSMichał Górny    def test_platform_file_wronly_fail(self):
969929cfbcSMichał Górny        server = self.connect_to_debug_monitor()
979929cfbcSMichał Górny        self.assertIsNotNone(server)
989929cfbcSMichał Górny
998872c9d1SMichał Górny        temp_path = self.getBuildArtifact("test")
1009929cfbcSMichał Górny        self.assertFalse(os.path.exists(temp_path))
1019929cfbcSMichał Górny
1029929cfbcSMichał Górny        # attempt to open the file without O_CREAT
1039929cfbcSMichał Górny        self.do_handshake()
1049929cfbcSMichał Górny        self.test_sequence.add_log_lines(
1059929cfbcSMichał Górny            ["read packet: $vFile:open:%s,1,0#00" % (
1069929cfbcSMichał Górny                binascii.b2a_hex(temp_path.encode()).decode(),),
1079929cfbcSMichał Górny             {"direction": "send",
1089929cfbcSMichał Górny             "regex": r"^\$F-1,[0-9a-fA-F]+#[0-9a-fA-F]{2}$"}],
1099929cfbcSMichał Górny            True)
1109929cfbcSMichał Górny        self.expect_gdbremote_sequence()
1119929cfbcSMichał Górny
11227b238afSMichał Górny    @skipIfWindows
11352d89d26SMichał Górny    @add_test_categories(["llgs"])
1149929cfbcSMichał Górny    def test_platform_file_wronly_creat_excl_fail(self):
1159929cfbcSMichał Górny        server = self.connect_to_debug_monitor()
1169929cfbcSMichał Górny        self.assertIsNotNone(server)
1179929cfbcSMichał Górny
1188872c9d1SMichał Górny        temp_file = self.getBuildArtifact("test")
1198872c9d1SMichał Górny        with open(temp_file, "wb"):
1208872c9d1SMichał Górny            pass
1218872c9d1SMichał Górny
1229929cfbcSMichał Górny        # attempt to open the file with O_CREAT|O_EXCL
1239929cfbcSMichał Górny        self.do_handshake()
1249929cfbcSMichał Górny        self.test_sequence.add_log_lines(
1259929cfbcSMichał Górny            ["read packet: $vFile:open:%s,a01,0#00" % (
1268872c9d1SMichał Górny                binascii.b2a_hex(temp_file.encode()).decode(),),
1279929cfbcSMichał Górny             {"direction": "send",
1289929cfbcSMichał Górny             "regex": r"^\$F-1,[0-9a-fA-F]+#[0-9a-fA-F]{2}$"}],
1299929cfbcSMichał Górny            True)
1309929cfbcSMichał Górny        self.expect_gdbremote_sequence()
1319929cfbcSMichał Górny
1328872c9d1SMichał Górny    @skipIfWindows
1338872c9d1SMichał Górny    @add_test_categories(["llgs"])
1348872c9d1SMichał Górny    def test_platform_file_size(self):
1358872c9d1SMichał Górny        server = self.connect_to_debug_monitor()
1368872c9d1SMichał Górny        self.assertIsNotNone(server)
1378872c9d1SMichał Górny
1388872c9d1SMichał Górny        temp_path = self.getBuildArtifact("test")
1398872c9d1SMichał Górny        test_data = b"test data of some length"
1408872c9d1SMichał Górny        with open(temp_path, "wb") as temp_file:
1418872c9d1SMichał Górny            temp_file.write(test_data)
1428872c9d1SMichał Górny
1438872c9d1SMichał Górny        self.do_handshake()
1448872c9d1SMichał Górny        self.test_sequence.add_log_lines(
1458872c9d1SMichał Górny            ["read packet: $vFile:size:%s#00" % (
1468872c9d1SMichał Górny                binascii.b2a_hex(temp_path.encode()).decode(),),
1478872c9d1SMichał Górny             {"direction": "send",
1488872c9d1SMichał Górny             "regex": r"^\$F([0-9a-fA-F]+)+#[0-9a-fA-F]{2}$",
1498872c9d1SMichał Górny             "capture": {1: "size"}}],
1508872c9d1SMichał Górny            True)
1518872c9d1SMichał Górny        context = self.expect_gdbremote_sequence()
1528872c9d1SMichał Górny        self.assertEqual(int(context["size"], 16), len(test_data))
1538872c9d1SMichał Górny
1548872c9d1SMichał Górny    @skipIfWindows
1558872c9d1SMichał Górny    @add_test_categories(["llgs"])
1568872c9d1SMichał Górny    def test_platform_file_mode(self):
1578872c9d1SMichał Górny        server = self.connect_to_debug_monitor()
1588872c9d1SMichał Górny        self.assertIsNotNone(server)
1598872c9d1SMichał Górny
1608872c9d1SMichał Górny        temp_path = self.getBuildArtifact("test")
1618872c9d1SMichał Górny        test_mode = 0o751
1628872c9d1SMichał Górny
1638872c9d1SMichał Górny        with open(temp_path, "wb") as temp_file:
1648872c9d1SMichał Górny            os.chmod(temp_file.fileno(), test_mode)
1658872c9d1SMichał Górny
1668872c9d1SMichał Górny        self.do_handshake()
1678872c9d1SMichał Górny        self.test_sequence.add_log_lines(
1688872c9d1SMichał Górny            ["read packet: $vFile:mode:%s#00" % (
1698872c9d1SMichał Górny                binascii.b2a_hex(temp_path.encode()).decode(),),
1708872c9d1SMichał Górny             {"direction": "send",
1718872c9d1SMichał Górny             "regex": r"^\$F([0-9a-fA-F]+)+#[0-9a-fA-F]{2}$",
1728872c9d1SMichał Górny             "capture": {1: "mode"}}],
1738872c9d1SMichał Górny            True)
1748872c9d1SMichał Górny        context = self.expect_gdbremote_sequence()
1758872c9d1SMichał Górny        self.assertEqual(int(context["mode"], 16), test_mode)
1768872c9d1SMichał Górny
1778872c9d1SMichał Górny    @skipIfWindows
1788872c9d1SMichał Górny    @add_test_categories(["llgs"])
179dbb0c14dSMichał Górny    def test_platform_file_mode_fail(self):
180dbb0c14dSMichał Górny        server = self.connect_to_debug_monitor()
181dbb0c14dSMichał Górny        self.assertIsNotNone(server)
182dbb0c14dSMichał Górny
183dbb0c14dSMichał Górny        temp_path = self.getBuildArtifact("nonexist")
184dbb0c14dSMichał Górny
185dbb0c14dSMichał Górny        self.do_handshake()
186dbb0c14dSMichał Górny        self.test_sequence.add_log_lines(
187dbb0c14dSMichał Górny            ["read packet: $vFile:mode:%s#00" % (
188dbb0c14dSMichał Górny                binascii.b2a_hex(temp_path.encode()).decode(),),
189dbb0c14dSMichał Górny             {"direction": "send",
190dbb0c14dSMichał Górny             "regex": r"^\$F-1,0*2+#[0-9a-fA-F]{2}$"}],
191dbb0c14dSMichał Górny            True)
192dbb0c14dSMichał Górny        self.expect_gdbremote_sequence()
193dbb0c14dSMichał Górny
194dbb0c14dSMichał Górny    @skipIfWindows
195dbb0c14dSMichał Górny    @add_test_categories(["llgs"])
1968872c9d1SMichał Górny    def test_platform_file_exists(self):
1978872c9d1SMichał Górny        server = self.connect_to_debug_monitor()
1988872c9d1SMichał Górny        self.assertIsNotNone(server)
1998872c9d1SMichał Górny
2008872c9d1SMichał Górny        temp_path = self.getBuildArtifact("test")
2018872c9d1SMichał Górny        with open(temp_path, "wb"):
2028872c9d1SMichał Górny            pass
2038872c9d1SMichał Górny
2048872c9d1SMichał Górny        self.do_handshake()
2058872c9d1SMichał Górny        self.test_sequence.add_log_lines(
2068872c9d1SMichał Górny            ["read packet: $vFile:exists:%s#00" % (
2078872c9d1SMichał Górny                binascii.b2a_hex(temp_path.encode()).decode(),),
2088872c9d1SMichał Górny             "send packet: $F,1#00"],
2098872c9d1SMichał Górny            True)
2108872c9d1SMichał Górny        self.expect_gdbremote_sequence()
2118872c9d1SMichał Górny
2128872c9d1SMichał Górny    @skipIfWindows
2138872c9d1SMichał Górny    @add_test_categories(["llgs"])
2148872c9d1SMichał Górny    def test_platform_file_exists_not(self):
2158872c9d1SMichał Górny        server = self.connect_to_debug_monitor()
2168872c9d1SMichał Górny        self.assertIsNotNone(server)
2178872c9d1SMichał Górny
2188872c9d1SMichał Górny        test_path = self.getBuildArtifact("nonexist")
2198872c9d1SMichał Górny        self.do_handshake()
2208872c9d1SMichał Górny        self.test_sequence.add_log_lines(
2218872c9d1SMichał Górny            ["read packet: $vFile:exists:%s#00" % (
2228872c9d1SMichał Górny                binascii.b2a_hex(test_path.encode()).decode(),),
2238872c9d1SMichał Górny             "send packet: $F,0#00"],
2248872c9d1SMichał Górny            True)
2258872c9d1SMichał Górny        self.expect_gdbremote_sequence()
2268872c9d1SMichał Górny
227a1097d31SMichał Górny    @skipIfWindows
228a1097d31SMichał Górny    @add_test_categories(["llgs"])
229a1097d31SMichał Górny    def test_platform_file_fstat(self):
230a1097d31SMichał Górny        server = self.connect_to_debug_monitor()
231a1097d31SMichał Górny        self.assertIsNotNone(server)
232a1097d31SMichał Górny
233a1097d31SMichał Górny        with tempfile.NamedTemporaryFile() as temp_file:
234a1097d31SMichał Górny            temp_file.write(b"some test data for stat")
235a1097d31SMichał Górny            temp_file.flush()
236a1097d31SMichał Górny
237a1097d31SMichał Górny            self.do_handshake()
238a1097d31SMichał Górny            self.test_sequence.add_log_lines(
239a1097d31SMichał Górny                ["read packet: $vFile:open:%s,0,0#00" % (
240a1097d31SMichał Górny                    binascii.b2a_hex(temp_file.name.encode()).decode(),),
241a1097d31SMichał Górny                 {"direction": "send",
242a1097d31SMichał Górny                 "regex": r"^\$F([0-9a-fA-F]+)#[0-9a-fA-F]{2}$",
243a1097d31SMichał Górny                 "capture": {1: "fd"}}],
244a1097d31SMichał Górny                True)
245a1097d31SMichał Górny
246a1097d31SMichał Górny            context = self.expect_gdbremote_sequence()
247a1097d31SMichał Górny            self.assertIsNotNone(context)
248a1097d31SMichał Górny            fd = int(context["fd"], 16)
249a1097d31SMichał Górny
250a1097d31SMichał Górny            self.reset_test_sequence()
251a1097d31SMichał Górny            self.test_sequence.add_log_lines(
252a1097d31SMichał Górny                ["read packet: $vFile:fstat:%x#00" % (fd,),
253a1097d31SMichał Górny                 {"direction": "send",
254a1097d31SMichał Górny                 "regex": r"^\$F([0-9a-fA-F]+);(.*)#[0-9a-fA-F]{2}$",
255a1097d31SMichał Górny                 "capture": {1: "size", 2: "data"}}],
256a1097d31SMichał Górny                True)
257a1097d31SMichał Górny            context = self.expect_gdbremote_sequence()
258a1097d31SMichał Górny            self.assertEqual(int(context["size"], 16), 64)
259a1097d31SMichał Górny            # NB: we're using .encode() as a hack because the test suite
260a1097d31SMichał Górny            # is wrongly using (unicode) str instead of bytes
261a1097d31SMichał Górny            gdb_stat = GDBStat(
262a1097d31SMichał Górny                *struct.unpack(">IIIIIIIQQQIII",
263a1097d31SMichał Górny                               self.decode_gdbremote_binary(context["data"])
264a1097d31SMichał Górny                                .encode("iso-8859-1")))
265a1097d31SMichał Górny            sys_stat = os.fstat(temp_file.fileno())
266a1097d31SMichał Górny
267a1097d31SMichał Górny            self.assertEqual(gdb_stat.st_dev, uint32_or_zero(sys_stat.st_dev))
268a1097d31SMichał Górny            self.assertEqual(gdb_stat.st_ino, uint32_or_zero(sys_stat.st_ino))
269a1097d31SMichał Górny            self.assertEqual(gdb_stat.st_mode, uint32_trunc(sys_stat.st_mode))
270a1097d31SMichał Górny            self.assertEqual(gdb_stat.st_nlink, uint32_or_max(sys_stat.st_nlink))
271a1097d31SMichał Górny            self.assertEqual(gdb_stat.st_uid, uint32_or_zero(sys_stat.st_uid))
272a1097d31SMichał Górny            self.assertEqual(gdb_stat.st_gid, uint32_or_zero(sys_stat.st_gid))
273a1097d31SMichał Górny            self.assertEqual(gdb_stat.st_rdev, uint32_or_zero(sys_stat.st_rdev))
274a1097d31SMichał Górny            self.assertEqual(gdb_stat.st_size, sys_stat.st_size)
275a1097d31SMichał Górny            self.assertEqual(gdb_stat.st_blksize, sys_stat.st_blksize)
276a1097d31SMichał Górny            self.assertEqual(gdb_stat.st_blocks, sys_stat.st_blocks)
277a1097d31SMichał Górny            self.assertEqual(gdb_stat.st_atime,
278a1097d31SMichał Górny                             uint32_or_zero(int(sys_stat.st_atime)))
279a1097d31SMichał Górny            self.assertEqual(gdb_stat.st_mtime,
280a1097d31SMichał Górny                             uint32_or_zero(int(sys_stat.st_mtime)))
281a1097d31SMichał Górny            self.assertEqual(gdb_stat.st_ctime,
282a1097d31SMichał Górny                             uint32_or_zero(int(sys_stat.st_ctime)))
283a1097d31SMichał Górny
284a1097d31SMichał Górny            self.reset_test_sequence()
285a1097d31SMichał Górny            self.test_sequence.add_log_lines(
286a1097d31SMichał Górny                ["read packet: $vFile:close:%x#00" % (fd,),
287a1097d31SMichał Górny                 "send packet: $F0#00"],
288a1097d31SMichał Górny                True)
289a1097d31SMichał Górny            self.expect_gdbremote_sequence()
290a1097d31SMichał Górny
2919929cfbcSMichał Górny    def expect_error(self):
2929929cfbcSMichał Górny        self.test_sequence.add_log_lines(
2939929cfbcSMichał Górny            [{"direction": "send",
2949929cfbcSMichał Górny             "regex": r"^\$F-1,[0-9a-fA-F]+#[0-9a-fA-F]{2}$"}],
2959929cfbcSMichał Górny            True)
2969929cfbcSMichał Górny        self.expect_gdbremote_sequence()
2979929cfbcSMichał Górny
2989929cfbcSMichał Górny    def vFile_test(self, read=False, write=False, append=False, trunc=False,
2999929cfbcSMichał Górny                   creat=False, excl=False):
3009929cfbcSMichał Górny        if read and write:
3019929cfbcSMichał Górny            mode = 2
3029929cfbcSMichał Górny        elif write:
3039929cfbcSMichał Górny            mode = 1
3049929cfbcSMichał Górny        else:  # read
3059929cfbcSMichał Górny            mode = 0
3069929cfbcSMichał Górny        if append:
3079929cfbcSMichał Górny            mode |= 8
3089929cfbcSMichał Górny        if creat:
3099929cfbcSMichał Górny            mode |= 0x200
3109929cfbcSMichał Górny        if trunc:
3119929cfbcSMichał Górny            mode |= 0x400
3129929cfbcSMichał Górny        if excl:
3139929cfbcSMichał Górny            mode |= 0x800
3149929cfbcSMichał Górny
3154c830b5fSMichał Górny        old_umask = os.umask(0o22)
316d6bf9dcbSMichał Górny        try:
3179929cfbcSMichał Górny            server = self.connect_to_debug_monitor()
318d6bf9dcbSMichał Górny        finally:
319d6bf9dcbSMichał Górny            os.umask(old_umask)
3209929cfbcSMichał Górny        self.assertIsNotNone(server)
3219929cfbcSMichał Górny
3229929cfbcSMichał Górny        # create a temporary file with some data
3238872c9d1SMichał Górny        temp_path = self.getBuildArtifact("test")
3249929cfbcSMichał Górny        test_data = 'some test data longer than 16 bytes\n'
3259929cfbcSMichał Górny
3269929cfbcSMichał Górny        if creat:
3279929cfbcSMichał Górny            self.assertFalse(os.path.exists(temp_path))
3289929cfbcSMichał Górny        else:
3298872c9d1SMichał Górny            with open(temp_path, "wb") as temp_file:
3309929cfbcSMichał Górny                temp_file.write(test_data.encode())
3319929cfbcSMichał Górny
3329929cfbcSMichał Górny        # open the file for reading
3339929cfbcSMichał Górny        self.do_handshake()
3349929cfbcSMichał Górny        self.test_sequence.add_log_lines(
3354c830b5fSMichał Górny            ["read packet: $vFile:open:%s,%x,1a0#00" % (
3369929cfbcSMichał Górny                binascii.b2a_hex(temp_path.encode()).decode(),
3379929cfbcSMichał Górny                mode),
3389929cfbcSMichał Górny             {"direction": "send",
3399929cfbcSMichał Górny             "regex": r"^\$F([0-9a-fA-F]+)#[0-9a-fA-F]{2}$",
3409929cfbcSMichał Górny             "capture": {1: "fd"}}],
3419929cfbcSMichał Górny            True)
3429929cfbcSMichał Górny
3439929cfbcSMichał Górny        context = self.expect_gdbremote_sequence()
3449929cfbcSMichał Górny        self.assertIsNotNone(context)
3459929cfbcSMichał Górny        fd = int(context["fd"], 16)
3469929cfbcSMichał Górny
3479929cfbcSMichał Górny        # read data from the file
3489929cfbcSMichał Górny        self.reset_test_sequence()
3499929cfbcSMichał Górny        self.test_sequence.add_log_lines(
3509929cfbcSMichał Górny            ["read packet: $vFile:pread:%x,11,10#00" % (fd,)],
3519929cfbcSMichał Górny            True)
3529929cfbcSMichał Górny        if read:
3539929cfbcSMichał Górny            self.test_sequence.add_log_lines(
3549929cfbcSMichał Górny                [{"direction": "send",
3559929cfbcSMichał Górny                 "regex": r"^\$F([0-9a-fA-F]+);(.*)#[0-9a-fA-F]{2}$",
3569929cfbcSMichał Górny                 "capture": {1: "size", 2: "data"}}],
3579929cfbcSMichał Górny                True)
3589929cfbcSMichał Górny            context = self.expect_gdbremote_sequence()
3599929cfbcSMichał Górny            self.assertIsNotNone(context)
3609929cfbcSMichał Górny            if trunc:
3619929cfbcSMichał Górny                self.assertEqual(context["size"], "0")
3629929cfbcSMichał Górny                self.assertEqual(context["data"], "")
3639929cfbcSMichał Górny            else:
3649929cfbcSMichał Górny                self.assertEqual(context["size"], "11")  # hex
3659929cfbcSMichał Górny                self.assertEqual(context["data"], test_data[0x10:0x10 + 0x11])
3669929cfbcSMichał Górny        else:
3679929cfbcSMichał Górny            self.expect_error()
3689929cfbcSMichał Górny
3699929cfbcSMichał Górny        # another offset
3709929cfbcSMichał Górny        if read and not trunc:
3719929cfbcSMichał Górny            self.reset_test_sequence()
3729929cfbcSMichał Górny            self.test_sequence.add_log_lines(
3739929cfbcSMichał Górny                ["read packet: $vFile:pread:%x,6,3#00" % (fd,),
3749929cfbcSMichał Górny                 {"direction": "send",
3759929cfbcSMichał Górny                 "regex": r"^\$F([0-9a-fA-F]+);(.+)#[0-9a-fA-F]{2}$",
3769929cfbcSMichał Górny                 "capture": {1: "size", 2: "data"}}],
3779929cfbcSMichał Górny                True)
3789929cfbcSMichał Górny            context = self.expect_gdbremote_sequence()
3799929cfbcSMichał Górny            self.assertIsNotNone(context)
3809929cfbcSMichał Górny            self.assertEqual(context["size"], "6")  # hex
3819929cfbcSMichał Górny            self.assertEqual(context["data"], test_data[3:3 + 6])
3829929cfbcSMichał Górny
3839929cfbcSMichał Górny        # write data to the file
3849929cfbcSMichał Górny        self.reset_test_sequence()
3859929cfbcSMichał Górny        self.test_sequence.add_log_lines(
3869929cfbcSMichał Górny            ["read packet: $vFile:pwrite:%x,6,somedata#00" % (fd,)],
3879929cfbcSMichał Górny            True)
3889929cfbcSMichał Górny        if write:
3899929cfbcSMichał Górny            self.test_sequence.add_log_lines(
3909929cfbcSMichał Górny                ["send packet: $F8#00"],
3919929cfbcSMichał Górny                True)
3929929cfbcSMichał Górny            self.expect_gdbremote_sequence()
3939929cfbcSMichał Górny        else:
3949929cfbcSMichał Górny            self.expect_error()
3959929cfbcSMichał Górny
3969929cfbcSMichał Górny        # close the file
3979929cfbcSMichał Górny        self.reset_test_sequence()
3989929cfbcSMichał Górny        self.test_sequence.add_log_lines(
3999929cfbcSMichał Górny            ["read packet: $vFile:close:%x#00" % (fd,),
4009929cfbcSMichał Górny             "send packet: $F0#00"],
4019929cfbcSMichał Górny            True)
4029929cfbcSMichał Górny        self.expect_gdbremote_sequence()
4039929cfbcSMichał Górny
4049929cfbcSMichał Górny        if write:
4059929cfbcSMichał Górny            # check if the data was actually written
4068872c9d1SMichał Górny            with open(temp_path, "rb") as temp_file:
4079929cfbcSMichał Górny                if creat:
4089929cfbcSMichał Górny                    self.assertEqual(os.fstat(temp_file.fileno()).st_mode & 0o7777,
4094c830b5fSMichał Górny                                     0o640)
4109929cfbcSMichał Górny                data = test_data.encode()
4119929cfbcSMichał Górny                if trunc or creat:
4129929cfbcSMichał Górny                    data = b"\0" * 6 + b"somedata"
4139929cfbcSMichał Górny                elif append:
4149929cfbcSMichał Górny                    data += b"somedata"
4159929cfbcSMichał Górny                else:
4169929cfbcSMichał Górny                    data = data[:6] + b"somedata" + data[6 + 8:]
4179929cfbcSMichał Górny                self.assertEqual(temp_file.read(), data)
418