1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
10 ** GNU Lesser General Public License Usage
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
31 **************************************************************************/
33 #define QT_NO_CAST_FROM_ASCII
35 #include "pdbengine.h"
37 #include "debuggerstartparameters.h"
38 #include "debuggeractions.h"
39 #include "debuggercore.h"
40 #include "debuggerdialogs.h"
41 #include "debuggerplugin.h"
42 #include "debuggerstringutils.h"
43 #include "debuggertooltipmanager.h"
45 #include "breakhandler.h"
46 #include "moduleshandler.h"
47 #include "registerhandler.h"
48 #include "stackhandler.h"
49 #include "watchhandler.h"
50 #include "watchutils.h"
52 #include "../gdb/gdbmi.h"
54 #include <utils/qtcassert.h>
56 #include <texteditor/itexteditor.h>
57 #include <coreplugin/ifile.h>
58 #include <coreplugin/icore.h>
60 #include <QtCore/QDateTime>
61 #include <QtCore/QDebug>
62 #include <QtCore/QDir>
63 #include <QtCore/QFileInfo>
64 #include <QtCore/QTimer>
65 #include <QtCore/QVariant>
67 #include <QtGui/QApplication>
68 #include <QtGui/QMessageBox>
69 #include <QtGui/QToolTip>
72 #define DEBUG_SCRIPT 1
74 # define SDEBUG(s) qDebug() << s
78 # define XSDEBUG(s) qDebug() << s
81 #define CB(callback) &PdbEngine::callback, STRINGIFY(callback)
86 ///////////////////////////////////////////////////////////////////////
90 ///////////////////////////////////////////////////////////////////////
92 PdbEngine::PdbEngine(const DebuggerStartParameters &startParameters)
93 : DebuggerEngine(startParameters)
95 setObjectName(QLatin1String("PdbEngine"));
98 PdbEngine::~PdbEngine()
101 void PdbEngine::executeDebuggerCommand(const QString &command)
103 QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
104 //XSDEBUG("PdbEngine::executeDebuggerCommand:" << command);
105 if (state() == DebuggerNotReady) {
106 showMessage(_("PDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: ") + command);
109 QTC_ASSERT(m_pdbProc.state() == QProcess::Running, notifyEngineIll());
110 postCommand(command.toLatin1(), CB(handleExecuteDebuggerCommand));
113 void PdbEngine::handleExecuteDebuggerCommand(const PdbResponse &response)
118 void PdbEngine::postDirectCommand(const QByteArray &command)
120 QTC_ASSERT(m_pdbProc.state() == QProcess::Running, notifyEngineIll());
121 showMessage(_(command), LogInput);
122 m_pdbProc.write(command + '\n');
125 void PdbEngine::postCommand(const QByteArray &command,
126 // PdbCommandFlags flags,
127 PdbCommandCallback callback,
128 const char *callbackName,
129 const QVariant &cookie)
131 QTC_ASSERT(m_pdbProc.state() == QProcess::Running, notifyEngineIll());
133 cmd.command = command;
134 cmd.callback = callback;
135 cmd.callbackName = callbackName;
137 m_commands.enqueue(cmd);
138 qDebug() << "ENQUEUE: " << command << cmd.callbackName;
139 showMessage(_(cmd.command), LogInput);
140 m_pdbProc.write(cmd.command + '\n');
143 void PdbEngine::shutdownInferior()
145 QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
146 notifyInferiorShutdownOk();
149 void PdbEngine::shutdownEngine()
151 QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
155 void PdbEngine::setupEngine()
157 QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
160 showMessage(_("STARTING PDB ") + m_pdb);
162 connect(&m_pdbProc, SIGNAL(error(QProcess::ProcessError)),
163 SLOT(handlePdbError(QProcess::ProcessError)));
164 connect(&m_pdbProc, SIGNAL(finished(int, QProcess::ExitStatus)),
165 SLOT(handlePdbFinished(int, QProcess::ExitStatus)));
166 connect(&m_pdbProc, SIGNAL(readyReadStandardOutput()),
167 SLOT(readPdbStandardOutput()));
168 connect(&m_pdbProc, SIGNAL(readyReadStandardError()),
169 SLOT(readPdbStandardError()));
171 connect(this, SIGNAL(outputReady(QByteArray)),
172 SLOT(handleOutput2(QByteArray)), Qt::QueuedConnection);
174 // We will stop immediately, so setup a proper callback.
176 cmd.callback = &PdbEngine::handleFirstCommand;
177 m_commands.enqueue(cmd);
179 m_pdbProc.start(m_pdb, QStringList() << _("-i"));
181 if (!m_pdbProc.waitForStarted()) {
182 const QString msg = tr("Unable to start pdb '%1': %2")
183 .arg(m_pdb, m_pdbProc.errorString());
184 notifyEngineSetupFailed();
185 showMessage(_("ADAPTER START FAILED"));
186 if (!msg.isEmpty()) {
187 const QString title = tr("Adapter start failed");
188 Core::ICore::instance()->showWarningWithOptions(title, msg);
190 notifyEngineSetupFailed();
193 notifyEngineSetupOk();
196 void PdbEngine::setupInferior()
198 QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
200 QString fileName = QFileInfo(startParameters().executable).absoluteFilePath();
201 QFile scriptFile(fileName);
202 if (!scriptFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
203 showMessageBox(QMessageBox::Critical, tr("Python Error"),
204 _("Cannot open script file %1:\n%2").
205 arg(fileName, scriptFile.errorString()));
206 notifyInferiorSetupFailed();
209 notifyInferiorSetupOk();
212 void PdbEngine::runEngine()
214 QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
215 showStatusMessage(tr("Running requested..."), 5000);
216 const QByteArray dumperSourcePath =
217 Core::ICore::instance()->resourcePath().toLocal8Bit() + "/gdbmacros/";
218 QString fileName = QFileInfo(startParameters().executable).absoluteFilePath();
219 postDirectCommand("import sys");
220 postDirectCommand("sys.argv.append('" + fileName.toLocal8Bit() + "')");
221 postDirectCommand("execfile('/usr/bin/pdb')");
222 postDirectCommand("execfile('" + dumperSourcePath + "pdumper.py')");
223 attemptBreakpointSynchronization();
224 notifyEngineRunAndInferiorStopOk();
228 void PdbEngine::interruptInferior()
230 notifyInferiorStopOk();
233 void PdbEngine::executeStep()
236 notifyInferiorRunRequested();
237 notifyInferiorRunOk();
238 postCommand("step", CB(handleUpdateAll));
241 void PdbEngine::executeStepI()
244 notifyInferiorRunRequested();
245 notifyInferiorRunOk();
246 postCommand("step", CB(handleUpdateAll));
249 void PdbEngine::executeStepOut()
252 notifyInferiorRunRequested();
253 notifyInferiorRunOk();
254 postCommand("finish", CB(handleUpdateAll));
257 void PdbEngine::executeNext()
260 notifyInferiorRunRequested();
261 notifyInferiorRunOk();
262 postCommand("next", CB(handleUpdateAll));
265 void PdbEngine::executeNextI()
268 notifyInferiorRunRequested();
269 notifyInferiorRunOk();
270 postCommand("next", CB(handleUpdateAll));
273 void PdbEngine::continueInferior()
276 notifyInferiorRunRequested();
277 notifyInferiorRunOk();
278 // Callback will be triggered e.g. when breakpoint is hit.
279 postCommand("continue", CB(handleUpdateAll));
282 void PdbEngine::executeRunToLine(const ContextData &data)
285 SDEBUG("FIXME: PdbEngine::runToLineExec()");
288 void PdbEngine::executeRunToFunction(const QString &functionName)
290 Q_UNUSED(functionName)
291 XSDEBUG("FIXME: PdbEngine::runToFunctionExec()");
294 void PdbEngine::executeJumpToLine(const ContextData &data)
297 XSDEBUG("FIXME: PdbEngine::jumpToLineExec()");
300 void PdbEngine::activateFrame(int frameIndex)
303 if (state() != InferiorStopOk && state() != InferiorUnrunnable)
306 StackHandler *handler = stackHandler();
307 int oldIndex = handler->currentIndex();
309 //if (frameIndex == handler->stackSize()) {
310 // reloadFullStack();
314 QTC_ASSERT(frameIndex < handler->stackSize(), return);
316 if (oldIndex != frameIndex) {
317 // Assuming the command always succeeds this saves a roundtrip.
318 // Otherwise the lines below would need to get triggered
319 // after a response to this -stack-select-frame here.
320 handler->setCurrentIndex(frameIndex);
321 //postCommand("-stack-select-frame " + QByteArray::number(frameIndex),
322 // CB(handleStackSelectFrame));
324 gotoLocation(handler->currentFrame());
327 void PdbEngine::selectThread(int index)
332 bool PdbEngine::acceptsBreakpoint(BreakpointId id) const
334 const QString fileName = breakHandler()->fileName(id);
335 return fileName.endsWith(QLatin1String(".py"));
338 void PdbEngine::insertBreakpoint(BreakpointId id)
340 BreakHandler *handler = breakHandler();
341 QTC_ASSERT(handler->state(id) == BreakpointInsertRequested, /**/);
342 handler->notifyBreakpointInsertProceeding(id);
345 if (handler->type(id) == BreakpointByFunction)
346 loc = handler->functionName(id).toLatin1();
348 loc = handler->fileName(id).toLocal8Bit() + ':'
349 + QByteArray::number(handler->lineNumber(id));
351 postCommand("break " + loc, CB(handleBreakInsert), QVariant(id));
354 void PdbEngine::handleBreakInsert(const PdbResponse &response)
356 //qDebug() << "BP RESPONSE: " << response.data;
357 // "Breakpoint 1 at /pdb/math.py:10"
358 BreakpointId id(response.cookie.toInt());
359 BreakHandler *handler = breakHandler();
360 QTC_ASSERT(response.data.startsWith("Breakpoint "), return);
361 int pos1 = response.data.indexOf(" at ");
362 QTC_ASSERT(pos1 != -1, return);
363 QByteArray bpnr = response.data.mid(11, pos1 - 11);
364 int pos2 = response.data.lastIndexOf(":");
365 QByteArray file = response.data.mid(pos1 + 4, pos2 - pos1 - 4);
366 QByteArray line = response.data.mid(pos2 + 1);
367 BreakpointResponse br;
368 br.number = bpnr.toInt();
369 br.fileName = _(file);
370 br.lineNumber = line.toInt();
371 handler->setResponse(id, br);
374 void PdbEngine::removeBreakpoint(BreakpointId id)
376 BreakHandler *handler = breakHandler();
377 QTC_ASSERT(handler->state(id) == BreakpointRemoveRequested, /**/);
378 handler->notifyBreakpointRemoveProceeding(id);
379 BreakpointResponse br = handler->response(id);
380 showMessage(_("DELETING BP %1 IN %2").arg(br.number)
381 .arg(handler->fileName(id)));
382 postCommand("clear " + QByteArray::number(br.number));
383 // Pretend it succeeds without waiting for response.
384 handler->notifyBreakpointRemoveOk(id);
387 void PdbEngine::loadSymbols(const QString &moduleName)
392 void PdbEngine::loadAllSymbols()
396 void PdbEngine::reloadModules()
398 //postCommand("qdebug('listmodules')", CB(handleListModules));
401 void PdbEngine::handleListModules(const PdbResponse &response)
404 out.fromString(response.data.trimmed());
406 foreach (const GdbMi &item, out.children()) {
408 module.moduleName = _(item.findChild("name").data());
409 QString path = _(item.findChild("value").data());
410 int pos = path.indexOf(_("' from '"));
412 path = path.mid(pos + 8);
413 if (path.size() >= 2)
415 } else if (path.startsWith(_("<module '"))
416 && path.endsWith(_("' (built-in)>"))) {
417 path = _("(builtin)");
419 module.modulePath = path;
420 modules.append(module);
422 modulesHandler()->setModules(modules);
425 void PdbEngine::requestModuleSymbols(const QString &moduleName)
427 postCommand("qdebug('listsymbols','" + moduleName.toLatin1() + "')",
428 CB(handleListSymbols), moduleName);
431 void PdbEngine::handleListSymbols(const PdbResponse &response)
434 out.fromString(response.data.trimmed());
436 QString moduleName = response.cookie.toString();
437 foreach (const GdbMi &item, out.children()) {
439 symbol.name = _(item.findChild("name").data());
440 symbols.append(symbol);
442 debuggerCore()->showModuleSymbols(moduleName, symbols);
445 //////////////////////////////////////////////////////////////////////
447 // Tooltip specific stuff
449 //////////////////////////////////////////////////////////////////////
452 static WatchData m_toolTip;
453 static QPoint m_toolTipPos;
454 static QHash<QString, WatchData> m_toolTipCache;
456 bool PdbEngine::setToolTipExpression(const QPoint &mousePos,
457 TextEditor::ITextEditor *editor, const DebuggerToolTipContext &ctx)
462 if (state() != InferiorStopOk) {
463 //SDEBUG("SUPPRESSING DEBUGGER TOOLTIP, INFERIOR NOT STOPPED");
466 // Check mime type and get expression (borrowing some C++ - functions)
467 const QString javaPythonMimeType =
468 QLatin1String("application/javascript");
469 if (!editor->file() || editor->file()->mimeType() != javaPythonMimeType)
474 QString exp = cppExpressionAt(editor, ctx.position, &line, &column);
477 if (m_toolTipCache.contains(exp)) {
478 const WatchData & data = m_toolTipCache[exp];
479 q->watchHandler()->removeChildren(data.iname);
485 QToolTip::hideText();
486 if (exp.isEmpty() || exp.startsWith(QLatin1Char('#'))) {
487 QToolTip::hideText();
491 if (!hasLetterOrNumber(exp)) {
492 QToolTip::showText(m_toolTipPos, tr("'%1' contains no identifier").arg(exp));
496 if (exp.startsWith(QLatin1Char('"')) && exp.endsWith(QLatin1Char('"'))) {
497 QToolTip::showText(m_toolTipPos, tr("String literal %1").arg(exp));
501 if (exp.startsWith(QLatin1String("++")) || exp.startsWith(QLatin1String("--")))
504 if (exp.endsWith(QLatin1String("++")) || exp.endsWith(QLatin1String("--")))
507 if (exp.startsWith(QLatin1Char('<')) || exp.startsWith(QLatin1Char('[')))
510 if (hasSideEffects(exp)) {
511 QToolTip::showText(m_toolTipPos,
512 tr("Cowardly refusing to evaluate expression '%1' "
513 "with potential side effects").arg(exp));
518 //if (status() != InferiorStopOk)
521 // FIXME: 'exp' can contain illegal characters
522 m_toolTip = WatchData();
524 m_toolTip.name = exp;
525 m_toolTip.iname = tooltipIName;
526 insertData(m_toolTip);
532 //////////////////////////////////////////////////////////////////////
534 // Watch specific stuff
536 //////////////////////////////////////////////////////////////////////
538 void PdbEngine::assignValueInDebugger(const Internal::WatchData *, const QString &expression, const QVariant &value)
540 Q_UNUSED(expression);
542 SDEBUG("ASSIGNING: " << (expression + QLatin1Char('=') + value.toString()));
544 m_scriptEngine->evaluate(expression + QLatin1Char('=') + value.toString());
550 void PdbEngine::updateWatchData(const WatchData &data, const WatchUpdateFlags &flags)
557 void PdbEngine::handlePdbError(QProcess::ProcessError error)
559 qDebug() << "HANDLE PDB ERROR";
560 showMessage(_("HANDLE PDB ERROR"));
562 case QProcess::Crashed:
563 break; // will get a processExited() as well
564 // impossible case QProcess::FailedToStart:
565 case QProcess::ReadError:
566 case QProcess::WriteError:
567 case QProcess::Timedout:
569 //setState(EngineShutdownRequested, true);
571 showMessageBox(QMessageBox::Critical, tr("Pdb I/O Error"),
572 errorMessage(error));
577 QString PdbEngine::errorMessage(QProcess::ProcessError error) const
580 case QProcess::FailedToStart:
581 return tr("The Pdb process failed to start. Either the "
582 "invoked program '%1' is missing, or you may have insufficient "
583 "permissions to invoke the program.")
585 case QProcess::Crashed:
586 return tr("The Pdb process crashed some time after starting "
588 case QProcess::Timedout:
589 return tr("The last waitFor...() function timed out. "
590 "The state of QProcess is unchanged, and you can try calling "
591 "waitFor...() again.");
592 case QProcess::WriteError:
593 return tr("An error occurred when attempting to write "
594 "to the Pdb process. For example, the process may not be running, "
595 "or it may have closed its input channel.");
596 case QProcess::ReadError:
597 return tr("An error occurred when attempting to read from "
598 "the Pdb process. For example, the process may not be running.");
600 return tr("An unknown error in the Pdb process occurred. ");
604 void PdbEngine::handlePdbFinished(int code, QProcess::ExitStatus type)
606 qDebug() << "PDB FINISHED";
607 showMessage(_("PDB PROCESS FINISHED, status %1, code %2").arg(type).arg(code));
608 notifyEngineSpontaneousShutdown();
611 void PdbEngine::readPdbStandardError()
613 QByteArray err = m_pdbProc.readAllStandardError();
614 qDebug() << "\nPDB STDERR" << err;
615 //qWarning() << "Unexpected pdb stderr:" << err;
616 //showMessage(_("Unexpected pdb stderr: " + err));
620 void PdbEngine::readPdbStandardOutput()
622 QByteArray out = m_pdbProc.readAllStandardOutput();
623 qDebug() << "\nPDB STDOUT" << out;
627 void PdbEngine::handleOutput(const QByteArray &data)
629 //qDebug() << "READ: " << data;
630 m_inbuffer.append(data);
631 qDebug() << "BUFFER FROM: '" << m_inbuffer << "'";
633 int pos = m_inbuffer.indexOf("(Pdb)");
635 pos = m_inbuffer.indexOf(">>>");
638 QByteArray response = m_inbuffer.left(pos).trimmed();
639 m_inbuffer = m_inbuffer.mid(pos + 6);
640 emit outputReady(response);
642 qDebug() << "BUFFER LEFT: '" << m_inbuffer << "'";
643 //m_inbuffer.clear();
647 void PdbEngine::handleOutput2(const QByteArray &data)
649 PdbResponse response;
650 response.data = data;
651 showMessage(_(data));
652 QTC_ASSERT(!m_commands.isEmpty(), qDebug() << "RESPONSE: " << data; return)
653 PdbCommand cmd = m_commands.dequeue();
654 response.cookie = cmd.cookie;
655 qDebug() << "DEQUE: " << cmd.command << cmd.callbackName;
657 //qDebug() << "EXECUTING CALLBACK " << cmd.callbackName
658 // << " RESPONSE: " << response.data;
659 (this->*cmd.callback)(response);
661 qDebug() << "NO CALLBACK FOR RESPONSE: " << response.data;
665 void PdbEngine::handleResponse(const QByteArray &response0)
667 QByteArray response = response0;
668 qDebug() << "RESPONSE: '" << response << "'";
669 if (response.startsWith("--Call--")) {
670 qDebug() << "SKIPPING '--Call--' MARKER";
671 response = response.mid(9);
673 if (response.startsWith("--Return--")) {
674 qDebug() << "SKIPPING '--Return--' MARKER";
675 response = response.mid(11);
677 if (response.startsWith("> ")) {
678 int pos1 = response.indexOf('(');
679 int pos2 = response.indexOf(')', pos1);
680 if (pos1 != -1 && pos2 != -1) {
681 int lineNumber = response.mid(pos1 + 1, pos2 - pos1 - 1).toInt();
682 QByteArray fileName = response.mid(2, pos1 - 2);
683 qDebug() << " " << pos1 << pos2 << lineNumber << fileName
684 << response.mid(pos1 + 1, pos2 - pos1 - 1);
686 frame.file = _(fileName);
687 frame.line = lineNumber;
688 if (frame.line > 0 && QFileInfo(frame.file).exists()) {
690 notifyInferiorSpontaneousStop();
695 qDebug() << "COULD NOT PARSE RESPONSE: '" << response << "'";
699 void PdbEngine::handleFirstCommand(const PdbResponse &response)
704 void PdbEngine::handleUpdateAll(const PdbResponse &response)
707 notifyInferiorSpontaneousStop();
711 void PdbEngine::updateAll()
713 postCommand("bt", CB(handleBacktrace));
717 void PdbEngine::updateLocals()
719 WatchHandler *handler = watchHandler();
722 //if (!m_toolTipExpression.isEmpty())
723 // watchers += m_toolTipExpression.toLatin1()
724 // + '#' + tooltipINameForExpression(m_toolTipExpression.toLatin1());
726 QHash<QByteArray, int> watcherNames = handler->watcherNames();
727 QHashIterator<QByteArray, int> it(watcherNames);
728 while (it.hasNext()) {
730 if (!watchers.isEmpty())
732 watchers += it.key() + "#watch." + QByteArray::number(it.value());
736 if (debuggerCore()->boolSetting(UseDebuggingHelpers))
738 if (debuggerCore()->boolSetting(AutoDerefPointers))
739 options += "autoderef,";
740 if (options.isEmpty())
741 options += "defaults,";
744 postCommand("qdebug('" + options + "','"
745 + handler->expansionRequests() + "','"
746 + handler->typeFormatRequests() + "','"
747 + handler->individualFormatRequests() + "','"
748 + watchers.toHex() + "')", CB(handleListLocals));
751 void PdbEngine::handleBacktrace(const PdbResponse &response)
753 //qDebug() << " BACKTRACE: '" << response.data << "'";
754 // " /usr/lib/python2.6/bdb.py(368)run()"
755 // "-> exec cmd in globals, locals"
756 // " <string>(1)<module>()"
757 // " /python/math.py(19)<module>()"
759 // " /python/math.py(14)main()"
760 // "-> print cube(3)"
761 // " /python/math.py(7)cube()"
762 // "-> x = square(a)"
763 // "> /python/math.py(2)square()"
764 // "-> def square(a):"
766 // Populate stack view.
767 StackFrames stackFrames;
769 int currentIndex = -1;
770 foreach (const QByteArray &line, response.data.split('\n')) {
771 //qDebug() << " LINE: '" << line << "'";
772 if (line.startsWith("> ") || line.startsWith(" ")) {
773 int pos1 = line.indexOf('(');
774 int pos2 = line.indexOf(')', pos1);
775 if (pos1 != -1 && pos2 != -1) {
776 int lineNumber = line.mid(pos1 + 1, pos2 - pos1 - 1).toInt();
777 QByteArray fileName = line.mid(2, pos1 - 2);
778 //qDebug() << " " << pos1 << pos2 << lineNumber << fileName
779 // << line.mid(pos1 + 1, pos2 - pos1 - 1);
781 frame.file = _(fileName);
782 frame.line = lineNumber;
783 frame.function = _(line.mid(pos2 + 1));
784 if (frame.line > 0 && QFileInfo(frame.file).exists()) {
785 if (line.startsWith("> "))
786 currentIndex = level;
788 stackFrames.prepend(frame);
794 const int frameCount = stackFrames.size();
795 for (int i = 0; i != frameCount; ++i)
796 stackFrames[i].level = frameCount - stackFrames[i].level - 1;
797 stackHandler()->setFrames(stackFrames);
799 // Select current frame.
800 if (currentIndex != -1) {
801 currentIndex = frameCount - currentIndex - 1;
802 stackHandler()->setCurrentIndex(currentIndex);
803 gotoLocation(stackFrames.at(currentIndex));
809 void PdbEngine::handleListLocals(const PdbResponse &response)
811 //qDebug() << " LOCALS: '" << response.data << "'";
812 QByteArray out = response.data.trimmed();
815 all.fromStringMultiple(out);
816 //qDebug() << "ALL: " << all.toString();
818 //GdbMi data = all.findChild("data");
819 QList<WatchData> list;
820 WatchHandler *handler = watchHandler();
821 foreach (const GdbMi &child, all.children()) {
823 dummy.iname = child.findChild("iname").data();
824 dummy.name = _(child.findChild("name").data());
825 //qDebug() << "CHILD: " << child.toString();
826 parseWatchData(handler->expandedINames(), dummy, child, &list);
828 handler->insertBulkData(list);
831 unsigned PdbEngine::debuggerCapabilities() const
833 return ReloadModuleCapability|BreakConditionCapability;
836 DebuggerEngine *createPdbEngine(const DebuggerStartParameters &startParameters)
838 return new PdbEngine(startParameters);
842 } // namespace Internal
843 } // namespace Debugger