forked from qt-creator/qt-creator
ProcessStub: Fix start sequencing
An application that is using ptrace will send SIGTRAP as soon as it reaches its execve call. The process stub previously expected the only signal sent from the inferior to be SIGSTOP due to the PTRACE_DETACH call with the SIGSTOP argument. This meant that a race could occur where the SIGTRAP was received instead of the SIGSTOP and so the PTRACE_DETACH did not actually detach correctly. This patch fixes it so that it first waits for the SIGTRAP and then calls detach and waits for the expected SIGSTOP. Should this fail, more debug output is added to ease debugging failures. Fixes: QTCREATORBUG-29463 Change-Id: Ibac8b75de0c5604aeb20faba8aff58633329341e Reviewed-by: Artem Sokolovskii <artem.sokolovskii@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -1450,9 +1450,11 @@ void GdbEngine::handleStop2(const GdbMi &data)
|
||||
|
||||
void GdbEngine::handleStop3()
|
||||
{
|
||||
DebuggerCommand cmd("-thread-info", Discardable);
|
||||
cmd.callback = CB(handleThreadInfo);
|
||||
runCommand(cmd);
|
||||
if (terminal() && state() != InferiorRunOk) {
|
||||
DebuggerCommand cmd("-thread-info", Discardable);
|
||||
cmd.callback = CB(handleThreadInfo);
|
||||
runCommand(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
void GdbEngine::handleShowVersion(const DebuggerResponse &response)
|
||||
|
@@ -211,6 +211,38 @@ void onInferiorErrorOccurered(QProcess::ProcessError error)
|
||||
qCWarning(log) << "Inferior error: " << error << inferiorProcess.errorString();
|
||||
}
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
QString statusToString(int status)
|
||||
{
|
||||
if (WIFEXITED(status))
|
||||
return QString("exit, status=%1").arg(WEXITSTATUS(status));
|
||||
else if (WIFSIGNALED(status))
|
||||
return QString("Killed by: %1").arg(WTERMSIG(status));
|
||||
else if (WIFSTOPPED(status)) {
|
||||
return QString("Stopped by: %1").arg(WSTOPSIG(status));
|
||||
} else if (WIFCONTINUED(status))
|
||||
return QString("Continued");
|
||||
|
||||
return QString("Unknown status");
|
||||
}
|
||||
|
||||
bool waitFor(int signalToWaitFor)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
waitpid(inferiorId, &status, WUNTRACED);
|
||||
|
||||
if (!WIFSTOPPED(status) || WSTOPSIG(status) != signalToWaitFor) {
|
||||
qCCritical(log) << "Unexpected status during startup:" << statusToString(status)
|
||||
<< ", aborting";
|
||||
sendCrash(0xFF);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void onInferiorStarted()
|
||||
{
|
||||
inferiorId = inferiorProcess.processId();
|
||||
@@ -223,25 +255,21 @@ void onInferiorStarted()
|
||||
if (!debugMode)
|
||||
sendPid(inferiorId);
|
||||
#else
|
||||
|
||||
if (debugMode) {
|
||||
qCInfo(log) << "Waiting for SIGTRAP from inferiors execve ...";
|
||||
if (!waitFor(SIGTRAP))
|
||||
return;
|
||||
|
||||
qCInfo(log) << "Detaching ...";
|
||||
ptrace(PTRACE_DETACH, inferiorId, 0, SIGSTOP);
|
||||
|
||||
// Wait until the process actually finished detaching
|
||||
int status = 0;
|
||||
waitpid(inferiorId, &status, WUNTRACED);
|
||||
if (log().isInfoEnabled()) {
|
||||
if (WIFEXITED(status))
|
||||
qCInfo(log) << "inferior exited, status=" << WEXITSTATUS(status);
|
||||
else if (WIFSIGNALED(status))
|
||||
qCInfo(log) << "inferior killed by signal" << WTERMSIG(status);
|
||||
else if (WIFSTOPPED(status))
|
||||
qCInfo(log) << "inferior stopped by signal" << WSTOPSIG(status);
|
||||
else if (WIFCONTINUED(status))
|
||||
qCInfo(log) << "inferior continued";
|
||||
}
|
||||
if (!waitFor(SIGSTOP))
|
||||
return;
|
||||
}
|
||||
|
||||
qCInfo(log) << "Sending pid:" << inferiorId;
|
||||
sendPid(inferiorId);
|
||||
#endif
|
||||
}
|
||||
|
Reference in New Issue
Block a user