From 373886bc21926e77803110765d90a339b57d3af2 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 29 Aug 2023 09:24:35 +0200 Subject: [PATCH] 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 Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/debugger/gdb/gdbengine.cpp | 8 ++-- src/tools/process_stub/main.cpp | 52 ++++++++++++++++++++------ 2 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index d52e2bc7104..49d28c46fdc 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -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) diff --git a/src/tools/process_stub/main.cpp b/src/tools/process_stub/main.cpp index c54480af4c1..3749333e460 100644 --- a/src/tools/process_stub/main.cpp +++ b/src/tools/process_stub/main.cpp @@ -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 }