From 89646aadce9037bbd990f752c85b777e488d988e Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 25 Feb 2021 12:38:44 +0100 Subject: [PATCH] Utils: Don't raise SIGSTOP in the process stub Previously, the starting inferior was sent a SIGSTOP to avoid progress before the debugger could attach. However, these signals are then also visible in the debugger and need to be ignored as part of the startup handling in Creator. The waiting effect can be achieved less intrusively by waiting on a pipe read between fork() and exec(). Task-number: QTCREATORBUG-25073 Task-number: QTCREATORBUG-25082 Task-number: QTCREATORBUG-25227 Change-Id: Ie70b9eb5ea865f85411c26b0dbf377a019fec8d5 Reviewed-by: Eike Ziller Reviewed-by: Christian Stenger --- share/qtcreator/debugger/lldbbridge.py | 11 -------- src/libs/utils/consoleprocess.cpp | 12 +++++++++ src/libs/utils/consoleprocess.h | 1 + src/libs/utils/process_stub_unix.c | 36 +++++++++++++++++++------- src/plugins/debugger/gdb/gdbengine.cpp | 25 +++--------------- src/plugins/debugger/terminal.cpp | 5 ++++ src/plugins/debugger/terminal.h | 1 + 7 files changed, 50 insertions(+), 41 deletions(-) diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index e1e0222d02b..c83b349e80a 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -904,14 +904,6 @@ class Dumper(DumperBase): except: # Could have been deleted in the mean time. pass - self.ignoreStops = 0 - if platform.system() == 'Linux': - if self.startMode_ == DebuggerStartMode.AttachCore: - pass - else: - if self.useTerminal_: - self.ignoreStops = 1 - if self.platform_: self.debugger.SetCurrentPlatform(self.platform_) # sysroot has to be set *after* the platform @@ -1450,9 +1442,6 @@ class Dumper(DumperBase): if self.isInterrupting_: self.isInterrupting_ = False self.reportState("inferiorstopok") - elif self.ignoreStops > 0: - self.ignoreStops -= 1 - self.process.Continue() else: self.reportState("stopped") else: diff --git a/src/libs/utils/consoleprocess.cpp b/src/libs/utils/consoleprocess.cpp index bd6f6231b8c..18f6a73e6da 100644 --- a/src/libs/utils/consoleprocess.cpp +++ b/src/libs/utils/consoleprocess.cpp @@ -611,6 +611,18 @@ bool ConsoleProcess::start() return true; } +void Utils::ConsoleProcess::kickoffProcess() +{ +#ifdef Q_OS_WIN + // Not used. +#else + if (d->m_stubSocket && d->m_stubSocket->isWritable()) { + d->m_stubSocket->write("c", 1); + d->m_stubSocket->flush(); + } +#endif +} + void ConsoleProcess::interruptProcess() { #ifdef Q_OS_WIN diff --git a/src/libs/utils/consoleprocess.h b/src/libs/utils/consoleprocess.h index ce53e0d87c7..16373fe76e0 100644 --- a/src/libs/utils/consoleprocess.h +++ b/src/libs/utils/consoleprocess.h @@ -90,6 +90,7 @@ public: bool isRunning() const; // This reflects the state of the console+stub qint64 applicationPID() const; + void kickoffProcess(); void interruptProcess(); void killProcess(); void killStub(); diff --git a/src/libs/utils/process_stub_unix.c b/src/libs/utils/process_stub_unix.c index 271404fe3bb..d7a7ff15b09 100644 --- a/src/libs/utils/process_stub_unix.c +++ b/src/libs/utils/process_stub_unix.c @@ -57,6 +57,7 @@ extern char **environ; static int qtcFd; static char *sleepMsg; static int chldPipe[2]; +static int blockingPipe[2]; static int isDebug; static volatile int isDetached; static volatile int chldPid; @@ -236,10 +237,21 @@ int main(int argc, char *argv[]) perror("Cannot create status pipe"); doExit(3); } + /* The debugged program is not supposed to inherit these handles. But we cannot * close the writing end before calling exec(). Just handle both ends the same way ... */ fcntl(chldPipe[0], F_SETFD, FD_CLOEXEC); fcntl(chldPipe[1], F_SETFD, FD_CLOEXEC); + + if (isDebug) { + /* Create execution start notification pipe. The child waits on this until + the parent writes to it, triggered by an 'c' message from Creator */ + if (pipe(blockingPipe)) { + perror("Cannot create blocking pipe"); + doExit(3); + } + } + switch ((chldPid = fork())) { case -1: perror("Cannot fork child process"); @@ -262,9 +274,15 @@ int main(int argc, char *argv[]) #ifdef __linux__ prctl(PR_SET_PTRACER, atoi(argv[ArgPid])); #endif - /* Stop the child to allow the debugger to attach */ - if (isDebug) - kill(chldPid, SIGSTOP); + /* Block to allow the debugger to attach */ + if (isDebug) { + char buf; + int res = read(blockingPipe[0], &buf, 1); + if (res < 0) + perror("Could not read from blocking pipe"); + close(blockingPipe[0]); + close(blockingPipe[1]); + } if (env) environ = env; @@ -296,6 +314,7 @@ int main(int argc, char *argv[]) break; } else { int i; + char c = 'i'; for (i = 0; i < nbytes; ++i) { switch (buffer[i]) { case 'k': @@ -305,13 +324,12 @@ int main(int argc, char *argv[]) kill(chldPid, SIGKILL); } break; - case 'i': - if (chldPid > 0) { - int res = kill(chldPid, SIGINT); - if (res) - perror("Stub could not interrupt inferior"); - } + case 'c': { + int res = write(blockingPipe[1], &c, 1); + if (res < 0) + perror("Could not write to blocking pipe"); break; + } case 'd': isDetached = 1; break; diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 42ee110f7e8..3d5c6c07188 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -1147,26 +1147,6 @@ void GdbEngine::handleStopResponse(const GdbMi &data) return; } - // Ignore signals from the process stub. - const GdbMi frame = data["frame"]; - if (terminal() - && data["reason"].data() == "signal-received" - && data["signal-name"].data() == "SIGSTOP") - { - const QString from = frame["from"].data(); - const QString func = frame["func"].data(); - if (from.endsWith("/ld-linux.so.2") - || from.endsWith("/ld-linux-x86-64.so.2") - || func == "clone" - || func == "kill") - { - showMessage("INTERNAL CONTINUE AFTER SIGSTOP FROM STUB", LogMisc); - notifyInferiorSpontaneousStop(); - continueInferiorInternal(); - return; - } - } - if (!m_onStop.isEmpty()) { notifyInferiorStopOk(); showMessage("HANDLING QUEUED COMMANDS AFTER TEMPORARY STOP", LogMisc); @@ -1184,6 +1164,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data) QString fullName; QString function; QString language; + const GdbMi frame = data["frame"]; if (frame.isValid()) { const GdbMi lineNumberG = frame["line"]; function = frame["function"].data(); // V4 protocol @@ -4919,7 +4900,9 @@ void GdbEngine::handleStubAttached(const DebuggerResponse &response, qint64 main notifyEngineRunAndInferiorStopOk(); continueInferiorInternal(); } else { - showMessage("INFERIOR ATTACHED AND RUNNING"); + showMessage("INFERIOR ATTACHED"); + QTC_ASSERT(terminal(), return); + terminal()->kickoffProcess(); //notifyEngineRunAndInferiorRunOk(); // Wait for the upcoming *stopped and handle it there. } diff --git a/src/plugins/debugger/terminal.cpp b/src/plugins/debugger/terminal.cpp index c54336c0456..24b1f72f23d 100644 --- a/src/plugins/debugger/terminal.cpp +++ b/src/plugins/debugger/terminal.cpp @@ -183,6 +183,11 @@ TerminalRunner::TerminalRunner(RunControl *runControl, const Runnable &stubRunna this, [this] { reportDone(); }); } +void TerminalRunner::kickoffProcess() +{ + m_stubProc.kickoffProcess(); +} + void TerminalRunner::interruptProcess() { m_stubProc.interruptProcess(); diff --git a/src/plugins/debugger/terminal.h b/src/plugins/debugger/terminal.h index 410d0fb7d91..ceacf3fddd7 100644 --- a/src/plugins/debugger/terminal.h +++ b/src/plugins/debugger/terminal.h @@ -77,6 +77,7 @@ public: qint64 applicationPid() const { return m_applicationPid; } qint64 applicationMainThreadId() const { return m_applicationMainThreadId; } + void kickoffProcess(); void interruptProcess(); void setRunAsRoot(bool on);