This infrastructure has proven proven its worth, so give it a more prominent place. My immediate motivation for this is the desire to reuse this infrastructure for qemu platform testing, but I believe this move makes sense independently of that. Moving this code to the packages tree will allow as to add more structure to the gdb client tests -- currently they are all crammed into the same test folder as that was the only way they could access this code. I'm splitting the code into two parts while moving it. The first once contains just the generic gdb protocol wrappers, while the other one contains the unit test glue. The reason for that is that for qemu testing, I need to run the gdb code in a separate process, so I will only be using the first part there. Differential Revision: https://reviews.llvm.org/D113893
222 lines
8.0 KiB
Python
222 lines
8.0 KiB
Python
from lldbsuite.test.gdbclientutils import *
|
|
from lldbsuite.test.decorators import *
|
|
from lldbsuite.test.lldbgdbclient import GDBPlatformClientTestBase
|
|
|
|
class TestGDBRemotePlatformFile(GDBPlatformClientTestBase):
|
|
|
|
mydir = GDBPlatformClientTestBase.compute_mydir(__file__)
|
|
|
|
def test_file(self):
|
|
"""Test mock operations on a remote file"""
|
|
|
|
class Responder(MockGDBServerResponder):
|
|
def vFile(self, packet):
|
|
if packet.startswith("vFile:open:"):
|
|
return "F10"
|
|
elif packet.startswith("vFile:pread:"):
|
|
return "Fd;frobnicator"
|
|
elif packet.startswith("vFile:pwrite:"):
|
|
return "Fa"
|
|
elif packet.startswith("vFile:close:"):
|
|
return "F0"
|
|
return "F-1,58"
|
|
|
|
self.server.responder = Responder()
|
|
|
|
self.match("platform file open /some/file.txt -v 0755",
|
|
[r"File Descriptor = 16"])
|
|
self.match("platform file read 16 -o 11 -c 13",
|
|
[r"Return = 11\nData = \"frobnicator\""])
|
|
self.match("platform file write 16 -o 11 -d teststring",
|
|
[r"Return = 10"])
|
|
self.match("platform file close 16",
|
|
[r"file 16 closed."])
|
|
self.assertPacketLogContains([
|
|
"vFile:open:2f736f6d652f66696c652e747874,00000202,000001ed",
|
|
"vFile:pread:10,d,b",
|
|
"vFile:pwrite:10,b,teststring",
|
|
"vFile:close:10",
|
|
])
|
|
|
|
def test_file_fail(self):
|
|
"""Test mocked failures of remote operations"""
|
|
|
|
class Responder(MockGDBServerResponder):
|
|
def vFile(self, packet):
|
|
# use ENOSYS as this constant differs between GDB Remote
|
|
# Protocol and Linux, so we can test the translation
|
|
return "F-1,58"
|
|
|
|
self.server.responder = Responder()
|
|
|
|
self.match("platform file open /some/file.txt -v 0755",
|
|
[r"error: Function not implemented"],
|
|
error=True)
|
|
self.match("platform file read 16 -o 11 -c 13",
|
|
[r"error: Function not implemented"],
|
|
error=True)
|
|
self.match("platform file write 16 -o 11 -d teststring",
|
|
[r"error: Function not implemented"],
|
|
error=True)
|
|
self.match("platform file close 16",
|
|
[r"error: Function not implemented"],
|
|
error=True)
|
|
self.assertPacketLogContains([
|
|
"vFile:open:2f736f6d652f66696c652e747874,00000202,000001ed",
|
|
"vFile:pread:10,d,b",
|
|
"vFile:pwrite:10,b,teststring",
|
|
"vFile:close:10",
|
|
])
|
|
|
|
def test_file_size(self):
|
|
"""Test 'platform get-size'"""
|
|
|
|
class Responder(MockGDBServerResponder):
|
|
def vFile(self, packet):
|
|
return "F1000"
|
|
|
|
self.server.responder = Responder()
|
|
|
|
self.match("platform get-size /some/file.txt",
|
|
[r"File size of /some/file\.txt \(remote\): 4096"])
|
|
self.assertPacketLogContains([
|
|
"vFile:size:2f736f6d652f66696c652e747874",
|
|
])
|
|
|
|
def test_file_size_fallback(self):
|
|
"""Test 'platform get-size fallback to vFile:fstat'"""
|
|
|
|
class Responder(MockGDBServerResponder):
|
|
def vFile(self, packet):
|
|
if packet.startswith("vFile:open:"):
|
|
return "F5"
|
|
elif packet.startswith("vFile:fstat:"):
|
|
return "F40;" + 28 * "\0" + "\0\0\0\0\0\1\2\3" + 28 * "\0"
|
|
if packet.startswith("vFile:close:"):
|
|
return "F0"
|
|
return ""
|
|
|
|
self.server.responder = Responder()
|
|
|
|
self.match("platform get-size /some/file.txt",
|
|
[r"File size of /some/file\.txt \(remote\): 66051"])
|
|
self.assertPacketLogContains([
|
|
"vFile:size:2f736f6d652f66696c652e747874",
|
|
"vFile:open:2f736f6d652f66696c652e747874,00000000,00000000",
|
|
"vFile:fstat:5",
|
|
"vFile:close:5",
|
|
])
|
|
|
|
@skipIfWindows
|
|
def test_file_permissions(self):
|
|
"""Test 'platform get-permissions'"""
|
|
|
|
class Responder(MockGDBServerResponder):
|
|
def vFile(self, packet):
|
|
return "F1a4"
|
|
|
|
self.server.responder = Responder()
|
|
|
|
self.match("platform get-permissions /some/file.txt",
|
|
[r"File permissions of /some/file\.txt \(remote\): 0o0644"])
|
|
self.assertPacketLogContains([
|
|
"vFile:mode:2f736f6d652f66696c652e747874",
|
|
])
|
|
|
|
@skipIfWindows
|
|
def test_file_permissions_fallback(self):
|
|
"""Test 'platform get-permissions' fallback to fstat"""
|
|
|
|
class Responder(MockGDBServerResponder):
|
|
def vFile(self, packet):
|
|
if packet.startswith("vFile:open:"):
|
|
return "F5"
|
|
elif packet.startswith("vFile:fstat:"):
|
|
return "F40;" + 8 * "\0" + "\0\0\1\xA4" + 52 * "\0"
|
|
if packet.startswith("vFile:close:"):
|
|
return "F0"
|
|
return ""
|
|
|
|
self.server.responder = Responder()
|
|
|
|
try:
|
|
self.match("platform get-permissions /some/file.txt",
|
|
[r"File permissions of /some/file\.txt \(remote\): 0o0644"])
|
|
self.assertPacketLogContains([
|
|
"vFile:mode:2f736f6d652f66696c652e747874",
|
|
"vFile:open:2f736f6d652f66696c652e747874,00000000,00000000",
|
|
"vFile:fstat:5",
|
|
"vFile:close:5",
|
|
])
|
|
finally:
|
|
self.dbg.GetSelectedPlatform().DisconnectRemote()
|
|
|
|
def test_file_exists(self):
|
|
"""Test 'platform file-exists'"""
|
|
|
|
class Responder(MockGDBServerResponder):
|
|
def vFile(self, packet):
|
|
return "F,1"
|
|
|
|
self.server.responder = Responder()
|
|
|
|
self.match("platform file-exists /some/file.txt",
|
|
[r"File /some/file\.txt \(remote\) exists"])
|
|
self.assertPacketLogContains([
|
|
"vFile:exists:2f736f6d652f66696c652e747874",
|
|
])
|
|
|
|
def test_file_exists_not(self):
|
|
"""Test 'platform file-exists' with non-existing file"""
|
|
|
|
class Responder(MockGDBServerResponder):
|
|
def vFile(self, packet):
|
|
return "F,0"
|
|
|
|
self.server.responder = Responder()
|
|
|
|
self.match("platform file-exists /some/file.txt",
|
|
[r"File /some/file\.txt \(remote\) does not exist"])
|
|
self.assertPacketLogContains([
|
|
"vFile:exists:2f736f6d652f66696c652e747874",
|
|
])
|
|
|
|
def test_file_exists_fallback(self):
|
|
"""Test 'platform file-exists' fallback to open"""
|
|
|
|
class Responder(MockGDBServerResponder):
|
|
def vFile(self, packet):
|
|
if packet.startswith("vFile:open:"):
|
|
return "F5"
|
|
if packet.startswith("vFile:close:"):
|
|
return "F0"
|
|
return ""
|
|
|
|
self.server.responder = Responder()
|
|
|
|
self.match("platform file-exists /some/file.txt",
|
|
[r"File /some/file\.txt \(remote\) exists"])
|
|
self.assertPacketLogContains([
|
|
"vFile:exists:2f736f6d652f66696c652e747874",
|
|
"vFile:open:2f736f6d652f66696c652e747874,00000000,00000000",
|
|
"vFile:close:5",
|
|
])
|
|
|
|
def test_file_exists_not_fallback(self):
|
|
"""Test 'platform file-exists' fallback to open with non-existing file"""
|
|
|
|
class Responder(MockGDBServerResponder):
|
|
def vFile(self, packet):
|
|
if packet.startswith("vFile:open:"):
|
|
return "F-1,2"
|
|
return ""
|
|
|
|
self.server.responder = Responder()
|
|
|
|
self.match("platform file-exists /some/file.txt",
|
|
[r"File /some/file\.txt \(remote\) does not exist"])
|
|
self.assertPacketLogContains([
|
|
"vFile:exists:2f736f6d652f66696c652e747874",
|
|
"vFile:open:2f736f6d652f66696c652e747874,00000000,00000000",
|
|
])
|