Skip to content

Commit

Permalink
[lldb] [llgs] Implement the 'T' packet
Browse files Browse the repository at this point in the history
Implement the 'T' packet that is used to verify whether the specified
thread belongs to the debugged processes.

Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.llvm.org/D128170
  • Loading branch information
mgorny committed Jun 24, 2022
1 parent 630da0e commit e827e51
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
&GDBRemoteCommunicationServerLLGS::Handle_P);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC,
&GDBRemoteCommunicationServerLLGS::Handle_qC);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_T,
&GDBRemoteCommunicationServerLLGS::Handle_T);
RegisterMemberFunctionHandler(
StringExtractorGDBRemote::eServerPacketType_qfThreadInfo,
&GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo);
Expand Down Expand Up @@ -3898,6 +3900,36 @@ GDBRemoteCommunicationServerLLGS::Handle_vCtrlC(
return SendOKResponse();
}

GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_T(StringExtractorGDBRemote &packet) {
packet.SetFilePos(strlen("T"));
auto pid_tid = packet.GetPidTid(m_current_process ? m_current_process->GetID()
: LLDB_INVALID_PROCESS_ID);
if (!pid_tid)
return SendErrorResponse(llvm::make_error<StringError>(
inconvertibleErrorCode(), "Malformed thread-id"));

lldb::pid_t pid = pid_tid->first;
lldb::tid_t tid = pid_tid->second;

// Technically, this would also be caught by the PID check but let's be more
// explicit about the error.
if (pid == LLDB_INVALID_PROCESS_ID)
return SendErrorResponse(llvm::make_error<StringError>(
inconvertibleErrorCode(), "No current process and no PID provided"));

// Check the process ID and find respective process instance.
auto new_process_it = m_debugged_processes.find(pid);
if (new_process_it == m_debugged_processes.end())
return SendErrorResponse(1);

// Check the thread ID
if (!new_process_it->second->GetThreadByID(tid))
return SendErrorResponse(2);

return SendOKResponse();
}

void GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection() {
Log *log = GetLog(LLDBLog::Process);

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

PacketResult Handle_QMemTags(StringExtractorGDBRemote &packet);

PacketResult Handle_T(StringExtractorGDBRemote &packet);

void SetCurrentThreadID(lldb::tid_t tid);

lldb::tid_t GetCurrentThreadID() const;
Expand Down
73 changes: 73 additions & 0 deletions lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py
Original file line number Diff line number Diff line change
Expand Up @@ -866,3 +866,76 @@ def test_qC(self):
"send packet: $QCp{:x}.{:x}#00".format(*pidtid),
], True)
self.expect_gdbremote_sequence()

@add_test_categories(["fork"])
def test_T(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"]),
]
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()

pidtids = set(self.parse_threadinfo_packets(ret))
self.assertEqual(len(pidtids), 4)
max_pid = max(pid for pid, tid in pidtids)
max_tid = max(tid for pid, tid in pidtids)
bad_pidtids = (
(max_pid, max_tid + 1, "E02"),
(max_pid + 1, max_tid, "E01"),
(max_pid + 1, max_tid + 1, "E01"),
)

for pidtid in pidtids:
self.test_sequence.add_log_lines(
[
# test explicit PID+TID
"read packet: $Tp{:x}.{:x}#00".format(*pidtid),
"send packet: $OK#00",
# test implicit PID via Hg
"read packet: $Hgp{:x}.{:x}#00".format(*pidtid),
"send packet: $OK#00",
"read packet: $T{:x}#00".format(max_tid + 1),
"send packet: $E02#00",
"read packet: $T{:x}#00".format(pidtid[1]),
"send packet: $OK#00",
], True)
for pid, tid, expected in bad_pidtids:
self.test_sequence.add_log_lines(
["read packet: $Tp{:x}.{:x}#00".format(pid, tid),
"send packet: ${}#00".format(expected),
], True)
self.expect_gdbremote_sequence()

0 comments on commit e827e51

Please sign in to comment.