[Lldb-commits] [PATCH] change debugserver $qC to return thread id; change lldb gdb-remote to use $qProcessInfo

Todd Fiala todd.fiala at gmail.com
Wed May 7 11:15:43 PDT 2014


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 $qC immediately after
a launched inferior returns the same thread reported by $?.  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).
-- 
-Todd
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-commits/attachments/20140507/6c7c9dee/attachment.html>
-------------- next part --------------
Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
===================================================================
--- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp	(revision 208224)
+++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp	(working copy)
@@ -57,6 +57,7 @@
     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 @@
     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 @@
     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 @@
 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)
     {
-        if (response.GetChar() == 'Q')
-            if (response.GetChar() == 'C')
-                return response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID);
+        // We really got it.
+        return m_curr_pid;
     }
+    else
+    {
+        // 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 @@
             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 @@
                     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);
Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
===================================================================
--- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h	(revision 208224)
+++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h	(working copy)
@@ -537,6 +537,7 @@
     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 @@
         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
 
Index: test/tools/lldb-gdbserver/TestLldbGdbServer.py
===================================================================
--- test/tools/lldb-gdbserver/TestLldbGdbServer.py	(revision 208224)
+++ test/tools/lldb-gdbserver/TestLldbGdbServer.py	(working copy)
@@ -108,7 +108,7 @@
             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 @@
 
     @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 @@
         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()
Index: test/tools/lldb-gdbserver/lldbgdbserverutils.py
===================================================================
--- test/tools/lldb-gdbserver/lldbgdbserverutils.py	(revision 208224)
+++ test/tools/lldb-gdbserver/lldbgdbserverutils.py	(working copy)
@@ -3,8 +3,10 @@
 
 import os
 import os.path
+import platform
 import re
 import select
+import subprocess
 import time
 
 
@@ -142,9 +144,10 @@
         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 @@
             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,7 +408,46 @@
                         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()
     if EXE_PATH:
Index: tools/debugserver/source/RNBRemote.cpp
===================================================================
--- tools/debugserver/source/RNBRemote.cpp	(revision 208224)
+++ tools/debugserver/source/RNBRemote.cpp	(working copy)
@@ -1404,15 +1404,21 @@
 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