summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp55
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h3
-rw-r--r--lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py44
-rw-r--r--lldb/test/tools/lldb-gdbserver/lldbgdbserverutils.py50
-rw-r--r--lldb/tools/debugserver/source/RNBRemote.cpp16
5 files changed, 151 insertions, 17 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 0b642733414..30004202186 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -57,6 +57,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
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::GDBRemoteCommunicationClient(bool is_platform) :
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::ResetDiscoverableSettings()
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::SendInterrupt
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::GetCurrentProcessInfo ()
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::GetCurrentProcessInfo ()
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);
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 4293e8b12d7..6b1aec53928 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -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
diff --git a/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py b/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py
index c093d6e4b42..727f328ee3b 100644
--- a/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py
+++ b/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py
@@ -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()
diff --git a/lldb/test/tools/lldb-gdbserver/lldbgdbserverutils.py b/lldb/test/tools/lldb-gdbserver/lldbgdbserverutils.py
index 0bd44ef7f45..8a70e7b8d71 100644
--- a/lldb/test/tools/lldb-gdbserver/lldbgdbserverutils.py
+++ b/lldb/test/tools/lldb-gdbserver/lldbgdbserverutils.py
@@ -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()
diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp
index 71d3b8357c9..7b592ff1e7a 100644
--- a/lldb/tools/debugserver/source/RNBRemote.cpp
+++ b/lldb/tools/debugserver/source/RNBRemote.cpp
@@ -1404,15 +1404,21 @@ RNBRemote::HandlePacket_qRcmd (const char *p)
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());
}
OpenPOWER on IntegriCloud