416 lines
14 KiB
Python
416 lines
14 KiB
Python
# lldb test suite imports
|
|
from lldbsuite.test.decorators import *
|
|
from lldbsuite.test.lldbtest import TestBase
|
|
|
|
# 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
|
|
|
|
# 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)
|
|
|
|
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:
|
|
os.chmod(temp_file.fileno(), test_mode)
|
|
|
|
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
|
|
|
|
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
|
|
@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()
|
|
|
|
self.do_handshake()
|
|
self.test_sequence.add_log_lines(
|
|
["read packet: $vFile:open:%s,0,0#00" % (
|
|
binascii.b2a_hex(temp_file.name.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))
|
|
else:
|
|
with open(temp_path, "wb") as temp_file:
|
|
temp_file.write(test_data.encode())
|
|
|
|
# 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
|
|
with open(temp_path, "rb") as temp_file:
|
|
if creat:
|
|
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)
|