It is necessary to transfer the test file to/from the really remote target (for example Windows host and Linux target). Also ignore chmod check in case of the Windows host.
491 lines
16 KiB
Python
491 lines
16 KiB
Python
# lldb test suite imports
|
|
from lldbsuite.test.decorators import *
|
|
from lldbsuite.test.lldbtest import TestBase
|
|
from lldbsuite.test import lldbutil
|
|
|
|
# gdb-remote-specific imports
|
|
import lldbgdbserverutils
|
|
from gdbremote_testcase import GdbRemoteTestCaseBase
|
|
|
|
import binascii
|
|
import os
|
|
import stat
|
|
import struct
|
|
import typing
|
|
|
|
|
|
class GDBStat(typing.NamedTuple):
|
|
st_dev: int
|
|
st_ino: int
|
|
st_mode: int
|
|
st_nlink: int
|
|
st_uid: int
|
|
st_gid: int
|
|
st_rdev: int
|
|
st_size: int
|
|
st_blksize: int
|
|
st_blocks: int
|
|
st_atime: int
|
|
st_mtime: int
|
|
st_ctime: int
|
|
|
|
|
|
def uint32_or_zero(x):
|
|
return x if x < 2**32 and x >= 0 else 0
|
|
|
|
|
|
def uint32_or_max(x):
|
|
return x if x < 2**32 and x >= 0 else 2**32 - 1
|
|
|
|
|
|
def uint32_trunc(x):
|
|
return x & (2**32 - 1)
|
|
|
|
|
|
class TestGdbRemotePlatformFile(GdbRemoteTestCaseBase):
|
|
@skipIfWindows
|
|
@add_test_categories(["llgs"])
|
|
def test_platform_file_rdonly(self):
|
|
self.vFile_test(read=True)
|
|
|
|
@skipIfWindows
|
|
@add_test_categories(["llgs"])
|
|
def test_platform_file_wronly(self):
|
|
self.vFile_test(write=True)
|
|
|
|
@skipIfWindows
|
|
@add_test_categories(["llgs"])
|
|
def test_platform_file_rdwr(self):
|
|
self.vFile_test(read=True, write=True)
|
|
|
|
@skipIfWindows
|
|
@add_test_categories(["llgs"])
|
|
def test_platform_file_wronly_append(self):
|
|
self.vFile_test(write=True, append=True)
|
|
|
|
@skipIfWindows
|
|
@add_test_categories(["llgs"])
|
|
def test_platform_file_rdwr_append(self):
|
|
self.vFile_test(read=True, write=True, append=True)
|
|
|
|
@skipIfWindows
|
|
@add_test_categories(["llgs"])
|
|
def test_platform_file_wronly_trunc(self):
|
|
self.vFile_test(write=True, trunc=True)
|
|
|
|
@skipIfWindows
|
|
@add_test_categories(["llgs"])
|
|
def test_platform_file_rdwr_trunc(self):
|
|
self.vFile_test(read=True, write=True, trunc=True)
|
|
|
|
@skipIfWindows
|
|
@add_test_categories(["llgs"])
|
|
def test_platform_file_wronly_creat(self):
|
|
self.vFile_test(write=True, creat=True)
|
|
|
|
@skipIfWindows
|
|
@add_test_categories(["llgs"])
|
|
def test_platform_file_wronly_creat_excl(self):
|
|
self.vFile_test(write=True, creat=True, excl=True)
|
|
|
|
@skipIfWindows
|
|
@add_test_categories(["llgs"])
|
|
def test_platform_file_wronly_fail(self):
|
|
server = self.connect_to_debug_monitor()
|
|
self.assertIsNotNone(server)
|
|
|
|
temp_path = self.getBuildArtifact("test")
|
|
self.assertFalse(os.path.exists(temp_path))
|
|
|
|
# attempt to open the file without O_CREAT
|
|
self.do_handshake()
|
|
self.test_sequence.add_log_lines(
|
|
[
|
|
"read packet: $vFile:open:%s,1,0#00"
|
|
% (binascii.b2a_hex(temp_path.encode()).decode(),),
|
|
{"direction": "send", "regex": r"^\$F-1,[0-9a-fA-F]+#[0-9a-fA-F]{2}$"},
|
|
],
|
|
True,
|
|
)
|
|
self.expect_gdbremote_sequence()
|
|
|
|
@skipIfWindows
|
|
@add_test_categories(["llgs"])
|
|
def test_platform_file_wronly_creat_excl_fail(self):
|
|
server = self.connect_to_debug_monitor()
|
|
self.assertIsNotNone(server)
|
|
|
|
temp_file = self.getBuildArtifact("test")
|
|
with open(temp_file, "wb"):
|
|
pass
|
|
temp_file = lldbutil.install_to_target(self, temp_file)
|
|
|
|
# attempt to open the file with O_CREAT|O_EXCL
|
|
self.do_handshake()
|
|
self.test_sequence.add_log_lines(
|
|
[
|
|
"read packet: $vFile:open:%s,a01,0#00"
|
|
% (binascii.b2a_hex(temp_file.encode()).decode(),),
|
|
{"direction": "send", "regex": r"^\$F-1,[0-9a-fA-F]+#[0-9a-fA-F]{2}$"},
|
|
],
|
|
True,
|
|
)
|
|
self.expect_gdbremote_sequence()
|
|
|
|
@skipIfWindows
|
|
@add_test_categories(["llgs"])
|
|
def test_platform_file_size(self):
|
|
server = self.connect_to_debug_monitor()
|
|
self.assertIsNotNone(server)
|
|
|
|
temp_path = self.getBuildArtifact("test")
|
|
test_data = b"test data of some length"
|
|
with open(temp_path, "wb") as temp_file:
|
|
temp_file.write(test_data)
|
|
temp_path = lldbutil.install_to_target(self, temp_path)
|
|
|
|
self.do_handshake()
|
|
self.test_sequence.add_log_lines(
|
|
[
|
|
"read packet: $vFile:size:%s#00"
|
|
% (binascii.b2a_hex(temp_path.encode()).decode(),),
|
|
{
|
|
"direction": "send",
|
|
"regex": r"^\$F([0-9a-fA-F]+)+#[0-9a-fA-F]{2}$",
|
|
"capture": {1: "size"},
|
|
},
|
|
],
|
|
True,
|
|
)
|
|
context = self.expect_gdbremote_sequence()
|
|
self.assertEqual(int(context["size"], 16), len(test_data))
|
|
|
|
@skipIfWindows
|
|
@add_test_categories(["llgs"])
|
|
def test_platform_file_mode(self):
|
|
server = self.connect_to_debug_monitor()
|
|
self.assertIsNotNone(server)
|
|
|
|
temp_path = self.getBuildArtifact("test")
|
|
test_mode = 0o751
|
|
|
|
with open(temp_path, "wb") as temp_file:
|
|
if lldbplatformutil.getHostPlatform() == "windows":
|
|
test_mode = 0o700
|
|
else:
|
|
os.chmod(temp_file.fileno(), test_mode)
|
|
temp_path = lldbutil.install_to_target(self, temp_path)
|
|
|
|
self.do_handshake()
|
|
self.test_sequence.add_log_lines(
|
|
[
|
|
"read packet: $vFile:mode:%s#00"
|
|
% (binascii.b2a_hex(temp_path.encode()).decode(),),
|
|
{
|
|
"direction": "send",
|
|
"regex": r"^\$F([0-9a-fA-F]+)+#[0-9a-fA-F]{2}$",
|
|
"capture": {1: "mode"},
|
|
},
|
|
],
|
|
True,
|
|
)
|
|
context = self.expect_gdbremote_sequence()
|
|
self.assertEqual(int(context["mode"], 16), test_mode)
|
|
|
|
@skipIfWindows
|
|
@add_test_categories(["llgs"])
|
|
def test_platform_file_mode_fail(self):
|
|
server = self.connect_to_debug_monitor()
|
|
self.assertIsNotNone(server)
|
|
|
|
temp_path = self.getBuildArtifact("nonexist")
|
|
|
|
self.do_handshake()
|
|
self.test_sequence.add_log_lines(
|
|
[
|
|
"read packet: $vFile:mode:%s#00"
|
|
% (binascii.b2a_hex(temp_path.encode()).decode(),),
|
|
{"direction": "send", "regex": r"^\$F-1,0*2+#[0-9a-fA-F]{2}$"},
|
|
],
|
|
True,
|
|
)
|
|
self.expect_gdbremote_sequence()
|
|
|
|
@skipIfWindows
|
|
@add_test_categories(["llgs"])
|
|
def test_platform_file_exists(self):
|
|
server = self.connect_to_debug_monitor()
|
|
self.assertIsNotNone(server)
|
|
|
|
temp_path = self.getBuildArtifact("test")
|
|
with open(temp_path, "wb"):
|
|
pass
|
|
temp_path = lldbutil.install_to_target(self, temp_path)
|
|
|
|
self.do_handshake()
|
|
self.test_sequence.add_log_lines(
|
|
[
|
|
"read packet: $vFile:exists:%s#00"
|
|
% (binascii.b2a_hex(temp_path.encode()).decode(),),
|
|
"send packet: $F,1#00",
|
|
],
|
|
True,
|
|
)
|
|
self.expect_gdbremote_sequence()
|
|
|
|
@skipIfWindows
|
|
@add_test_categories(["llgs"])
|
|
def test_platform_file_exists_not(self):
|
|
server = self.connect_to_debug_monitor()
|
|
self.assertIsNotNone(server)
|
|
|
|
test_path = self.getBuildArtifact("nonexist")
|
|
self.do_handshake()
|
|
self.test_sequence.add_log_lines(
|
|
[
|
|
"read packet: $vFile:exists:%s#00"
|
|
% (binascii.b2a_hex(test_path.encode()).decode(),),
|
|
"send packet: $F,0#00",
|
|
],
|
|
True,
|
|
)
|
|
self.expect_gdbremote_sequence()
|
|
|
|
@skipIfWindows
|
|
# FIXME: lldb.remote_platform.Install() cannot copy opened temp file on Windows.
|
|
# It is possible to use tempfile.NamedTemporaryFile(..., delete=False) and
|
|
# delete the temp file manually at the end.
|
|
@skipIf(hostoslist=["windows"])
|
|
@add_test_categories(["llgs"])
|
|
def test_platform_file_fstat(self):
|
|
server = self.connect_to_debug_monitor()
|
|
self.assertIsNotNone(server)
|
|
|
|
with tempfile.NamedTemporaryFile() as temp_file:
|
|
temp_file.write(b"some test data for stat")
|
|
temp_file.flush()
|
|
temp_path = lldbutil.install_to_target(self, temp_file.name)
|
|
|
|
self.do_handshake()
|
|
self.test_sequence.add_log_lines(
|
|
[
|
|
"read packet: $vFile:open:%s,0,0#00"
|
|
% (binascii.b2a_hex(temp_path.encode()).decode(),),
|
|
{
|
|
"direction": "send",
|
|
"regex": r"^\$F([0-9a-fA-F]+)#[0-9a-fA-F]{2}$",
|
|
"capture": {1: "fd"},
|
|
},
|
|
],
|
|
True,
|
|
)
|
|
|
|
context = self.expect_gdbremote_sequence()
|
|
self.assertIsNotNone(context)
|
|
fd = int(context["fd"], 16)
|
|
|
|
self.reset_test_sequence()
|
|
self.test_sequence.add_log_lines(
|
|
[
|
|
"read packet: $vFile:fstat:%x#00" % (fd,),
|
|
{
|
|
"direction": "send",
|
|
"regex": r"^\$F([0-9a-fA-F]+);(.*)#[0-9a-fA-F]{2}$",
|
|
"capture": {1: "size", 2: "data"},
|
|
},
|
|
],
|
|
True,
|
|
)
|
|
context = self.expect_gdbremote_sequence()
|
|
self.assertEqual(int(context["size"], 16), 64)
|
|
# NB: we're using .encode() as a hack because the test suite
|
|
# is wrongly using (unicode) str instead of bytes
|
|
gdb_stat = GDBStat(
|
|
*struct.unpack(
|
|
">IIIIIIIQQQIII",
|
|
self.decode_gdbremote_binary(context["data"]).encode("iso-8859-1"),
|
|
)
|
|
)
|
|
sys_stat = os.fstat(temp_file.fileno())
|
|
|
|
self.assertEqual(gdb_stat.st_dev, uint32_or_zero(sys_stat.st_dev))
|
|
self.assertEqual(gdb_stat.st_ino, uint32_or_zero(sys_stat.st_ino))
|
|
self.assertEqual(gdb_stat.st_mode, uint32_trunc(sys_stat.st_mode))
|
|
self.assertEqual(gdb_stat.st_nlink, uint32_or_max(sys_stat.st_nlink))
|
|
self.assertEqual(gdb_stat.st_uid, uint32_or_zero(sys_stat.st_uid))
|
|
self.assertEqual(gdb_stat.st_gid, uint32_or_zero(sys_stat.st_gid))
|
|
self.assertEqual(gdb_stat.st_rdev, uint32_or_zero(sys_stat.st_rdev))
|
|
self.assertEqual(gdb_stat.st_size, sys_stat.st_size)
|
|
self.assertEqual(gdb_stat.st_blksize, sys_stat.st_blksize)
|
|
self.assertEqual(gdb_stat.st_blocks, sys_stat.st_blocks)
|
|
self.assertEqual(gdb_stat.st_atime, uint32_or_zero(int(sys_stat.st_atime)))
|
|
self.assertEqual(gdb_stat.st_mtime, uint32_or_zero(int(sys_stat.st_mtime)))
|
|
self.assertEqual(gdb_stat.st_ctime, uint32_or_zero(int(sys_stat.st_ctime)))
|
|
|
|
self.reset_test_sequence()
|
|
self.test_sequence.add_log_lines(
|
|
["read packet: $vFile:close:%x#00" % (fd,), "send packet: $F0#00"], True
|
|
)
|
|
self.expect_gdbremote_sequence()
|
|
|
|
def expect_error(self):
|
|
self.test_sequence.add_log_lines(
|
|
[{"direction": "send", "regex": r"^\$F-1,[0-9a-fA-F]+#[0-9a-fA-F]{2}$"}],
|
|
True,
|
|
)
|
|
self.expect_gdbremote_sequence()
|
|
|
|
def vFile_test(
|
|
self,
|
|
read=False,
|
|
write=False,
|
|
append=False,
|
|
trunc=False,
|
|
creat=False,
|
|
excl=False,
|
|
):
|
|
if read and write:
|
|
mode = 2
|
|
elif write:
|
|
mode = 1
|
|
else: # read
|
|
mode = 0
|
|
if append:
|
|
mode |= 8
|
|
if creat:
|
|
mode |= 0x200
|
|
if trunc:
|
|
mode |= 0x400
|
|
if excl:
|
|
mode |= 0x800
|
|
|
|
old_umask = os.umask(0o22)
|
|
try:
|
|
server = self.connect_to_debug_monitor()
|
|
finally:
|
|
os.umask(old_umask)
|
|
self.assertIsNotNone(server)
|
|
|
|
# create a temporary file with some data
|
|
temp_path = self.getBuildArtifact("test")
|
|
test_data = "some test data longer than 16 bytes\n"
|
|
|
|
if creat:
|
|
self.assertFalse(os.path.exists(temp_path))
|
|
if lldb.remote_platform:
|
|
temp_path = lldbutil.append_to_process_working_directory(self, "test")
|
|
else:
|
|
with open(temp_path, "wb") as temp_file:
|
|
temp_file.write(test_data.encode())
|
|
temp_path = lldbutil.install_to_target(self, temp_path)
|
|
|
|
# open the file for reading
|
|
self.do_handshake()
|
|
self.test_sequence.add_log_lines(
|
|
[
|
|
"read packet: $vFile:open:%s,%x,1a0#00"
|
|
% (binascii.b2a_hex(temp_path.encode()).decode(), mode),
|
|
{
|
|
"direction": "send",
|
|
"regex": r"^\$F([0-9a-fA-F]+)#[0-9a-fA-F]{2}$",
|
|
"capture": {1: "fd"},
|
|
},
|
|
],
|
|
True,
|
|
)
|
|
|
|
context = self.expect_gdbremote_sequence()
|
|
self.assertIsNotNone(context)
|
|
fd = int(context["fd"], 16)
|
|
|
|
# read data from the file
|
|
self.reset_test_sequence()
|
|
self.test_sequence.add_log_lines(
|
|
["read packet: $vFile:pread:%x,11,10#00" % (fd,)], True
|
|
)
|
|
if read:
|
|
self.test_sequence.add_log_lines(
|
|
[
|
|
{
|
|
"direction": "send",
|
|
"regex": r"^\$F([0-9a-fA-F]+);(.*)#[0-9a-fA-F]{2}$",
|
|
"capture": {1: "size", 2: "data"},
|
|
}
|
|
],
|
|
True,
|
|
)
|
|
context = self.expect_gdbremote_sequence()
|
|
self.assertIsNotNone(context)
|
|
if trunc:
|
|
self.assertEqual(context["size"], "0")
|
|
self.assertEqual(context["data"], "")
|
|
else:
|
|
self.assertEqual(context["size"], "11") # hex
|
|
self.assertEqual(context["data"], test_data[0x10 : 0x10 + 0x11])
|
|
else:
|
|
self.expect_error()
|
|
|
|
# another offset
|
|
if read and not trunc:
|
|
self.reset_test_sequence()
|
|
self.test_sequence.add_log_lines(
|
|
[
|
|
"read packet: $vFile:pread:%x,6,3#00" % (fd,),
|
|
{
|
|
"direction": "send",
|
|
"regex": r"^\$F([0-9a-fA-F]+);(.+)#[0-9a-fA-F]{2}$",
|
|
"capture": {1: "size", 2: "data"},
|
|
},
|
|
],
|
|
True,
|
|
)
|
|
context = self.expect_gdbremote_sequence()
|
|
self.assertIsNotNone(context)
|
|
self.assertEqual(context["size"], "6") # hex
|
|
self.assertEqual(context["data"], test_data[3 : 3 + 6])
|
|
|
|
# write data to the file
|
|
self.reset_test_sequence()
|
|
self.test_sequence.add_log_lines(
|
|
["read packet: $vFile:pwrite:%x,6,somedata#00" % (fd,)], True
|
|
)
|
|
if write:
|
|
self.test_sequence.add_log_lines(["send packet: $F8#00"], True)
|
|
self.expect_gdbremote_sequence()
|
|
else:
|
|
self.expect_error()
|
|
|
|
# close the file
|
|
self.reset_test_sequence()
|
|
self.test_sequence.add_log_lines(
|
|
["read packet: $vFile:close:%x#00" % (fd,), "send packet: $F0#00"], True
|
|
)
|
|
self.expect_gdbremote_sequence()
|
|
|
|
if write:
|
|
# check if the data was actually written
|
|
if lldb.remote_platform:
|
|
local_path = self.getBuildArtifact("file_from_target")
|
|
error = lldb.remote_platform.Get(
|
|
lldb.SBFileSpec(temp_path, False), lldb.SBFileSpec(local_path, True)
|
|
)
|
|
self.assertTrue(
|
|
error.Success(),
|
|
"Reading file {0} failed: {1}".format(temp_path, error),
|
|
)
|
|
temp_path = local_path
|
|
|
|
with open(temp_path, "rb") as temp_file:
|
|
if creat and lldbplatformutil.getHostPlatform() != "windows":
|
|
self.assertEqual(
|
|
os.fstat(temp_file.fileno()).st_mode & 0o7777, 0o640
|
|
)
|
|
data = test_data.encode()
|
|
if trunc or creat:
|
|
data = b"\0" * 6 + b"somedata"
|
|
elif append:
|
|
data += b"somedata"
|
|
else:
|
|
data = data[:6] + b"somedata" + data[6 + 8 :]
|
|
self.assertEqual(temp_file.read(), data)
|