Fixes: debugger: work on shutdown

This commit is contained in:
hjk
2009-02-16 13:29:57 +01:00
parent 137ba736a7
commit e4a9d85c00
6 changed files with 62 additions and 73 deletions

View File

@@ -150,7 +150,6 @@ void DebuggerManager::init()
{ {
m_status = -1; m_status = -1;
m_busy = false; m_busy = false;
m_shutdown = false;
m_attachedPID = 0; m_attachedPID = 0;
m_startMode = startInternal; m_startMode = startInternal;
@@ -578,7 +577,7 @@ void DebuggerManager::notifyInferiorExited()
void DebuggerManager::notifyInferiorPidChanged(int pid) void DebuggerManager::notifyInferiorPidChanged(int pid)
{ {
//QMessageBox::warning(0, "PID", "PID: " + QString::number(pid)); //QMessageBox::warning(0, "PID", "PID: " + QString::number(pid));
qDebug() << "PID: " << pid; //qDebug() << "PID: " << pid;
emit inferiorPidChanged(pid); emit inferiorPidChanged(pid);
} }
@@ -590,9 +589,10 @@ void DebuggerManager::showApplicationOutput(const QString &str)
void DebuggerManager::shutdown() void DebuggerManager::shutdown()
{ {
//qDebug() << "DEBUGGER_MANAGER SHUTDOWN START"; //qDebug() << "DEBUGGER_MANAGER SHUTDOWN START";
m_shutdown = true; if (m_engine) {
if (m_engine) //qDebug() << "SHUTTING DOWN ENGINE" << m_engine;
m_engine->shutdown(); m_engine->shutdown();
}
m_engine = 0; m_engine = 0;
delete scriptEngine; delete scriptEngine;
@@ -835,9 +835,8 @@ void DebuggerManager::cleanupViews()
void DebuggerManager::exitDebugger() void DebuggerManager::exitDebugger()
{ {
if (m_shutdown) //qDebug() << "DebuggerManager::exitDebugger";
return; if (m_engine)
QTC_ASSERT(m_engine, return);
m_engine->exitDebugger(); m_engine->exitDebugger();
cleanupViews(); cleanupViews();
setStatus(DebuggerProcessNotReady); setStatus(DebuggerProcessNotReady);
@@ -960,33 +959,6 @@ void DebuggerManager::dumpLog()
ts << m_outputWindow->combinedContents(); ts << m_outputWindow->combinedContents();
} }
#if 0
// call after m_gdbProc exited.
void GdbEngine::procFinished()
{
//qDebug() << "GDB PROCESS FINISHED";
setStatus(DebuggerProcessNotReady);
showStatusMessage(tr("Done"), 5000);
q->m_breakHandler->procFinished();
q->m_watchHandler->cleanup();
m_stackHandler->m_stackFrames.clear();
m_stackHandler->resetModel();
m_threadsHandler->resetModel();
if (q->m_modulesHandler)
q->m_modulesHandler->procFinished();
q->resetLocation();
setStatus(DebuggerProcessNotReady);
emit q->previousModeRequested();
emit q->debuggingFinished();
//exitDebugger();
//showStatusMessage("Gdb killed");
m_shortToFullName.clear();
m_fullToShortName.clear();
m_shared = 0;
q->m_busy = false;
}
#endif
void DebuggerManager::addToWatchWindow() void DebuggerManager::addToWatchWindow()
{ {
// requires a selection, but that's the only case we want... // requires a selection, but that's the only case we want...

View File

@@ -466,8 +466,6 @@ private:
IDebuggerEngine *engine(); IDebuggerEngine *engine();
IDebuggerEngine *m_engine; IDebuggerEngine *m_engine;
DebuggerSettings m_settings; DebuggerSettings m_settings;
// set during application shutdown
bool m_shutdown;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -115,6 +115,8 @@ DebuggerRunControl::DebuggerRunControl(DebuggerManager *manager,
connect(m_manager, SIGNAL(inferiorPidChanged(qint64)), connect(m_manager, SIGNAL(inferiorPidChanged(qint64)),
this, SLOT(bringApplicationToForeground(qint64)), this, SLOT(bringApplicationToForeground(qint64)),
Qt::QueuedConnection); Qt::QueuedConnection);
connect(this, SIGNAL(stopRequested()),
m_manager, SLOT(exitDebugger()));
} }
void DebuggerRunControl::start() void DebuggerRunControl::start()
@@ -148,17 +150,21 @@ void DebuggerRunControl::slotAddToOutputWindowInline(const QString &data)
void DebuggerRunControl::stop() void DebuggerRunControl::stop()
{ {
m_manager->exitDebugger(); //qDebug() << "DebuggerRunControl::stop";
m_running = false;
emit stopRequested();
} }
void DebuggerRunControl::debuggingFinished() void DebuggerRunControl::debuggingFinished()
{ {
m_running = false; m_running = false;
//qDebug() << "DebuggerRunControl::finished";
//emit addToOutputWindow(this, tr("Debugging %1 finished").arg(m_executable)); //emit addToOutputWindow(this, tr("Debugging %1 finished").arg(m_executable));
emit finished(); emit finished();
} }
bool DebuggerRunControl::isRunning() const bool DebuggerRunControl::isRunning() const
{ {
//qDebug() << "DebuggerRunControl::isRunning" << m_running;
return m_running; return m_running;
} }

View File

@@ -82,6 +82,9 @@ public:
virtual void stop(); virtual void stop();
virtual bool isRunning() const; virtual bool isRunning() const;
signals:
void stopRequested();
private slots: private slots:
void debuggingFinished(); void debuggingFinished();
void slotAddToOutputWindowInline(const QString &output); void slotAddToOutputWindowInline(const QString &output);

View File

@@ -257,6 +257,8 @@ GdbEngine::GdbEngine(DebuggerManager *parent)
GdbEngine::~GdbEngine() GdbEngine::~GdbEngine()
{ {
// prevent sending error messages afterwards
m_gdbProc.disconnect(this);
} }
void GdbEngine::initializeConnections() void GdbEngine::initializeConnections()
@@ -386,6 +388,11 @@ void GdbEngine::readDebugeeOutput(const QByteArray &data)
data.constData(), data.length(), &m_outputCodecState)); data.constData(), data.length(), &m_outputCodecState));
} }
void GdbEngine::debugMessage(const QString &msg)
{
emit gdbOutputAvailable("debug:", msg);
}
// called asyncronously as response to Gdb stdout output in // called asyncronously as response to Gdb stdout output in
// gdbResponseAvailable() // gdbResponseAvailable()
void GdbEngine::handleResponse() void GdbEngine::handleResponse()
@@ -656,7 +663,7 @@ void GdbEngine::interruptInferior()
sendCommand("-exec-interrupt", GdbExecInterrupt); sendCommand("-exec-interrupt", GdbExecInterrupt);
qq->notifyInferiorStopped(); qq->notifyInferiorStopped();
#else #else
qDebug() << "CANNOT STOP INFERIOR" << m_gdbProc.pid(); debugMessage(QString("CANNOT STOP INFERIOR %1").arg(m_gdbProc.pid()));
if (interruptChildProcess(m_gdbProc.pid())) if (interruptChildProcess(m_gdbProc.pid()))
qq->notifyInferiorStopped(); qq->notifyInferiorStopped();
#endif #endif
@@ -666,12 +673,12 @@ void GdbEngine::maybeHandleInferiorPidChanged(const QString &pid0)
{ {
int pid = pid0.toInt(); int pid = pid0.toInt();
if (pid == 0) { if (pid == 0) {
qDebug() << "Cannot parse PID from " << pid0; debugMessage(QString("Cannot parse PID from %1").arg(pid0));
return; return;
} }
if (pid == q->m_attachedPID) if (pid == q->m_attachedPID)
return; return;
qDebug() << "FOUND PID " << pid; debugMessage(QString("FOUND PID %1").arg(pid));
q->m_attachedPID = pid; q->m_attachedPID = pid;
qq->notifyInferiorPidChanged(pid); qq->notifyInferiorPidChanged(pid);
} }
@@ -686,7 +693,7 @@ void GdbEngine::sendCommand(const QString &command, int type,
const QVariant &cookie, bool needStop, bool synchronized) const QVariant &cookie, bool needStop, bool synchronized)
{ {
if (m_gdbProc.state() == QProcess::NotRunning) { if (m_gdbProc.state() == QProcess::NotRunning) {
//qDebug() << "NO GDB PROCESS RUNNING, CMD IGNORED:" << command; debugMessage("NO GDB PROCESS RUNNING, CMD IGNORED: " + command);
return; return;
} }
@@ -718,9 +725,7 @@ void GdbEngine::sendCommand(const QString &command, int type,
m_cookieForToken[currentToken()] = cmd; m_cookieForToken[currentToken()] = cmd;
//qDebug() << "";
if (!command.isEmpty()) { if (!command.isEmpty()) {
//qDebug() << qPrintable(currentTime()) << "RUNNING" << cmd.command;
m_gdbProc.write(cmd.command.toLatin1() + "\r\n"); m_gdbProc.write(cmd.command.toLatin1() + "\r\n");
//emit gdbInputAvailable(QString(), " " + currentTime()); //emit gdbInputAvailable(QString(), " " + currentTime());
//emit gdbInputAvailable(QString(), "[" + currentTime() + "] " + cmd.command); //emit gdbInputAvailable(QString(), "[" + currentTime() + "] " + cmd.command);
@@ -920,8 +925,8 @@ void GdbEngine::handleResult(const GdbResultRecord & record, int type,
break; break;
default: default:
qDebug() << "FIXME: GdbEngine::handleResult: " debugMessage(QString("FIXME: GdbEngine::handleResult: "
"should not happen" << type; "should not happen %1").arg(type));
break; break;
} }
} }
@@ -930,7 +935,7 @@ void GdbEngine::executeDebuggerCommand(const QString &command)
{ {
//createGdbProcessIfNeeded(); //createGdbProcessIfNeeded();
if (m_gdbProc.state() == QProcess::NotRunning) { if (m_gdbProc.state() == QProcess::NotRunning) {
qDebug() << "NO GDB PROCESS RUNNING, PLAIN CMD IGNORED: " << command; debugMessage("NO GDB PROCESS RUNNING, PLAIN CMD IGNORED: " + command);
return; return;
} }
@@ -938,11 +943,6 @@ void GdbEngine::executeDebuggerCommand(const QString &command)
cmd.command = command; cmd.command = command;
cmd.type = -1; cmd.type = -1;
//m_cookieForToken[currentToken()] = cmd;
//++currentToken();
//qDebug() << "";
//qDebug() << currentTime() << "Running command: " << cmd.command;
emit gdbInputAvailable(QString(), cmd.command); emit gdbInputAvailable(QString(), cmd.command);
m_gdbProc.write(cmd.command.toLatin1() + "\r\n"); m_gdbProc.write(cmd.command.toLatin1() + "\r\n");
} }
@@ -969,7 +969,7 @@ void GdbEngine::handleQueryPwd(const GdbResultRecord &record)
m_pwd = record.data.findChild("consolestreamoutput").data(); m_pwd = record.data.findChild("consolestreamoutput").data();
m_pwd = m_pwd.trimmed(); m_pwd = m_pwd.trimmed();
#endif #endif
//qDebug() << "PWD RESULT:" << m_pwd; debugMessage("PWD RESULT: " + m_pwd);
} }
} }
@@ -1146,8 +1146,8 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data)
QString msg = data.findChild("consolestreamoutput").data(); QString msg = data.findChild("consolestreamoutput").data();
if (msg.contains("Stopped due to shared library event") || reason.isEmpty()) { if (msg.contains("Stopped due to shared library event") || reason.isEmpty()) {
if (qq->wantsSelectedPluginBreakpoints()) { if (qq->wantsSelectedPluginBreakpoints()) {
qDebug() << "SHARED LIBRARY EVENT " << data.toString(); debugMessage("SHARED LIBRARY EVENT: " + data.toString());
qDebug() << "PATTERN" << qq->selectedPluginBreakpointsPattern(); debugMessage("PATTERN: " + qq->selectedPluginBreakpointsPattern());
sendCommand("sharedlibrary " + qq->selectedPluginBreakpointsPattern()); sendCommand("sharedlibrary " + qq->selectedPluginBreakpointsPattern());
continueInferior(); continueInferior();
q->showStatusMessage(tr("Loading %1...").arg(QString(data.toString()))); q->showStatusMessage(tr("Loading %1...").arg(QString(data.toString())));
@@ -1182,6 +1182,8 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data)
+ data.findChild("signal-name").toString(); + data.findChild("signal-name").toString();
} }
q->showStatusMessage(msg); q->showStatusMessage(msg);
// FIXME: shouldn't this use a statis change?
debugMessage("CALLING PARENT EXITDEBUGGER");
q->exitDebugger(); q->exitDebugger();
return; return;
} }
@@ -1193,21 +1195,21 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data)
if (qq->skipKnownFrames()) { if (qq->skipKnownFrames()) {
if (reason == "end-stepping-range" || reason == "function-finished") { if (reason == "end-stepping-range" || reason == "function-finished") {
GdbMi frame = data.findChild("frame"); GdbMi frame = data.findChild("frame");
//qDebug() << frame.toString(); //debugMessage(frame.toString());
m_currentFrame = frame.findChild("addr").data() + '%' + m_currentFrame = frame.findChild("addr").data() + '%' +
frame.findChild("func").data() + '%'; frame.findChild("func").data() + '%';
QString funcName = frame.findChild("func").data(); QString funcName = frame.findChild("func").data();
QString fileName = frame.findChild("file").data(); QString fileName = frame.findChild("file").data();
if (isLeavableFunction(funcName, fileName)) { if (isLeavableFunction(funcName, fileName)) {
//qDebug() << "LEAVING" << funcName; //debugMessage("LEAVING" + funcName);
++stepCounter; ++stepCounter;
q->stepOutExec(); q->stepOutExec();
//stepExec(); //stepExec();
return; return;
} }
if (isSkippableFunction(funcName, fileName)) { if (isSkippableFunction(funcName, fileName)) {
//qDebug() << "SKIPPING" << funcName; //debugMessage("SKIPPING" + funcName);
++stepCounter; ++stepCounter;
q->stepExec(); q->stepExec();
return; return;
@@ -1227,7 +1229,7 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data)
if (reason == "breakpoint-hit") { if (reason == "breakpoint-hit") {
q->showStatusMessage(tr("Stopped at breakpoint")); q->showStatusMessage(tr("Stopped at breakpoint"));
GdbMi frame = data.findChild("frame"); GdbMi frame = data.findChild("frame");
//qDebug() << "HIT BREAKPOINT: " << frame.toString(); //debugMessage("HIT BREAKPOINT: " + frame.toString());
m_currentFrame = frame.findChild("addr").data() + '%' + m_currentFrame = frame.findChild("addr").data() + '%' +
frame.findChild("func").data() + '%'; frame.findChild("func").data() + '%';
@@ -1243,7 +1245,7 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data)
return; return;
} }
qDebug() << "STOPPED FOR UNKNOWN REASON" << data.toString(); debugMessage("STOPPED FOR UNKNOWN REASON: " + data.toString());
// Ignore it. Will be handled with full response later in the // Ignore it. Will be handled with full response later in the
// JumpToLine or RunToFunction handlers // JumpToLine or RunToFunction handlers
#if 1 #if 1
@@ -1310,7 +1312,7 @@ void GdbEngine::handleShowVersion(const GdbResultRecord &response)
QString msg = response.data.findChild("consolestreamoutput").data(); QString msg = response.data.findChild("consolestreamoutput").data();
QRegExp supported("GNU gdb(.*) (\\d+)\\.(\\d+)(\\.(\\d+))?"); QRegExp supported("GNU gdb(.*) (\\d+)\\.(\\d+)(\\.(\\d+))?");
if (supported.indexIn(msg) == -1) { if (supported.indexIn(msg) == -1) {
qDebug() << "UNSUPPORTED GDB VERSION " << msg; debugMessage("UNSUPPORTED GDB VERSION " + msg);
QStringList list = msg.split("\n"); QStringList list = msg.split("\n");
while (list.size() > 2) while (list.size() > 2)
list.removeLast(); list.removeLast();
@@ -1331,7 +1333,7 @@ void GdbEngine::handleShowVersion(const GdbResultRecord &response)
m_gdbVersion = 10000 * supported.cap(2).toInt() m_gdbVersion = 10000 * supported.cap(2).toInt()
+ 100 * supported.cap(3).toInt() + 100 * supported.cap(3).toInt()
+ 1 * supported.cap(5).toInt(); + 1 * supported.cap(5).toInt();
//qDebug() << "GDB VERSION " << m_gdbVersion; //debugMessage(QString("GDB VERSION: %1").arg(m_gdbVersion));
} }
} }
} }
@@ -1387,7 +1389,7 @@ QString GdbEngine::fullName(const QString &fileName)
if (fileName.isEmpty()) if (fileName.isEmpty())
return QString(); return QString();
QString full = m_shortToFullName.value(fileName, QString()); QString full = m_shortToFullName.value(fileName, QString());
//qDebug() << "RESOLVING: " << fileName << full; //debugMessage("RESOLVING: " + fileName + " " + full);
if (!full.isEmpty()) if (!full.isEmpty())
return full; return full;
QFileInfo fi(fileName); QFileInfo fi(fileName);
@@ -1397,7 +1399,7 @@ QString GdbEngine::fullName(const QString &fileName)
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
full = QDir::cleanPath(full); full = QDir::cleanPath(full);
#endif #endif
//qDebug() << "STORING: " << fileName << full; //debugMessage("STORING: " + fileName + " " + full);
m_shortToFullName[fileName] = full; m_shortToFullName[fileName] = full;
m_fullToShortName[full] = fileName; m_fullToShortName[full] = fileName;
return full; return full;
@@ -1425,22 +1427,29 @@ void GdbEngine::shutdown()
void GdbEngine::exitDebugger() void GdbEngine::exitDebugger()
{ {
//qDebug() << "EXITING: " << m_gdbProc.state(); debugMessage(QString("GDBENGINE EXITDEBUFFER: %1").arg(m_gdbProc.state()));
if (m_gdbProc.state() == QProcess::Starting) if (m_gdbProc.state() == QProcess::Starting) {
debugMessage(QString("WAITING FOR GDB STARTUP TO SHUTDOWN: %1")
.arg(m_gdbProc.state()));
m_gdbProc.waitForStarted(); m_gdbProc.waitForStarted();
}
if (m_gdbProc.state() == QProcess::Running) { if (m_gdbProc.state() == QProcess::Running) {
debugMessage(QString("WAITING FOR RUNNING GDB TO SHUTDOWN: %1")
.arg(m_gdbProc.state()));
interruptInferior(); interruptInferior();
sendCommand("kill"); sendCommand("kill");
sendCommand("-gdb-exit"); sendCommand("-gdb-exit");
// 20s can easily happen when loading webkit debug information // 20s can easily happen when loading webkit debug information
m_gdbProc.waitForFinished(20000); m_gdbProc.waitForFinished(20000);
if (m_gdbProc.state() != QProcess::Running) { if (m_gdbProc.state() != QProcess::Running) {
debugMessage(QString("FORCING TERMINATION: %1")
.arg(m_gdbProc.state()));
m_gdbProc.terminate(); m_gdbProc.terminate();
m_gdbProc.waitForFinished(20000); m_gdbProc.waitForFinished(20000);
} }
} }
if (m_gdbProc.state() != QProcess::NotRunning) if (m_gdbProc.state() != QProcess::NotRunning)
qDebug() << "PROBLEM STOPPING DEBUGGER"; debugMessage("PROBLEM STOPPING DEBUGGER");
m_outputCollector.shutdown(); m_outputCollector.shutdown();
initializeVariables(); initializeVariables();
@@ -1462,7 +1471,7 @@ bool GdbEngine::startDebugger()
QString fileName = '"' + fi.absoluteFilePath() + '"'; QString fileName = '"' + fi.absoluteFilePath() + '"';
if (m_gdbProc.state() != QProcess::NotRunning) { if (m_gdbProc.state() != QProcess::NotRunning) {
qDebug() << "GDB IS ALREADY RUNNING!"; debugMessage("GDB IS ALREADY RUNNING!");
return false; return false;
} }
@@ -1636,16 +1645,16 @@ void GdbEngine::handleStart(const GdbResultRecord &response)
QString msg = response.data.findChild("consolestreamoutput").data(); QString msg = response.data.findChild("consolestreamoutput").data();
QRegExp needle("0x([0-9a-f]+) <" + startSymbolName() + "\\+.*>:"); QRegExp needle("0x([0-9a-f]+) <" + startSymbolName() + "\\+.*>:");
if (needle.indexIn(msg) != -1) { if (needle.indexIn(msg) != -1) {
//qDebug() << "STREAM: " << msg << needle.cap(1); //debugMessage("STREAM: " + msg + " " + needle.cap(1));
sendCommand("tbreak *0x" + needle.cap(1)); sendCommand("tbreak *0x" + needle.cap(1));
m_waitingForFirstBreakpointToBeHit = true; m_waitingForFirstBreakpointToBeHit = true;
sendCommand("-exec-run"); sendCommand("-exec-run");
qq->notifyInferiorRunningRequested(); qq->notifyInferiorRunningRequested();
} else { } else {
qDebug() << "PARSING START ADDRESS FAILED" << msg; debugMessage("PARSING START ADDRESS FAILED: " + msg);
} }
} else if (response.resultClass == GdbResultError) { } else if (response.resultClass == GdbResultError) {
qDebug() << "PARSING START ADDRESS FAILED" << response.toString(); debugMessage("PARSING START ADDRESS FAILED: " + response.toString());
} }
} }
@@ -1740,12 +1749,12 @@ void GdbEngine::setTokenBarrier()
void GdbEngine::setDebugDumpers(bool on) void GdbEngine::setDebugDumpers(bool on)
{ {
if (on) { if (on) {
qDebug() << "SWITCHING ON DUMPER DEBUGGING"; debugMessage("SWITCHING ON DUMPER DEBUGGING");
sendCommand("set unwindonsignal off"); sendCommand("set unwindonsignal off");
q->breakByFunction("qDumpObjectData440"); q->breakByFunction("qDumpObjectData440");
//updateLocals(); //updateLocals();
} else { } else {
qDebug() << "SWITCHING OFF DUMPER DEBUGGING"; debugMessage("SWITCHING OFF DUMPER DEBUGGING");
sendCommand("set unwindonsignal on"); sendCommand("set unwindonsignal on");
} }
} }

View File

@@ -193,6 +193,7 @@ private:
void handleShowVersion(const GdbResultRecord &response); void handleShowVersion(const GdbResultRecord &response);
void handleQueryPwd(const GdbResultRecord &response); void handleQueryPwd(const GdbResultRecord &response);
void handleQuerySources(const GdbResultRecord &response); void handleQuerySources(const GdbResultRecord &response);
void debugMessage(const QString &msg);
OutputCollector m_outputCollector; OutputCollector m_outputCollector;
QTextCodec *m_outputCodec; QTextCodec *m_outputCodec;