[Lldb-commits] [lldb] r208241 - Modify debugserver to follow gdb remote $qC protocol definition.

Todd Fiala todd.fiala at gmail.com
Wed May 7 12:28:21 PDT 2014


Author: tfiala
Date: Wed May  7 14:28:21 2014
New Revision: 208241

URL: http://llvm.org/viewvc/llvm-project?rev=208241&view=rev
Log:
Modify debugserver to follow gdb remote $qC protocol definition.

$qC from debugserver now returns the current thread's thread-id (and, like $?, will set a current thread if one is not already selected).  Previously it was returning the current process id.

lldb will now query $qProcessInfo to retrieve the process id.  The process id is now cached lazily and reset like other cached values.  Retrieval of the process id will fall back to the old $qC method for vendor==Apple and os==iOS if the qProcessInfo retrieval fails.

Added a gdb remote protocol-level test to verify that $qProcessInfo reports a valid process id after launching a process, while the process is in the initial stopped state.  Verifies the given process id is a currently valid process on host OSes for which we know how to check (MacOSX, Linux, {Free/Net}BSD).  Ignores the live process check for OSes where we don't know how to do this.  (I saw no portable way to do this in stock Python without pulling in other libs).

Modified:
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
    lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py
    lldb/trunk/test/tools/lldb-gdbserver/lldbgdbserverutils.py
    lldb/trunk/tools/debugserver/source/RNBRemote.cpp

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp?rev=208241&r1=208240&r2=208241&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp Wed May  7 14:28:21 2014
@@ -57,6 +57,7 @@ GDBRemoteCommunicationClient::GDBRemoteC
     m_supports_vCont_s (eLazyBoolCalculate),
     m_supports_vCont_S (eLazyBoolCalculate),
     m_qHostInfo_is_valid (eLazyBoolCalculate),
+    m_curr_pid_is_valid (eLazyBoolCalculate),
     m_qProcessInfo_is_valid (eLazyBoolCalculate),
     m_qGDBServerVersion_is_valid (eLazyBoolCalculate),
     m_supports_alloc_dealloc_memory (eLazyBoolCalculate),
@@ -86,6 +87,7 @@ GDBRemoteCommunicationClient::GDBRemoteC
     m_supports_z4 (true),
     m_supports_QEnvironment (true),
     m_supports_QEnvironmentHexEncoded (true),
+    m_curr_pid (LLDB_INVALID_PROCESS_ID),
     m_curr_tid (LLDB_INVALID_THREAD_ID),
     m_curr_tid_run (LLDB_INVALID_THREAD_ID),
     m_num_supported_hardware_watchpoints (0),
@@ -308,6 +310,7 @@ GDBRemoteCommunicationClient::ResetDisco
     m_supports_x = eLazyBoolCalculate;
     m_supports_QSaveRegisterState = eLazyBoolCalculate;
     m_qHostInfo_is_valid = eLazyBoolCalculate;
+    m_curr_pid_is_valid = eLazyBoolCalculate;
     m_qProcessInfo_is_valid = eLazyBoolCalculate;
     m_qGDBServerVersion_is_valid = eLazyBoolCalculate;
     m_supports_alloc_dealloc_memory = eLazyBoolCalculate;
@@ -1178,13 +1181,43 @@ GDBRemoteCommunicationClient::SendInterr
 lldb::pid_t
 GDBRemoteCommunicationClient::GetCurrentProcessID ()
 {
-    StringExtractorGDBRemote response;
-    if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false) == PacketResult::Success)
+    if (m_curr_pid_is_valid == eLazyBoolYes)
+        return m_curr_pid;
+    
+    // First try to retrieve the pid via the qProcessInfo request.
+    GetCurrentProcessInfo ();
+    if (m_curr_pid_is_valid == eLazyBoolYes)
+    {
+        // We really got it.
+        return m_curr_pid;
+    }
+    else
     {
-        if (response.GetChar() == 'Q')
-            if (response.GetChar() == 'C')
-                return response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID);
+        // For Apple iOS targets, go back and ask the qC packet for its result.  In earlier iterations of debugserver, $qC returned
+        // the process id of the current process.
+        const llvm::Triple &triple = GetProcessArchitecture().GetTriple();
+        if ((triple.getVendor() == llvm::Triple::Apple) &&
+            (triple.getOS() == llvm::Triple::IOS))
+        {
+            StringExtractorGDBRemote response;
+            if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false) == PacketResult::Success)
+            {
+                if (response.GetChar() == 'Q')
+                {
+                    if (response.GetChar() == 'C')
+                    {
+                        m_curr_pid = response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID);
+                        if (m_curr_pid != LLDB_INVALID_PROCESS_ID)
+                        {
+                            m_curr_pid_is_valid = eLazyBoolYes;
+                            return m_curr_pid;
+                        }
+                    }
+                }
+            }
+        }
     }
+    
     return LLDB_INVALID_PROCESS_ID;
 }
 
@@ -2346,6 +2379,7 @@ GDBRemoteCommunicationClient::GetCurrent
             StringExtractor extractor;
             ByteOrder byte_order = eByteOrderInvalid;
             uint32_t num_keys_decoded = 0;
+            lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
             while (response.GetNameColonValue(name, value))
             {
                 if (name.compare("cputype") == 0)
@@ -2388,9 +2422,20 @@ GDBRemoteCommunicationClient::GetCurrent
                     if (pointer_byte_size != 0)
                         ++num_keys_decoded;
                 }
+                else if (name.compare("pid") == 0)
+                {
+                    pid = Args::StringToUInt64(value.c_str(), 0, 16);
+                    if (pid != LLDB_INVALID_PROCESS_ID)
+                        ++num_keys_decoded;
+                }
             }
             if (num_keys_decoded > 0)
                 m_qProcessInfo_is_valid = eLazyBoolYes;
+            if (pid != LLDB_INVALID_PROCESS_ID)
+            {
+                m_curr_pid_is_valid = eLazyBoolYes;
+                m_curr_pid = pid;
+            }
             if (cpu != LLDB_INVALID_CPUTYPE && !os_name.empty() && !vendor_name.empty())
             {
                 m_process_arch.SetArchitecture (eArchTypeMachO, cpu, sub);

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h?rev=208241&r1=208240&r2=208241&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h Wed May  7 14:28:21 2014
@@ -537,6 +537,7 @@ protected:
     lldb_private::LazyBool m_supports_vCont_s;
     lldb_private::LazyBool m_supports_vCont_S;
     lldb_private::LazyBool m_qHostInfo_is_valid;
+    lldb_private::LazyBool m_curr_pid_is_valid;
     lldb_private::LazyBool m_qProcessInfo_is_valid;
     lldb_private::LazyBool m_qGDBServerVersion_is_valid;
     lldb_private::LazyBool m_supports_alloc_dealloc_memory;
@@ -569,7 +570,7 @@ protected:
         m_supports_QEnvironment:1,
         m_supports_QEnvironmentHexEncoded:1;
     
-
+    lldb::pid_t m_curr_pid;
     lldb::tid_t m_curr_tid;         // Current gdb remote protocol thread index for all other operations
     lldb::tid_t m_curr_tid_run;     // Current gdb remote protocol thread index for continue, step, etc
 

Modified: lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py?rev=208241&r1=208240&r2=208241&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py Wed May  7 14:28:21 2014
@@ -108,7 +108,7 @@ class LldbGdbServerTestCase(TestBase):
             True)
 
     def expect_gdbremote_sequence(self):
-        expect_lldb_gdbserver_replay(self, self.sock, self.test_sequence, self._TIMEOUT_SECONDS, self.logger)
+        return expect_lldb_gdbserver_replay(self, self.sock, self.test_sequence, self._TIMEOUT_SECONDS, self.logger)
 
     @debugserver_test
     def test_exe_starts_debugserver(self):
@@ -324,7 +324,6 @@ class LldbGdbServerTestCase(TestBase):
 
     @debugserver_test
     @dsym_test
-    @unittest2.expectedFailure() # Possible bug.
     def test_first_launch_stop_reply_thread_matches_first_qC_debugserver_dsym(self):
         self.init_debugserver_test()
         self.buildDsym()
@@ -338,7 +337,48 @@ class LldbGdbServerTestCase(TestBase):
         self.buildDwarf()
         self.first_launch_stop_reply_thread_matches_first_qC()
 
+    def qProcessInfo_returns_running_process(self):
+        server = self.start_server()
+        self.assertIsNotNone(server)
+
+        # Build launch args
+        launch_args = [os.path.abspath('a.out'), "hello, world"]
+
+        # Build the expected protocol stream
+        self.add_no_ack_remote_stream()
+        self.add_verified_launch_packets(launch_args)
+        self.test_sequence.add_log_lines(
+            ["read packet: $qProcessInfo#00",
+             { "direction":"send", "regex":r"^\$pid:([0-9a-fA-F]+);", "capture":{1:"pid"} }],
+            True)
+
+        # Run the stream
+        context = self.expect_gdbremote_sequence()
+        self.assertIsNotNone(context)
+
+        # Ensure the process id looks reasonable.
+        pid_text = context.get('pid', None)
+        self.assertIsNotNone(pid_text)
+        pid = int(pid_text, base=16)
+        self.assertNotEqual(0, pid)
+
+        # If possible, verify that the process is running.
+        self.assertTrue(process_is_running(pid, True))
 
+    @debugserver_test
+    @dsym_test
+    def test_qProcessInfo_returns_running_process_debugserver_dsym(self):
+        self.init_debugserver_test()
+        self.buildDsym()
+        self.qProcessInfo_returns_running_process()
+
+    @llgs_test
+    @dwarf_test
+    @unittest2.expectedFailure()
+    def test_qProcessInfo_returns_running_process_llgs_dwarf(self):
+        self.init_llgs_test()
+        self.buildDwarf()
+        self.qProcessInfo_returns_running_process()
 
 if __name__ == '__main__':
     unittest2.main()

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=208241&r1=208240&r2=208241&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/lldbgdbserverutils.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/lldbgdbserverutils.py Wed May  7 14:28:21 2014
@@ -3,8 +3,10 @@
 
 import os
 import os.path
+import platform
 import re
 import select
+import subprocess
 import time
 
 
@@ -142,9 +144,10 @@ def expect_lldb_gdbserver_replay(
         logger: a Python logger instance.
 
     Returns:
-        None if no issues.  Raises an exception if the expected communication does not
-        occur.
-
+        The context dictionary from running the given gdbremote
+        protocol sequence.  This will contain any of the capture
+        elements specified to any GdbRemoteEntry instances in
+        test_sequence.
     """
     received_lines = []
     receive_buffer = ''
@@ -205,7 +208,7 @@ def expect_lldb_gdbserver_replay(
             if len(received_lines) > 0:
                 received_packet = received_lines.pop(0)
                 context = sequence_entry.assert_match(asserter, received_packet, context=context)
-    return None
+    return context
 
 
 def gdbremote_hex_encode_string(str):
@@ -405,6 +408,45 @@ class GdbRemoteTestSequence(object):
                         self.logger.info("processed dict sequence to match receiving from remote")
                     self.entries.append(GdbRemoteEntry(is_send_to_remote=False, regex=regex, capture=capture, expect_captures=expect_captures))
 
+def process_is_running(pid, unknown_value=True):
+    """If possible, validate that the given pid represents a running process on the local system.
+
+    Args:
+
+        pid: an OS-specific representation of a process id.  Should be an integral value.
+
+        unknown_value: value used when we cannot determine how to check running local
+        processes on the OS.
+
+    Returns:
+
+        If we can figure out how to check running process ids on the given OS:
+        return True if the process is running, or False otherwise.
+
+        If we don't know how to check running process ids on the given OS:
+        return the value provided by the unknown_value arg.
+    """
+    if type(pid) != int:
+        raise Exception("pid must be of type int")
+
+    process_ids = []
+
+    if platform.system() in ['Darwin', 'Linux', 'FreeBSD', 'NetBSD']:
+        # Build the list of running process ids
+        output = subprocess.check_output("ps ax | awk '{ print $1; }'", shell=True)
+        text_process_ids = output.split('\n')[1:]
+        # Convert text pids to ints
+        process_ids = [int(text_pid) for text_pid in text_process_ids if text_pid != '']
+    # elif {your_platform_here}:
+    #   fill in process_ids as a list of int type process IDs running on
+    #   the local system.
+    else:
+        # Don't know how to get list of running process IDs on this
+        # OS, so return the "don't know" value.
+        return unknown_value
+
+    # Check if the pid is in the process_ids
+    return pid in process_ids
 
 if __name__ == '__main__':
     EXE_PATH = get_lldb_gdbserver_exe()

Modified: lldb/trunk/tools/debugserver/source/RNBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBRemote.cpp?rev=208241&r1=208240&r2=208241&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/RNBRemote.cpp (original)
+++ lldb/trunk/tools/debugserver/source/RNBRemote.cpp Wed May  7 14:28:21 2014
@@ -1404,15 +1404,21 @@ RNBRemote::HandlePacket_qRcmd (const cha
 rnb_err_t
 RNBRemote::HandlePacket_qC (const char *p)
 {
-    nub_process_t pid;
+    nub_thread_t tid;
     std::ostringstream rep;
     // If we haven't run the process yet, we tell the debugger the
     // pid is 0.  That way it can know to tell use to run later on.
-    if (m_ctx.HasValidProcessID())
-        pid = m_ctx.ProcessID();
+    if (!m_ctx.HasValidProcessID())
+        tid = 0;
     else
-        pid = 0;
-    rep << "QC" << std::hex << pid;
+    {
+        // Grab the current thread.
+        tid = DNBProcessGetCurrentThread (m_ctx.ProcessID());
+        // Make sure we set the current thread so g and p packets return
+        // the data the gdb will expect.
+        SetCurrentThread (tid);
+    }
+    rep << "QC" << std::hex << tid;
     return SendPacket (rep.str());
 }
 





More information about the lldb-commits mailing list