[lldb] [gdb-remote server] Introduce new stop reasons for fork and vfork

Introduce three new stop reasons for fork, vfork and vforkdone events.
This includes server support for serializing fork/vfork events into
gdb-remote protocol.  The stop infos for the two base events take a pair
of PID and TID for the newly forked process.

Differential Revision: https://reviews.llvm.org/D100196
This commit is contained in:
Michał Górny
2021-03-29 17:05:30 +02:00
parent 312257688e
commit 6c37984eba
16 changed files with 99 additions and 0 deletions

View File

@@ -104,6 +104,9 @@ public:
eStopReasonSignal 1 unix signal number
eStopReasonException N exception data
eStopReasonExec 0
eStopReasonFork 1 pid of the child process
eStopReasonVFork 1 pid of the child process
eStopReasonVForkDone 0
eStopReasonPlanComplete 0") GetStopReasonDataAtIndex;
uint64_t
GetStopReasonDataAtIndex(uint32_t idx);

View File

@@ -73,6 +73,9 @@ public:
eStopReasonSignal 1 unix signal number
eStopReasonException N exception data
eStopReasonExec 0
eStopReasonFork 1 pid of the child process
eStopReasonVFork 1 pid of the child process
eStopReasonVForkDone 0
eStopReasonPlanComplete 0") GetStopReasonDataAtIndex;
uint64_t
GetStopReasonDataAtIndex(uint32_t idx);

View File

@@ -342,6 +342,9 @@ StopReason
.. py:data:: eStopReasonSignal
.. py:data:: eStopReasonException
.. py:data:: eStopReasonExec
.. py:data:: eStopReasonFork
.. py:data:: eStopReasonVFork
.. py:data:: eStopReasonVForkDone
.. py:data:: eStopReasonPlanComplete
.. py:data:: eStopReasonThreadExiting
.. py:data:: eStopReasonInstrumentation

View File

@@ -255,6 +255,15 @@ class TestCase:
select_thread = True
if self.verbose:
print("signal %d" % (thread.GetStopReasonDataAtIndex(0)))
elif stop_reason == lldb.eStopReasonFork:
if self.verbose:
print("fork pid = %d" % (thread.GetStopReasonDataAtIndex(0)))
elif stop_reason == lldb.eStopReasonVFork:
if self.verbose:
print("vfork pid = %d" % (thread.GetStopReasonDataAtIndex(0)))
elif stop_reason == lldb.eStopReasonVForkDone:
if self.verbose:
print("vfork done")
if select_thread and not selected_thread:
self.thread = thread

View File

@@ -66,6 +66,9 @@ public:
/// eStopReasonSignal 1 unix signal number
/// eStopReasonException N exception data
/// eStopReasonExec 0
/// eStopReasonFork 1 pid of the child process
/// eStopReasonVFork 1 pid of the child process
/// eStopReasonVForkDone 0
/// eStopReasonPlanComplete 0
uint64_t GetStopReasonDataAtIndex(uint32_t idx);

View File

@@ -58,6 +58,9 @@ public:
/// eStopReasonSignal 1 unix signal number
/// eStopReasonException N exception data
/// eStopReasonExec 0
/// eStopReasonFork 1 pid of the child process
/// eStopReasonVFork 1 pid of the child process
/// eStopReasonVForkDone 0
/// eStopReasonPlanComplete 0
uint64_t GetStopReasonDataAtIndex(uint32_t idx);

View File

@@ -144,6 +144,12 @@ struct ThreadStopInfo {
uint32_t data_count;
lldb::addr_t data[8];
} exception;
// eStopReasonFork / eStopReasonVFork
struct {
lldb::pid_t child_pid;
lldb::tid_t child_tid;
} fork;
} details;
};
}

View File

@@ -249,6 +249,9 @@ enum StopReason {
eStopReasonThreadExiting,
eStopReasonInstrumentation,
eStopReasonProcessorTrace,
eStopReasonFork,
eStopReasonVFork,
eStopReasonVForkDone,
};
/// Command Return Status Types.

View File

@@ -252,6 +252,12 @@ def stop_reason_to_str(enum):
return "watchpoint"
elif enum == lldb.eStopReasonExec:
return "exec"
elif enum == lldb.eStopReasonFork:
return "fork"
elif enum == lldb.eStopReasonVFork:
return "vfork"
elif enum == lldb.eStopReasonVForkDone:
return "vforkdone"
elif enum == lldb.eStopReasonSignal:
return "signal"
elif enum == lldb.eStopReasonException:

View File

@@ -173,6 +173,7 @@ size_t SBThread::GetStopReasonDataCount() {
case eStopReasonThreadExiting:
case eStopReasonInstrumentation:
case eStopReasonProcessorTrace:
case eStopReasonVForkDone:
// There is no data for these stop reasons.
return 0;
@@ -195,6 +196,12 @@ size_t SBThread::GetStopReasonDataCount() {
case eStopReasonException:
return 1;
case eStopReasonFork:
return 1;
case eStopReasonVFork:
return 1;
}
}
}
@@ -225,6 +232,7 @@ uint64_t SBThread::GetStopReasonDataAtIndex(uint32_t idx) {
case eStopReasonThreadExiting:
case eStopReasonInstrumentation:
case eStopReasonProcessorTrace:
case eStopReasonVForkDone:
// There is no data for these stop reasons.
return 0;
@@ -258,6 +266,12 @@ uint64_t SBThread::GetStopReasonDataAtIndex(uint32_t idx) {
case eStopReasonException:
return stop_info_sp->GetValue();
case eStopReasonFork:
return stop_info_sp->GetValue();
case eStopReasonVFork:
return stop_info_sp->GetValue();
}
}
}

View File

@@ -659,6 +659,12 @@ static const char *GetStopReasonString(StopReason stop_reason) {
return "exec";
case eStopReasonProcessorTrace:
return "processor trace";
case eStopReasonFork:
return "fork";
case eStopReasonVFork:
return "vfork";
case eStopReasonVForkDone:
return "vforkdone";
case eStopReasonInstrumentation:
case eStopReasonInvalid:
case eStopReasonPlanComplete:
@@ -934,6 +940,22 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread(
}
}
// Include child process PID/TID for forks.
if (tid_stop_info.reason == eStopReasonFork ||
tid_stop_info.reason == eStopReasonVFork) {
assert(bool(m_extensions_supported &
NativeProcessProtocol::Extension::multiprocess));
if (tid_stop_info.reason == eStopReasonFork)
assert(bool(m_extensions_supported &
NativeProcessProtocol::Extension::fork));
if (tid_stop_info.reason == eStopReasonVFork)
assert(bool(m_extensions_supported &
NativeProcessProtocol::Extension::vfork));
response.Printf("%s:p%" PRIx64 ".%" PRIx64 ";", reason_str,
tid_stop_info.details.fork.child_pid,
tid_stop_info.details.fork.child_tid);
}
return SendPacketNoLock(response.GetString());
}

View File

@@ -822,6 +822,9 @@ bool Process::HandleProcessStateChangedEvent(const EventSP &event_sp,
case eStopReasonWatchpoint:
case eStopReasonException:
case eStopReasonExec:
case eStopReasonFork:
case eStopReasonVFork:
case eStopReasonVForkDone:
case eStopReasonThreadExiting:
case eStopReasonInstrumentation:
case eStopReasonProcessorTrace:

View File

@@ -131,6 +131,9 @@ void StackFrameList::ResetCurrentInlinedDepth() {
case eStopReasonWatchpoint:
case eStopReasonException:
case eStopReasonExec:
case eStopReasonFork:
case eStopReasonVFork:
case eStopReasonVForkDone:
case eStopReasonSignal:
// In all these cases we want to stop in the deepest frame.
m_current_inlined_pc = curr_pc;

View File

@@ -1679,6 +1679,12 @@ std::string Thread::StopReasonAsString(lldb::StopReason reason) {
return "exception";
case eStopReasonExec:
return "exec";
case eStopReasonFork:
return "fork";
case eStopReasonVFork:
return "vfork";
case eStopReasonVForkDone:
return "vfork done";
case eStopReasonPlanComplete:
return "plan complete";
case eStopReasonThreadExiting:

View File

@@ -878,6 +878,15 @@ llvm::json::Value CreateThreadStopped(lldb::SBThread &thread,
case lldb::eStopReasonExec:
body.try_emplace("reason", "entry");
break;
case lldb::eStopReasonFork:
body.try_emplace("reason", "fork");
break;
case lldb::eStopReasonVFork:
body.try_emplace("reason", "vfork");
break;
case lldb::eStopReasonVForkDone:
body.try_emplace("reason", "vforkdone");
break;
case lldb::eStopReasonThreadExiting:
case lldb::eStopReasonInvalid:
case lldb::eStopReasonNone:

View File

@@ -56,6 +56,9 @@ bool ThreadHasStopReason(lldb::SBThread &thread) {
case lldb::eStopReasonException:
case lldb::eStopReasonExec:
case lldb::eStopReasonProcessorTrace:
case lldb::eStopReasonFork:
case lldb::eStopReasonVFork:
case lldb::eStopReasonVForkDone:
return true;
case lldb::eStopReasonThreadExiting:
case lldb::eStopReasonInvalid: