[Lldb-commits] [lldb] r212923 - Modified gdb-remote tests to run with automatically-chosen ports.
Todd Fiala
todd.fiala at gmail.com
Sun Jul 13 23:24:45 PDT 2014
Author: tfiala
Date: Mon Jul 14 01:24:44 2014
New Revision: 212923
URL: http://llvm.org/viewvc/llvm-project?rev=212923&view=rev
Log:
Modified gdb-remote tests to run with automatically-chosen ports.
Now that llgs supports communicating the 0-port choose-a-port
mechanism and can communicate that back to a caller via the
--named-pipe option (at parity with debugserver), we use this
mechanism to always start llgs and debugserver gdb-remote
protocol tests without needing to use some port arbitration
mechanism. This eliminates some potential intermittent failures vs. the
previous random port and collision-avoidance strategy used.
Removed:
lldb/trunk/test/tools/lldb-gdbserver/commandline/TestStubNamedPipe.py
Modified:
lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py
lldb/trunk/test/tools/lldb-gdbserver/lldbgdbserverutils.py
Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp?rev=212923&r1=212922&r2=212923&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp Mon Jul 14 01:24:44 2014
@@ -36,8 +36,8 @@
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/NativeRegisterContext.h"
-#include "../../../Host/common/NativeProcessProtocol.h"
-#include "../../../Host/common/NativeThreadProtocol.h"
+#include "Host/common/NativeProcessProtocol.h"
+#include "Host/common/NativeThreadProtocol.h"
// Project includes
#include "Utility/StringExtractorGDBRemote.h"
@@ -3041,24 +3041,38 @@ GDBRemoteCommunicationServer::Handle_qfT
if (!IsGdbServer())
return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_qfThreadInfo() unimplemented");
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
// Fail if we don't have a current process.
if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
- return SendErrorResponse (68);
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s() no process (%s), returning OK", __FUNCTION__, m_debugged_process_sp ? "invalid process id" : "null m_debugged_process_sp");
+ return SendOKResponse ();
+ }
StreamGDBRemote response;
response.PutChar ('m');
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s() starting thread iteration", __FUNCTION__);
+
NativeThreadProtocolSP thread_sp;
uint32_t thread_index;
for (thread_index = 0, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index);
thread_sp;
++thread_index, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index))
{
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s() iterated thread %" PRIu32 "(%s, tid=0x%" PRIx64 ")", __FUNCTION__, thread_index, thread_sp ? "is not null" : "null", thread_sp ? thread_sp->GetID () : LLDB_INVALID_THREAD_ID);
if (thread_index > 0)
response.PutChar(',');
response.Printf ("%" PRIx64, thread_sp->GetID ());
}
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s() finished thread iteration", __FUNCTION__);
+
return SendPacketNoLock(response.GetData(), response.GetSize());
}
Removed: lldb/trunk/test/tools/lldb-gdbserver/commandline/TestStubNamedPipe.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/commandline/TestStubNamedPipe.py?rev=212922&view=auto
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/commandline/TestStubNamedPipe.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/commandline/TestStubNamedPipe.py (removed)
@@ -1,90 +0,0 @@
-import unittest2
-
-# Add the directory above ours to the python library path since we
-# will import from there.
-import os.path
-import sys
-sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
-
-import gdbremote_testcase
-import os
-import select
-import tempfile
-import time
-from lldbtest import *
-
-class TestStubNamedPipeTestCase(gdbremote_testcase.GdbRemoteTestCaseBase):
- def create_named_pipe(self):
- temp_dir = tempfile.mkdtemp()
- named_pipe_path = os.path.join(temp_dir, "stub_port_number")
- try:
- os.mkfifo(named_pipe_path)
- except OSError, e:
- # print "Failed to create named pipe: %s" % e
- raise e
- return named_pipe_path
-
- def get_port_from_named_pipe(self):
- # Set port to 0
- self.port = 0
-
- # Don't turn on any kind of logging
- self.debug_monitor_extra_args = ""
-
- # Create the named pipe that we're reading on.
- self.named_pipe_path = self.create_named_pipe()
- self.assertIsNotNone(self.named_pipe_path)
- # print "using named pipe:{}".format(self.named_pipe_path)
- try:
- # print "launching server..."
- server = self.launch_debug_monitor()
- # print "server launched..."
- self.assertIsNotNone(server)
- self.assertTrue(server.isalive())
- server.expect("(debugserver|lldb-gdbserver)", timeout=10)
-
- # print "about to open named pipe..."
- # Open the read side of the pipe in non-blocking mode. This will return right away, ready or not.
- fd = os.open(self.named_pipe_path, os.O_RDONLY | os.O_NONBLOCK)
- named_pipe = os.fdopen(fd, "r")
- self.assertIsNotNone(named_pipe)
-
- # print "waiting on content from the named pipe..."
- # Wait for something to read with a max timeout.
- (ready_readers, _, _) = select.select([fd], [], [], 5)
- self.assertIsNotNone(ready_readers, "write side of pipe has not written anything - stub isn't writing to pipe.")
- self.assertNotEqual(len(ready_readers), 0, "write side of pipe has not written anything - stub isn't writing to pipe.")
-
- try:
- # Read the port from the named pipe.
- stub_port_raw = named_pipe.read()
- self.assertIsNotNone(stub_port_raw)
- self.assertNotEqual(len(stub_port_raw), 0, "no content to read on pipe")
-
- # Trim null byte, convert to int.
- stub_port_raw = stub_port_raw[:-1]
- stub_port = int(stub_port_raw)
- self.assertTrue(stub_port > 0)
- finally:
- named_pipe.close()
- # print "stub is listening on port: {} (from text '{}')".format(stub_port, stub_port_raw)
- finally:
- temp_dir = os.path.dirname(self.named_pipe_path)
- try:
- os.remove(self.named_pipe_path)
- except:
- # Not required.
- None
- os.rmdir(temp_dir)
-
- @debugserver_test
- def test_get_port_from_named_pipe_debugserver(self):
- self.init_debugserver_test()
- self.set_inferior_startup_launch()
- self.get_port_from_named_pipe()
-
- @llgs_test
- def test_get_port_from_named_pipe_llgs(self):
- self.init_llgs_test()
- self.set_inferior_startup_launch()
- self.get_port_from_named_pipe()
Modified: lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py?rev=212923&r1=212922&r2=212923&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py Mon Jul 14 01:24:44 2014
@@ -3,7 +3,8 @@ Base class for gdb-remote test cases.
"""
import errno
-import unittest2
+import os
+import os.path
import pexpect
import platform
import random
@@ -13,11 +14,12 @@ import signal
import socket
import subprocess
import sys
+import tempfile
import time
+import unittest2
from lldbtest import *
from lldbgdbserverutils import *
import logging
-import os.path
class GdbRemoteTestCaseBase(TestBase):
@@ -51,6 +53,8 @@ class GdbRemoteTestCaseBase(TestBase):
self.set_inferior_startup_launch()
self.port = self.get_next_port()
self.named_pipe_path = None
+ self.named_pipe = None
+ self.named_pipe_fd = None
def get_next_port(self):
return 12000 + random.randint(0,3999)
@@ -58,17 +62,86 @@ class GdbRemoteTestCaseBase(TestBase):
def reset_test_sequence(self):
self.test_sequence = GdbRemoteTestSequence(self.logger)
- def init_llgs_test(self):
+ def create_named_pipe(self):
+ # Create a temp dir and name for a pipe.
+ temp_dir = tempfile.mkdtemp()
+ named_pipe_path = os.path.join(temp_dir, "stub_port_number")
+
+ # Create the named pipe.
+ os.mkfifo(named_pipe_path)
+
+ # Open the read side of the pipe in non-blocking mode. This will return right away, ready or not.
+ named_pipe_fd = os.open(named_pipe_path, os.O_RDONLY | os.O_NONBLOCK)
+
+ # Create the file for the named pipe. Note this will follow semantics of
+ # a non-blocking read side of a named pipe, which has different semantics
+ # than a named pipe opened for read in non-blocking mode.
+ named_pipe = os.fdopen(named_pipe_fd, "r")
+ self.assertIsNotNone(named_pipe)
+
+ def shutdown_named_pipe():
+ # Close the pipe.
+ try:
+ named_pipe.close()
+ except:
+ print "failed to close named pipe"
+ None
+
+ # Delete the pipe.
+ try:
+ os.remove(named_pipe_path)
+ except:
+ print "failed to delete named pipe: {}".format(named_pipe_path)
+ None
+
+ # Delete the temp directory.
+ try:
+ os.rmdir(temp_dir)
+ except:
+ print "failed to delete temp dir: {}, directory contents: '{}'".format(temp_dir, os.listdir(temp_dir))
+ None
+
+ # Add the shutdown hook to clean up the named pipe.
+ self.addTearDownHook(shutdown_named_pipe)
+
+ # Clear the port so the stub selects a port number.
+ self.port = 0
+
+ return (named_pipe_path, named_pipe, named_pipe_fd)
+
+ def get_stub_port_from_named_socket(self, read_timeout_seconds=5):
+ # Wait for something to read with a max timeout.
+ (ready_readers, _, _) = select.select([self.named_pipe_fd], [], [], read_timeout_seconds)
+ self.assertIsNotNone(ready_readers, "write side of pipe has not written anything - stub isn't writing to pipe.")
+ self.assertNotEqual(len(ready_readers), 0, "write side of pipe has not written anything - stub isn't writing to pipe.")
+
+ # Read the port from the named pipe.
+ stub_port_raw = self.named_pipe.read()
+ self.assertIsNotNone(stub_port_raw)
+ self.assertNotEqual(len(stub_port_raw), 0, "no content to read on pipe")
+
+ # Trim null byte, convert to int.
+ stub_port_raw = stub_port_raw[:-1]
+ stub_port = int(stub_port_raw)
+ self.assertTrue(stub_port > 0)
+
+ return stub_port
+
+ def init_llgs_test(self, use_named_pipe=True):
self.debug_monitor_exe = get_lldb_gdbserver_exe()
if not self.debug_monitor_exe:
self.skipTest("lldb_gdbserver exe not found")
self.debug_monitor_extra_args = " -c 'log enable -T -f process-{}.log lldb break process thread' -c 'log enable -T -f packets-{}.log gdb-remote packets'".format(self.id(), self.id(), self.id())
+ if use_named_pipe:
+ (self.named_pipe_path, self.named_pipe, self.named_pipe_fd) = self.create_named_pipe()
- def init_debugserver_test(self):
+ def init_debugserver_test(self, use_named_pipe=True):
self.debug_monitor_exe = get_debugserver_exe()
if not self.debug_monitor_exe:
self.skipTest("debugserver exe not found")
self.debug_monitor_extra_args = " --log-file=/tmp/packets-{}.log --log-flags=0x800000".format(self._testMethodName)
+ if use_named_pipe:
+ (self.named_pipe_path, self.named_pipe, self.named_pipe_fd) = self.create_named_pipe()
def create_socket(self):
sock = socket.socket()
@@ -89,7 +162,10 @@ class GdbRemoteTestCaseBase(TestBase):
self.addTearDownHook(shutdown_socket)
- sock.connect(('localhost', self.port))
+ connect_info = ("localhost", self.port)
+ # print "connecting to stub on {}:{}".format(connect_info[0], connect_info[1])
+ sock.connect(connect_info)
+
return sock
def set_inferior_startup_launch(self):
@@ -108,6 +184,13 @@ class GdbRemoteTestCaseBase(TestBase):
# Start the server.
server = pexpect.spawn(commandline)
+ self.assertIsNotNone(server)
+ server.expect(r"(debugserver|lldb-gdbserver)", timeout=10)
+
+ # If we're receiving the stub's listening port from the named pipe, do that here.
+ if self.named_pipe:
+ self.port = self.get_stub_port_from_named_socket()
+ # print "debug server listening on {}".format(self.port)
# Turn on logging for what the child sends back.
if self.TraceOn():
@@ -116,6 +199,27 @@ class GdbRemoteTestCaseBase(TestBase):
return server
def connect_to_debug_monitor(self, attach_pid=None):
+ if self.named_pipe:
+ # Create the stub.
+ server = self.launch_debug_monitor(attach_pid=attach_pid)
+ self.assertIsNotNone(server)
+
+ def shutdown_debug_monitor():
+ try:
+ server.close()
+ except:
+ logger.warning("failed to close pexpect server for debug monitor: {}; ignoring".format(sys.exc_info()[0]))
+ self.addTearDownHook(shutdown_debug_monitor)
+
+ # Schedule debug monitor to be shut down during teardown.
+ logger = self.logger
+
+ # Attach to the stub and return a socket opened to it.
+ self.sock = self.create_socket()
+ return server
+
+ # We're using a random port algorithm to try not to collide with other ports,
+ # and retry a max # times.
attempts = 0
MAX_ATTEMPTS = 20
Modified: lldb/trunk/test/tools/lldb-gdbserver/lldbgdbserverutils.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/lldbgdbserverutils.py?rev=212923&r1=212922&r2=212923&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/lldbgdbserverutils.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/lldbgdbserverutils.py Mon Jul 14 01:24:44 2014
@@ -195,7 +195,11 @@ def expect_lldb_gdbserver_replay(
# This is an entry to send to the remote debug monitor.
send_packet = sequence_entry.get_send_packet()
if logger:
- logger.info("sending packet to remote: %s" % send_packet)
+ if len(send_packet) == 1 and send_packet[0] == chr(3):
+ packet_desc = "^C"
+ else:
+ packet_desc = send_packet
+ logger.info("sending packet to remote: {}".format(packet_desc))
sock.sendall(send_packet)
else:
# This is an entry expecting to receive content from the remote debug monitor.
More information about the lldb-commits
mailing list