Author: tfiala Date: Wed Sep 10 16:28:38 2014 New Revision: 217549 URL: http://llvm.org/viewvc/llvm-project?rev=217549&view=rev Log: llgs: implement qThreadStopInfo.
This change implements this ticket: http://llvm.org/bugs/show_bug.cgi?id=20899 Adds the qThreadStopInfo RSP command for llgs and includes a test that verifies both debugserver and llgs respond with something reasonable on a multithreaded app. Added: lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemote_qThreadStopInfo.py Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h 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=217549&r1=217548&r2=217549&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp (original) +++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp Wed Sep 10 16:28:38 2014 @@ -429,6 +429,10 @@ GDBRemoteCommunicationServer::GetPacketA case StringExtractorGDBRemote::eServerPacketType_vAttach: packet_result = Handle_vAttach (packet); break; + + case StringExtractorGDBRemote::eServerPacketType_qThreadStopInfo: + packet_result = Handle_qThreadStopInfo (packet); + break; } } else @@ -2378,8 +2382,6 @@ GDBRemoteCommunicationServer::Handle_vCo return SendUnimplementedResponse (packet.GetStringRef().c_str()); } - // We handle $vCont messages for c. - // TODO add C, s and S. StreamString response; response.Printf("vCont;c;C;s;S"); @@ -4181,6 +4183,26 @@ GDBRemoteCommunicationServer::Handle_vAt return PacketResult::Success; } +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_qThreadStopInfo (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // We don't support if we're not llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse ("only supported for lldb-gdbserver"); + + packet.SetFilePos (strlen("qThreadStopInfo")); + const lldb::tid_t tid = packet.GetHexMaxU32 (false, LLDB_INVALID_THREAD_ID); + if (tid == LLDB_INVALID_THREAD_ID) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, could not parse thread id from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); + return SendErrorResponse (0x15); + } + return SendStopReplyPacketForThread (tid); +} + void GDBRemoteCommunicationServer::FlushInferiorOutput () { Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h?rev=217549&r1=217548&r2=217549&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h (original) +++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h Wed Sep 10 16:28:38 2014 @@ -463,6 +463,9 @@ protected: PacketResult Handle_vAttach (StringExtractorGDBRemote &packet); + PacketResult + Handle_qThreadStopInfo (StringExtractorGDBRemote &packet); + void SetCurrentThreadID (lldb::tid_t tid); Added: lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemote_qThreadStopInfo.py URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemote_qThreadStopInfo.py?rev=217549&view=auto ============================================================================== --- lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemote_qThreadStopInfo.py (added) +++ lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemote_qThreadStopInfo.py Wed Sep 10 16:28:38 2014 @@ -0,0 +1,87 @@ +import unittest2 + +import gdbremote_testcase +from lldbtest import * + +class TestGdbRemote_qThreadStopInfo(gdbremote_testcase.GdbRemoteTestCaseBase): + + def gather_stop_replies_via_qThreadStopInfo(self, thread_count): + # Set up the inferior args. + inferior_args=[] + for i in range(thread_count - 1): + inferior_args.append("thread:new") + inferior_args.append("sleep:10") + procs = self.prep_debug_monitor_and_inferior(inferior_args=inferior_args) + + # Assumes test_sequence has anything added needed to setup the initial state. + # (Like optionally enabling QThreadsInStopReply.) + self.test_sequence.add_log_lines([ + "read packet: $c#00" + ], True) + context = self.expect_gdbremote_sequence() + self.assertIsNotNone(context) + + # Give threads time to start up, then break. + time.sleep(1) + self.reset_test_sequence() + self.test_sequence.add_log_lines([ + "read packet: {}".format(chr(03)), + {"direction":"send", "regex":r"^\$T([0-9a-fA-F]+)([^#]+)#[0-9a-fA-F]{2}$", "capture":{1:"stop_result", 2:"key_vals_text"} }, + ], True) + context = self.expect_gdbremote_sequence() + self.assertIsNotNone(context) + + # Wait until all threads have started. + threads = self.wait_for_thread_count(thread_count, timeout_seconds=3) + self.assertIsNotNone(threads) + self.assertEquals(len(threads), thread_count) + + # Grab stop reply for each thread via qThreadStopInfo{tid:hex}. + for thread in threads: + # Run the qThreadStopInfo command. + self.reset_test_sequence() + self.test_sequence.add_log_lines([ + "read packet: $qThreadStopInfo{:x}#00".format(thread), + {"direction":"send", "regex":r"^\$T([0-9a-fA-F]+)([^#]+)#[0-9a-fA-F]{2}$", "capture":{1:"stop_result", 2:"key_vals_text"} }, + ], True) + context = self.expect_gdbremote_sequence() + self.assertIsNotNone(context) + + # Parse stop reply contents. + key_vals_text = context.get("key_vals_text") + self.assertIsNotNone(key_vals_text) + kv_dict = self.parse_key_val_dict(key_vals_text) + self.assertIsNotNone(kv_dict) + + # Verify there is a thread. + kv_thread = kv_dict.get("thread") + self.assertIsNotNone(kv_thread) + self.assertEquals(int(kv_thread, 16), thread) + + return threads + + def qThreadStopInfo_works_for_multiple_threads(self, thread_count): + # Gather threads from stop notification when QThreadsInStopReply is enabled. + # stop_reply_threads = self.gather_stop_replies_via_qThreadStopInfo(self.ENABLE_THREADS_IN_STOP_REPLY_ENTRIES, thread_count) + stop_reply_threads = self.gather_stop_replies_via_qThreadStopInfo(thread_count) + self.assertEquals(len(stop_reply_threads), thread_count) + + @debugserver_test + @dsym_test + def test_qThreadStopInfo_works_for_multiple_threads_debugserver_dsym(self): + self.init_debugserver_test() + self.buildDsym() + self.set_inferior_startup_launch() + self.qThreadStopInfo_works_for_multiple_threads(5) + + @llgs_test + @dwarf_test + def test_qThreadStopInfo_works_for_multiple_threads_llgs_dwarf(self): + self.init_llgs_test() + self.buildDwarf() + self.set_inferior_startup_launch() + self.qThreadStopInfo_works_for_multiple_threads(5) + + +if __name__ == '__main__': + unittest2.main() _______________________________________________ lldb-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits
