2014-04-21 13:30:08 +08:00
|
|
|
"""
|
|
|
|
Test lldb-gdbserver operation
|
|
|
|
"""
|
|
|
|
|
|
|
|
import unittest2
|
|
|
|
import pexpect
|
2014-04-23 07:16:53 +08:00
|
|
|
import socket
|
2014-04-21 13:30:08 +08:00
|
|
|
import sys
|
|
|
|
from lldbtest import *
|
|
|
|
from lldbgdbserverutils import *
|
2014-04-23 07:16:53 +08:00
|
|
|
import logging
|
2014-04-26 07:08:24 +08:00
|
|
|
import os.path
|
2014-04-21 13:30:08 +08:00
|
|
|
|
|
|
|
class LldbGdbServerTestCase(TestBase):
|
|
|
|
|
|
|
|
mydir = TestBase.compute_mydir(__file__)
|
|
|
|
|
|
|
|
port = 12345
|
|
|
|
|
2014-04-23 07:16:53 +08:00
|
|
|
_TIMEOUT_SECONDS = 5
|
|
|
|
|
|
|
|
_GDBREMOTE_KILL_PACKET = "$k#6b"
|
|
|
|
|
2014-04-28 12:49:40 +08:00
|
|
|
_LOGGING_LEVEL = logging.WARNING
|
|
|
|
# _LOGGING_LEVEL = logging.DEBUG
|
2014-04-23 07:16:53 +08:00
|
|
|
|
2014-04-21 13:30:08 +08:00
|
|
|
def setUp(self):
|
|
|
|
TestBase.setUp(self)
|
|
|
|
|
2014-04-23 07:16:53 +08:00
|
|
|
FORMAT = '%(asctime)-15s %(levelname)-8s %(message)s'
|
|
|
|
logging.basicConfig(format=FORMAT)
|
|
|
|
self.logger = logging.getLogger(__name__)
|
|
|
|
self.logger.setLevel(self._LOGGING_LEVEL)
|
|
|
|
|
2014-04-28 12:49:40 +08:00
|
|
|
def init_llgs_test(self):
|
|
|
|
self.debug_monitor_exe = get_lldb_gdbserver_exe()
|
|
|
|
if not self.debug_monitor_exe:
|
|
|
|
self.skipTest("lldb_gdbserver exe not found")
|
|
|
|
|
|
|
|
def init_debugserver_test(self):
|
|
|
|
self.debug_monitor_exe = get_debugserver_exe()
|
|
|
|
if not self.debug_monitor_exe:
|
|
|
|
self.skipTest("debugserver exe not found")
|
|
|
|
|
2014-04-23 07:16:53 +08:00
|
|
|
def create_socket(self):
|
|
|
|
sock = socket.socket()
|
2014-04-26 05:09:28 +08:00
|
|
|
logger = self.logger
|
2014-04-23 07:16:53 +08:00
|
|
|
|
|
|
|
def shutdown_socket():
|
|
|
|
if sock:
|
2014-04-26 05:09:28 +08:00
|
|
|
try:
|
|
|
|
# send the kill packet so lldb-gdbserver shuts down gracefully
|
|
|
|
sock.sendall(LldbGdbServerTestCase._GDBREMOTE_KILL_PACKET)
|
|
|
|
except:
|
|
|
|
logger.warning("failed to send kill packet to debug monitor: {}; ignoring".format(sys.exc_info()[0]))
|
|
|
|
|
|
|
|
try:
|
|
|
|
sock.close()
|
|
|
|
except:
|
|
|
|
logger.warning("failed to close socket to debug monitor: {}; ignoring".format(sys.exc_info()[0]))
|
2014-04-23 07:16:53 +08:00
|
|
|
|
|
|
|
self.addTearDownHook(shutdown_socket)
|
|
|
|
|
|
|
|
sock.connect(('localhost', self.port))
|
|
|
|
return sock
|
|
|
|
|
|
|
|
def start_server(self):
|
2014-04-21 13:30:08 +08:00
|
|
|
# start the server
|
2014-04-28 12:49:40 +08:00
|
|
|
server = pexpect.spawn("{} localhost:{}".format(self.debug_monitor_exe, self.port))
|
2014-04-21 13:30:08 +08:00
|
|
|
|
|
|
|
# Turn on logging for what the child sends back.
|
|
|
|
if self.TraceOn():
|
|
|
|
server.logfile_read = sys.stdout
|
|
|
|
|
2014-04-28 12:49:40 +08:00
|
|
|
# Schedule debug monitor to be shut down during teardown.
|
2014-04-26 05:09:28 +08:00
|
|
|
logger = self.logger
|
2014-04-28 12:49:40 +08:00
|
|
|
def shutdown_debug_monitor():
|
2014-04-26 05:09:28 +08:00
|
|
|
try:
|
|
|
|
server.close()
|
|
|
|
except:
|
|
|
|
logger.warning("failed to close pexpect server for debug monitor: {}; ignoring".format(sys.exc_info()[0]))
|
|
|
|
|
2014-04-28 12:49:40 +08:00
|
|
|
self.addTearDownHook(shutdown_debug_monitor)
|
2014-04-21 13:30:08 +08:00
|
|
|
|
|
|
|
# Wait until we receive the server ready message before continuing.
|
2014-04-28 12:49:40 +08:00
|
|
|
server.expect_exact('Listening to port {} for a connection from localhost'.format(self.port))
|
2014-04-21 13:30:08 +08:00
|
|
|
|
2014-04-23 07:16:53 +08:00
|
|
|
# Create a socket to talk to the server
|
|
|
|
self.sock = self.create_socket()
|
|
|
|
|
|
|
|
return server
|
|
|
|
|
|
|
|
def create_no_ack_remote_stream(self):
|
|
|
|
return [
|
|
|
|
"lldb-gdbserver < 19> read packet: +",
|
|
|
|
"lldb-gdbserver < 19> read packet: $QStartNoAckMode#b0",
|
|
|
|
"lldb-gdbserver < 1> send packet: +",
|
|
|
|
"lldb-gdbserver < 6> send packet: $OK#9a",
|
|
|
|
"lldb-gdbserver < 1> read packet: +"]
|
|
|
|
|
2014-04-28 12:49:40 +08:00
|
|
|
@debugserver_test
|
|
|
|
def test_exe_starts_debugserver(self):
|
|
|
|
self.init_debugserver_test()
|
|
|
|
server = self.start_server()
|
2014-04-23 07:16:53 +08:00
|
|
|
|
2014-04-28 12:49:40 +08:00
|
|
|
@llgs_test
|
|
|
|
def test_exe_starts_llgs(self):
|
|
|
|
self.init_llgs_test()
|
2014-04-23 07:16:53 +08:00
|
|
|
server = self.start_server()
|
|
|
|
|
2014-04-28 12:49:40 +08:00
|
|
|
def start_no_ack_mode(self):
|
2014-04-23 07:16:53 +08:00
|
|
|
server = self.start_server()
|
|
|
|
self.assertIsNotNone(server)
|
|
|
|
|
|
|
|
log_lines = self.create_no_ack_remote_stream()
|
|
|
|
|
|
|
|
expect_lldb_gdbserver_replay(self, self.sock, log_lines, True,
|
|
|
|
self._TIMEOUT_SECONDS, self.logger)
|
|
|
|
|
2014-04-28 12:49:40 +08:00
|
|
|
@debugserver_test
|
|
|
|
def test_start_no_ack_mode_debugserver(self):
|
|
|
|
self.init_debugserver_test()
|
|
|
|
self.start_no_ack_mode()
|
|
|
|
|
|
|
|
@llgs_test
|
|
|
|
def test_start_no_ack_mode_llgs(self):
|
|
|
|
self.init_llgs_test()
|
|
|
|
self.start_no_ack_mode()
|
|
|
|
|
|
|
|
def thread_suffix_supported(self):
|
2014-04-23 07:16:53 +08:00
|
|
|
server = self.start_server()
|
|
|
|
self.assertIsNotNone(server)
|
|
|
|
|
|
|
|
log_lines = self.create_no_ack_remote_stream()
|
2014-04-26 07:08:24 +08:00
|
|
|
log_lines.extend([
|
2014-04-23 07:16:53 +08:00
|
|
|
"lldb-gdbserver < 26> read packet: $QThreadSuffixSupported#e4",
|
|
|
|
"lldb-gdbserver < 6> send packet: $OK#9a"])
|
|
|
|
|
|
|
|
expect_lldb_gdbserver_replay(self, self.sock, log_lines, True,
|
|
|
|
self._TIMEOUT_SECONDS, self.logger)
|
|
|
|
|
2014-04-28 12:49:40 +08:00
|
|
|
@debugserver_test
|
|
|
|
def test_thread_suffix_supported_debugserver(self):
|
|
|
|
self.init_debugserver_test()
|
|
|
|
self.thread_suffix_supported()
|
|
|
|
|
|
|
|
@llgs_test
|
2014-04-23 07:16:53 +08:00
|
|
|
@unittest2.expectedFailure()
|
2014-04-28 12:49:40 +08:00
|
|
|
def test_thread_suffix_supported_llgs(self):
|
|
|
|
self.init_llgs_test()
|
|
|
|
self.thread_suffix_supported()
|
|
|
|
|
|
|
|
def list_threads_in_stop_reply_supported(self):
|
2014-04-23 07:16:53 +08:00
|
|
|
server = self.start_server()
|
|
|
|
self.assertIsNotNone(server)
|
|
|
|
|
|
|
|
log_lines = self.create_no_ack_remote_stream()
|
2014-04-26 07:08:24 +08:00
|
|
|
log_lines.extend([
|
2014-04-23 07:16:53 +08:00
|
|
|
"lldb-gdbserver < 27> read packet: $QListThreadsInStopReply#21",
|
|
|
|
"lldb-gdbserver < 6> send packet: $OK#9a"])
|
|
|
|
|
|
|
|
expect_lldb_gdbserver_replay(self, self.sock, log_lines, True,
|
|
|
|
self._TIMEOUT_SECONDS, self.logger)
|
|
|
|
|
2014-04-28 12:49:40 +08:00
|
|
|
@debugserver_test
|
|
|
|
def test_list_threads_in_stop_reply_supported_debugserver(self):
|
|
|
|
self.init_debugserver_test()
|
|
|
|
self.list_threads_in_stop_reply_supported()
|
|
|
|
|
|
|
|
@llgs_test
|
|
|
|
@unittest2.expectedFailure()
|
|
|
|
def test_list_threads_in_stop_reply_supported_llgs(self):
|
|
|
|
self.init_llgs_test()
|
|
|
|
self.list_threads_in_stop_reply_supported()
|
|
|
|
|
2014-04-26 07:08:24 +08:00
|
|
|
def start_inferior(self):
|
|
|
|
server = self.start_server()
|
|
|
|
self.assertIsNotNone(server)
|
|
|
|
|
|
|
|
# TODO grab the build output directory rather than current directory.
|
|
|
|
inferior_exe_name = os.path.abspath('a.out')
|
|
|
|
inferior_exe_name_hex = gdbremote_hex_encode_string(inferior_exe_name)
|
|
|
|
|
|
|
|
log_lines = self.create_no_ack_remote_stream()
|
|
|
|
log_lines.extend([
|
|
|
|
"lldb-gdbserver < 000> read packet: {}".format(
|
|
|
|
gdbremote_packet_encode_string(
|
|
|
|
"A{},0,{}".format(len(inferior_exe_name_hex), inferior_exe_name_hex))),
|
|
|
|
"lldb-gdbserver < 6> send packet: $OK#9a"])
|
|
|
|
|
|
|
|
expect_lldb_gdbserver_replay(self, self.sock, log_lines, True,
|
|
|
|
self._TIMEOUT_SECONDS, self.logger)
|
|
|
|
|
2014-04-28 12:49:40 +08:00
|
|
|
@debugserver_test
|
2014-04-26 07:08:24 +08:00
|
|
|
@dsym_test
|
2014-04-28 12:49:40 +08:00
|
|
|
def test_start_inferior_debugserver_dsym(self):
|
|
|
|
self.init_debugserver_test()
|
2014-04-26 07:08:24 +08:00
|
|
|
self.buildDsym()
|
|
|
|
self.start_inferior()
|
|
|
|
|
2014-04-28 12:49:40 +08:00
|
|
|
@llgs_test
|
2014-04-26 07:08:24 +08:00
|
|
|
@dwarf_test
|
2014-04-28 12:49:40 +08:00
|
|
|
def test_start_inferior_llgs_dwarf(self):
|
|
|
|
self.init_llgs_test()
|
2014-04-26 07:08:24 +08:00
|
|
|
self.buildDwarf()
|
|
|
|
self.start_inferior()
|
2014-04-23 07:16:53 +08:00
|
|
|
|
2014-04-29 13:01:01 +08:00
|
|
|
def inferior_print_exit(self):
|
|
|
|
server = self.start_server()
|
|
|
|
self.assertIsNotNone(server)
|
|
|
|
|
|
|
|
# TODO grab the build output directory rather than current directory.
|
|
|
|
inferior_exe_name = os.path.abspath('a.out')
|
|
|
|
inferior_exe_name_hex = gdbremote_hex_encode_string(inferior_exe_name)
|
|
|
|
|
|
|
|
log_lines = self.create_no_ack_remote_stream()
|
|
|
|
log_lines.extend([
|
|
|
|
"lldb-gdbserver < 000> read packet: {}".format(
|
|
|
|
gdbremote_packet_encode_string(
|
|
|
|
"A{},0,{}".format(len(inferior_exe_name_hex), inferior_exe_name_hex))),
|
|
|
|
"lldb-gdbserver < 6> send packet: $OK#00",
|
|
|
|
"lldb-gdbserver < 18> read packet: $qLaunchSuccess#a5",
|
|
|
|
"lldb-gdbserver < 6> send packet: $OK#00",
|
|
|
|
"lldb-gdbserver < 5> read packet: $vCont;c#00",
|
|
|
|
"lldb-gdbserver < 7> send packet: $O{}#00".format(gdbremote_hex_encode_string("hello, world\r\n")),
|
|
|
|
"lldb-gdbserver < 7> send packet: $W00#00"])
|
|
|
|
|
|
|
|
expect_lldb_gdbserver_replay(self, self.sock, log_lines, True,
|
|
|
|
self._TIMEOUT_SECONDS, self.logger)
|
|
|
|
|
|
|
|
@debugserver_test
|
|
|
|
@dsym_test
|
|
|
|
def test_inferior_print_exit_debugserver_dsym(self):
|
|
|
|
self.init_debugserver_test()
|
|
|
|
self.buildDsym()
|
|
|
|
self.inferior_print_exit()
|
|
|
|
|
|
|
|
@llgs_test
|
|
|
|
@dwarf_test
|
|
|
|
@unittest2.expectedFailure()
|
|
|
|
def test_inferior_print_exit_llgs_dwarf(self):
|
|
|
|
self.init_llgs_test()
|
|
|
|
self.buildDwarf()
|
|
|
|
self.inferior_print_exit()
|
|
|
|
|
|
|
|
|
2014-04-21 13:30:08 +08:00
|
|
|
if __name__ == '__main__':
|
|
|
|
unittest2.main()
|