mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-04-12 03:10:03 +00:00

Previously we would persist the flags indicating whether the remote side supports a particular feature across reconnects, which is obviously not a good idea. I implement the clearing by nuking (its the only way to be sure :) the entire GDBRemoteCommunication object in the disconnect operation and creating a new one upon connection. This allows us to maintain a nice invariant that the GDBRemoteCommunication object (which is now a pointer) exists only if it is connected. The downside to that is that a lot of functions now needs to check the validity of the pointer instead of blindly accessing the object. The process communication does not suffer from the same issue because we always destroy the entire Process object for a relaunch. Differential Revision: https://reviews.llvm.org/D116539
103 lines
3.4 KiB
Python
103 lines
3.4 KiB
Python
import os
|
|
import os.path
|
|
import lldb
|
|
from lldbsuite.test.lldbtest import *
|
|
from lldbsuite.test.gdbclientutils import *
|
|
|
|
class GDBRemoteTestBase(TestBase):
|
|
"""
|
|
Base class for GDB client tests.
|
|
|
|
This class will setup and start a mock GDB server for the test to use.
|
|
It also provides assertPacketLogContains, which simplifies the checking
|
|
of packets sent by the client.
|
|
"""
|
|
|
|
NO_DEBUG_INFO_TESTCASE = True
|
|
server = None
|
|
server_socket_class = TCPServerSocket
|
|
|
|
def setUp(self):
|
|
TestBase.setUp(self)
|
|
self.server = MockGDBServer(self.server_socket_class())
|
|
self.server.start()
|
|
|
|
def tearDown(self):
|
|
# TestBase.tearDown will kill the process, but we need to kill it early
|
|
# so its client connection closes and we can stop the server before
|
|
# finally calling the base tearDown.
|
|
if self.process() is not None:
|
|
self.process().Kill()
|
|
self.server.stop()
|
|
TestBase.tearDown(self)
|
|
|
|
def createTarget(self, yaml_path):
|
|
"""
|
|
Create a target by auto-generating the object based on the given yaml
|
|
instructions.
|
|
|
|
This will track the generated object so it can be automatically removed
|
|
during tearDown.
|
|
"""
|
|
yaml_base, ext = os.path.splitext(yaml_path)
|
|
obj_path = self.getBuildArtifact(yaml_base)
|
|
self.yaml2obj(yaml_path, obj_path)
|
|
return self.dbg.CreateTarget(obj_path)
|
|
|
|
def connect(self, target):
|
|
"""
|
|
Create a process by connecting to the mock GDB server.
|
|
|
|
Includes assertions that the process was successfully created.
|
|
"""
|
|
listener = self.dbg.GetListener()
|
|
error = lldb.SBError()
|
|
process = target.ConnectRemote(listener,
|
|
self.server.get_connect_url(), "gdb-remote", error)
|
|
self.assertTrue(error.Success(), error.description)
|
|
self.assertTrue(process, PROCESS_IS_VALID)
|
|
return process
|
|
|
|
def assertPacketLogContains(self, packets, log=None):
|
|
"""
|
|
Assert that the mock server's packet log contains the given packets.
|
|
|
|
The packet log includes all packets sent by the client and received
|
|
by the server. This fuction makes it easy to verify that the client
|
|
sent the expected packets to the server.
|
|
|
|
The check does not require that the packets be consecutive, but does
|
|
require that they are ordered in the log as they ordered in the arg.
|
|
"""
|
|
if log is None:
|
|
log = self.server.responder.packetLog
|
|
i = 0
|
|
j = 0
|
|
|
|
while i < len(packets) and j < len(log):
|
|
if log[j] == packets[i]:
|
|
i += 1
|
|
j += 1
|
|
if i < len(packets):
|
|
self.fail(u"Did not receive: %s\nLast 10 packets:\n\t%s" %
|
|
(packets[i], u'\n\t'.join(log)))
|
|
|
|
|
|
class GDBPlatformClientTestBase(GDBRemoteTestBase):
|
|
"""
|
|
Base class for platform server clients.
|
|
|
|
This class extends GDBRemoteTestBase by automatically connecting
|
|
via "platform connect" in the setUp() method.
|
|
"""
|
|
|
|
def setUp(self):
|
|
super().setUp()
|
|
self.runCmd("platform select remote-gdb-server")
|
|
self.runCmd("platform connect " + self.server.get_connect_url())
|
|
self.assertTrue(self.dbg.GetSelectedPlatform().IsConnected())
|
|
|
|
def tearDown(self):
|
|
self.dbg.GetSelectedPlatform().DisconnectRemote()
|
|
super().tearDown()
|