From ecd475c9035c1e161d4fa42f38825697d2f93a12 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 1 Feb 2010 16:14:57 +0100 Subject: [PATCH] debugger: fall back to instructionwise stepping when debuginfo for frame is missing --- src/plugins/debugger/cdb/cdbdebugengine.cpp | 4 +- src/plugins/debugger/cdb/cdbdebugengine.h | 3 +- src/plugins/debugger/debuggeragents.cpp | 23 ++++++- src/plugins/debugger/debuggeragents.h | 4 +- src/plugins/debugger/gdb/gdbengine.cpp | 72 ++++++++++++++++++--- src/plugins/debugger/gdb/gdbengine.h | 5 +- src/plugins/debugger/idebuggerengine.h | 3 +- 7 files changed, 93 insertions(+), 21 deletions(-) diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index b5c8c26086d..14b22a6dc51 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -1084,9 +1084,9 @@ bool CdbDebugEnginePrivate::attemptBreakpointSynchronization(QString *errorMessa return ok; } -void CdbDebugEngine::fetchDisassembler(DisassemblerViewAgent *agent, - const StackFrame & frame) +void CdbDebugEngine::fetchDisassembler(DisassemblerViewAgent *agent) { + StackFrame frame = agent->frame(); enum { ContextLines = 40 }; bool ok = false; QString errorMessage; diff --git a/src/plugins/debugger/cdb/cdbdebugengine.h b/src/plugins/debugger/cdb/cdbdebugengine.h index 0f900560d0c..1085a71de75 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.h +++ b/src/plugins/debugger/cdb/cdbdebugengine.h @@ -88,8 +88,7 @@ public: virtual void attemptBreakpointSynchronization(); - virtual void fetchDisassembler(DisassemblerViewAgent *agent, - const StackFrame &frame); + virtual void fetchDisassembler(DisassemblerViewAgent *agent); virtual void fetchMemory(MemoryViewAgent *, quint64 addr, quint64 length); virtual void reloadModules(); diff --git a/src/plugins/debugger/debuggeragents.cpp b/src/plugins/debugger/debuggeragents.cpp index 820b48c9498..d76b6f386bf 100644 --- a/src/plugins/debugger/debuggeragents.cpp +++ b/src/plugins/debugger/debuggeragents.cpp @@ -153,8 +153,11 @@ public: struct DisassemblerViewAgentPrivate { + DisassemblerViewAgentPrivate() { tryMixed = true; } + QPointer editor; StackFrame frame; + bool tryMixed; QPointer manager; LocationMark2 *locationMark; QHash cache; @@ -230,10 +233,24 @@ QString frameKey(const StackFrame &frame) return _("%1:%2:%3").arg(frame.function).arg(frame.file).arg(frame.from); } -void DisassemblerViewAgent::setFrame(const StackFrame &frame) +const StackFrame &DisassemblerViewAgent::frame() const +{ + return d->frame; +} + +bool DisassemblerViewAgent::isMixed() const +{ + return d->tryMixed + && d->frame.line > 0 + && !d->frame.function.isEmpty() + && d->frame.function != _("??"); +} + +void DisassemblerViewAgent::setFrame(const StackFrame &frame, bool tryMixed) { d->frame = frame; - if (!frame.function.isEmpty() && frame.function != _("??")) { + d->tryMixed = tryMixed; + if (isMixed()) { QHash::ConstIterator it = d->cache.find(frameKey(frame)); if (it != d->cache.end()) { QString msg = _("Use cache disassembler for '%1' in '%2'") @@ -245,7 +262,7 @@ void DisassemblerViewAgent::setFrame(const StackFrame &frame) } IDebuggerEngine *engine = d->manager->currentEngine(); QTC_ASSERT(engine, return); - engine->fetchDisassembler(this, frame); + engine->fetchDisassembler(this); } void DisassemblerViewAgent::setContents(const QString &contents) diff --git a/src/plugins/debugger/debuggeragents.h b/src/plugins/debugger/debuggeragents.h index f0888c6b92f..63d3e7ba238 100644 --- a/src/plugins/debugger/debuggeragents.h +++ b/src/plugins/debugger/debuggeragents.h @@ -83,12 +83,14 @@ public: explicit DisassemblerViewAgent(DebuggerManager *manager); ~DisassemblerViewAgent(); - void setFrame(const StackFrame &frame); + void setFrame(const StackFrame &frame, bool tryMixed = true); + const StackFrame &frame() const; void resetLocation(); Q_SLOT void setContents(const QString &contents); QString address() const; bool contentsCoversAddress(const QString &contents) const; void cleanup(); + bool isMixed() const; private: DisassemblerViewAgentPrivate *d; diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 355ff71b887..ee415d667e5 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -1727,9 +1727,35 @@ void GdbEngine::stepExec() setState(InferiorRunningRequested); showStatusMessage(tr("Step requested..."), 5000); if (manager()->isReverseDebugging()) - postCommand("-reverse-step", RunRequest, CB(handleExecContinue)); + postCommand("-reverse-step", RunRequest, CB(handleExecStep)); else - postCommand("-exec-step", RunRequest, CB(handleExecContinue)); + postCommand("-exec-step", RunRequest, CB(handleExecStep)); +} + +void GdbEngine::handleExecStep(const GdbResponse &response) +{ + if (response.resultClass == GdbResultRunning) { + // The "running" state is picked up in handleResponse() + QTC_ASSERT(state() == InferiorRunning, /**/); + } else { + if (state() == InferiorRunningRequested_Kill) { + setState(InferiorStopped); + shutdown(); + return; + } + QTC_ASSERT(state() == InferiorRunningRequested, /**/); + setState(InferiorStopped); + QByteArray msg = response.data.findChild("msg").data(); + if (msg.startsWith("Cannot find bounds of current function")) { + if (!m_commandsToRunOnTemporaryBreak.isEmpty()) + flushQueuedCommands(); + stepIExec(); // Fall back to instruction-wise stepping. + } else { + showMessageBox(QMessageBox::Critical, tr("Execution Error"), + tr("Cannot continue debugged process:\n") + QString::fromLocal8Bit(msg)); + shutdown(); + } + } } void GdbEngine::stepIExec() @@ -1760,9 +1786,35 @@ void GdbEngine::nextExec() setState(InferiorRunningRequested); showStatusMessage(tr("Step next requested..."), 5000); if (manager()->isReverseDebugging()) - postCommand("-reverse-next", RunRequest, CB(handleExecContinue)); + postCommand("-reverse-next", RunRequest, CB(handleExecNext)); else - postCommand("-exec-next", RunRequest, CB(handleExecContinue)); + postCommand("-exec-next", RunRequest, CB(handleExecNext)); +} + +void GdbEngine::handleExecNext(const GdbResponse &response) +{ + if (response.resultClass == GdbResultRunning) { + // The "running" state is picked up in handleResponse() + QTC_ASSERT(state() == InferiorRunning, /**/); + } else { + if (state() == InferiorRunningRequested_Kill) { + setState(InferiorStopped); + shutdown(); + return; + } + QTC_ASSERT(state() == InferiorRunningRequested, /**/); + setState(InferiorStopped); + QByteArray msg = response.data.findChild("msg").data(); + if (msg.startsWith("Cannot find bounds of current function")) { + if (!m_commandsToRunOnTemporaryBreak.isEmpty()) + flushQueuedCommands(); + nextIExec(); // Fall back to instruction-wise stepping. + } else { + showMessageBox(QMessageBox::Critical, tr("Execution Error"), + tr("Cannot continue debugged process:\n") + QString::fromLocal8Bit(msg)); + shutdown(); + } + } } void GdbEngine::nextIExec() @@ -3405,18 +3457,20 @@ struct DisassemblerAgentCookie QPointer agent; }; -void GdbEngine::fetchDisassembler(DisassemblerViewAgent *agent, - const StackFrame &frame) + +// FIXME: add agent->frame() accessor and use that +void GdbEngine::fetchDisassembler(DisassemblerViewAgent *agent) { - if (frame.file.isEmpty()) { - fetchDisassemblerByAddress(agent, true); - } else { + if (agent->isMixed()) { // Disassemble full function: + const StackFrame &frame = agent->frame(); QByteArray cmd = "-data-disassemble" " -f " + frame.file.toLocal8Bit() + " -l " + QByteArray::number(frame.line) + " -n -1 -- 1"; postCommand(cmd, Discardable, CB(handleFetchDisassemblerByLine), QVariant::fromValue(DisassemblerAgentCookie(agent))); + } else { + fetchDisassemblerByAddress(agent, true); } } diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 6fd2c5e2cf1..df6e9df97f0 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -300,6 +300,8 @@ private: ////////// Inferior Management ////////// virtual void jumpToLineExec(const QString &fileName, int lineNumber); void handleExecContinue(const GdbResponse &response); + void handleExecStep(const GdbResponse &response); + void handleExecNext(const GdbResponse &response); qint64 inferiorPid() const { return m_manager->inferiorPid(); } void handleInferiorPidChanged(qint64 pid) { manager()->notifyInferiorPidChanged(pid); } @@ -357,8 +359,7 @@ private: ////////// View & Data Stuff ////////// // // Disassembler specific stuff // - virtual void fetchDisassembler(DisassemblerViewAgent *agent, - const StackFrame &frame); + virtual void fetchDisassembler(DisassemblerViewAgent *agent); void fetchDisassemblerByAddress(DisassemblerViewAgent *agent, bool useMixedMode); void handleFetchDisassemblerByLine(const GdbResponse &response); diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h index 2c72aa845b4..6733971d2d5 100644 --- a/src/plugins/debugger/idebuggerengine.h +++ b/src/plugins/debugger/idebuggerengine.h @@ -56,7 +56,6 @@ namespace Internal { class DisassemblerViewAgent; class MemoryViewAgent; -struct StackFrame; class Symbol; class WatchData; @@ -111,7 +110,7 @@ public: virtual void watchPoint(const QPoint &) {} virtual void fetchMemory(MemoryViewAgent *, quint64 addr, quint64 length) { Q_UNUSED(addr); Q_UNUSED(length); } - virtual void fetchDisassembler(DisassemblerViewAgent *, const StackFrame &) {} + virtual void fetchDisassembler(DisassemblerViewAgent *) {} virtual void setRegisterValue(int regnr, const QString &value) { Q_UNUSED(regnr); Q_UNUSED(value); }