Skip to content

Commit

Permalink
[lldb] [llgs] Support multiprocess in qfThreadInfo
Browse files Browse the repository at this point in the history
Update the `qfThreadInfo` handler to report threads of all debugged
processes and include PIDs when in multiprocess mode.

Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.llvm.org/D128152
  • Loading branch information
mgorny committed Jun 24, 2022
1 parent 0481d8e commit 75757c8
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,14 @@ def parse_threadinfo_response(response_packet):
response_packet = _STRIP_COMMAND_PREFIX_M_REGEX.sub("", response_packet)
response_packet = _STRIP_CHECKSUM_REGEX.sub("", response_packet)

# Return list of thread ids
return [int(thread_id_hex, 16) for thread_id_hex in response_packet.split(
",") if len(thread_id_hex) > 0]
for tid in response_packet.split(","):
if not tid:
continue
if tid.startswith("p"):
pid, _, tid = tid.partition(".")
yield (int(pid[1:], 16), int(tid, 16))
else:
yield int(tid, 16)


def unpack_endian_binary_string(endian, value_string):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1974,38 +1974,46 @@ GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo(
return SendPacketNoLock(response.GetString());
}

GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo(
StringExtractorGDBRemote &packet) {
void GDBRemoteCommunicationServerLLGS::AddProcessThreads(
StreamGDBRemote &response, NativeProcessProtocol &process, bool &had_any) {
Log *log = GetLog(LLDBLog::Thread);

// Fail if we don't have a current process.
if (!m_current_process ||
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
LLDB_LOG(log, "no process ({0}), returning OK",
m_current_process ? "invalid process id"
: "null m_current_process");
return SendOKResponse();
}

StreamGDBRemote response;
response.PutChar('m');
lldb::pid_t pid = process.GetID();
if (pid == LLDB_INVALID_PROCESS_ID)
return;

LLDB_LOG(log, "starting thread iteration");
LLDB_LOG(log, "iterating over threads of process {0}", process.GetID());
NativeThreadProtocol *thread;
uint32_t thread_index;
for (thread_index = 0,
thread = m_current_process->GetThreadAtIndex(thread_index);
thread; ++thread_index,
thread = m_current_process->GetThreadAtIndex(thread_index)) {
LLDB_LOG(log, "iterated thread {0}(tid={2})", thread_index,
for (thread_index = 0, thread = process.GetThreadAtIndex(thread_index);
thread;
++thread_index, thread = process.GetThreadAtIndex(thread_index)) {
LLDB_LOG(log, "iterated thread {0} (tid={1})", thread_index,
thread->GetID());
if (thread_index > 0)
response.PutChar(',');
response.Printf("%" PRIx64, thread->GetID());
response.PutChar(had_any ? ',' : 'm');
if (bool(m_extensions_supported &
NativeProcessProtocol::Extension::multiprocess))
response.Format("p{0:x-}.", pid);
response.Format("{0:x-}", thread->GetID());
had_any = true;
}
}

LLDB_LOG(log, "finished thread iteration");
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo(
StringExtractorGDBRemote &packet) {
assert(m_debugged_processes.size() == 1 ||
bool(m_extensions_supported &
NativeProcessProtocol::Extension::multiprocess));

bool had_any = false;
StreamGDBRemote response;

for (auto &pid_ptr : m_debugged_processes)
AddProcessThreads(response, *pid_ptr.second, had_any);

if (!had_any)
response.PutChar('l');
return SendPacketNoLock(response.GetString());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ class GDBRemoteCommunicationServerLLGS

PacketResult Handle_qRegisterInfo(StringExtractorGDBRemote &packet);

void AddProcessThreads(StreamGDBRemote &response,
NativeProcessProtocol &process, bool &had_any);

PacketResult Handle_qfThreadInfo(StringExtractorGDBRemote &packet);

PacketResult Handle_qsThreadInfo(StringExtractorGDBRemote &packet);
Expand Down
60 changes: 60 additions & 0 deletions lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,66 @@ def test_vCont_all_processes_implicit(self):
], True)
self.expect_gdbremote_sequence()

@add_test_categories(["fork"])
def test_threadinfo(self):
self.build()
self.prep_debug_monitor_and_inferior(
inferior_args=["fork",
"thread:new",
"trap",
])
self.add_qSupported_packets(["multiprocess+",
"fork-events+"])
ret = self.expect_gdbremote_sequence()
self.assertIn("fork-events+", ret["qSupported_response"])
self.reset_test_sequence()

# continue and expect fork
self.test_sequence.add_log_lines([
"read packet: $c#00",
{"direction": "send", "regex": self.fork_regex.format("fork"),
"capture": self.fork_capture},
], True)
self.add_threadinfo_collection_packets()
ret = self.expect_gdbremote_sequence()
pidtids = [
(ret["parent_pid"], ret["parent_tid"]),
(ret["child_pid"], ret["child_tid"]),
]
prev_pidtids = set(self.parse_threadinfo_packets(ret))
self.assertEqual(prev_pidtids,
frozenset((int(pid, 16), int(tid, 16))
for pid, tid in pidtids))
self.reset_test_sequence()

for pidtid in pidtids:
self.test_sequence.add_log_lines(
["read packet: $Hcp{}.{}#00".format(*pidtid),
"send packet: $OK#00",
"read packet: $c#00",
{"direction": "send",
"regex": "^[$]T05thread:p{}.{}.*".format(*pidtid),
},
], True)
self.add_threadinfo_collection_packets()
ret = self.expect_gdbremote_sequence()
self.reset_test_sequence()
new_pidtids = set(self.parse_threadinfo_packets(ret))
added_pidtid = new_pidtids - prev_pidtids
prev_pidtids = new_pidtids

# verify that we've got exactly one new thread, and that
# the PID matches
self.assertEqual(len(added_pidtid), 1)
self.assertEqual(added_pidtid.pop()[0], int(pidtid[0], 16))

for pidtid in new_pidtids:
self.test_sequence.add_log_lines(
["read packet: $Hgp{:x}.{:x}#00".format(*pidtid),
"send packet: $OK#00",
], True)
self.expect_gdbremote_sequence()

@add_test_categories(["fork"])
def test_memory_read_write(self):
self.build()
Expand Down

0 comments on commit 75757c8

Please sign in to comment.