OSDN Git Service

17810f3c7cc9c8a6cd3e55d0c522bead5fbb3e92
[qt-creator-jp/qt-creator-jp.git] / src / plugins / debugger / gdb / gdbengine.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #define QT_NO_CAST_FROM_ASCII
35
36 #include "gdbengine.h"
37
38 #include "debuggerstartparameters.h"
39 #include "disassemblerlines.h"
40 #include "attachgdbadapter.h"
41 #include "coregdbadapter.h"
42 #include "localplaingdbadapter.h"
43 #include "termgdbadapter.h"
44 #include "remotegdbserveradapter.h"
45 #include "remoteplaingdbadapter.h"
46 #include "trkgdbadapter.h"
47 #include "codagdbadapter.h"
48
49 #include "debuggeractions.h"
50 #include "debuggerconstants.h"
51 #include "debuggercore.h"
52 #include "debuggerplugin.h"
53 #include "debuggerrunner.h"
54 #include "debuggerstringutils.h"
55 #include "debuggertooltipmanager.h"
56 #include "disassembleragent.h"
57 #include "gdbmi.h"
58 #include "gdboptionspage.h"
59 #include "memoryagent.h"
60 #include "watchutils.h"
61
62 #include "breakhandler.h"
63 #include "moduleshandler.h"
64 #include "registerhandler.h"
65 #include "snapshothandler.h"
66 #include "sourcefileshandler.h"
67 #include "stackhandler.h"
68 #include "threadshandler.h"
69 #include "watchhandler.h"
70 #include "debuggersourcepathmappingwidget.h"
71
72 #ifdef Q_OS_WIN
73 #    include "dbgwinutils.h"
74 #endif
75 #include "logwindow.h"
76
77 #include <coreplugin/icore.h>
78 #include <coreplugin/ifile.h>
79 #include <projectexplorer/abi.h>
80 #include <projectexplorer/projectexplorerconstants.h>
81 #include <texteditor/itexteditor.h>
82 #include <utils/qtcassert.h>
83
84 #include <QtCore/QCoreApplication>
85 #include <QtCore/QDebug>
86 #include <QtCore/QDir>
87 #include <QtCore/QFileInfo>
88 #include <QtCore/QMetaObject>
89 #include <QtCore/QTime>
90 #include <QtCore/QTimer>
91 #include <QtCore/QTemporaryFile>
92 #include <QtCore/QTextStream>
93
94 #include <QtGui/QAction>
95 #include <QtGui/QDialogButtonBox>
96 #include <QtGui/QLabel>
97 #include <QtGui/QMainWindow>
98 #include <QtGui/QMessageBox>
99 #include <QtGui/QPushButton>
100
101 #ifdef Q_OS_UNIX
102 #include <unistd.h>
103 #include <dlfcn.h>
104 #endif
105 #include <ctype.h>
106
107 using namespace ProjectExplorer;
108
109 namespace Debugger {
110 namespace Internal {
111
112 class GdbToolTipContext : public DebuggerToolTipContext
113 {
114 public:
115     GdbToolTipContext(const DebuggerToolTipContext &c) :
116         DebuggerToolTipContext(c), editor(0) {}
117
118     QPoint mousePosition;
119     QString expression;
120     Core::IEditor *editor;
121 };
122
123 static const char winPythonVersionC[] = "python2.5";
124
125 enum { debugPending = 0 };
126
127 #define PENDING_DEBUG(s) do { if (debugPending) qDebug() << s; } while (0)
128
129 #define CB(callback) &GdbEngine::callback, STRINGIFY(callback)
130
131 QByteArray GdbEngine::tooltipIName(const QString &exp)
132 {
133     return "tooltip." + exp.toLatin1().toHex();
134 }
135
136 static bool stateAcceptsGdbCommands(DebuggerState state)
137 {
138     switch (state) {
139     case EngineSetupRequested:
140     case EngineSetupOk:
141     case EngineSetupFailed:
142     case InferiorUnrunnable:
143     case InferiorSetupRequested:
144     case InferiorSetupFailed:
145     case EngineRunRequested:
146     case InferiorRunRequested:
147     case InferiorRunOk:
148     case InferiorStopRequested:
149     case InferiorStopOk:
150     case InferiorShutdownRequested:
151     case EngineShutdownRequested:
152     case InferiorShutdownOk:
153     case InferiorShutdownFailed:
154         return true;
155     case DebuggerNotReady:
156     case InferiorStopFailed:
157     case InferiorSetupOk:
158     case EngineRunFailed:
159     case InferiorExitOk:
160     case InferiorRunFailed:
161     case EngineShutdownOk:
162     case EngineShutdownFailed:
163     case DebuggerFinished:
164         return false;
165     }
166     return false;
167 }
168
169 static int &currentToken()
170 {
171     static int token = 0;
172     return token;
173 }
174
175 static QByteArray parsePlainConsoleStream(const GdbResponse &response)
176 {
177     GdbMi output = response.data.findChild("consolestreamoutput");
178     QByteArray out = output.data();
179     // FIXME: proper decoding needed
180     if (out.endsWith("\\n"))
181         out.chop(2);
182     while (out.endsWith('\n') || out.endsWith(' '))
183         out.chop(1);
184     int pos = out.indexOf(" = ");
185     return out.mid(pos + 3);
186 }
187
188 ///////////////////////////////////////////////////////////////////////
189 //
190 // GdbEngine
191 //
192 ///////////////////////////////////////////////////////////////////////
193
194 GdbEngine::GdbEngine(const DebuggerStartParameters &startParameters,
195         DebuggerEngine *masterEngine)
196   : DebuggerEngine(startParameters, masterEngine)
197 {
198     setObjectName(_("GdbEngine"));
199
200     m_busy = false;
201     m_gdbAdapter = 0;
202     m_debuggingHelperState = DebuggingHelperUninitialized;
203     m_gdbVersion = 100;
204     m_gdbBuildVersion = -1;
205     m_isMacGdb = false;
206     m_hasPython = false;
207     m_registerNamesListed = false;
208     m_hasInferiorThreadList = false;
209     m_sourcesListUpdating = false;
210     m_oldestAcceptableToken = -1;
211     m_outputCodec = QTextCodec::codecForLocale();
212     m_pendingWatchRequests = 0;
213     m_pendingBreakpointRequests = 0;
214     m_commandsDoneCallback = 0;
215     m_stackNeeded = false;
216     m_preparedForQmlBreak = false;
217     m_disassembleUsesComma = false;
218     m_qFatalBreakpointNumber = 0;
219
220     invalidateSourcesList();
221
222     m_gdbAdapter = createAdapter();
223
224     m_commandTimer.setSingleShot(true);
225     connect(&m_commandTimer, SIGNAL(timeout()), SLOT(commandTimeout()));
226
227     connect(debuggerCore()->action(AutoDerefPointers), SIGNAL(valueChanged(QVariant)),
228             SLOT(reloadLocals()));
229     connect(debuggerCore()->action(SortStructMembers), SIGNAL(valueChanged(QVariant)),
230             SLOT(reloadLocals()));
231     connect(debuggerCore()->action(ShowStdNamespace), SIGNAL(valueChanged(QVariant)),
232             SLOT(reloadLocals()));
233     connect(debuggerCore()->action(ShowQtNamespace), SIGNAL(valueChanged(QVariant)),
234             SLOT(reloadLocals()));
235     connect(debuggerCore()->action(CreateFullBacktrace), SIGNAL(triggered()),
236             SLOT(createFullBacktrace()));
237 }
238
239 DebuggerStartMode GdbEngine::startMode() const
240 {
241     return startParameters().startMode;
242 }
243
244 AbstractGdbProcess *GdbEngine::gdbProc() const
245 {
246     return m_gdbAdapter->gdbProc();
247 }
248
249 GdbEngine::~GdbEngine()
250 {
251     // Prevent sending error messages afterwards.
252     if (m_gdbAdapter)
253         disconnect(gdbProc(), 0, this, 0);
254     delete m_gdbAdapter;
255     m_gdbAdapter = 0;
256 }
257
258 QString GdbEngine::errorMessage(QProcess::ProcessError error)
259 {
260     switch (error) {
261         case QProcess::FailedToStart:
262             return tr("The gdb process failed to start. Either the "
263                 "invoked program '%1' is missing, or you may have insufficient "
264                 "permissions to invoke the program.\n%2")
265                 .arg(m_gdb, gdbProc()->errorString());
266         case QProcess::Crashed:
267             return tr("The gdb process crashed some time after starting "
268                 "successfully.");
269         case QProcess::Timedout:
270             return tr("The last waitFor...() function timed out. "
271                 "The state of QProcess is unchanged, and you can try calling "
272                 "waitFor...() again.");
273         case QProcess::WriteError:
274             return tr("An error occurred when attempting to write "
275                 "to the gdb process. For example, the process may not be running, "
276                 "or it may have closed its input channel.");
277         case QProcess::ReadError:
278             return tr("An error occurred when attempting to read from "
279                 "the gdb process. For example, the process may not be running.");
280         default:
281             return tr("An unknown error in the gdb process occurred. ");
282     }
283 }
284
285 #if 0
286 static void dump(const char *first, const char *middle, const QString & to)
287 {
288     QByteArray ba(first, middle - first);
289     Q_UNUSED(to)
290     // note that qDebug cuts off output after a certain size... (bug?)
291     qDebug("\n>>>>> %s\n%s\n====\n%s\n<<<<<\n",
292         qPrintable(currentTime()),
293         qPrintable(QString(ba).trimmed()),
294         qPrintable(to.trimmed()));
295     //qDebug() << "";
296     //qDebug() << qPrintable(currentTime())
297     //    << " Reading response:  " << QString(ba).trimmed() << "\n";
298 }
299 #endif
300
301 // Parse "~:gdb: unknown target exception 0xc0000139 at 0x77bef04e\n"
302 // and return an exception message
303 static inline QString msgWinException(const QByteArray &data)
304 {
305     const int exCodePos = data.indexOf("0x");
306     const int blankPos = exCodePos != -1 ? data.indexOf(' ', exCodePos + 1) : -1;
307     const int addressPos = blankPos != -1 ? data.indexOf("0x", blankPos + 1) : -1;
308     if (addressPos < 0)
309         return GdbEngine::tr("An exception was triggered.");
310     const unsigned exCode = data.mid(exCodePos, blankPos - exCodePos).toUInt(0, 0);
311     const quint64 address = data.mid(addressPos).trimmed().toULongLong(0, 0);
312     QString rc;
313     QTextStream str(&rc);
314     str << GdbEngine::tr("An exception was triggered: ");
315 #ifdef Q_OS_WIN
316     formatWindowsException(exCode, address, 0, 0, 0, str);
317 #else
318     Q_UNUSED(exCode)
319     Q_UNUSED(address)
320 #endif
321     str << '.';
322     return rc;
323 }
324
325 void GdbEngine::readDebugeeOutput(const QByteArray &data)
326 {
327     QString msg = m_outputCodec->toUnicode(data.constData(), data.length(),
328         &m_outputCodecState);
329     showMessage(msg, AppOutput);
330 }
331
332 void GdbEngine::handleResponse(const QByteArray &buff)
333 {
334     showMessage(QString::fromLocal8Bit(buff, buff.length()), LogOutput);
335
336 #if 0
337     static QTime lastTime;
338     qDebug() // << "#### start response handling #### "
339         << lastTime.msecsTo(QTime::currentTime()) << "ms,"
340         << "buf:" << buff.left(1500) << "..."
341         //<< "buf:" << buff
342         << "size:" << buff.size();
343     lastTime = QTime::currentTime();
344 #else
345     //qDebug() << "buf:" << buff;
346 #endif
347     if (buff.isEmpty() || buff == "(gdb) ")
348         return;
349
350     const char *from = buff.constData();
351     const char *to = from + buff.size();
352     const char *inner;
353
354     int token = -1;
355     // token is a sequence of numbers
356     for (inner = from; inner != to; ++inner)
357         if (*inner < '0' || *inner > '9')
358             break;
359     if (from != inner) {
360         token = QByteArray(from, inner - from).toInt();
361         from = inner;
362         //qDebug() << "found token" << token;
363     }
364
365     // next char decides kind of response
366     const char c = *from++;
367     //qDebug() << "CODE:" << c;
368     switch (c) {
369         case '*':
370         case '+':
371         case '=': {
372             QByteArray asyncClass;
373             for (; from != to; ++from) {
374                 const char c = *from;
375                 if (!isNameChar(c))
376                     break;
377                 asyncClass += *from;
378             }
379             //qDebug() << "ASYNCCLASS" << asyncClass;
380
381             GdbMi result;
382             while (from != to) {
383                 GdbMi data;
384                 if (*from != ',') {
385                     // happens on archer where we get
386                     // 23^running <NL> *running,thread-id="all" <NL> (gdb)
387                     result.m_type = GdbMi::Tuple;
388                     break;
389                 }
390                 ++from; // skip ','
391                 data.parseResultOrValue(from, to);
392                 if (data.isValid()) {
393                     //qDebug() << "parsed result:" << data.toString();
394                     result.m_children += data;
395                     result.m_type = GdbMi::Tuple;
396                 }
397             }
398             if (asyncClass == "stopped") {
399                 handleStopResponse(result);
400                 m_pendingLogStreamOutput.clear();
401                 m_pendingConsoleStreamOutput.clear();
402             } else if (asyncClass == "running") {
403                 // Archer has 'thread-id="all"' here
404             } else if (asyncClass == "library-loaded") {
405                 // Archer has 'id="/usr/lib/libdrm.so.2",
406                 // target-name="/usr/lib/libdrm.so.2",
407                 // host-name="/usr/lib/libdrm.so.2",
408                 // symbols-loaded="0"
409                 QByteArray id = result.findChild("id").data();
410                 if (!id.isEmpty())
411                     showStatusMessage(tr("Library %1 loaded").arg(_(id)), 1000);
412                 progressPing();
413                 invalidateSourcesList();
414             } else if (asyncClass == "library-unloaded") {
415                 // Archer has 'id="/usr/lib/libdrm.so.2",
416                 // target-name="/usr/lib/libdrm.so.2",
417                 // host-name="/usr/lib/libdrm.so.2"
418                 QByteArray id = result.findChild("id").data();
419                 progressPing();
420                 showStatusMessage(tr("Library %1 unloaded").arg(_(id)), 1000);
421                 invalidateSourcesList();
422             } else if (asyncClass == "thread-group-added") {
423                 // 7.1-symbianelf has "{id="i1"}"
424             } else if (asyncClass == "thread-group-created"
425                     || asyncClass == "thread-group-started") {
426                 // Archer had only "{id="28902"}" at some point of 6.8.x.
427                 // *-started seems to be standard in 7.1, but in early
428                 // 7.0.x, there was a *-created instead.
429                 progressPing();
430                 // 7.1.50 has thread-group-started,id="i1",pid="3529"
431                 QByteArray id = result.findChild("id").data();
432                 showStatusMessage(tr("Thread group %1 created").arg(_(id)), 1000);
433                 int pid = id.toInt();
434                 if (!pid) {
435                     id = result.findChild("pid").data();
436                     pid = id.toInt();
437                 }
438                 if (pid)
439                     notifyInferiorPid(pid);
440             } else if (asyncClass == "thread-created") {
441                 //"{id="1",group-id="28902"}"
442                 QByteArray id = result.findChild("id").data();
443                 showStatusMessage(tr("Thread %1 created").arg(_(id)), 1000);
444             } else if (asyncClass == "thread-group-exited") {
445                 // Archer has "{id="28902"}"
446                 QByteArray id = result.findChild("id").data();
447                 showStatusMessage(tr("Thread group %1 exited").arg(_(id)), 1000);
448             } else if (asyncClass == "thread-exited") {
449                 //"{id="1",group-id="28902"}"
450                 QByteArray id = result.findChild("id").data();
451                 QByteArray groupid = result.findChild("group-id").data();
452                 showStatusMessage(tr("Thread %1 in group %2 exited")
453                     .arg(_(id)).arg(_(groupid)), 1000);
454             } else if (asyncClass == "thread-selected") {
455                 QByteArray id = result.findChild("id").data();
456                 showStatusMessage(tr("Thread %1 selected").arg(_(id)), 1000);
457                 //"{id="2"}"
458             } else if (m_isMacGdb && asyncClass == "shlibs-updated") {
459                 // Apple's gdb announces updated libs.
460                 invalidateSourcesList();
461             } else if (m_isMacGdb && asyncClass == "shlibs-added") {
462                 // Apple's gdb announces added libs.
463                 // {shlib-info={num="2", name="libmathCommon.A_debug.dylib",
464                 // kind="-", dyld-addr="0x7f000", reason="dyld", requested-state="Y",
465                 // state="Y", path="/usr/lib/system/libmathCommon.A_debug.dylib",
466                 // description="/usr/lib/system/libmathCommon.A_debug.dylib",
467                 // loaded_addr="0x7f000", slide="0x7f000", prefix=""}}
468                 invalidateSourcesList();
469             } else if (m_isMacGdb && asyncClass == "resolve-pending-breakpoint") {
470                 // Apple's gdb announces resolved breakpoints.
471                 // new_bp="1",pended_bp="1",new_expr="\"gdbengine.cpp\":1584",
472                 // bkpt={number="1",type="breakpoint",disp="keep",enabled="y",
473                 // addr="0x0000000115cc3ddf",func="foo()",file="../foo.cpp",
474                 // line="1584",shlib="/../libFoo_debug.dylib",times="0"}
475                 const GdbMi bkpt = result.findChild("bkpt");
476                 const int number = bkpt.findChild("number").data().toInt();
477                 if (!isQmlStepBreakpoint1(number) && isQmlStepBreakpoint2(number)) {
478                     BreakpointId id = breakHandler()->findBreakpointByNumber(number);
479                     updateBreakpointDataFromOutput(id, bkpt);
480                     BreakpointResponse response = breakHandler()->response(id);
481                     if (response.correctedLineNumber == 0)
482                         attemptAdjustBreakpointLocation(id);
483                 }
484             } else {
485                 qDebug() << "IGNORED ASYNC OUTPUT"
486                     << asyncClass << result.toString();
487             }
488             break;
489         }
490
491         case '~': {
492             QByteArray data = GdbMi::parseCString(from, to);
493             m_pendingConsoleStreamOutput += data;
494
495             // Parse pid from noise.
496             if (!inferiorPid()) {
497                 // Linux/Mac gdb: [New [Tt]hread 0x545 (LWP 4554)]
498                 static QRegExp re1(_("New .hread 0x[0-9a-f]+ \\(LWP ([0-9]*)\\)"));
499                 // MinGW 6.8: [New thread 2437.0x435345]
500                 static QRegExp re2(_("New .hread ([0-9]+)\\.0x[0-9a-f]*"));
501                 // Mac: [Switching to process 9294 local thread 0x2e03] or
502                 // [Switching to process 31773]
503                 static QRegExp re3(_("Switching to process ([0-9]+)"));
504                 QTC_ASSERT(re1.isValid() && re2.isValid(), return);
505                 if (re1.indexIn(_(data)) != -1)
506                     maybeHandleInferiorPidChanged(re1.cap(1));
507                 else if (re2.indexIn(_(data)) != -1)
508                     maybeHandleInferiorPidChanged(re2.cap(1));
509                 else if (re3.indexIn(_(data)) != -1)
510                     maybeHandleInferiorPidChanged(re3.cap(1));
511             }
512
513             // Show some messages to give the impression something happens.
514             if (data.startsWith("Reading symbols from ")) {
515                 showStatusMessage(tr("Reading %1...").arg(_(data.mid(21))), 1000);
516                 progressPing();
517                 invalidateSourcesList();
518             } else if (data.startsWith("[New ") || data.startsWith("[Thread ")) {
519                 if (data.endsWith('\n'))
520                     data.chop(1);
521                 progressPing();
522                 showStatusMessage(_(data), 1000);
523             } else if (data.startsWith("gdb: unknown target exception 0x")) {
524                 // [Windows, most likely some DLL/Entry point not found]:
525                 // "gdb: unknown target exception 0xc0000139 at 0x77bef04e"
526                 // This may be fatal and cause the target to exit later
527                 m_lastWinException = msgWinException(data);
528                 showMessage(m_lastWinException, LogMisc);
529             }
530
531             if (data.startsWith("QMLBP:")) {
532                 int pos1 = 6;
533                 int pos2 = data.indexOf(' ', pos1);
534                 m_qmlBreakpointNumbers[2] = data.mid(pos1, pos2 - pos1).toInt();
535                 //qDebug() << "FOUND QMLBP: " << m_qmlBreakpointNumbers[2];
536                 //qDebug() << "CURRENT: " << m_qmlBreakpointNumbers;
537             }
538
539             break;
540         }
541
542         case '@': {
543             readDebugeeOutput(GdbMi::parseCString(from, to));
544             break;
545         }
546
547         case '&': {
548             QByteArray data = GdbMi::parseCString(from, to);
549             m_pendingLogStreamOutput += data;
550             // On Windows, the contents seem to depend on the debugger
551             // version and/or OS version used.
552             if (data.startsWith("warning:"))
553                 showMessage(_(data.mid(9)), AppStuff); // Cut "warning: "
554             break;
555         }
556
557         case '^': {
558             GdbResponse response;
559
560             response.token = token;
561
562             for (inner = from; inner != to; ++inner)
563                 if (*inner < 'a' || *inner > 'z')
564                     break;
565
566             QByteArray resultClass = QByteArray::fromRawData(from, inner - from);
567             if (resultClass == "done") {
568                 response.resultClass = GdbResultDone;
569             } else if (resultClass == "running") {
570                 response.resultClass = GdbResultRunning;
571             } else if (resultClass == "connected") {
572                 response.resultClass = GdbResultConnected;
573             } else if (resultClass == "error") {
574                 response.resultClass = GdbResultError;
575             } else if (resultClass == "exit") {
576                 response.resultClass = GdbResultExit;
577             } else {
578                 response.resultClass = GdbResultUnknown;
579             }
580
581             from = inner;
582             if (from != to) {
583                 if (*from == ',') {
584                     ++from;
585                     response.data.parseTuple_helper(from, to);
586                     response.data.m_type = GdbMi::Tuple;
587                     response.data.m_name = "data";
588                 } else {
589                     // Archer has this.
590                     response.data.m_type = GdbMi::Tuple;
591                     response.data.m_name = "data";
592                 }
593             }
594
595             //qDebug() << "\nLOG STREAM:" + m_pendingLogStreamOutput;
596             //qDebug() << "\nCONSOLE STREAM:" + m_pendingConsoleStreamOutput;
597             response.data.setStreamOutput("logstreamoutput",
598                 m_pendingLogStreamOutput);
599             response.data.setStreamOutput("consolestreamoutput",
600                 m_pendingConsoleStreamOutput);
601             m_pendingLogStreamOutput.clear();
602             m_pendingConsoleStreamOutput.clear();
603
604             handleResultRecord(&response);
605             break;
606         }
607         default: {
608             qDebug() << "UNKNOWN RESPONSE TYPE" << c;
609             break;
610         }
611     }
612 }
613
614 void GdbEngine::readGdbStandardError()
615 {
616     QByteArray err = gdbProc()->readAllStandardError();
617     showMessage(_("UNEXPECTED GDB STDERR: " + err));
618     if (err == "Undefined command: \"bb\".  Try \"help\".\n")
619         return;
620     if (err.startsWith("BFD: reopening"))
621         return;
622     qWarning() << "Unexpected GDB stderr:" << err;
623 }
624
625 void GdbEngine::readGdbStandardOutput()
626 {
627     m_commandTimer.start(); // Restart timer.
628
629     int newstart = 0;
630     int scan = m_inbuffer.size();
631
632     m_inbuffer.append(gdbProc()->readAllStandardOutput());
633
634     // This can trigger when a dialog starts a nested event loop.
635     if (m_busy)
636         return;
637
638     while (newstart < m_inbuffer.size()) {
639         int start = newstart;
640         int end = m_inbuffer.indexOf('\n', scan);
641         if (end < 0) {
642             m_inbuffer.remove(0, start);
643             return;
644         }
645         newstart = end + 1;
646         scan = newstart;
647         if (end == start)
648             continue;
649 #        if defined(Q_OS_WIN)
650         if (m_inbuffer.at(end - 1) == '\r') {
651             --end;
652             if (end == start)
653                 continue;
654         }
655 #        endif
656         m_busy = true;
657         handleResponse(QByteArray::fromRawData(m_inbuffer.constData() + start, end - start));
658         m_busy = false;
659     }
660     m_inbuffer.clear();
661 }
662
663 void GdbEngine::interruptInferior()
664 {
665     QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state(); return);
666
667     if (debuggerCore()->boolSetting(TargetAsync)) {
668         postCommand("-exec-interrupt");
669     } else {
670         showStatusMessage(tr("Stop requested..."), 5000);
671         showMessage(_("TRYING TO INTERRUPT INFERIOR"));
672         m_gdbAdapter->interruptInferior();
673     }
674 }
675
676 void GdbEngine::interruptInferiorTemporarily()
677 {
678     foreach (const GdbCommand &cmd, m_commandsToRunOnTemporaryBreak) {
679         if (cmd.flags & LosesChild) {
680             notifyInferiorIll();
681             return;
682         }
683     }
684     requestInterruptInferior();
685 }
686
687 void GdbEngine::maybeHandleInferiorPidChanged(const QString &pid0)
688 {
689     const qint64 pid = pid0.toLongLong();
690     if (pid == 0) {
691         showMessage(_("Cannot parse PID from %1").arg(pid0));
692         return;
693     }
694     if (pid == inferiorPid())
695         return;
696
697     showMessage(_("FOUND PID %1").arg(pid));
698     notifyInferiorPid(pid);
699 }
700
701 void GdbEngine::postCommand(const QByteArray &command, AdapterCallback callback,
702                             const char *callbackName, const QVariant &cookie)
703 {
704     postCommand(command, NoFlags, callback, callbackName, cookie);
705 }
706
707 void GdbEngine::postCommand(const QByteArray &command, GdbCommandFlags flags,
708                             AdapterCallback callback,
709                             const char *callbackName, const QVariant &cookie)
710 {
711     GdbCommand cmd;
712     cmd.command = command;
713     cmd.flags = flags;
714     cmd.adapterCallback = callback;
715     cmd.callbackName = callbackName;
716     cmd.cookie = cookie;
717     postCommandHelper(cmd);
718 }
719
720 void GdbEngine::postCommand(const QByteArray &command, GdbCommandCallback callback,
721                             const char *callbackName, const QVariant &cookie)
722 {
723     postCommand(command, NoFlags, callback, callbackName, cookie);
724 }
725
726 void GdbEngine::postCommand(const QByteArray &command, GdbCommandFlags flags,
727                             GdbCommandCallback callback, const char *callbackName,
728                             const QVariant &cookie)
729 {
730     GdbCommand cmd;
731     cmd.command = command;
732     cmd.flags = flags;
733     cmd.callback = callback;
734     cmd.callbackName = callbackName;
735     cmd.cookie = cookie;
736     postCommandHelper(cmd);
737 }
738
739 void GdbEngine::postCommandHelper(const GdbCommand &cmd)
740 {
741     if (!stateAcceptsGdbCommands(state())) {
742         PENDING_DEBUG(_("NO GDB PROCESS RUNNING, CMD IGNORED: " + cmd.command));
743         showMessage(_("NO GDB PROCESS RUNNING, CMD IGNORED: %1 %2")
744             .arg(_(cmd.command)).arg(state()));
745         return;
746     }
747
748     if (cmd.flags & RebuildWatchModel) {
749         ++m_pendingWatchRequests;
750         PENDING_DEBUG("   WATCH MODEL:" << cmd.command << "=>" << cmd.callbackName
751                       << "INCREMENTS PENDING TO" << m_pendingWatchRequests);
752     } else if (cmd.flags & RebuildBreakpointModel) {
753         ++m_pendingBreakpointRequests;
754         PENDING_DEBUG("   BRWAKPOINT MODEL:" << cmd.command << "=>" << cmd.callbackName
755                       << "INCREMENTS PENDING TO" << m_pendingBreakpointRequests);
756     } else {
757         PENDING_DEBUG("   OTHER (IN):" << cmd.command << "=>" << cmd.callbackName
758                       << "LEAVES PENDING WATCH AT" << m_pendingWatchRequests
759                       << "LEAVES PENDING BREAKPOINT AT" << m_pendingBreakpointRequests);
760     }
761
762     // FIXME: clean up logic below
763     if (cmd.flags & Immediate) {
764         // This should always be sent.
765         flushCommand(cmd);
766     } else if ((cmd.flags & NeedsStop)
767             || !m_commandsToRunOnTemporaryBreak.isEmpty()) {
768         if (state() == InferiorStopOk || state() == InferiorUnrunnable
769             || state() == InferiorSetupRequested || state() == EngineSetupOk
770             || state() == InferiorShutdownRequested) {
771             // Can be safely sent now.
772             flushCommand(cmd);
773         } else {
774             // Queue the commands that we cannot send at once.
775             showMessage(_("QUEUING COMMAND " + cmd.command));
776             m_commandsToRunOnTemporaryBreak.append(cmd);
777             if (state() == InferiorStopRequested) {
778                 if (cmd.flags & LosesChild) {
779                     notifyInferiorIll();
780                 }
781                 showMessage(_("CHILD ALREADY BEING INTERRUPTED. STILL HOPING."));
782                 // Calling shutdown() here breaks all situations where two
783                 // NeedsStop commands are issued in quick succession.
784             } else if (state() == InferiorRunOk) {
785                 showStatusMessage(tr("Stopping temporarily"), 1000);
786                 interruptInferiorTemporarily();
787             } else {
788                 qDebug() << "ATTEMPTING TO QUEUE COMMAND "
789                     << cmd.command << "IN INAPPROPRIATE STATE" << state();
790             }
791         }
792     } else if (!cmd.command.isEmpty()) {
793         flushCommand(cmd);
794     }
795 }
796
797 void GdbEngine::flushQueuedCommands()
798 {
799     showStatusMessage(tr("Processing queued commands"), 1000);
800     while (!m_commandsToRunOnTemporaryBreak.isEmpty()) {
801         GdbCommand cmd = m_commandsToRunOnTemporaryBreak.takeFirst();
802         showMessage(_("RUNNING QUEUED COMMAND " + cmd.command + ' '
803             + cmd.callbackName));
804         flushCommand(cmd);
805     }
806 }
807
808 void GdbEngine::flushCommand(const GdbCommand &cmd0)
809 {
810     if (!stateAcceptsGdbCommands(state())) {
811         showMessage(_(cmd0.command), LogInput);
812         showMessage(_("GDB PROCESS ACCEPTS NO CMD IN STATE %1 ").arg(state()));
813         return;
814     }
815
816     QTC_ASSERT(gdbProc()->state() == QProcess::Running, return;)
817
818     ++currentToken();
819     GdbCommand cmd = cmd0;
820     cmd.postTime = QTime::currentTime();
821     m_cookieForToken[currentToken()] = cmd;
822     if (cmd.flags & ConsoleCommand)
823         cmd.command = "-interpreter-exec console \"" + cmd.command + '"';
824     cmd.command = QByteArray::number(currentToken()) + cmd.command;
825     showMessage(_(cmd.command), LogInput);
826
827     m_gdbAdapter->write(cmd.command + "\r\n");
828
829     // Start Watchdog.
830     if (m_commandTimer.interval() <= 20000)
831         m_commandTimer.setInterval(commandTimeoutTime());
832     // The process can die for external reason between the "-gdb-exit" was
833     // sent and a response could be retrieved. We don't want the watchdog
834     // to bark in that case since the only possible outcome is a dead
835     // process anyway.
836     if (!cmd.command.endsWith("-gdb-exit"))
837         m_commandTimer.start();
838
839     //if (cmd.flags & LosesChild)
840     //    notifyInferiorIll();
841 }
842
843 int GdbEngine::commandTimeoutTime() const
844 {
845     int time = debuggerCore()->action(GdbWatchdogTimeout)->value().toInt();
846     return 1000 * qMax(40, time);
847 }
848
849 void GdbEngine::commandTimeout()
850 {
851     QList<int> keys = m_cookieForToken.keys();
852     qSort(keys);
853     bool killIt = false;
854     foreach (int key, keys) {
855         const GdbCommand &cmd = m_cookieForToken.value(key);
856         if (!(cmd.flags & NonCriticalResponse))
857             killIt = true;
858         QByteArray msg = QByteArray::number(key);
859         msg += ": " + cmd.command + " => ";
860         msg += cmd.callbackName ? cmd.callbackName : "<unnamed callback>";
861         showMessage(_(msg));
862     }
863     if (killIt) {
864         showMessage(_("TIMED OUT WAITING FOR GDB REPLY. COMMANDS STILL IN PROGRESS:"));
865         int timeOut = m_commandTimer.interval();
866         //m_commandTimer.stop();
867         const QString msg = tr("The gdb process has not responded "
868             "to a command within %1 seconds. This could mean it is stuck "
869             "in an endless loop or taking longer than expected to perform "
870             "the operation.\nYou can choose between waiting "
871             "longer or abort debugging.").arg(timeOut / 1000);
872         QMessageBox *mb = showMessageBox(QMessageBox::Critical,
873             tr("GDB not responding"), msg,
874             QMessageBox::Ok | QMessageBox::Cancel);
875         mb->button(QMessageBox::Cancel)->setText(tr("Give GDB more time"));
876         mb->button(QMessageBox::Ok)->setText(tr("Stop debugging"));
877         if (mb->exec() == QMessageBox::Ok) {
878             showMessage(_("KILLING DEBUGGER AS REQUESTED BY USER"));
879             // This is an undefined state, so we just pull the emergency brake.
880             watchHandler()->endCycle();
881             gdbProc()->kill();
882         } else {
883             showMessage(_("CONTINUE DEBUGGER AS REQUESTED BY USER"));
884         }
885     } else {
886         showMessage(_("\nNON-CRITICAL TIMEOUT\n"));
887     }
888 }
889
890 void GdbEngine::handleResultRecord(GdbResponse *response)
891 {
892     //qDebug() << "TOKEN:" << response.token
893     //    << " ACCEPTABLE:" << m_oldestAcceptableToken;
894     //qDebug() << "\nRESULT" << response.token << response.toString();
895
896     int token = response->token;
897     if (token == -1)
898         return;
899
900     if (!m_cookieForToken.contains(token)) {
901         // In theory this should not happen (rather the error should be
902         // reported in the "first" response to the command) in practice it
903         // does. We try to handle a few situations we are aware of gracefully.
904         // Ideally, this code should not be present at all.
905         showMessage(_("COOKIE FOR TOKEN %1 ALREADY EATEN (%2). "
906                       "TWO RESPONSES FOR ONE COMMAND?").arg(token).
907                     arg(QString::fromAscii(stateName(state()))));
908         if (response->resultClass == GdbResultError) {
909             QByteArray msg = response->data.findChild("msg").data();
910             if (msg == "Cannot find new threads: generic error") {
911                 // Handle a case known to occur on Linux/gdb 6.8 when debugging moc
912                 // with helpers enabled. In this case we get a second response with
913                 // msg="Cannot find new threads: generic error"
914                 showMessage(_("APPLYING WORKAROUND #1"));
915                 showMessageBox(QMessageBox::Critical,
916                     tr("Executable failed"), QString::fromLocal8Bit(msg));
917                 showStatusMessage(tr("Process failed to start"));
918                 //shutdown();
919                 notifyInferiorIll();
920             } else if (msg == "\"finish\" not meaningful in the outermost frame.") {
921                 // Handle a case known to appear on GDB 6.4 symbianelf when
922                 // the stack is cut due to access to protected memory.
923                 //showMessage(_("APPLYING WORKAROUND #2"));
924                 notifyInferiorStopOk();
925             } else if (msg.startsWith("Cannot find bounds of current function")) {
926                 // Happens when running "-exec-next" in a function for which
927                 // there is no debug information. Divert to "-exec-next-step"
928                 showMessage(_("APPLYING WORKAROUND #3"));
929                 notifyInferiorStopOk();
930                 executeNextI();
931             } else if (msg.startsWith("Couldn't get registers: No such process.")) {
932                 // Happens on archer-tromey-python 6.8.50.20090910-cvs
933                 // There might to be a race between a process shutting down
934                 // and library load messages.
935                 showMessage(_("APPLYING WORKAROUND #4"));
936                 notifyInferiorStopOk();
937                 //notifyInferiorIll();
938                 //showStatusMessage(tr("Executable failed: %1")
939                 //    .arg(QString::fromLocal8Bit(msg)));
940                 //shutdown();
941                 //showMessageBox(QMessageBox::Critical,
942                 //    tr("Executable failed"), QString::fromLocal8Bit(msg));
943             } else if (msg.contains("Cannot insert breakpoint")) {
944                 // For breakpoints set by address to non-existent addresses we
945                 // might get something like "6^error,msg="Warning:\nCannot insert
946                 // breakpoint 3.\nError accessing memory address 0x34592327:
947                 // Input/output error.\nCannot insert breakpoint 4.\nError
948                 // accessing memory address 0x34592335: Input/output error.\n".
949                 // This should not stop us from proceeding.
950                 // Most notably, that happens after a "6^running" and "*running"
951                 // We are probably sitting at _start and can't proceed as
952                 // long as the breakpoints are enabled.
953                 // FIXME: Should we silently disable the offending breakpoints?
954                 showMessage(_("APPLYING WORKAROUND #5"));
955                 showMessageBox(QMessageBox::Critical,
956                     tr("Setting breakpoints failed"), QString::fromLocal8Bit(msg));
957                 QTC_ASSERT(state() == InferiorRunOk, /**/);
958                 notifyInferiorSpontaneousStop();
959                 notifyEngineIll();
960             } else {
961                 // Windows: Some DLL or some function not found. Report
962                 // the exception now in a box.
963                 if (msg.startsWith("During startup program exited with"))
964                     notifyInferiorExited();
965                 QString logMsg;
966                 if (!m_lastWinException.isEmpty())
967                     logMsg = m_lastWinException + QLatin1Char('\n');
968                 logMsg += QString::fromLocal8Bit(msg);
969                 showMessageBox(QMessageBox::Critical, tr("Executable Failed"), logMsg);
970                 showStatusMessage(tr("Executable failed: %1").arg(logMsg));
971             }
972         }
973         return;
974     }
975
976     GdbCommand cmd = m_cookieForToken.take(token);
977     if (debuggerCore()->boolSetting(LogTimeStamps)) {
978         showMessage(_("Response time: %1: %2 s")
979             .arg(_(cmd.command))
980             .arg(cmd.postTime.msecsTo(QTime::currentTime()) / 1000.),
981             LogTime);
982     }
983
984     if (response->token < m_oldestAcceptableToken && (cmd.flags & Discardable)) {
985         //showMessage(_("### SKIPPING OLD RESULT") + response.toString());
986         return;
987     }
988
989     response->cookie = cmd.cookie;
990
991     bool isExpectedResult =
992            (response->resultClass == GdbResultError) // Can always happen.
993         || (response->resultClass == GdbResultRunning && (cmd.flags & RunRequest))
994         || (response->resultClass == GdbResultExit && (cmd.flags & ExitRequest))
995         || (response->resultClass == GdbResultDone);
996         // GdbResultDone can almost "always" happen. Known examples are:
997         //  (response->resultClass == GdbResultDone && cmd.command == "continue")
998         // Happens with some incarnations of gdb 6.8 for "jump to line"
999         //  (response->resultClass == GdbResultDone && cmd.command.startsWith("jump"))
1000         //  (response->resultClass == GdbResultDone && cmd.command.startsWith("detach"))
1001         // Happens when stepping finishes very quickly and issues *stopped/^done
1002         // instead of ^running/*stopped
1003         //  (response->resultClass == GdbResultDone && (cmd.flags & RunRequest));
1004
1005     if (!isExpectedResult) {
1006 #ifdef Q_OS_WIN
1007         // Ignore spurious 'running' responses to 'attach'
1008         const bool warning = !((startParameters().startMode == AttachExternal
1009                                || startParameters().useTerminal)
1010                                && cmd.command.startsWith("attach"));
1011 #else
1012         const bool warning = true;
1013 #endif
1014         if (warning) {
1015             QByteArray rsp = GdbResponse::stringFromResultClass(response->resultClass);
1016             rsp = "UNEXPECTED RESPONSE '" + rsp + "' TO COMMAND '" + cmd.command + "'";
1017             qWarning() << rsp << " AT " __FILE__ ":" STRINGIFY(__LINE__);
1018             showMessage(_(rsp));
1019         }
1020     }
1021
1022     if (cmd.callback)
1023         (this->*cmd.callback)(*response);
1024     else if (cmd.adapterCallback)
1025         (m_gdbAdapter->*cmd.adapterCallback)(*response);
1026
1027     if (cmd.flags & RebuildWatchModel) {
1028         --m_pendingWatchRequests;
1029         PENDING_DEBUG("   WATCH" << cmd.command << "=>" << cmd.callbackName
1030                       << "DECREMENTS PENDING WATCH TO" << m_pendingWatchRequests);
1031         if (m_pendingWatchRequests <= 0) {
1032             PENDING_DEBUG("\n\n ... AND TRIGGERS WATCH MODEL UPDATE\n");
1033             rebuildWatchModel();
1034         }
1035     } else if (cmd.flags & RebuildBreakpointModel) {
1036         --m_pendingBreakpointRequests;
1037         PENDING_DEBUG("   BREAKPOINT" << cmd.command << "=>" << cmd.callbackName
1038                       << "DECREMENTS PENDING TO" << m_pendingWatchRequests);
1039         if (m_pendingBreakpointRequests <= 0) {
1040             PENDING_DEBUG("\n\n ... AND TRIGGERS BREAKPOINT MODEL UPDATE\n");
1041             attemptBreakpointSynchronization();
1042         }
1043     } else {
1044         PENDING_DEBUG("   OTHER (OUT):" << cmd.command << "=>" << cmd.callbackName
1045                       << "LEAVES PENDING WATCH AT" << m_pendingWatchRequests
1046                       << "LEAVES PENDING BREAKPOINT AT" << m_pendingBreakpointRequests);
1047     }
1048
1049     // Commands were queued, but we were in RunningRequested state, so the interrupt
1050     // was postponed.
1051     // This is done after the command callbacks so the running-requesting commands
1052     // can assert on the right state.
1053     if (state() == InferiorRunOk && !m_commandsToRunOnTemporaryBreak.isEmpty())
1054         interruptInferiorTemporarily();
1055
1056     // Continue only if there are no commands wire anymore, so this will
1057     // be fully synchronous.
1058     // This is somewhat inefficient, as it makes the last command synchronous.
1059     // An optimization would be requesting the continue immediately when the
1060     // event loop is entered, and let individual commands have a flag to suppress
1061     // that behavior.
1062     if (m_commandsDoneCallback && m_cookieForToken.isEmpty()) {
1063         showMessage(_("ALL COMMANDS DONE; INVOKING CALLBACK"));
1064         CommandsDoneCallback cont = m_commandsDoneCallback;
1065         m_commandsDoneCallback = 0;
1066         (this->*cont)();
1067     } else {
1068         PENDING_DEBUG("MISSING TOKENS: " << m_cookieForToken.keys());
1069     }
1070
1071     if (m_cookieForToken.isEmpty())
1072         m_commandTimer.stop();
1073 }
1074
1075 bool GdbEngine::acceptsDebuggerCommands() const
1076 {
1077     return state() == InferiorStopOk
1078         || state() == InferiorUnrunnable;
1079 }
1080
1081 void GdbEngine::executeDebuggerCommand(const QString &command)
1082 {
1083     QTC_ASSERT(acceptsDebuggerCommands(), /**/);
1084     m_gdbAdapter->write(command.toLatin1() + "\r\n");
1085 }
1086
1087 // This is called from CoreAdapter and AttachAdapter.
1088 void GdbEngine::updateAll()
1089 {
1090     if (hasPython())
1091         updateAllPython();
1092     else
1093         updateAllClassic();
1094 }
1095
1096 void GdbEngine::handleQuerySources(const GdbResponse &response)
1097 {
1098     m_sourcesListUpdating = false;
1099     m_sourcesListOutdated = false;
1100     if (response.resultClass == GdbResultDone) {
1101         QMap<QString, QString> oldShortToFull = m_shortToFullName;
1102         m_shortToFullName.clear();
1103         m_fullToShortName.clear();
1104         // "^done,files=[{file="../../../../bin/gdbmacros/gdbmacros.cpp",
1105         // fullname="/data5/dev/ide/main/bin/gdbmacros/gdbmacros.cpp"},
1106         GdbMi files = response.data.findChild("files");
1107         foreach (const GdbMi &item, files.children()) {
1108             GdbMi fullName = item.findChild("fullname");
1109             GdbMi fileName = item.findChild("file");
1110             QString file = QString::fromLocal8Bit(fileName.data());
1111             if (fullName.isValid()) {
1112                 QString full = cleanupFullName(QString::fromLocal8Bit(fullName.data()));
1113                 m_shortToFullName[file] = full;
1114                 m_fullToShortName[full] = file;
1115             } else if (fileName.isValid()) {
1116                 m_shortToFullName[file] = tr("<unknown>");
1117             }
1118         }
1119         if (m_shortToFullName != oldShortToFull)
1120             sourceFilesHandler()->setSourceFiles(m_shortToFullName);
1121     }
1122 }
1123
1124 void GdbEngine::handleExecuteJumpToLine(const GdbResponse &response)
1125 {
1126     if (response.resultClass == GdbResultRunning) {
1127         doNotifyInferiorRunOk();
1128         // All is fine. Waiting for the temporary breakpoint to be hit.
1129     } else if (response.resultClass == GdbResultDone) {
1130         // This happens on old gdb. Trigger the effect of a '*stopped'.
1131         showStatusMessage(tr("Jumped. Stopped"));
1132         notifyInferiorSpontaneousStop();
1133         handleStop1(response);
1134     }
1135 }
1136
1137 void GdbEngine::handleExecuteRunToLine(const GdbResponse &response)
1138 {
1139     if (response.resultClass == GdbResultRunning) {
1140         doNotifyInferiorRunOk();
1141         // All is fine. Waiting for the temporary breakpoint to be hit.
1142     } else if (response.resultClass == GdbResultDone) {
1143         // This happens on old gdb. Trigger the effect of a '*stopped'.
1144         // >&"continue\n"
1145         // >~"Continuing.\n"
1146         //>~"testArray () at ../simple/app.cpp:241\n"
1147         //>~"241\t    s[1] = \"b\";\n"
1148         //>122^done
1149         gotoLocation(m_targetFrame);
1150         showStatusMessage(tr("Target line hit. Stopped"));
1151         notifyInferiorSpontaneousStop();
1152         handleStop1(response);
1153     }
1154 }
1155
1156 static bool isExitedReason(const QByteArray &reason)
1157 {
1158     return reason == "exited-normally"   // inferior exited normally
1159         || reason == "exited-signalled"  // inferior exited because of a signal
1160         //|| reason == "signal-received" // inferior received signal
1161         || reason == "exited";           // inferior exited
1162 }
1163
1164 #if 0
1165 void GdbEngine::handleAqcuiredInferior()
1166 {
1167     // Reverse debugging. FIXME: Should only be used when available.
1168     //if (debuggerCore()->boolSetting(EnableReverseDebugging))
1169     //    postCommand("target response");
1170
1171     tryLoadDebuggingHelpers();
1172
1173 #    ifndef Q_OS_MAC
1174     // intentionally after tryLoadDebuggingHelpers(),
1175     // otherwise we'd interrupt solib loading.
1176     if (debuggerCore()->boolSetting(AllPluginBreakpoints)) {
1177         postCommand("set auto-solib-add on");
1178         postCommand("set stop-on-solib-events 0");
1179         postCommand("sharedlibrary .*");
1180     } else if (debuggerCore()->boolSetting(SelectedPluginBreakpoints)) {
1181         postCommand("set auto-solib-add on");
1182         postCommand("set stop-on-solib-events 1");
1183         postCommand("sharedlibrary "
1184           + theDebuggerStringSetting(SelectedPluginBreakpointsPattern));
1185     } else if (debuggerCore()->boolSetting(NoPluginBreakpoints)) {
1186         // should be like that already
1187         postCommand("set auto-solib-add off");
1188         postCommand("set stop-on-solib-events 0");
1189     }
1190 #    endif
1191
1192     // It's nicer to see a bit of the world we live in.
1193     reloadModulesInternal();
1194 }
1195 #endif
1196
1197 #ifdef Q_OS_UNIX
1198 # define STOP_SIGNAL "SIGINT"
1199 # define CROSS_STOP_SIGNAL "SIGTRAP"
1200 #else
1201 # define STOP_SIGNAL "SIGTRAP"
1202 # define CROSS_STOP_SIGNAL "SIGINT"
1203 #endif
1204
1205 void GdbEngine::handleStopResponse(const GdbMi &data)
1206 {
1207     // This is gdb 7+'s initial *stopped in response to attach.
1208     // For consistency, we just discard it.
1209     if (state() == InferiorSetupRequested)
1210         return;
1211
1212     if (isDying()) {
1213         notifyInferiorStopOk();
1214         return;
1215     }
1216
1217     const QByteArray reason = data.findChild("reason").data();
1218
1219     if (isExitedReason(reason)) {
1220         //   // The user triggered a stop, but meanwhile the app simply exited ...
1221         //    QTC_ASSERT(state() == InferiorStopRequested
1222         //            /*|| state() == InferiorStopRequested_Kill*/,
1223         //               qDebug() << state());
1224         QString msg;
1225         if (reason == "exited") {
1226             msg = tr("Application exited with exit code %1")
1227                 .arg(_(data.findChild("exit-code").toString()));
1228         } else if (reason == "exited-signalled" || reason == "signal-received") {
1229             msg = tr("Application exited after receiving signal %1")
1230                 .arg(_(data.findChild("signal-name").toString()));
1231         } else {
1232             msg = tr("Application exited normally");
1233         }
1234         showStatusMessage(msg);
1235         notifyInferiorExited();
1236         return;
1237     }
1238
1239     const int bkptno = data.findChild("bkptno").data().toInt();
1240     const GdbMi frame = data.findChild("frame");
1241
1242     const int lineNumber = frame.findChild("line").data().toInt();
1243     QString fullName = QString::fromUtf8(frame.findChild("fullname").data());
1244
1245     if (fullName.isEmpty())
1246         fullName = QString::fromUtf8(frame.findChild("file").data());
1247
1248     if (bkptno && frame.isValid()
1249             && !isQmlStepBreakpoint1(bkptno)
1250             && !isQmlStepBreakpoint2(bkptno)
1251             && !isQFatalBreakpoint(bkptno)) {
1252         // Use opportunity to update the breakpoint marker position.
1253         BreakHandler *handler = breakHandler();
1254         //qDebug() << " PROBLEM: " << m_qmlBreakpointNumbers << bkptno
1255         //    << isQmlStepBreakpoint1(bkptno)
1256         //    << isQmlStepBreakpoint2(bkptno)
1257         BreakpointId id = handler->findBreakpointByNumber(bkptno);
1258         const BreakpointResponse &response = handler->response(id);
1259         QString fileName = response.fileName;
1260         if (fileName.isEmpty())
1261             fileName = handler->fileName(id);
1262         if (fileName.isEmpty())
1263             fileName = fullName;
1264         if (!fileName.isEmpty())
1265             handler->setMarkerFileAndLine(id, fileName, lineNumber);
1266     }
1267
1268     //qDebug() << "BP " << bkptno << data.toString();
1269     // Quickly set the location marker.
1270     if (lineNumber && !debuggerCore()->boolSetting(OperateByInstruction)
1271             && QFileInfo(fullName).exists()
1272             && !isQmlStepBreakpoint1(bkptno)
1273             && !isQmlStepBreakpoint2(bkptno)
1274             && !isQFatalBreakpoint(bkptno))
1275         gotoLocation(Location(fullName, lineNumber));
1276
1277     if (!m_commandsToRunOnTemporaryBreak.isEmpty()) {
1278         QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state())
1279         notifyInferiorStopOk();
1280         flushQueuedCommands();
1281         if (state() == InferiorStopOk) {
1282             QTC_ASSERT(m_commandsDoneCallback == 0, /**/);
1283             m_commandsDoneCallback = &GdbEngine::autoContinueInferior;
1284         } else {
1285             QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state())
1286         }
1287         return;
1288     }
1289
1290     if (state() == InferiorRunOk) {
1291         // Stop triggered by a breakpoint or otherwise not directly
1292         // initiated by the user.
1293         notifyInferiorSpontaneousStop();
1294     } else if (state() == InferiorRunRequested) {
1295         // Stop triggered by something like "-exec-step\n"
1296         // "&"Cannot access memory at address 0xbfffedd4\n"
1297         // In this case a proper response 94^error,msg="" will follow and
1298         // be handled in the result handler.
1299         // -- or --
1300         // *stopped arriving earlier than ^done response to an -exec-step
1301         doNotifyInferiorRunOk();
1302         notifyInferiorSpontaneousStop();
1303     } else if (state() == InferiorStopOk && isQmlStepBreakpoint2(bkptno)) {
1304         // That's expected.
1305     } else {
1306         QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
1307         notifyInferiorStopOk();
1308     }
1309
1310     // FIXME: Replace the #ifdef by the "target" architecture.
1311 #ifdef Q_OS_LINUX
1312     if (!m_entryPoint.isEmpty()) {
1313         // This is needed as long as we support stock gdb 6.8.
1314         if (frame.findChild("addr").data() == m_entryPoint) {
1315             // There are two expected reasons for getting here:
1316             // 1) For some reason, attaching to a stopped process causes *two*
1317             // SIGSTOPs
1318             //    when trying to continue (kernel i386 2.6.24-23-ubuntu, gdb 6.8).
1319             //    Interestingly enough, on MacOSX no signal is delivered at all.
1320             // 2) The explicit tbreak at the entry point we set to query the PID.
1321             //    Gdb <= 6.8 reports a frame but no reason, 6.8.50+ reports
1322             //    everything.
1323             // The case of the user really setting a breakpoint at _start is simply
1324             // unsupported.
1325             if (!inferiorPid()) // For programs without -pthread under gdb <= 6.8.
1326                 postCommand("info proc", CB(handleInfoProc));
1327             continueInferiorInternal();
1328             return;
1329         }
1330         // We are past the initial stop(s). No need to waste time on further checks.
1331         m_entryPoint.clear();
1332     }
1333 #endif
1334
1335     //qDebug() << "STOP: " << m_qmlBreakpointNumbers;
1336
1337     if (isQmlStepBreakpoint1(bkptno))
1338         return;
1339
1340     handleStop0(data);
1341 }
1342
1343 void GdbEngine::handleStop0(const GdbMi &data)
1344 {
1345 #if 0 // See http://vladimir_prus.blogspot.com/2007/12/debugger-stories-pending-breakpoints.html
1346     // Due to LD_PRELOADing the dumpers, these events can occur even before
1347     // reaching the entry point. So handle it before the entry point hacks below.
1348     if (reason.isEmpty() && m_gdbVersion < 70000 && !m_isMacGdb) {
1349         // On Linux it reports "Stopped due to shared library event\n", but
1350         // on Windows it simply forgets about it. Thus, we identify the response
1351         // based on it having no frame information.
1352         if (!data.findChild("frame").isValid()) {
1353             invalidateSourcesList();
1354             // Each stop causes a roundtrip and button flicker, so prevent
1355             // a flood of useless stops. Will be automatically re-enabled.
1356             postCommand("set stop-on-solib-events 0");
1357 #if 0
1358             // The related code (handleAqcuiredInferior()) is disabled as well.
1359             if (debuggerCore()->boolSetting(SelectedPluginBreakpoints)) {
1360                 QString dataStr = _(data.toString());
1361                 showMessage(_("SHARED LIBRARY EVENT: ") + dataStr);
1362                 QString pat = theDebuggerStringSetting(SelectedPluginBreakpointsPattern);
1363                 showMessage(_("PATTERN: ") + pat);
1364                 postCommand("sharedlibrary " + pat.toLocal8Bit());
1365                 showStatusMessage(tr("Loading %1...").arg(dataStr));
1366             }
1367 #endif
1368             continueInferiorInternal();
1369             return;
1370         }
1371     }
1372 #endif
1373
1374     const GdbMi frame = data.findChild("frame");
1375     const QByteArray reason = data.findChild("reason").data();
1376
1377     // This was seen on XP after removing a breakpoint while running
1378     //  >945*stopped,reason="signal-received",signal-name="SIGTRAP",
1379     //  signal-meaning="Trace/breakpoint trap",thread-id="2",
1380     //  frame={addr="0x7c91120f",func="ntdll!DbgUiConnectToDbg",
1381     //  args=[],from="C:\\WINDOWS\\system32\\ntdll.dll"}
1382     // also seen on gdb 6.8-symbianelf without qXfer:libraries:read+;
1383     // FIXME: remote.c parses "loaded" reply. It should be turning
1384     // that into a TARGET_WAITKIND_LOADED. Does it?
1385     // The bandaid here has the problem that it breaks for 'next' over a
1386     // statement that indirectly loads shared libraries
1387     // 6.1.2010: Breaks interrupting inferiors, disabled:
1388     // if (reason == "signal-received"
1389     //      && data.findChild("signal-name").data() == "SIGTRAP") {
1390     //    continueInferiorInternal();
1391     //    return;
1392     // }
1393
1394     // Jump over well-known frames.
1395     static int stepCounter = 0;
1396     if (debuggerCore()->boolSetting(SkipKnownFrames)) {
1397         if (reason == "end-stepping-range" || reason == "function-finished") {
1398             //showMessage(frame.toString());
1399             QString funcName = _(frame.findChild("func").data());
1400             QString fileName = QString::fromLocal8Bit(frame.findChild("file").data());
1401             if (isLeavableFunction(funcName, fileName)) {
1402                 //showMessage(_("LEAVING ") + funcName);
1403                 ++stepCounter;
1404                 executeStepOut();
1405                 return;
1406             }
1407             if (isSkippableFunction(funcName, fileName)) {
1408                 //showMessage(_("SKIPPING ") + funcName);
1409                 ++stepCounter;
1410                 executeStep();
1411                 return;
1412             }
1413             //if (stepCounter)
1414             //    qDebug() << "STEPCOUNTER:" << stepCounter;
1415             stepCounter = 0;
1416         }
1417     }
1418
1419     // Show return value if possible, usually with reason "function-finished".
1420     // *stopped,reason="function-finished",frame={addr="0x080556da",
1421     // func="testReturnValue",args=[],file="/../app.cpp",
1422     // fullname="/../app.cpp",line="1611"},gdb-result-var="$1",
1423     // return-value="{d = 0x808d998}",thread-id="1",stopped-threads="all",
1424     // core="1"
1425     GdbMi resultVar = data.findChild("gdb-result-var");
1426     if (resultVar.isValid())
1427         m_resultVarName = resultVar.data();
1428     else
1429         m_resultVarName.clear();
1430
1431     bool initHelpers = m_debuggingHelperState == DebuggingHelperUninitialized
1432                        || m_debuggingHelperState == DebuggingHelperLoadTried;
1433     // Don't load helpers on stops triggered by signals unless it's
1434     // an intentional trap.
1435     if (initHelpers
1436             && m_gdbAdapter->dumperHandling() != AbstractGdbAdapter::DumperLoadedByGdbPreload
1437             && reason == "signal-received") {
1438         QByteArray name = data.findChild("signal-name").data();
1439         if (name != STOP_SIGNAL
1440             && (startParameters().startMode != AttachToRemote
1441                 || name != CROSS_STOP_SIGNAL))
1442             initHelpers = false;
1443     }
1444     if (isSynchronous())
1445         initHelpers = false;
1446     if (initHelpers) {
1447         tryLoadDebuggingHelpersClassic();
1448         QVariant var = QVariant::fromValue<GdbMi>(data);
1449         postCommand("p 4", CB(handleStop1), var);  // dummy
1450     } else {
1451         handleStop1(data);
1452     }
1453     // Dumper loading is sequenced, as otherwise the display functions
1454     // will start requesting data without knowing that dumpers are available.
1455 }
1456
1457 void GdbEngine::handleStop1(const GdbResponse &response)
1458 {
1459     handleStop1(response.cookie.value<GdbMi>());
1460 }
1461
1462 void GdbEngine::handleStop1(const GdbMi &data)
1463 {
1464     if (isDying()) {
1465         qDebug() << "HANDLING STOP WHILE DYING";
1466         notifyInferiorStopOk();
1467         return;
1468     }
1469
1470     QByteArray reason = data.findChild("reason").data();
1471
1472 #ifdef Q_OS_WIN
1473     if (startParameters().useTerminal && reason == "signal-received"
1474         && data.findChild("signal-name").data() == "SIGTRAP") {
1475         // Command line start up trap
1476         showMessage(_("INTERNAL CONTINUE"), LogMisc);
1477         continueInferiorInternal();
1478         return;
1479     }
1480 #endif
1481
1482     // This is for display only.
1483     if (m_modulesListOutdated)
1484         reloadModulesInternal();
1485
1486     if (m_breakListOutdated) {
1487         reloadBreakListInternal();
1488     } else {
1489         // Older gdb versions do not produce "library loaded" messages
1490         // so the breakpoint update is not triggered.
1491         if (m_gdbVersion < 70000 && !m_isMacGdb && breakHandler()->size() > 0)
1492             reloadBreakListInternal();
1493     }
1494
1495     if (reason == "watchpoint-trigger") {
1496         // *stopped,reason="watchpoint-trigger",wpt={number="2",exp="*0xbfffed40"},
1497         // value={old="1",new="0"},frame={addr="0x00451e1b",
1498         // func="QScopedPointer",args=[{name="this",value="0xbfffed40"},
1499         // {name="p",value="0x0"}],file="x.h",fullname="/home/.../x.h",line="95"},
1500         // thread-id="1",stopped-threads="all",core="2"
1501         GdbMi wpt = data.findChild("wpt");
1502         const int bpNumber = wpt.findChild("number").data().toInt();
1503         const BreakpointId id = breakHandler()->findBreakpointByNumber(bpNumber);
1504         const quint64 bpAddress = wpt.findChild("exp").data().mid(1).toULongLong(0, 0);
1505         QString msg = msgWatchpointTriggered(id, bpNumber, bpAddress);
1506         GdbMi value = data.findChild("value");
1507         GdbMi oldValue = value.findChild("old");
1508         GdbMi newValue = value.findChild("new");
1509         if (oldValue.isValid() && newValue.isValid()) {
1510             msg += QLatin1Char(' ');
1511             msg += tr("Value changed from %1 to %2.")
1512                 .arg(_(oldValue.data())).arg(_(newValue.data()));
1513         }
1514         showStatusMessage(msg);
1515     } else if (reason == "breakpoint-hit") {
1516         GdbMi gNumber = data.findChild("bkptno"); // 'number' or 'bkptno'?
1517         if (!gNumber.isValid())
1518             gNumber = data.findChild("number");
1519         const int bpNumber = gNumber.data().toInt();
1520         const QByteArray threadId = data.findChild("thread-id").data();
1521         const BreakpointId id = breakHandler()->findBreakpointByNumber(bpNumber);
1522         showStatusMessage(msgBreakpointTriggered(id, bpNumber, _(threadId)));
1523         m_currentThread = threadId;
1524     } else {
1525         QString reasontr = msgStopped(_(reason));
1526         if (reason == "signal-received") {
1527             QByteArray name = data.findChild("signal-name").data();
1528             QByteArray meaning = data.findChild("signal-meaning").data();
1529             // Ignore these as they are showing up regularly when
1530             // stopping debugging.
1531             if (name == STOP_SIGNAL) {
1532                 showMessage(_(STOP_SIGNAL " CONSIDERED HARMLESS. CONTINUING."));
1533             } else if (startParameters().startMode == AttachToRemote
1534                     && name == CROSS_STOP_SIGNAL) {
1535                 showMessage(_(CROSS_STOP_SIGNAL " CONSIDERED HARMLESS. CONTINUING."));
1536             } else {
1537                 showMessage(_("HANDLING SIGNAL" + name));
1538                 if (debuggerCore()->boolSetting(UseMessageBoxForSignals))
1539                     showStoppedBySignalMessageBox(_(meaning), _(name));
1540                 if (!name.isEmpty() && !meaning.isEmpty())
1541                     reasontr = msgStoppedBySignal(_(meaning), _(name));
1542             }
1543         }
1544
1545         if (reason.isEmpty())
1546             showStatusMessage(msgStopped());
1547         else
1548             showStatusMessage(reasontr);
1549     }
1550
1551     // Let the event loop run before deciding whether to update the stack.
1552     m_stackNeeded = true; // setTokenBarrier() might reset this.
1553     m_currentThreadId = data.findChild("thread-id").data().toInt();
1554     QTimer::singleShot(0, this, SLOT(handleStop2()));
1555 }
1556
1557 void GdbEngine::handleStop2()
1558 {
1559     // We are already continuing.
1560     if (!m_stackNeeded)
1561         return;
1562
1563     reloadStack(false); // Will trigger register reload.
1564
1565     if (supportsThreads()) {
1566         if (m_gdbAdapter->isTrkAdapter()) {
1567             m_gdbAdapter->trkReloadThreads();
1568         } else if (m_isMacGdb) {
1569             postCommand("-thread-list-ids", Discardable,
1570                 CB(handleThreadListIds), m_currentThreadId);
1571         } else {
1572             // This is only available in gdb 7.1+.
1573             postCommand("-thread-info", Discardable,
1574                 CB(handleThreadInfo), m_currentThreadId);
1575         }
1576     }
1577
1578 }
1579
1580 void GdbEngine::handleInfoProc(const GdbResponse &response)
1581 {
1582     if (response.resultClass == GdbResultDone) {
1583         static QRegExp re(_("\\bprocess ([0-9]+)\n"));
1584         QTC_ASSERT(re.isValid(), return);
1585         if (re.indexIn(_(response.data.findChild("consolestreamoutput").data())) != -1)
1586             maybeHandleInferiorPidChanged(re.cap(1));
1587     }
1588 }
1589
1590 void GdbEngine::handleShowVersion(const GdbResponse &response)
1591 {
1592     showMessage(_("PARSING VERSION: " + response.toString()));
1593     if (response.resultClass == GdbResultDone) {
1594         m_gdbVersion = 100;
1595         m_gdbBuildVersion = -1;
1596         m_isMacGdb = false;
1597         GdbMi version = response.data.findChild("consolestreamoutput");
1598         QString msg = QString::fromLocal8Bit(version.data());
1599         extractGdbVersion(msg,
1600               &m_gdbVersion, &m_gdbBuildVersion, &m_isMacGdb);
1601         if (m_gdbVersion > 60500 && m_gdbVersion < 200000)
1602             showMessage(_("SUPPORTED GDB VERSION ") + msg);
1603         else
1604             showMessage(_("UNSUPPORTED GDB VERSION ") + msg);
1605
1606         showMessage(_("USING GDB VERSION: %1, BUILD: %2%3").arg(m_gdbVersion)
1607             .arg(m_gdbBuildVersion).arg(_(m_isMacGdb ? " (APPLE)" : "")));
1608     }
1609 }
1610
1611 void GdbEngine::handleHasPython(const GdbResponse &response)
1612 {
1613     if (response.resultClass == GdbResultDone) {
1614         m_hasPython = true;
1615         GdbMi contents = response.data.findChild("consolestreamoutput");
1616         GdbMi data;
1617         data.fromStringMultiple(contents.data());
1618         const GdbMi dumpers = data.findChild("dumpers");
1619         foreach (const GdbMi &dumper, dumpers.children()) {
1620             QByteArray type = dumper.findChild("type").data();
1621             QStringList formats(tr("Raw structure"));
1622             foreach (const QByteArray &format,
1623                      dumper.findChild("formats").data().split(',')) {
1624                 if (format == "Normal")
1625                     formats.append(tr("Normal"));
1626                 else if (format == "Displayed")
1627                     formats.append(tr("Displayed"));
1628                 else if (!format.isEmpty())
1629                     formats.append(_(format));
1630             }
1631             watchHandler()->addTypeFormats(type, formats);
1632         }
1633         const GdbMi hasInferiorThreadList = data.findChild("hasInferiorThreadList");
1634         m_hasInferiorThreadList = (hasInferiorThreadList.data().toInt() != 0);
1635     } else {
1636         pythonDumpersFailed();
1637     }
1638 }
1639
1640 void GdbEngine::pythonDumpersFailed()
1641 {
1642     m_hasPython = false;
1643     if (m_gdbAdapter->dumperHandling()
1644                 == AbstractGdbAdapter::DumperLoadedByGdbPreload
1645             && checkDebuggingHelpersClassic()) {
1646 #ifdef Q_OS_MAC
1647         const char * const LD_PRELOAD_ENV_VAR = "DYLD_INSERT_LIBRARIES";
1648 #else
1649         const char * const LD_PRELOAD_ENV_VAR = "LD_PRELOAD";
1650 #endif
1651         QByteArray cmd = "set environment ";
1652         cmd += LD_PRELOAD_ENV_VAR;
1653         cmd += ' ';
1654         cmd += startParameters().startMode == StartRemoteGdb
1655            ? startParameters().remoteDumperLib
1656            : qtDumperLibraryName().toLocal8Bit();
1657         postCommand(cmd);
1658         m_debuggingHelperState = DebuggingHelperLoadTried;
1659     }
1660 }
1661
1662 void GdbEngine::showExecutionError(const QString &message)
1663 {
1664     showMessageBox(QMessageBox::Critical, tr("Execution Error"),
1665        tr("Cannot continue debugged process:\n") + message);
1666 }
1667
1668 void GdbEngine::handleExecuteContinue(const GdbResponse &response)
1669 {
1670     QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
1671     if (response.resultClass == GdbResultRunning) {
1672         doNotifyInferiorRunOk();
1673         return;
1674     }
1675     QByteArray msg = response.data.findChild("msg").data();
1676     if (msg.startsWith("Cannot find bounds of current function")) {
1677         notifyInferiorRunFailed();
1678         if (isDying())
1679             return;
1680         if (!m_commandsToRunOnTemporaryBreak.isEmpty())
1681             flushQueuedCommands();
1682         QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
1683         showStatusMessage(tr("Stopped."), 5000);
1684         reloadStack(true);
1685     } else if (msg.startsWith("\"finish\" not meaningful in the outermost frame")) {
1686         notifyInferiorRunFailed();
1687         if (isDying())
1688             return;
1689         QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
1690         // FIXME: Fix translation in master.
1691         showStatusMessage(QString::fromLocal8Bit(msg), 5000);
1692         gotoLocation(stackHandler()->currentFrame());
1693     } else {
1694         showExecutionError(QString::fromLocal8Bit(msg));
1695         notifyInferiorIll();
1696     }
1697 }
1698
1699 QString GdbEngine::fullName(const QString &fileName)
1700 {
1701     if (fileName.isEmpty())
1702         return QString();
1703     //QTC_ASSERT(!m_sourcesListOutdated, /* */)
1704     QTC_ASSERT(!m_sourcesListUpdating, /* */)
1705     return m_shortToFullName.value(fileName, QString());
1706 }
1707
1708 QString GdbEngine::cleanupFullName(const QString &fileName)
1709 {
1710     QString cleanFilePath = fileName;
1711 #ifdef Q_OS_WIN
1712     QTC_ASSERT(!fileName.isEmpty(), return QString())
1713     // Gdb on windows often delivers "fullnames" which
1714     // (a) have no drive letter and (b) are not normalized.
1715     QFileInfo fi(fileName);
1716     if (fi.isReadable())
1717         cleanFilePath = QDir::cleanPath(fi.absoluteFilePath());
1718 #endif
1719     if (startMode() == StartRemoteGdb) {
1720         cleanFilePath.replace(0, startParameters().remoteMountPoint.length(),
1721             startParameters().localMountDir);
1722     }
1723     return cleanFilePath;
1724 }
1725
1726 void GdbEngine::shutdownInferior()
1727 {
1728     QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
1729     m_commandsToRunOnTemporaryBreak.clear();
1730     m_gdbAdapter->shutdownInferior();
1731 }
1732
1733 void GdbEngine::defaultInferiorShutdown(const char *cmd)
1734 {
1735     QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
1736     postCommand(cmd, NeedsStop | LosesChild, CB(handleInferiorShutdown));
1737 }
1738
1739 void GdbEngine::handleInferiorShutdown(const GdbResponse &response)
1740 {
1741     QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
1742     if (response.resultClass == GdbResultDone) {
1743         notifyInferiorShutdownOk();
1744         return;
1745     }
1746     QByteArray ba = response.data.findChild("msg").data();
1747     if (ba.contains(": No such file or directory.")) {
1748         // This happens when someone removed the binary behind our back.
1749         // It is not really an error from a user's point of view.
1750         showMessage(_("NOTE: " + ba));
1751         notifyInferiorShutdownOk();
1752         return;
1753     }
1754     showMessageBox(QMessageBox::Critical,
1755         tr("Failed to shut down application"),
1756         AbstractGdbAdapter::msgInferiorStopFailed(QString::fromLocal8Bit(ba)));
1757     notifyInferiorShutdownFailed();
1758 }
1759
1760 void GdbEngine::shutdownEngine()
1761 {
1762     m_gdbAdapter->shutdownAdapter();
1763 }
1764
1765 void GdbEngine::notifyAdapterShutdownFailed()
1766 {
1767     showMessage(_("ADAPTER SHUTDOWN FAILED"));
1768     QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
1769     notifyEngineShutdownFailed();
1770 }
1771
1772 void GdbEngine::notifyAdapterShutdownOk()
1773 {
1774     QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
1775     showMessage(_("INITIATE GDBENGINE SHUTDOWN IN STATE %1, PROC: %2")
1776         .arg(lastGoodState()).arg(gdbProc()->state()));
1777     m_commandsDoneCallback = 0;
1778     switch (gdbProc()->state()) {
1779     case QProcess::Running:
1780         postCommand("-gdb-exit", GdbEngine::ExitRequest, CB(handleGdbExit));
1781         break;
1782     case QProcess::NotRunning:
1783         // Cannot find executable.
1784         notifyEngineShutdownOk();
1785         break;
1786     case QProcess::Starting:
1787         showMessage(_("GDB NOT REALLY RUNNING; KILLING IT"));
1788         gdbProc()->kill();
1789         notifyEngineShutdownFailed();
1790         break;
1791     }
1792 }
1793
1794 void GdbEngine::handleGdbExit(const GdbResponse &response)
1795 {
1796     if (response.resultClass == GdbResultExit) {
1797         showMessage(_("GDB CLAIMS EXIT; WAITING"));
1798         // Don't set state here, this will be handled in handleGdbFinished()
1799         //notifyEngineShutdownOk();
1800     } else {
1801         QString msg = m_gdbAdapter->msgGdbStopFailed(
1802             QString::fromLocal8Bit(response.data.findChild("msg").data()));
1803         qDebug() << (_("GDB WON'T EXIT (%1); KILLING IT").arg(msg));
1804         showMessage(_("GDB WON'T EXIT (%1); KILLING IT").arg(msg));
1805         gdbProc()->kill();
1806     }
1807 }
1808
1809 void GdbEngine::detachDebugger()
1810 {
1811     QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
1812     QTC_ASSERT(startMode() != AttachCore, qDebug() << startMode());
1813     postCommand("detach", GdbEngine::ExitRequest, CB(handleDetach));
1814 }
1815
1816 void GdbEngine::handleDetach(const GdbResponse &response)
1817 {
1818     Q_UNUSED(response);
1819     QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
1820     notifyInferiorExited();
1821 }
1822
1823 int GdbEngine::currentFrame() const
1824 {
1825     return stackHandler()->currentIndex();
1826 }
1827
1828 QString msgNoGdbBinaryForToolChain(const ProjectExplorer::Abi &tc)
1829 {
1830     return GdbEngine::tr("There is no gdb binary available for binaries in format '%1'")
1831         .arg(tc.toString());
1832 }
1833
1834 AbstractGdbAdapter *GdbEngine::createAdapter()
1835 {
1836     const DebuggerStartParameters &sp = startParameters();
1837     if (sp.toolChainAbi.os() == ProjectExplorer::Abi::SymbianOS) {
1838         // FIXME: 1 of 3 testing hacks.
1839         if (sp.debugClient == DebuggerStartParameters::DebugClientCoda)
1840             return new CodaGdbAdapter(this);
1841         else
1842             return new TrkGdbAdapter(this);
1843     }
1844
1845     switch (sp.startMode) {
1846     case AttachCore:
1847         return new CoreGdbAdapter(this);
1848     case AttachToRemote:
1849         return new RemoteGdbServerAdapter(this, sp.toolChainAbi);
1850     case StartRemoteGdb:
1851         return new RemotePlainGdbAdapter(this);
1852     case AttachExternal:
1853         return new AttachGdbAdapter(this);
1854     default:
1855         if (sp.useTerminal)
1856             return new TermGdbAdapter(this);
1857         return new LocalPlainGdbAdapter(this);
1858     }
1859 }
1860
1861 void GdbEngine::setupEngine()
1862 {
1863     QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
1864     QTC_ASSERT(m_debuggingHelperState == DebuggingHelperUninitialized, /**/);
1865
1866     if (m_gdbAdapter->dumperHandling() != AbstractGdbAdapter::DumperNotAvailable) {
1867         connect(debuggerCore()->action(UseDebuggingHelpers),
1868             SIGNAL(valueChanged(QVariant)),
1869             SLOT(setUseDebuggingHelpers(QVariant)));
1870     }
1871
1872     QTC_ASSERT(state() == EngineSetupRequested, /**/);
1873     m_gdbAdapter->startAdapter();
1874 }
1875
1876 unsigned GdbEngine::debuggerCapabilities() const
1877 {
1878     unsigned caps = ReverseSteppingCapability
1879         | AutoDerefPointersCapability
1880         | DisassemblerCapability
1881         | RegisterCapability
1882         | ShowMemoryCapability
1883         | JumpToLineCapability
1884         | ReloadModuleCapability
1885         | ReloadModuleSymbolsCapability
1886         | BreakOnThrowAndCatchCapability
1887         | BreakConditionCapability
1888         | TracePointCapability
1889         | ReturnFromFunctionCapability
1890         | CreateFullBacktraceCapability
1891         | WatchpointCapability
1892         | AddWatcherCapability
1893         | ShowModuleSymbolsCapability
1894         | CatchCapability;
1895
1896     if (startParameters().startMode == AttachCore)
1897         return caps;
1898
1899     return caps | SnapshotCapability;
1900 }
1901
1902 bool GdbEngine::canWatchWidgets() const
1903 {
1904     return true;
1905 }
1906
1907 void GdbEngine::continueInferiorInternal()
1908 {
1909     QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
1910     notifyInferiorRunRequested();
1911     showStatusMessage(tr("Running requested..."), 5000);
1912     QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
1913     postCommand("-exec-continue", RunRequest, CB(handleExecuteContinue));
1914 }
1915
1916 void GdbEngine::doNotifyInferiorRunOk()
1917 {
1918     clearToolTip();
1919     notifyInferiorRunOk();
1920 }
1921
1922 void GdbEngine::autoContinueInferior()
1923 {
1924     resetLocation();
1925     continueInferiorInternal();
1926     showStatusMessage(tr("Continuing after temporary stop..."), 1000);
1927 }
1928
1929 void GdbEngine::continueInferior()
1930 {
1931     QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
1932     setTokenBarrier();
1933     continueInferiorInternal();
1934 }
1935
1936 void GdbEngine::executeStep()
1937 {
1938     QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
1939     setTokenBarrier();
1940     notifyInferiorRunRequested();
1941     showStatusMessage(tr("Step requested..."), 5000);
1942     if (m_gdbAdapter->isTrkAdapter() && stackHandler()->stackSize() > 0)
1943         postCommand("sal step,0x" + QByteArray::number(stackHandler()->topAddress(), 16));
1944     if (isReverseDebugging())
1945         postCommand("reverse-step", RunRequest, CB(handleExecuteStep));
1946     else
1947         postCommand("-exec-step", RunRequest, CB(handleExecuteStep));
1948 }
1949
1950 void GdbEngine::handleExecuteStep(const GdbResponse &response)
1951 {
1952     if (response.resultClass == GdbResultDone) {
1953         // Step was finishing too quick, and a '*stopped' messages should
1954         // have preceded it, so just ignore this result.
1955         QTC_ASSERT(state() == InferiorStopOk, /**/);
1956         return;
1957     }
1958     QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
1959     if (response.resultClass == GdbResultRunning) {
1960         doNotifyInferiorRunOk();
1961         return;
1962     }
1963     QByteArray msg = response.data.findChild("msg").data();
1964     if (msg.startsWith("Cannot find bounds of current function")) {
1965         notifyInferiorRunFailed();
1966         if (isDying())
1967             return;
1968         if (!m_commandsToRunOnTemporaryBreak.isEmpty())
1969             flushQueuedCommands();
1970         executeStepI(); // Fall back to instruction-wise stepping.
1971     } else {
1972         showExecutionError(QString::fromLocal8Bit(msg));
1973         notifyInferiorIll();
1974     }
1975 }
1976
1977 void GdbEngine::executeStepI()
1978 {
1979     QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
1980     setTokenBarrier();
1981     notifyInferiorRunRequested();
1982     showStatusMessage(tr("Step by instruction requested..."), 5000);
1983     if (isReverseDebugging())
1984         postCommand("reverse-stepi", RunRequest, CB(handleExecuteContinue));
1985     else
1986         postCommand("-exec-step-instruction", RunRequest, CB(handleExecuteContinue));
1987 }
1988
1989 void GdbEngine::executeStepOut()
1990 {
1991     QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
1992     postCommand("-stack-select-frame 0");
1993     setTokenBarrier();
1994     notifyInferiorRunRequested();
1995     showStatusMessage(tr("Finish function requested..."), 5000);
1996     postCommand("-exec-finish", RunRequest, CB(handleExecuteContinue));
1997 }
1998
1999 void GdbEngine::executeNext()
2000 {
2001     QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
2002     setTokenBarrier();
2003     notifyInferiorRunRequested();
2004     showStatusMessage(tr("Step next requested..."), 5000);
2005     if (m_gdbAdapter->isTrkAdapter() && stackHandler()->stackSize() > 0)
2006         postCommand("sal next,0x" + QByteArray::number(stackHandler()->topAddress(), 16));
2007     if (isReverseDebugging())
2008         postCommand("reverse-next", RunRequest, CB(handleExecuteNext));
2009     else
2010         postCommand("-exec-next", RunRequest, CB(handleExecuteNext));
2011 }
2012
2013 void GdbEngine::handleExecuteNext(const GdbResponse &response)
2014 {
2015     if (response.resultClass == GdbResultDone) {
2016         // Step was finishing too quick, and a '*stopped' messages should
2017         // have preceded it, so just ignore this result.
2018         QTC_ASSERT(state() == InferiorStopOk, /**/);
2019         return;
2020     }
2021     QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
2022     if (response.resultClass == GdbResultRunning) {
2023         doNotifyInferiorRunOk();
2024         return;
2025     }
2026     QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
2027     QByteArray msg = response.data.findChild("msg").data();
2028     if (msg.startsWith("Cannot find bounds of current function")) {
2029         if (!m_commandsToRunOnTemporaryBreak.isEmpty())
2030             flushQueuedCommands();
2031         notifyInferiorRunFailed();
2032         if (!isDying())
2033             executeNextI(); // Fall back to instruction-wise stepping.
2034     } else {
2035         showMessageBox(QMessageBox::Critical, tr("Execution Error"),
2036            tr("Cannot continue debugged process:\n") + QString::fromLocal8Bit(msg));
2037         notifyInferiorIll();
2038     }
2039 }
2040
2041 void GdbEngine::executeNextI()
2042 {
2043     QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
2044     setTokenBarrier();
2045     notifyInferiorRunRequested();
2046     showStatusMessage(tr("Step next instruction requested..."), 5000);
2047     if (isReverseDebugging())
2048         postCommand("reverse-nexti", RunRequest, CB(handleExecuteContinue));
2049     else
2050         postCommand("-exec-next-instruction", RunRequest, CB(handleExecuteContinue));
2051 }
2052
2053 static QByteArray addressSpec(quint64 address)
2054 {
2055     return "*0x" + QByteArray::number(address, 16);
2056 }
2057
2058 void GdbEngine::executeRunToLine(const ContextData &data)
2059 {
2060     QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
2061     setTokenBarrier();
2062     notifyInferiorRunRequested();
2063     showStatusMessage(tr("Run to line %1 requested...").arg(data.lineNumber), 5000);
2064 #if 1
2065     m_targetFrame.file = data.fileName;
2066     m_targetFrame.line = data.lineNumber;
2067     QByteArray loc;
2068     if (data.address)
2069         loc = addressSpec(data.address);
2070     else
2071         loc = '"' + breakLocation(data.fileName).toLocal8Bit() + '"' + ':'
2072             + QByteArray::number(data.lineNumber);
2073     postCommand("tbreak " + loc);
2074     postCommand("continue", RunRequest, CB(handleExecuteRunToLine));
2075 #else
2076     // Seems to jump to unpredicatable places. Observed in the manual
2077     // tests in the Foo::Foo() constructor with both gdb 6.8 and 7.1.
2078     QByteArray args = '"' + breakLocation(fileName).toLocal8Bit() + '"' + ':'
2079         + QByteArray::number(lineNumber);
2080     postCommand("-exec-until " + args, RunRequest, CB(handleExecuteContinue));
2081 #endif
2082 }
2083
2084 void GdbEngine::executeRunToFunction(const QString &functionName)
2085 {
2086     QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
2087     setTokenBarrier();
2088     postCommand("-break-insert -t " + functionName.toLatin1());
2089     showStatusMessage(tr("Run to function %1 requested...").arg(functionName), 5000);
2090     continueInferiorInternal();
2091 }
2092
2093 void GdbEngine::executeJumpToLine(const ContextData &data)
2094 {
2095     QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
2096     QByteArray loc;
2097     if (data.address)
2098         loc = addressSpec(data.address);
2099     else
2100         loc = '"' + breakLocation(data.fileName).toLocal8Bit() + '"' + ':'
2101         + QByteArray::number(data.lineNumber);
2102     postCommand("tbreak " + loc);
2103     notifyInferiorRunRequested();
2104     postCommand("jump " + loc, RunRequest, CB(handleExecuteJumpToLine));
2105     // will produce something like
2106     //  &"jump \"/home/apoenitz/dev/work/test1/test1.cpp\":242"
2107     //  ~"Continuing at 0x4058f3."
2108     //  ~"run1 (argc=1, argv=0x7fffbf1f5538) at test1.cpp:242"
2109     //  ~"242\t x *= 2;"
2110     //  23^done"
2111 }
2112
2113 void GdbEngine::executeReturn()
2114 {
2115     QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
2116     setTokenBarrier();
2117     notifyInferiorRunRequested();
2118     showStatusMessage(tr("Immediate return from function requested..."), 5000);
2119     postCommand("-exec-finish", RunRequest, CB(handleExecuteReturn));
2120 }
2121
2122 void GdbEngine::handleExecuteReturn(const GdbResponse &response)
2123 {
2124     if (response.resultClass == GdbResultDone) {
2125         notifyInferiorStopOk();
2126         updateAll();
2127         return;
2128     }
2129     notifyInferiorRunFailed();
2130 }
2131
2132 /*!
2133     \fn void Debugger::Internal::GdbEngine::setTokenBarrier()
2134     \brief Discard the results of all pending watch-updating commands.
2135
2136     This method is called at the beginning of all step/next/finish etc.
2137     debugger functions.
2138     If non-watch-updating commands with call-backs are still in the pipe,
2139     it will complain.
2140 */
2141
2142 void GdbEngine::setTokenBarrier()
2143 {
2144     foreach (const GdbCommand &cookie, m_cookieForToken) {
2145         QTC_ASSERT(!cookie.callback || (cookie.flags & Discardable),
2146             qDebug() << "CMD:" << cookie.command
2147                 << " FLAGS:" << cookie.flags
2148                 << " CALLBACK:" << cookie.callbackName;
2149             return
2150         );
2151     }
2152     PENDING_DEBUG("\n--- token barrier ---\n");
2153     showMessage(_("--- token barrier ---"), LogMiscInput);
2154     if (debuggerCore()->boolSetting(LogTimeStamps))
2155         showMessage(LogWindow::logTimeStamp(), LogMiscInput);
2156     m_oldestAcceptableToken = currentToken();
2157     m_stackNeeded = false;
2158 }
2159
2160
2161 //////////////////////////////////////////////////////////////////////
2162 //
2163 // Breakpoint specific stuff
2164 //
2165 //////////////////////////////////////////////////////////////////////
2166
2167 void GdbEngine::updateBreakpointDataFromOutput(BreakpointId id, const GdbMi &bkpt)
2168 {
2169     QTC_ASSERT(bkpt.isValid(), return);
2170
2171     BreakpointResponse response = breakHandler()->response(id);
2172
2173     response.multiple = false;
2174     response.enabled = true;
2175     response.pending = false;
2176     response.condition.clear();
2177     QByteArray file, fullName;
2178     foreach (const GdbMi &child, bkpt.children()) {
2179         if (child.hasName("number")) {
2180             response.number = child.data().toInt();
2181         } else if (child.hasName("func")) {
2182             response.functionName = _(child.data());
2183         } else if (child.hasName("addr")) {
2184             // <MULTIPLE> happens in constructors, inline functions, and
2185             // at other places like 'foreach' lines. In this case there are
2186             // fields named "addr" in the response and/or the address
2187             // is called <MULTIPLE>.
2188             //qDebug() << "ADDR: " << child.data() << (child.data() == "<MULTIPLE>");
2189             if (child.data().startsWith("0x")) {
2190                 response.address = child.data().mid(2).toULongLong(0, 16);
2191             } else {
2192                 response.extra = child.data();
2193                 if (child.data() == "<MULTIPLE>")
2194                     response.multiple = true;
2195             }
2196         } else if (child.hasName("file")) {
2197             file = child.data();
2198         } else if (child.hasName("fullname")) {
2199             fullName = child.data();
2200         } else if (child.hasName("line")) {
2201             // The line numbers here are the uncorrected ones. So don't
2202             // change it if we know better already.
2203             if (response.correctedLineNumber == 0)
2204                 response.lineNumber = child.data().toInt();
2205         } else if (child.hasName("cond")) {
2206             // gdb 6.3 likes to "rewrite" conditions. Just accept that fact.
2207             response.condition = child.data();
2208         } else if (child.hasName("enabled")) {
2209             response.enabled = (child.data() == "y");
2210         } else if (child.hasName("pending")) {
2211             // Any content here would be interesting only if we did accept
2212             // spontaneously appearing breakpoints (user using gdb commands).
2213             response.pending = true;
2214         } else if (child.hasName("at")) {
2215             // Happens with gdb 6.4 symbianelf.
2216             QByteArray ba = child.data();
2217             if (ba.startsWith('<') && ba.endsWith('>'))
2218                 ba = ba.mid(1, ba.size() - 2);
2219             response.functionName = _(ba);
2220         } else if (child.hasName("thread")) {
2221             response.threadSpec = child.data().toInt();
2222         } else if (child.hasName("type")) {
2223             // "breakpoint", "hw breakpoint", "tracepoint"
2224             if (child.data().contains("tracepoint"))
2225                 response.tracepoint = true;
2226             else if (!child.data().contains("reakpoint"))
2227                 response.type = Watchpoint;
2228         }
2229         // This field is not present.  Contents needs to be parsed from
2230         // the plain "ignore" response.
2231         //else if (child.hasName("ignore"))
2232         //    response.ignoreCount = child.data();
2233     }
2234
2235     QString name;
2236     if (!fullName.isEmpty()) {
2237         name = cleanupFullName(QFile::decodeName(fullName));
2238         response.fileName = name;
2239         //if (data->markerFileName().isEmpty())
2240         //    data->setMarkerFileName(name);
2241     } else {
2242         name = QFile::decodeName(file);
2243         // Use fullName() once we have a mapping which is more complete than
2244         // gdb's own. No point in assigning markerFileName for now.
2245     }
2246     if (!name.isEmpty())
2247         response.fileName = name;
2248
2249     breakHandler()->setResponse(id, response);
2250 }
2251
2252 QString GdbEngine::breakLocation(const QString &file) const
2253 {
2254     //QTC_ASSERT(!m_breakListOutdated, /* */)
2255     QString where = m_fullToShortName.value(file);
2256     if (where.isEmpty())
2257         return QFileInfo(file).fileName();
2258     return where;
2259 }
2260
2261 QByteArray GdbEngine::breakpointLocation(BreakpointId id)
2262 {
2263     BreakHandler *handler = breakHandler();
2264     const BreakpointParameters &data = handler->breakpointData(id);
2265     QTC_ASSERT(data.type != UnknownType, return QByteArray());
2266     // FIXME: Non-GCC-runtime
2267     if (data.type == BreakpointAtThrow)
2268         return "__cxa_throw";
2269     if (data.type == BreakpointAtCatch)
2270         return "__cxa_begin_catch";
2271     if (data.type == BreakpointAtMain)
2272 #ifdef Q_OS_WIN
2273         // FIXME: Should be target specific.
2274         return "qMain";
2275 #else
2276         return "main";
2277 #endif
2278     if (data.type == BreakpointByFunction)
2279         return data.functionName.toUtf8();
2280     if (data.type == BreakpointByAddress)
2281         return addressSpec(data.address);
2282
2283     const QString fileName = data.pathUsage == BreakpointUseFullPath
2284         ? data.fileName : breakLocation(data.fileName);
2285     // The argument is simply a C-quoted version of the argument to the
2286     // non-MI "break" command, including the "original" quoting it wants.
2287     return "\"\\\"" + GdbMi::escapeCString(fileName).toLocal8Bit() + "\\\":"
2288         + QByteArray::number(data.lineNumber) + '"';
2289 }
2290
2291 QByteArray GdbEngine::breakpointLocation2(BreakpointId id)
2292 {
2293     BreakHandler *handler = breakHandler();
2294     const BreakpointParameters &data = handler->breakpointData(id);
2295     const QString fileName = data.pathUsage == BreakpointUseFullPath
2296         ? data.fileName : breakLocation(data.fileName);
2297     return  GdbMi::escapeCString(fileName).toLocal8Bit() + ':'
2298         + QByteArray::number(data.lineNumber);
2299 }
2300
2301 void GdbEngine::handleWatchInsert(const GdbResponse &response)
2302 {
2303     const int id = response.cookie.toInt();
2304     if (response.resultClass == GdbResultDone) {
2305         // "Hardware watchpoint 2: *0xbfffed40\n"
2306         QByteArray ba = response.data.findChild("consolestreamoutput").data();
2307         if (ba.startsWith("Hardware watchpoint ")
2308                 || ba.startsWith("Watchpoint ")) {
2309             const int end = ba.indexOf(':');
2310             const int begin = ba.lastIndexOf(' ', end) + 1;
2311             const QByteArray address = ba.mid(end + 3).trimmed();
2312             BreakHandler *handler = breakHandler();
2313             BreakpointResponse response = handler->response(id);
2314             response.number = ba.mid(begin, end - begin).toInt();
2315             response.address = address.toULongLong(0, 0);
2316             handler->setResponse(id, response);
2317             QTC_ASSERT(!handler->needsChange(id), /**/);
2318             handler->notifyBreakpointInsertOk(id);
2319         } else {
2320             showMessage(_("CANNOT PARSE WATCHPOINT FROM " + ba));
2321         }
2322     }
2323 }
2324
2325 void GdbEngine::attemptAdjustBreakpointLocation(BreakpointId id)
2326 {
2327     if (!debuggerCore()->boolSetting(AdjustBreakpointLocations))
2328         return;
2329     BreakpointResponse response = breakHandler()->response(id);
2330     if (response.address == 0 || response.correctedLineNumber != 0)
2331         return;
2332     // Prevent endless loop.
2333     response.correctedLineNumber = -1;
2334     breakHandler()->setResponse(id, response);
2335     postCommand("info line *0x" + QByteArray::number(response.address, 16),
2336         NeedsStop | RebuildBreakpointModel,
2337         CB(handleInfoLine), id);
2338 }
2339
2340 void GdbEngine::handleCatchInsert(const GdbResponse &response)
2341 {
2342     BreakHandler *handler = breakHandler();
2343     BreakpointId id(response.cookie.toInt());
2344     if (response.resultClass == GdbResultDone) {
2345         handler->notifyBreakpointInsertOk(id);
2346         attemptAdjustBreakpointLocation(id);
2347     }
2348 }
2349
2350 void GdbEngine::handleBreakInsert1(const GdbResponse &response)
2351 {
2352     BreakHandler *handler = breakHandler();
2353     BreakpointId id(response.cookie.toInt());
2354     if (response.resultClass == GdbResultDone) {
2355         // Interesting only on Mac?
2356         GdbMi bkpt = response.data.findChild("bkpt");
2357         updateBreakpointDataFromOutput(id, bkpt);
2358         if (handler->needsChange(id)) {
2359             handler->notifyBreakpointChangeAfterInsertNeeded(id);
2360             changeBreakpoint(id);
2361         } else {
2362             handler->notifyBreakpointInsertOk(id);
2363             attemptAdjustBreakpointLocation(id);
2364         }
2365     } else if (response.data.findChild("msg").data().contains("Unknown option")) {
2366         // Older version of gdb don't know the -a option to set tracepoints
2367         // ^error,msg="mi_cmd_break_insert: Unknown option ``a''"
2368         const QString fileName = handler->fileName(id);
2369         const int lineNumber = handler->lineNumber(id);
2370         QByteArray cmd = "trace "
2371             "\"" + GdbMi::escapeCString(fileName).toLocal8Bit() + "\":"
2372             + QByteArray::number(lineNumber);
2373         postCommand(cmd, NeedsStop | RebuildBreakpointModel,
2374             CB(handleTraceInsert2), id);
2375     } else {
2376         // Some versions of gdb like "GNU gdb (GDB) SUSE (6.8.91.20090930-2.4)"
2377         // know how to do pending breakpoints using CLI but not MI. So try
2378         // again with MI.
2379         QByteArray cmd = "break " + breakpointLocation2(id);
2380         postCommand(cmd, NeedsStop | RebuildBreakpointModel,
2381             CB(handleBreakInsert2), id);
2382     }
2383 }
2384
2385 void GdbEngine::handleBreakInsert2(const GdbResponse &response)
2386 {
2387     if (response.resultClass == GdbResultDone) {
2388         BreakpointId id(response.cookie.toInt());
2389         attemptAdjustBreakpointLocation(id);
2390         breakHandler()->notifyBreakpointInsertOk(id);
2391     } else {
2392         // Note: gdb < 60800  doesn't "do" pending breakpoints.
2393         // Not much we can do about it except implementing the
2394         // logic on top of shared library events, and that's not
2395         // worth the effort.
2396     }
2397 }
2398
2399 void GdbEngine::handleTraceInsert2(const GdbResponse &response)
2400 {
2401     if (response.resultClass == GdbResultDone)
2402         reloadBreakListInternal();
2403 }
2404
2405 void GdbEngine::reloadBreakListInternal()
2406 {
2407     postCommand("-break-list",
2408         NeedsStop | RebuildBreakpointModel,
2409         CB(handleBreakList));
2410 }
2411
2412 void GdbEngine::handleBreakList(const GdbResponse &response)
2413 {
2414     // 45^done,BreakpointTable={nr_rows="2",nr_cols="6",hdr=[
2415     // {width="3",alignment="-1",col_name="number",colhdr="Num"}, ...
2416     // body=[bkpt={number="1",type="breakpoint",disp="keep",enabled="y",
2417     //  addr="0x000000000040109e",func="main",file="app.cpp",
2418     //  fullname="/home/apoenitz/dev/work/plugintest/app/app.cpp",
2419     //  line="11",times="1"},
2420     //  bkpt={number="2",type="breakpoint",disp="keep",enabled="y",
2421     //  addr="<PENDING>",pending="plugin.cpp:7",times="0"}] ... }
2422
2423     if (response.resultClass == GdbResultDone) {
2424         GdbMi table = response.data.findChild("BreakpointTable");
2425         if (table.isValid())
2426             handleBreakList(table);
2427     }
2428 }
2429
2430 void GdbEngine::handleBreakList(const GdbMi &table)
2431 {
2432     const GdbMi body = table.findChild("body");
2433     QList<GdbMi> bkpts;
2434     if (body.isValid()) {
2435         // Non-Mac
2436         bkpts = body.children();
2437     } else {
2438         // Mac
2439         bkpts = table.children();
2440         // Remove the 'hdr' and artificial items.
2441         for (int i = bkpts.size(); --i >= 0; ) {
2442             int num = bkpts.at(i).findChild("number").data().toInt();
2443             if (num <= 0)
2444                 bkpts.removeAt(i);
2445         }
2446     }
2447
2448     foreach (const GdbMi &bkpt, bkpts) {
2449         BreakpointResponse needle;
2450         needle.number = bkpt.findChild("number").data().toInt();
2451         if (isQmlStepBreakpoint2(needle.number))
2452             continue;
2453         if (isQFatalBreakpoint(needle.number))
2454             continue;
2455         BreakpointId id = breakHandler()->findSimilarBreakpoint(needle);
2456         if (id != BreakpointId(-1)) {
2457             updateBreakpointDataFromOutput(id, bkpt);
2458             BreakpointResponse response = breakHandler()->response(id);
2459             if (response.correctedLineNumber == 0)
2460                 attemptAdjustBreakpointLocation(id);
2461             if (response.multiple && response.addresses.isEmpty())
2462                 postCommand("info break " + QByteArray::number(response.number),
2463                     NeedsStop, CB(handleBreakListMultiple), QVariant(id));
2464         } else {
2465             qDebug() << "  NOTHING SUITABLE FOUND";
2466             showMessage(_("CANNOT FIND BP: " + bkpt.toString()));
2467         }
2468     }
2469
2470     m_breakListOutdated = false;
2471 }
2472
2473 void GdbEngine::handleBreakListMultiple(const GdbResponse &response)
2474 {
2475     QTC_ASSERT(response.resultClass == GdbResultDone, /**/)
2476     const BreakpointId id = response.cookie.toInt();
2477     const QString str = QString::fromLocal8Bit(
2478         response.data.findChild("consolestreamoutput").data());
2479     extractDataFromInfoBreak(str, id);
2480 }
2481
2482 void GdbEngine::handleBreakDisable(const GdbResponse &response)
2483 {
2484     QTC_ASSERT(response.resultClass == GdbResultDone, /**/)
2485     const BreakpointId id = response.cookie.toInt();
2486     BreakHandler *handler = breakHandler();
2487     // This should only be the requested state.
2488     QTC_ASSERT(!handler->isEnabled(id), /* Prevent later recursion */);
2489     BreakpointResponse br = handler->response(id);
2490     br.enabled = false;
2491     handler->setResponse(id, br);
2492     changeBreakpoint(id); // Maybe there's more to do.
2493 }
2494
2495 void GdbEngine::handleBreakEnable(const GdbResponse &response)
2496 {
2497     QTC_ASSERT(response.resultClass == GdbResultDone, /**/)
2498     const BreakpointId id = response.cookie.toInt();
2499     BreakHandler *handler = breakHandler();
2500     // This should only be the requested state.
2501     QTC_ASSERT(handler->isEnabled(id), /* Prevent later recursion */);
2502     BreakpointResponse br = handler->response(id);
2503     br.enabled = true;
2504     handler->setResponse(id, br);
2505     changeBreakpoint(id); // Maybe there's more to do.
2506 }
2507
2508 void GdbEngine::handleBreakThreadSpec(const GdbResponse &response)
2509 {
2510     QTC_ASSERT(response.resultClass == GdbResultDone, /**/)
2511     const BreakpointId id = response.cookie.toInt();
2512     BreakHandler *handler = breakHandler();
2513     BreakpointResponse br = handler->response(id);
2514     br.threadSpec = handler->threadSpec(id);
2515     handler->setResponse(id, br);
2516     handler->notifyBreakpointNeedsReinsertion(id);
2517     insertBreakpoint(id);
2518 }
2519
2520 void GdbEngine::handleBreakIgnore(const GdbResponse &response)
2521 {
2522     // gdb 6.8:
2523     // ignore 2 0:
2524     // ~"Will stop next time breakpoint 2 is reached.\n"
2525     // 28^done
2526     // ignore 2 12:
2527     // &"ignore 2 12\n"
2528     // ~"Will ignore next 12 crossings of breakpoint 2.\n"
2529     // 29^done
2530     //
2531     // gdb 6.3 does not produce any console output
2532     QTC_ASSERT(response.resultClass == GdbResultDone, /**/)
2533     QString msg = _(response.data.findChild("consolestreamoutput").data());
2534     BreakpointId id = response.cookie.toInt();
2535     BreakHandler *handler = breakHandler();
2536     BreakpointResponse br = handler->response(id);
2537     //if (msg.contains(__("Will stop next time breakpoint")))
2538     //    response.ignoreCount = _("0");
2539     //else if (msg.contains(__("Will ignore next")))
2540     //    response.ignoreCount = data->ignoreCount;
2541     // FIXME: this assumes it is doing the right thing...
2542     const BreakpointParameters &parameters = handler->breakpointData(id);
2543     br.ignoreCount = parameters.ignoreCount;
2544     br.command = parameters.command;
2545     handler->setResponse(id, br);
2546     changeBreakpoint(id); // Maybe there's more to do.
2547 }
2548
2549 void GdbEngine::handleBreakCondition(const GdbResponse &response)
2550 {
2551     // Can happen at invalid condition strings.
2552     //QTC_ASSERT(response.resultClass == GdbResultDone, /**/)
2553     const BreakpointId id = response.cookie.toInt();
2554     BreakHandler *handler = breakHandler();
2555     // We just assume it was successful. Otherwise we had to parse
2556     // the output stream data.
2557     // The following happens on Mac:
2558     //   QByteArray msg = response.data.findChild("msg").data();
2559     //   if (1 || msg.startsWith("Error parsing breakpoint condition. "
2560     //            " Will try again when we hit the breakpoint.")) {
2561     BreakpointResponse br = handler->response(id);
2562     br.condition = handler->condition(id);
2563     handler->setResponse(id, br);
2564     changeBreakpoint(id); // Maybe there's more to do.
2565 }
2566
2567 void GdbEngine::extractDataFromInfoBreak(const QString &output, BreakpointId id)
2568 {
2569     //qDebug() << output;
2570     if (output.isEmpty())
2571         return;
2572     // "Num     Type           Disp Enb Address            What
2573     // 4       breakpoint     keep y   <MULTIPLE>         0x00000000004066ad
2574     // 4.1                         y     0x00000000004066ad in CTorTester
2575     //  at /data5/dev/ide/main/tests/manual/gdbdebugger/simple/app.cpp:124
2576     // - or -
2577     // everything on a single line on Windows for constructors of classes
2578     // within namespaces.
2579     // Sometimes the path is relative too.
2580
2581     // 2    breakpoint     keep y   <MULTIPLE> 0x0040168e
2582     // 2.1    y     0x0040168e in MainWindow::MainWindow(QWidget*) at mainwindow.cpp:7
2583     // 2.2    y     0x00401792 in MainWindow::MainWindow(QWidget*) at mainwindow.cpp:7
2584
2585     // tested in ../../../tests/auto/debugger/
2586     QRegExp re(_("MULTIPLE.*(0x[0-9a-f]+) in (.*)\\s+at (.*):([\\d]+)([^\\d]|$)"));
2587     re.setMinimal(true);
2588
2589     BreakpointResponse response;
2590     response.fileName = _("<MULTIPLE>");
2591
2592     QString requestedFileName = breakHandler()->fileName(id);
2593
2594     if (re.indexIn(output) != -1) {
2595         response.address = re.cap(1).toULongLong(0, 16);
2596         response.functionName = re.cap(2).trimmed();
2597         response.lineNumber = re.cap(4).toInt();
2598         QString full = fullName(re.cap(3));
2599         if (full.isEmpty()) {
2600             // FIXME: This happens without UsePreciseBreakpoints regularly.
2601             // We need to revive that "fill full name mapping bit by bit"
2602             // approach of 1.2.x
2603             //qDebug() << "NO FULL NAME KNOWN FOR" << re.cap(3);
2604             full = cleanupFullName(re.cap(3));
2605             if (full.isEmpty()) {
2606                 qDebug() << "FILE IS NOT RESOLVABLE" << re.cap(3);
2607                 full = re.cap(3); // FIXME: wrong, but prevents recursion
2608             }
2609         }
2610         // The variable full could still contain, say "foo.cpp" when we asked
2611         // for "/full/path/to/foo.cpp". In this case, using the requested
2612         // instead of the acknowledged name makes sense as it will allow setting
2613         // the marker in more cases.
2614         if (requestedFileName.endsWith(full))
2615             full = requestedFileName;
2616         response.fileName = full;
2617     } else {
2618         qDebug() << "COULD NOT MATCH " << re.pattern() << " AND " << output;
2619         response.number = -1; // <unavailable>
2620     }
2621     breakHandler()->setResponse(id, response);
2622 }
2623
2624 void GdbEngine::handleBreakInfo(const GdbResponse &response)
2625 {
2626     if (response.resultClass == GdbResultDone) {
2627         // Old-style output for multiple breakpoints, presumably in a
2628         // constructor.
2629         const BreakpointId id(response.cookie.toInt());
2630         const QString str = QString::fromLocal8Bit(
2631             response.data.findChild("consolestreamoutput").data());
2632         extractDataFromInfoBreak(str, id);
2633     }
2634 }
2635
2636 void GdbEngine::handleInfoLine(const GdbResponse &response)
2637 {
2638     if (response.resultClass == GdbResultDone) {
2639         // Old-style output: "Line 1102 of \"simple/app.cpp\" starts
2640         // at address 0x80526aa <_Z10...+131> and ends at 0x80526b5
2641         // <_Z10testQStackv+142>.\n"
2642         QByteArray ba = response.data.findChild("consolestreamoutput").data();
2643         const BreakpointId id = response.cookie.toInt();
2644         const int pos = ba.indexOf(' ', 5);
2645         if (ba.startsWith("Line ") && pos != -1) {
2646             const int line = ba.mid(5, pos - 5).toInt();
2647             BreakpointResponse br = breakHandler()->response(id);
2648             br.lineNumber = line;
2649             br.correctedLineNumber = line;
2650             breakHandler()->setResponse(id, br);
2651         }
2652     }
2653 }
2654
2655 bool GdbEngine::stateAcceptsBreakpointChanges() const
2656 {
2657     switch (state()) {
2658     case InferiorSetupRequested:
2659     case InferiorRunRequested:
2660     case InferiorRunOk:
2661     case InferiorStopRequested:
2662     case InferiorStopOk:
2663         return true;
2664     default:
2665         return false;
2666     }
2667 }
2668
2669 bool GdbEngine::acceptsBreakpoint(BreakpointId id) const
2670 {
2671     return DebuggerEngine::isCppBreakpoint(breakHandler()->breakpointData(id));
2672 }
2673
2674 void GdbEngine::insertBreakpoint(BreakpointId id)
2675 {
2676     // Set up fallback in case of pending breakpoints which aren't handled
2677     // by the MI interface.
2678     BreakHandler *handler = breakHandler();
2679     QTC_ASSERT(handler->state(id) == BreakpointInsertRequested, /**/);
2680     handler->notifyBreakpointInsertProceeding(id);
2681     BreakpointType type = handler->type(id);
2682     if (type == Watchpoint) {
2683         postCommand("watch " + addressSpec(handler->address(id)),
2684             NeedsStop | RebuildBreakpointModel,
2685             CB(handleWatchInsert), id);
2686         return;
2687     }
2688     if (type == BreakpointAtFork) {
2689         postCommand("catch fork", NeedsStop | RebuildBreakpointModel,
2690             CB(handleCatchInsert), id);
2691         postCommand("catch vfork", NeedsStop | RebuildBreakpointModel,
2692             CB(handleCatchInsert), id);
2693         return;
2694     }
2695     //if (type == BreakpointAtVFork) {
2696     //    postCommand("catch vfork", NeedsStop | RebuildBreakpointModel,
2697     //        CB(handleCatchInsert), id);
2698     //    return;
2699     //}
2700     if (type == BreakpointAtExec) {
2701         postCommand("catch exec", NeedsStop | RebuildBreakpointModel,
2702             CB(handleCatchInsert), id);
2703         return;
2704     }
2705     if (type == BreakpointAtSysCall) {
2706         postCommand("catch syscall", NeedsStop | RebuildBreakpointModel,
2707             CB(handleCatchInsert), id);
2708         return;
2709     }
2710
2711     QByteArray cmd = "xxx";
2712     if (handler->isTracepoint(id)) {
2713         cmd = "-break-insert -a -f ";
2714     } else if (m_isMacGdb) {
2715         cmd = "-break-insert -l -1 -f ";
2716     } else if (m_gdbAdapter->isTrkAdapter()) {
2717         cmd = "-break-insert -h -f ";
2718     } else if (m_gdbVersion >= 70000) {
2719         int spec = handler->threadSpec(id);
2720         cmd = "-break-insert ";
2721         if (spec >= 0)
2722             cmd += "-p " + QByteArray::number(spec);
2723         cmd += " -f ";
2724     } else if (m_gdbVersion >= 60800) {
2725         // Probably some earlier version would work as well.
2726         cmd = "-break-insert -f ";
2727     } else {
2728         cmd = "-break-insert ";
2729     }
2730     //if (!data->condition.isEmpty())
2731     //    cmd += "-c " + data->condition + ' ';
2732     cmd += breakpointLocation(id);
2733     postCommand(cmd, NeedsStop | RebuildBreakpointModel,
2734         CB(handleBreakInsert1), id);
2735 }
2736
2737 void GdbEngine::changeBreakpoint(BreakpointId id)
2738 {
2739     BreakHandler *handler = breakHandler();
2740     const BreakpointParameters &data = handler->breakpointData(id);
2741     QTC_ASSERT(data.type != UnknownType, return);
2742     const BreakpointResponse &response = handler->response(id);
2743     QTC_ASSERT(response.number > 0, return);
2744     const QByteArray bpnr = QByteArray::number(response.number);
2745     QTC_ASSERT(response.number > 0, return);
2746     const BreakpointState state = handler->state(id);
2747     if (state == BreakpointChangeRequested)
2748         handler->notifyBreakpointChangeProceeding(id);
2749     const BreakpointState state2 = handler->state(id);
2750     QTC_ASSERT(state2 == BreakpointChangeProceeding, qDebug() << state2);
2751
2752     if (data.threadSpec != response.threadSpec) {
2753         // The only way to change this seems to be to re-set the bp completely.
2754         postCommand("-break-delete " + bpnr,
2755             NeedsStop | RebuildBreakpointModel,
2756             CB(handleBreakThreadSpec), id);
2757         return;
2758     }
2759     if (data.command != response.command) {
2760         QByteArray breakCommand = "-break-commands " + bpnr;
2761         foreach (const QString &command, data.command.split(QLatin1String("\\n"))) {
2762             if (!command.isEmpty()) {
2763                 breakCommand.append(" \"");
2764                 breakCommand.append(command.toLatin1());
2765                 breakCommand.append('"');
2766             }
2767         }
2768         postCommand(breakCommand, NeedsStop | RebuildBreakpointModel,
2769                     CB(handleBreakIgnore), id);
2770         return;
2771     }
2772     if (!data.conditionsMatch(response.condition)) {
2773         postCommand("condition " + bpnr + ' '  + data.condition,
2774             NeedsStop | RebuildBreakpointModel,
2775             CB(handleBreakCondition), id);
2776         return;
2777     }
2778     if (data.ignoreCount != response.ignoreCount) {
2779         postCommand("ignore " + bpnr + ' ' + QByteArray::number(data.ignoreCount),
2780             NeedsStop | RebuildBreakpointModel,
2781             CB(handleBreakIgnore), id);
2782         return;
2783     }
2784     if (!data.enabled && response.enabled) {
2785         postCommand("-break-disable " + bpnr,
2786             NeedsStop | RebuildBreakpointModel,
2787             CB(handleBreakDisable), id);
2788         return;
2789     }
2790     if (data.enabled && !response.enabled) {
2791         postCommand("-break-enable " + bpnr,
2792             NeedsStop | RebuildBreakpointModel,
2793             CB(handleBreakEnable), id);
2794         return;
2795     }
2796     handler->notifyBreakpointChangeOk(id);
2797     attemptAdjustBreakpointLocation(id);
2798 }
2799
2800 void GdbEngine::removeBreakpoint(BreakpointId id)
2801 {
2802     BreakHandler *handler = breakHandler();
2803     QTC_ASSERT(handler->state(id) == BreakpointRemoveRequested, /**/);
2804     handler->notifyBreakpointRemoveProceeding(id);
2805     BreakpointResponse br = handler->response(id);
2806     showMessage(_("DELETING BP %1 IN %2").arg(br.number)
2807         .arg(handler->fileName(id)));
2808     postCommand("-break-delete " + QByteArray::number(br.number),
2809         NeedsStop | RebuildBreakpointModel);
2810     // Pretend it succeeds without waiting for response. Feels better.
2811     // FIXME: Really?
2812     handler->notifyBreakpointRemoveOk(id);
2813 }
2814
2815
2816 //////////////////////////////////////////////////////////////////////
2817 //
2818 // Modules specific stuff
2819 //
2820 //////////////////////////////////////////////////////////////////////
2821
2822 void GdbEngine::loadSymbols(const QString &moduleName)
2823 {
2824     // FIXME: gdb does not understand quoted names here (tested with 6.8)
2825     postCommand("sharedlibrary " + dotEscape(moduleName.toLocal8Bit()));
2826     reloadModulesInternal();
2827     reloadBreakListInternal();
2828     reloadStack(true);
2829     updateLocals();
2830 }
2831
2832 void GdbEngine::loadAllSymbols()
2833 {
2834     postCommand("sharedlibrary .*");
2835     reloadModulesInternal();
2836     reloadBreakListInternal();
2837     reloadStack(true);
2838     updateLocals();
2839 }
2840
2841 void GdbEngine::loadSymbolsForStack()
2842 {
2843     bool needUpdate = false;
2844     const Modules &modules = modulesHandler()->modules();
2845     foreach (const StackFrame &frame, stackHandler()->frames()) {
2846         if (frame.function == _("??")) {
2847             //qDebug() << "LOAD FOR " << frame.address;
2848             foreach (const Module &module, modules) {
2849                 if (module.startAddress <= frame.address
2850                         && frame.address < module.endAddress) {
2851                     postCommand("sharedlibrary "
2852                         + dotEscape(module.moduleName.toLocal8Bit()));
2853                     needUpdate = true;
2854                 }
2855             }
2856         }
2857     }
2858     if (needUpdate) {
2859         reloadModulesInternal();
2860         reloadBreakListInternal();
2861         reloadStack(true);
2862         updateLocals();
2863     }
2864 }
2865
2866 void GdbEngine::requestModuleSymbols(const QString &moduleName)
2867 {
2868     QTemporaryFile tf(QDir::tempPath() + _("/gdbsymbols"));
2869     if (!tf.open())
2870         return;
2871     QString fileName = tf.fileName();
2872     tf.close();
2873     postCommand("maint print msymbols " + fileName.toLocal8Bit()
2874             + ' ' + moduleName.toLocal8Bit(),
2875         NeedsStop, CB(handleShowModuleSymbols),
2876         QVariant(moduleName + QLatin1Char('@') +  fileName));
2877 }
2878
2879 void GdbEngine::handleShowModuleSymbols(const GdbResponse &response)
2880 {
2881     const QString cookie = response.cookie.toString();
2882     const QString moduleName = cookie.section(QLatin1Char('@'), 0, 0);
2883     const QString fileName = cookie.section(QLatin1Char('@'), 1, 1);
2884     if (response.resultClass == GdbResultDone) {
2885         Symbols rc;
2886         QFile file(fileName);
2887         file.open(QIODevice::ReadOnly);
2888         // Object file /opt/dev/qt/lib/libQtNetworkMyns.so.4:
2889         // [ 0] A 0x16bd64 _DYNAMIC  moc_qudpsocket.cpp
2890         // [12] S 0xe94680 _ZN4myns5QFileC1Ev section .plt  myns::QFile::QFile()
2891         foreach (const QByteArray &line, file.readAll().split('\n')) {
2892             if (line.isEmpty())
2893                 continue;
2894             if (line.at(0) != '[')
2895                 continue;
2896             int posCode = line.indexOf(']') + 2;
2897             int posAddress = line.indexOf("0x", posCode);
2898             if (posAddress == -1)
2899                 continue;
2900             int posName = line.indexOf(" ", posAddress);
2901             int lenAddress = posName - posAddress - 1;
2902             int posSection = line.indexOf(" section ");
2903             int lenName = 0;
2904             int lenSection = 0;
2905             int posDemangled = 0;
2906             if (posSection == -1) {
2907                 lenName = line.size() - posName;
2908                 posDemangled = posName;
2909             } else {
2910                 lenName = posSection - posName;
2911                 posSection += 10;
2912                 posDemangled = line.indexOf(' ', posSection + 1);
2913                 if (posDemangled == -1) {
2914                     lenSection = line.size() - posSection;
2915                 } else {
2916                     lenSection = posDemangled - posSection;
2917                     posDemangled += 1;
2918                 }
2919             }
2920             int lenDemangled = 0;
2921             if (posDemangled != -1)
2922                 lenDemangled = line.size() - posDemangled;
2923             Symbol symbol;
2924             symbol.state = _(line.mid(posCode, 1));
2925             symbol.address = _(line.mid(posAddress, lenAddress));
2926             symbol.name = _(line.mid(posName, lenName));
2927             symbol.section = _(line.mid(posSection, lenSection));
2928             symbol.demangled = _(line.mid(posDemangled, lenDemangled));
2929             rc.push_back(symbol);
2930         }
2931         file.close();
2932         file.remove();
2933         debuggerCore()->showModuleSymbols(moduleName, rc);
2934     } else {
2935         showMessageBox(QMessageBox::Critical, tr("Cannot Read Symbols"),
2936             tr("Cannot read symbols for module \"%1\".").arg(fileName));
2937     }
2938 }
2939
2940 void GdbEngine::reloadModules()
2941 {
2942     if (state() == InferiorRunOk || state() == InferiorStopOk)
2943         reloadModulesInternal();
2944 }
2945
2946 void GdbEngine::reloadModulesInternal()
2947 {
2948     m_modulesListOutdated = false;
2949     postCommand("info shared", NeedsStop, CB(handleModulesList));
2950 }
2951
2952 void GdbEngine::handleModulesList(const GdbResponse &response)
2953 {
2954     Modules modules;
2955     if (response.resultClass == GdbResultDone) {
2956         // That's console-based output, likely Linux or Windows,
2957         // but we can avoid the #ifdef here.
2958         QString data = QString::fromLocal8Bit(
2959             response.data.findChild("consolestreamoutput").data());
2960         QTextStream ts(&data, QIODevice::ReadOnly);
2961         while (!ts.atEnd()) {
2962             QString line = ts.readLine();
2963             Module module;
2964             QString symbolsRead;
2965             QTextStream ts(&line, QIODevice::ReadOnly);
2966             if (line.startsWith(__("0x"))) {
2967                 ts >> module.startAddress >> module.endAddress >> symbolsRead;
2968                 module.moduleName = ts.readLine().trimmed();
2969                 module.symbolsRead =
2970                     (symbolsRead == __("Yes") ? Module::ReadOk : Module::ReadFailed);
2971                 modules.append(module);
2972             } else if (line.trimmed().startsWith(__("No"))) {
2973                 // gdb 6.4 symbianelf
2974                 ts >> symbolsRead;
2975                 QTC_ASSERT(symbolsRead == __("No"), continue);
2976                 module.startAddress = 0;
2977                 module.endAddress = 0;
2978                 module.moduleName = ts.readLine().trimmed();
2979                 modules.append(module);
2980             }
2981         }
2982         if (modules.isEmpty()) {
2983             // Mac has^done,shlib-info={num="1",name="dyld",kind="-",
2984             // dyld-addr="0x8fe00000",reason="dyld",requested-state="Y",
2985             // state="Y",path="/usr/lib/dyld",description="/usr/lib/dyld",
2986             // loaded_addr="0x8fe00000",slide="0x0",prefix="__dyld_"},
2987             // shlib-info={...}...
2988             foreach (const GdbMi &item, response.data.children()) {
2989                 Module module;
2990                 module.moduleName =
2991                     QString::fromLocal8Bit(item.findChild("path").data());
2992                 module.symbolsRead = (item.findChild("state").data() == "Y")
2993                         ? Module::ReadOk : Module::ReadFailed;
2994                 module.startAddress =
2995                     item.findChild("loaded_addr").data().toULongLong(0, 0);
2996                 module.endAddress = 0; // FIXME: End address not easily available.
2997                 modules.append(module);
2998             }
2999         }
3000     }
3001     modulesHandler()->setModules(modules);
3002 }
3003
3004
3005 void GdbEngine::examineModules()
3006 {
3007     foreach (Module module, modulesHandler()->modules()) {
3008         if (module.symbolsType == Module::UnknownType) {
3009             QProcess proc;
3010             qDebug() << _("objdump -h \"%1\"").arg(module.moduleName);
3011             proc.start(_("objdump -h \"%1\"").arg(module.moduleName));
3012             if (!proc.waitForStarted())
3013                 continue;
3014             if (!proc.waitForFinished())
3015                 continue;
3016             QByteArray ba = proc.readAllStandardOutput();
3017             if (ba.contains(".gdb_index"))
3018                 module.symbolsType = Module::FastSymbols;
3019             else
3020                 module.symbolsType = Module::PlainSymbols;
3021             modulesHandler()->updateModule(module.moduleName, module);
3022         }
3023     }
3024 }
3025
3026 //////////////////////////////////////////////////////////////////////
3027 //
3028 // Source files specific stuff
3029 //
3030 //////////////////////////////////////////////////////////////////////
3031
3032 void GdbEngine::invalidateSourcesList()
3033 {
3034     m_modulesListOutdated = true;
3035     m_sourcesListOutdated = true;
3036     m_breakListOutdated = true;
3037 }
3038
3039 void GdbEngine::reloadSourceFiles()
3040 {
3041     if ((state() == InferiorRunOk || state() == InferiorStopOk)
3042         && !m_sourcesListUpdating)
3043         reloadSourceFilesInternal();
3044 }
3045
3046 void GdbEngine::reloadSourceFilesInternal()
3047 {
3048     QTC_ASSERT(!m_sourcesListUpdating, /**/);
3049     m_sourcesListUpdating = true;
3050     postCommand("-file-list-exec-source-files", NeedsStop, CB(handleQuerySources));
3051 #if 0
3052     if (m_gdbVersion < 70000 && !m_isMacGdb)
3053         postCommand("set stop-on-solib-events 1");
3054 #endif
3055 }
3056
3057
3058 //////////////////////////////////////////////////////////////////////
3059 //
3060 // Stack specific stuff
3061 //
3062 //////////////////////////////////////////////////////////////////////
3063
3064 void GdbEngine::selectThread(int index)
3065 {
3066     threadsHandler()->setCurrentThread(index);
3067     Threads threads = threadsHandler()->threads();
3068     QTC_ASSERT(index < threads.size(), return);
3069     const int id = threads.at(index).id;
3070     showStatusMessage(tr("Retrieving data for stack view thread 0x%1...")
3071         .arg(id, 0, 16), 10000);
3072     postCommand("-thread-select " + QByteArray::number(id), Discardable,
3073         CB(handleStackSelectThread));
3074 }
3075
3076 void GdbEngine::handleStackSelectThread(const GdbResponse &)
3077 {
3078     QTC_ASSERT(state() == InferiorUnrunnable || state() == InferiorStopOk, /**/);
3079     showStatusMessage(tr("Retrieving data for stack view..."), 3000);
3080     reloadStack(true); // Will reload registers.
3081     updateLocals();
3082 }
3083
3084 void GdbEngine::reloadFullStack()
3085 {
3086     PENDING_DEBUG("RELOAD FULL STACK");
3087     postCommand("-stack-list-frames", Discardable, CB(handleStackListFrames),
3088         QVariant::fromValue<StackCookie>(StackCookie(true, true)));
3089 }
3090
3091 void GdbEngine::reloadStack(bool forceGotoLocation)
3092 {
3093     PENDING_DEBUG("RELOAD STACK");
3094     QByteArray cmd = "-stack-list-frames";
3095     int stackDepth = debuggerCore()->action(MaximalStackDepth)->value().toInt();
3096     if (stackDepth && !m_gdbAdapter->isTrkAdapter())
3097         cmd += " 0 " + QByteArray::number(stackDepth);
3098     // FIXME: gdb 6.4 symbianelf likes to be asked twice. The first time it
3099     // returns with "^error,msg="Previous frame identical to this frame
3100     // (corrupt stack?)". Might be related to the fact that we can't
3101     // access the memory belonging to the lower frames. But as we know
3102     // this sometimes happens, ask the second time immediately instead
3103     // of waiting for the first request to fail.
3104     // FIXME: Seems to work with 6.8.
3105     if (m_gdbAdapter->isTrkAdapter() && m_gdbVersion < 6.8)
3106         postCommand(cmd);
3107     postCommand(cmd, Discardable, CB(handleStackListFrames),
3108         QVariant::fromValue<StackCookie>(StackCookie(false, forceGotoLocation)));
3109 }
3110
3111 StackFrame GdbEngine::parseStackFrame(const GdbMi &frameMi, int level)
3112 {
3113     //qDebug() << "HANDLING FRAME:" << frameMi.toString();
3114     StackFrame frame;
3115     frame.level = level;
3116     GdbMi fullName = frameMi.findChild("fullname");
3117     if (fullName.isValid())
3118         frame.file = cleanupFullName(QFile::decodeName(fullName.data()));
3119     else
3120         frame.file = QFile::decodeName(frameMi.findChild("file").data());
3121     frame.function = _(frameMi.findChild("func").data());
3122     frame.from = _(frameMi.findChild("from").data());
3123     frame.line = frameMi.findChild("line").data().toInt();
3124     frame.address = frameMi.findChild("addr").data().toULongLong(0, 16);
3125     frame.usable = QFileInfo(frame.file).isReadable();
3126     return frame;
3127 }
3128
3129 void GdbEngine::handleStackListFrames(const GdbResponse &response)
3130 {
3131     bool handleIt = (m_isMacGdb || response.resultClass == GdbResultDone);
3132     if (!handleIt) {
3133         // That always happens on symbian gdb with
3134         // ^error,data={msg="Previous frame identical to this frame (corrupt stack?)"
3135         // logstreamoutput="Previous frame identical to this frame (corrupt stack?)\n"
3136         //qDebug() << "LISTING STACK FAILED: " << response.toString();
3137         reloadRegisters();
3138         return;
3139     }
3140
3141     StackCookie cookie = response.cookie.value<StackCookie>();
3142     QList<StackFrame> stackFrames;
3143
3144     GdbMi stack = response.data.findChild("stack");
3145     if (!stack.isValid()) {
3146         qDebug() << "FIXME: stack:" << stack.toString();
3147         return;
3148     }
3149
3150     int targetFrame = -1;
3151
3152     int n = stack.childCount();
3153     for (int i = 0; i != n; ++i) {
3154         stackFrames.append(parseStackFrame(stack.childAt(i), i));
3155         const StackFrame &frame = stackFrames.back();
3156
3157 #        if defined(Q_OS_WIN)
3158         const bool isBogus =
3159             // Assume this is wrong and points to some strange stl_algobase
3160             // implementation. Happens on Karsten's XP system with Gdb 5.50
3161             (frame.file.endsWith(__("/bits/stl_algobase.h")) && frame.line == 150)
3162             // Also wrong. Happens on Vista with Gdb 5.50
3163                || (frame.function == __("operator new") && frame.line == 151);
3164
3165         // Immediately leave bogus frames.
3166         if (targetFrame == -1 && isBogus) {
3167             setTokenBarrier();
3168             notifyInferiorRunRequested();
3169             postCommand("-exec-finish", RunRequest, CB(handleExecuteContinue));
3170             showStatusMessage(tr("Jumping out of bogus frame..."), 1000);
3171             return;
3172         }
3173 #        endif
3174
3175         // Initialize top frame to the first valid frame.
3176         const bool isValid = frame.isUsable() && !frame.function.isEmpty();
3177         if (isValid && targetFrame == -1)
3178             targetFrame = i;
3179     }
3180
3181     bool canExpand = !cookie.isFull
3182         && (n >= debuggerCore()->action(MaximalStackDepth)->value().toInt());
3183     debuggerCore()->action(ExpandStack)->setEnabled(canExpand);
3184     stackHandler()->setFrames(stackFrames, canExpand);
3185
3186     // We can't jump to any file if we don't have any frames.
3187     if (stackFrames.isEmpty())
3188         return;
3189
3190     // targetFrame contains the top most frame for which we have source
3191     // information. That's typically the frame we'd like to jump to, with
3192     // a few exceptions:
3193
3194     // Always jump to frame #0 when stepping by instruction.
3195     if (debuggerCore()->boolSetting(OperateByInstruction))
3196         targetFrame = 0;
3197
3198     // If there is no frame with source, jump to frame #0.
3199     if (targetFrame == -1)
3200         targetFrame = 0;
3201
3202     stackHandler()->setCurrentIndex(targetFrame);
3203     activateFrame(targetFrame);
3204 }
3205
3206 void GdbEngine::activateFrame(int frameIndex)
3207 {
3208     if (state() != InferiorStopOk && state() != InferiorUnrunnable)
3209         return;
3210
3211     StackHandler *handler = stackHandler();
3212
3213     if (frameIndex == handler->stackSize()) {
3214         reloadFullStack();
3215         return;
3216     }
3217
3218     QTC_ASSERT(frameIndex < handler->stackSize(), return);
3219
3220     // Assuming the command always succeeds this saves a roundtrip.
3221     // Otherwise the lines below would need to get triggered
3222     // after a response to this -stack-select-frame here.
3223     handler->setCurrentIndex(frameIndex);
3224     QByteArray cmd = "-stack-select-frame";
3225     //if (!m_currentThread.isEmpty())
3226     //    cmd += " --thread " + m_currentThread;
3227     cmd += ' ';
3228     cmd += QByteArray::number(frameIndex);
3229     postCommand(cmd, Discardable, CB(handleStackSelectFrame));
3230     gotoLocation(stackHandler()->currentFrame());
3231     updateLocals();
3232     reloadRegisters();
3233 }
3234
3235 void GdbEngine::handleStackSelectFrame(const GdbResponse &response)
3236 {
3237     Q_UNUSED(response);
3238 }
3239
3240 void GdbEngine::handleThreadInfo(const GdbResponse &response)
3241 {
3242     const int id = response.cookie.toInt();
3243     if (response.resultClass == GdbResultDone) {
3244         int currentThreadId;
3245         const Threads threads =
3246             ThreadsHandler::parseGdbmiThreads(response.data, &currentThreadId);
3247         threadsHandler()->setThreads(threads);
3248         threadsHandler()->setCurrentThreadId(currentThreadId);
3249         updateViews(); // Adjust Threads combobox.
3250         if (m_hasInferiorThreadList && debuggerCore()->boolSetting(ShowThreadNames)) {
3251             postCommand("threadnames " +
3252                 debuggerCore()->action(MaximalStackDepth)->value().toByteArray(),
3253                 Discardable, CB(handleThreadNames), id);
3254         }
3255     } else {
3256         // Fall back for older versions: Try to get at least a list
3257         // of running threads.
3258         postCommand("-thread-list-ids", Discardable, CB(handleThreadListIds), id);
3259     }
3260 }
3261
3262 void GdbEngine::handleThreadListIds(const GdbResponse &response)
3263 {
3264     const int id = response.cookie.toInt();
3265     // "72^done,{thread-ids={thread-id="2",thread-id="1"},number-of-threads="2"}
3266     // In gdb 7.1+ additionally: current-thread-id="1"
3267     const QList<GdbMi> items = response.data.findChild("thread-ids").children();
3268     Threads threads;
3269     for (int index = 0, n = items.size(); index != n; ++index) {
3270         ThreadData thread;
3271         thread.id = items.at(index).data().toInt();
3272         threads.append(thread);
3273     }
3274     threadsHandler()->setThreads(threads);
3275     threadsHandler()->setCurrentThreadId(id);
3276 }
3277
3278 void GdbEngine::handleThreadNames(const GdbResponse &response)
3279 {
3280     if (response.resultClass == GdbResultDone) {
3281         GdbMi contents = response.data.findChild("consolestreamoutput");
3282         GdbMi names;
3283         names.fromString(contents.data());
3284
3285         Threads threads = threadsHandler()->threads();
3286
3287         foreach (const GdbMi &name, names.children()) {
3288             int id = name.findChild("id").data().toInt();
3289             for (int index = 0, n = threads.size(); index != n; ++index) {
3290                 ThreadData & thread = threads[index];
3291                 if (thread.id == (quint64)id) {
3292                     thread.name = decodeData(name.findChild("value").data(),
3293                         name.findChild("valueencoded").data().toInt());
3294                     break;
3295                 }
3296             }
3297         }
3298         threadsHandler()->setThreads(threads);
3299         updateViews();
3300     }
3301 }
3302
3303
3304 //////////////////////////////////////////////////////////////////////
3305 //
3306 // Snapshot specific stuff
3307 //
3308 //////////////////////////////////////////////////////////////////////
3309
3310 void GdbEngine::createSnapshot()
3311 {
3312     QString fileName;
3313     QTemporaryFile tf(QDir::tempPath() + _("/gdbsnapshot"));
3314     if (tf.open()) {
3315         fileName = tf.fileName();
3316         tf.close();
3317         postCommand("gcore " + fileName.toLocal8Bit(),
3318             NeedsStop, CB(handleMakeSnapshot), fileName);
3319     } else {
3320         showMessageBox(QMessageBox::Critical, tr("Snapshot Creation Error"),
3321             tr("Cannot create snapshot file."));
3322     }
3323 }
3324
3325 void GdbEngine::handleMakeSnapshot(const GdbResponse &response)
3326 {
3327     if (response.resultClass == GdbResultDone) {
3328         DebuggerStartParameters sp = startParameters();
3329         sp.startMode = AttachCore;
3330         sp.coreFile = response.cookie.toString();
3331         //snapshot.setDate(QDateTime::currentDateTime());
3332         StackFrames frames = stackHandler()->frames();
3333         QString function = _("<unknown>");
3334         if (!frames.isEmpty()) {
3335             const StackFrame &frame = frames.at(0);
3336             function = frame.function + _(":") + QString::number(frame.line);
3337         }
3338         sp.displayName = function + _(": ") + QDateTime::currentDateTime().toString();
3339         sp.isSnapshot = true;
3340         DebuggerRunControl *rc = DebuggerPlugin::createDebugger(sp);
3341         DebuggerPlugin::startDebugger(rc);
3342     } else {
3343         QByteArray msg = response.data.findChild("msg").data();
3344         showMessageBox(QMessageBox::Critical, tr("Snapshot Creation Error"),
3345             tr("Cannot create snapshot:\n") + QString::fromLocal8Bit(msg));
3346     }
3347 }
3348
3349
3350 //////////////////////////////////////////////////////////////////////
3351 //
3352 // Register specific stuff
3353 //
3354 //////////////////////////////////////////////////////////////////////
3355
3356 void GdbEngine::reloadRegisters()
3357 {
3358     if (!debuggerCore()->isDockVisible(_(Constants::DOCKWIDGET_REGISTER)))
3359         return;
3360
3361     if (state() != InferiorStopOk && state() != InferiorUnrunnable)
3362         return;
3363     if (!m_registerNamesListed) {
3364         postCommand("-data-list-register-names", CB(handleRegisterListNames));
3365         m_registerNamesListed = true;
3366         // FIXME: Maybe better completely re-do this logic in TRK adapter.
3367         if (m_gdbAdapter->isTrkAdapter())
3368             return;
3369     }
3370
3371     if (m_gdbAdapter->isTrkAdapter()) {
3372         m_gdbAdapter->trkReloadRegisters();
3373     } else {
3374         postCommand("-data-list-register-values x",
3375                     Discardable, CB(handleRegisterListValues));
3376     }
3377 }
3378
3379 void GdbEngine::setRegisterValue(int nr, const QString &value)
3380 {
3381     Register reg = registerHandler()->registers().at(nr);
3382     //qDebug() << "NOT IMPLEMENTED: CHANGE REGISTER " << nr << reg.name << ":"
3383     //    << value;
3384     postCommand("-var-delete \"R@\"");
3385     postCommand("-var-create \"R@\" * $" + reg.name);
3386     postCommand("-var-assign \"R@\" " + value.toLatin1());
3387     postCommand("-var-delete \"R@\"");
3388     //postCommand("-data-list-register-values d",
3389     //            Discardable, CB(handleRegisterListValues));
3390     reloadRegisters();
3391 }
3392
3393 void GdbEngine::handleRegisterListNames(const GdbResponse &response)
3394 {
3395     if (response.resultClass != GdbResultDone) {
3396         m_registerNamesListed = false;
3397         return;
3398     }
3399
3400     Registers registers;
3401     foreach (const GdbMi &item, response.data.findChild("register-names").children())
3402         registers.append(Register(item.data()));
3403
3404     registerHandler()->setRegisters(registers);
3405
3406     if (m_gdbAdapter->isTrkAdapter())
3407         m_gdbAdapter->trkReloadRegisters();
3408 }
3409
3410 void GdbEngine::handleRegisterListValues(const GdbResponse &response)
3411 {
3412     if (response.resultClass != GdbResultDone)
3413         return;
3414
3415     Registers registers = registerHandler()->registers();
3416
3417     // 24^done,register-values=[{number="0",value="0xf423f"},...]
3418     const GdbMi values = response.data.findChild("register-values");
3419     foreach (const GdbMi &item, values.children()) {
3420         const int index = item.findChild("number").data().toInt();
3421         if (index < registers.size()) {
3422             Register &reg = registers[index];
3423             GdbMi val = item.findChild("value");
3424             QByteArray ba;
3425             bool handled = false;
3426             if (val.data().startsWith('{')) {
3427                 int pos1 = val.data().indexOf("v2_int32");
3428                 if (pos1 == -1)
3429                     pos1 = val.data().indexOf("v4_int32");
3430                 if (pos1 != -1) {
3431                     // FIXME: This block wastes cycles.
3432                     pos1 = val.data().indexOf('{', pos1 + 1) + 1;
3433                     int pos2 = val.data().indexOf('}', pos1);
3434                     QByteArray ba2 = val.data().mid(pos1, pos2 - pos1);
3435                     foreach (QByteArray ba3, ba2.split(',')) {
3436                         ba3 = ba3.trimmed();
3437                         QTC_ASSERT(ba3.size() >= 3, continue);
3438                         QTC_ASSERT(ba3.size() <= 10, continue);
3439                         ba.prepend(QByteArray(10 - ba3.size(), '0'));
3440                         ba.prepend(ba3.mid(2));
3441                     }
3442                     ba.prepend("0x");
3443                     handled = true;
3444                 }
3445             }
3446             reg.value = _(handled ? ba : val.data());
3447         }
3448     }
3449     registerHandler()->setAndMarkRegisters(registers);
3450 }
3451
3452
3453 //////////////////////////////////////////////////////////////////////
3454 //
3455 // Thread specific stuff
3456 //
3457 //////////////////////////////////////////////////////////////////////
3458
3459 bool GdbEngine::supportsThreads() const
3460 {
3461     // FSF gdb 6.3 crashes happily on -thread-list-ids. So don't use it.
3462     // The test below is a semi-random pick, 6.8 works fine
3463     return m_isMacGdb || m_gdbVersion > 60500;
3464 }
3465
3466
3467 //////////////////////////////////////////////////////////////////////
3468 //
3469 // Tooltip specific stuff
3470 //
3471 //////////////////////////////////////////////////////////////////////
3472
3473 bool GdbEngine::showToolTip()
3474 {
3475     if (m_toolTipContext.isNull())
3476         return false;
3477     const QString expression = m_toolTipContext->expression;
3478     const QByteArray iname = tooltipIName(m_toolTipContext->expression);
3479     if (DebuggerToolTipManager::debug())
3480         qDebug() << "GdbEngine::showToolTip " << expression << iname << (*m_toolTipContext);
3481
3482     if (!debuggerCore()->boolSetting(UseToolTipsInMainEditor)) {
3483         watchHandler()->removeData(iname);
3484         return true;
3485     }
3486
3487     const QModelIndex index = watchHandler()->itemIndex(iname);
3488     if (!index.isValid()) {
3489         watchHandler()->removeData(iname);
3490         return false;
3491     }
3492     DebuggerTreeViewToolTipWidget *tw = new DebuggerTreeViewToolTipWidget;
3493     tw->setDebuggerModel(TooltipsWatch);
3494     tw->setExpression(expression);
3495     tw->setContext(*m_toolTipContext);
3496     tw->acquireEngine(this);
3497     DebuggerToolTipManager::instance()->showToolTip(m_toolTipContext->mousePosition,
3498                                                     m_toolTipContext->editor, tw);
3499     return true;
3500 }
3501
3502 QString GdbEngine::tooltipExpression() const
3503 {
3504     return m_toolTipContext.isNull() ? QString() : m_toolTipContext->expression;
3505 }
3506
3507 void GdbEngine::clearToolTip()
3508 {
3509     m_toolTipContext.reset();
3510 }
3511
3512 bool GdbEngine::setToolTipExpression(const QPoint &mousePos,
3513     TextEditor::ITextEditor *editor, const DebuggerToolTipContext &contextIn)
3514 {
3515     if (state() != InferiorStopOk || !isCppEditor(editor)) {
3516         //qDebug() << "SUPPRESSING DEBUGGER TOOLTIP, INFERIOR NOT STOPPED "
3517         // " OR NOT A CPPEDITOR";
3518         return false;
3519     }
3520
3521     DebuggerToolTipContext context = contextIn;
3522     int line, column;
3523     QString exp = cppExpressionAt(editor, context.position, &line, &column, &context.function);
3524     if (DebuggerToolTipManager::debug())
3525         qDebug() << "GdbEngine::setToolTipExpression1 " << exp << context;
3526     if (exp.isEmpty())
3527         return false;
3528
3529     // Extract the first identifier, everything else is considered
3530     // too dangerous.
3531     int pos1 = 0, pos2 = exp.size();
3532     bool inId = false;
3533     for (int i = 0; i != exp.size(); ++i) {
3534         const QChar c = exp.at(i);
3535         const bool isIdChar = c.isLetterOrNumber() || c.unicode() == '_';
3536         if (inId && !isIdChar) {
3537             pos2 = i;
3538             break;
3539         }
3540         if (!inId && isIdChar) {
3541             inId = true;
3542             pos1 = i;
3543         }
3544     }
3545     exp = exp.mid(pos1, pos2 - pos1);
3546
3547     if (exp.isEmpty() || exp.startsWith(_c('#')) || !hasLetterOrNumber(exp) || isKeyWord(exp))
3548         return false;
3549
3550     if (exp.startsWith(_c('"')) && exp.endsWith(_c('"')))
3551         return false;
3552
3553     if (exp.startsWith(__("++")) || exp.startsWith(__("--")))
3554         exp = exp.mid(2);
3555
3556     if (exp.endsWith(__("++")) || exp.endsWith(__("--")))
3557         exp = exp.mid(2);
3558
3559     if (exp.startsWith(_c('<')) || exp.startsWith(_c('[')))
3560         return false;
3561
3562     if (hasSideEffects(exp) || exp.isEmpty())
3563         return false;
3564
3565     if (!m_toolTipContext.isNull() && m_toolTipContext->expression == exp) {
3566         showToolTip();
3567         return true;
3568     }
3569
3570     m_toolTipContext.reset(new GdbToolTipContext(context));
3571     m_toolTipContext->mousePosition = mousePos;
3572     m_toolTipContext->expression = exp;
3573     m_toolTipContext->editor = editor;
3574     if (DebuggerToolTipManager::debug())
3575         qDebug() << "GdbEngine::setToolTipExpression2 " << exp << (*m_toolTipContext);
3576
3577     if (isSynchronous()) {
3578         updateLocals(QVariant());
3579         return true;
3580     }
3581
3582     WatchData toolTip;
3583     toolTip.exp = exp.toLatin1();
3584     toolTip.name = exp;
3585     toolTip.iname = tooltipIName(exp);
3586     watchHandler()->removeData(toolTip.iname);
3587     watchHandler()->insertData(toolTip);
3588     return true;
3589 }
3590
3591
3592 //////////////////////////////////////////////////////////////////////
3593 //
3594 // Watch specific stuff
3595 //
3596 //////////////////////////////////////////////////////////////////////
3597
3598 void GdbEngine::reloadLocals()
3599 {
3600     setTokenBarrier();
3601     updateLocals();
3602 }
3603
3604 bool GdbEngine::hasDebuggingHelperForType(const QByteArray &type) const
3605 {
3606     if (!debuggerCore()->boolSetting(UseDebuggingHelpers))
3607         return false;
3608
3609     if (m_gdbAdapter->dumperHandling() == AbstractGdbAdapter::DumperNotAvailable) {
3610         // Inferior calls are not possible in gdb when looking at core files.
3611         return type == "QString" || type.endsWith("::QString")
3612             || type == "QStringList" || type.endsWith("::QStringList");
3613     }
3614
3615     if (m_debuggingHelperState != DebuggingHelperAvailable)
3616         return false;
3617
3618     // Simple types.
3619     return m_dumperHelper.type(type) != QtDumperHelper::UnknownType;
3620 }
3621
3622
3623 void GdbEngine::updateWatchData(const WatchData &data, const WatchUpdateFlags &flags)
3624 {
3625     if (isSynchronous()) {
3626         // This should only be called for fresh expanded items, not for
3627         // items that had their children retrieved earlier.
3628         //qDebug() << "\nUPDATE WATCH DATA: " << data.toString() << "\n";
3629 #if 0
3630         WatchData data1 = data;
3631         data1.setAllUnneeded();
3632         insertData(data1);
3633         rebuildModel();
3634 #else
3635         if (data.iname.endsWith("."))
3636             return;
3637
3638         // Avoid endless loops created by faulty dumpers.
3639         QByteArray processedName = "1-" + data.iname;
3640         //qDebug() << "PROCESSED NAMES: " << processedName << m_processedNames;
3641         if (m_processedNames.contains(processedName)) {
3642             WatchData data1 = data;
3643             showMessage(_("<Breaking endless loop for " + data.iname + '>'),
3644                 LogMiscInput);
3645             data1.setAllUnneeded();
3646             data1.setValue(_("<unavailable>"));
3647             data1.setHasChildren(false);
3648             insertData(data1);
3649             return;
3650         }
3651         m_processedNames.insert(processedName);
3652
3653         // FIXME: Is this sufficient when "external" changes are
3654         // triggered e.g. by manually entered command in the gdb console?
3655         //qDebug() << "TRY PARTIAL: " << flags.tryIncremental
3656         //        << hasPython()
3657         //        << (m_pendingWatchRequests == 0)
3658         //        << (m_pendingBreakpointRequests == 0);
3659
3660         bool tryPartial = flags.tryIncremental
3661                 && hasPython()
3662                 && m_pendingWatchRequests == 0
3663                 && m_pendingBreakpointRequests == 0;
3664
3665         if (tryPartial)
3666             updateLocalsPython(true, data.iname);
3667         else
3668             updateLocals();
3669 #endif
3670     } else {
3671         // Bump requests to avoid model rebuilding during the nested
3672         // updateWatchModel runs.
3673         ++m_pendingWatchRequests;
3674         PENDING_DEBUG("UPDATE WATCH BUMPS PENDING UP TO " << m_pendingWatchRequests);
3675 #if 1
3676         QMetaObject::invokeMethod(this, "updateWatchDataHelper",
3677             Qt::QueuedConnection, Q_ARG(WatchData, data));
3678 #else
3679         updateWatchDataHelper(data);
3680 #endif
3681     }
3682 }
3683
3684 void GdbEngine::updateWatchDataHelper(const WatchData &data)
3685 {
3686     //m_pendingRequests = 0;
3687     PENDING_DEBUG("UPDATE WATCH DATA");
3688 #    if DEBUG_PENDING
3689     //qDebug() << "##############################################";
3690     qDebug() << "UPDATE MODEL, FOUND INCOMPLETE:";
3691     //qDebug() << data.toString();
3692 #    endif
3693
3694     updateSubItemClassic(data);
3695     //PENDING_DEBUG("INTERNAL TRIGGERING UPDATE WATCH MODEL");
3696     --m_pendingWatchRequests;
3697     PENDING_DEBUG("UPDATE WATCH DONE BUMPS PENDING DOWN TO " << m_pendingWatchRequests);
3698     if (m_pendingWatchRequests <= 0)
3699         rebuildWatchModel();
3700 }
3701
3702 void GdbEngine::rebuildWatchModel()
3703 {
3704     static int count = 0;
3705     ++count;
3706     if (!isSynchronous())
3707         m_processedNames.clear();
3708     PENDING_DEBUG("REBUILDING MODEL" << count);
3709     if (debuggerCore()->boolSetting(LogTimeStamps))
3710         showMessage(LogWindow::logTimeStamp(), LogMiscInput);
3711     showMessage(_("<Rebuild Watchmodel %1>").arg(count), LogMiscInput);
3712     showStatusMessage(tr("Finished retrieving data"), 400);
3713     watchHandler()->endCycle();
3714     showToolTip();
3715 }
3716
3717 static QByteArray arrayFillCommand(const char *array, const QByteArray &params)
3718 {
3719     QString buf;
3720     buf.sprintf("set {char[%d]} &%s = {", params.size(), array);
3721     QByteArray encoded;
3722     encoded.append(buf.toLocal8Bit());
3723     const int size = params.size();
3724     for (int i = 0; i != size; ++i) {
3725         buf.sprintf("%d,", int(params[i]));
3726         encoded.append(buf.toLocal8Bit());
3727     }
3728     encoded[encoded.size() - 1] = '}';
3729     return encoded;
3730 }
3731
3732 void GdbEngine::sendWatchParameters(const QByteArray &params0)
3733 {
3734     QByteArray params = params0;
3735     params.append('\0');
3736     const QByteArray inBufferCmd = arrayFillCommand("qDumpInBuffer", params);
3737
3738     params.replace('\0','!');
3739     showMessage(QString::fromUtf8(params), LogMiscInput);
3740
3741     params.clear();
3742     params.append('\0');
3743     const QByteArray outBufferCmd = arrayFillCommand("qDumpOutBuffer", params);
3744
3745     postCommand(inBufferCmd);
3746     postCommand(outBufferCmd);
3747 }
3748
3749 void GdbEngine::handleVarAssign(const GdbResponse &)
3750 {
3751     // Everything might have changed, force re-evaluation.
3752     setTokenBarrier();
3753     updateLocals();
3754 }
3755
3756 void GdbEngine::handleVarCreate(const GdbResponse &response)
3757 {
3758     WatchData data = response.cookie.value<WatchData>();
3759     // Happens e.g. when we already issued a var-evaluate command.
3760     if (!data.isValid())
3761         return;
3762     //qDebug() << "HANDLE VARIABLE CREATION:" << data.toString();
3763     if (response.resultClass == GdbResultDone) {
3764         data.variable = data.iname;
3765         setWatchDataType(data, response.data.findChild("type"));
3766         if (watchHandler()->isExpandedIName(data.iname)
3767                 && !response.data.findChild("children").isValid())
3768             data.setChildrenNeeded();
3769         else
3770             data.setChildrenUnneeded();
3771         setWatchDataChildCount(data, response.data.findChild("numchild"));
3772         insertData(data);
3773     } else {
3774         data.setError(QString::fromLocal8Bit(response.data.findChild("msg").data()));
3775         if (data.isWatcher()) {
3776             data.value = WatchData::msgNotInScope();
3777             data.type = " ";
3778             data.setAllUnneeded();
3779             data.setHasChildren(false);
3780             data.valueEnabled = false;
3781             data.valueEditable = false;
3782             insertData(data);
3783         }
3784     }
3785 }
3786
3787 void GdbEngine::handleDebuggingHelperSetup(const GdbResponse &response)
3788 {
3789     if (response.resultClass == GdbResultDone) {
3790     } else {
3791         QString msg = QString::fromLocal8Bit(response.data.findChild("msg").data());
3792         showStatusMessage(tr("Custom dumper setup: %1").arg(msg), 10000);
3793     }
3794 }
3795
3796 void GdbEngine::updateLocals(const QVariant &cookie)
3797 {
3798     m_pendingWatchRequests = 0;
3799     m_pendingBreakpointRequests = 0;
3800     if (hasPython())
3801         updateLocalsPython(false, QByteArray());
3802     else
3803         updateLocalsClassic(cookie);
3804     updateMemoryViews();
3805 }
3806
3807
3808 // Parse a local variable from GdbMi.
3809 WatchData GdbEngine::localVariable(const GdbMi &item,
3810                                    const QStringList &uninitializedVariables,
3811                                    QMap<QByteArray, int> *seen)
3812 {
3813     // Local variables of inlined code are reported as
3814     // 26^done,locals={varobj={exp="this",value="",name="var4",exp="this",
3815     // numchild="1",type="const QtSharedPointer::Basic<CPlusPlus::..."}}
3816     // We do not want these at all. Current hypotheses is that those
3817     // "spurious" locals have _two_ "exp" field. Try to filter them:
3818     QByteArray name;
3819     if (m_isMacGdb) {
3820         int numExps = 0;
3821         foreach (const GdbMi &child, item.children())
3822             numExps += int(child.name() == "exp");
3823         if (numExps > 1)
3824             return WatchData();
3825         name = item.findChild("exp").data();
3826     } else {
3827         name = item.findChild("name").data();
3828     }
3829     const QMap<QByteArray, int>::iterator it  = seen->find(name);
3830     if (it != seen->end()) {
3831         const int n = it.value();
3832         ++(it.value());
3833         WatchData data;
3834         QString nam = _(name);
3835         data.iname = "local." + name + QByteArray::number(n + 1);
3836         data.name = WatchData::shadowedName(nam, n);
3837         if (uninitializedVariables.contains(data.name)) {
3838             data.setError(WatchData::msgNotInScope());
3839             return data;
3840         }
3841         setWatchDataValue(data, item);
3842         //: Type of local variable or parameter shadowed by another
3843         //: variable of the same name in a nested block.
3844         data.setType(GdbEngine::tr("<shadowed>").toUtf8());
3845         data.setHasChildren(false);
3846         return data;
3847     }
3848     seen->insert(name, 1);
3849     WatchData data;
3850     QString nam = _(name);
3851     data.iname = "local." + name;
3852     data.name = nam;
3853     data.exp = name;
3854     setWatchDataType(data, item.findChild("type"));
3855     if (uninitializedVariables.contains(data.name)) {
3856         data.setError(WatchData::msgNotInScope());
3857         return data;
3858     }
3859     if (isSynchronous()) {
3860         setWatchDataValue(data, item);
3861         // We know that the complete list of children is
3862         // somewhere in the response.
3863         data.setChildrenUnneeded();
3864     } else {
3865         // Set value only directly if it is simple enough, otherwise
3866         // pass through the insertData() machinery.
3867         if (isIntOrFloatType(data.type) || isPointerType(data.type))
3868             setWatchDataValue(data, item);
3869         if (isSymbianIntType(data.type)) {
3870             setWatchDataValue(data, item);
3871             data.setHasChildren(false);
3872         }
3873     }
3874
3875     if (!watchHandler()->isExpandedIName(data.iname))
3876         data.setChildrenUnneeded();
3877
3878     GdbMi t = item.findChild("numchild");
3879     if (t.isValid())
3880         data.setHasChildren(t.data().toInt() > 0);
3881     else if (isPointerType(data.type) || data.name == __("this"))
3882         data.setHasChildren(true);
3883     return data;
3884 }
3885
3886 void GdbEngine::insertData(const WatchData &data0)
3887 {
3888     PENDING_DEBUG("INSERT DATA" << data0.toString());
3889     WatchData data = data0;
3890     if (data.value.startsWith(__("mi_cmd_var_create:"))) {
3891         qDebug() << "BOGUS VALUE:" << data.toString();
3892         return;
3893     }
3894     watchHandler()->insertData(data);
3895 }
3896
3897 void GdbEngine::assignValueInDebugger(const WatchData *,
3898     const QString &expression, const QVariant &value)
3899 {
3900     postCommand("-var-delete assign");
3901     postCommand("-var-create assign * " + expression.toLatin1());
3902     postCommand("-var-assign assign " + GdbMi::escapeCString(value.toString().toLatin1()),
3903         Discardable, CB(handleVarAssign));
3904 }
3905
3906 void GdbEngine::watchPoint(const QPoint &pnt)
3907 {
3908     QByteArray x = QByteArray::number(pnt.x());
3909     QByteArray y = QByteArray::number(pnt.y());
3910     postCommand("print '" + qtNamespace() + "QApplication::widgetAt'("
3911             + x + ',' + y + ')',
3912         NeedsStop, CB(handleWatchPoint));
3913 }
3914
3915 void GdbEngine::handleWatchPoint(const GdbResponse &response)
3916 {
3917     if (response.resultClass == GdbResultDone) {
3918         // "$5 = (void *) 0xbfa7ebfc\n"
3919         const QByteArray ba = parsePlainConsoleStream(response);
3920         //qDebug() << "BA: " << ba;
3921         const int posWidget = ba.indexOf("QWidget");
3922         const int pos0x = ba.indexOf("0x", posWidget + 7);
3923         if (posWidget == -1 || pos0x == -1) {
3924             showStatusMessage(tr("Cannot read widget data: %1").arg(_(ba)));
3925         } else {
3926             const QByteArray addr = ba.mid(pos0x);
3927             if (addr.toULongLong(0, 0)) { // Non-null pointer
3928                 const QByteArray ns = qtNamespace();
3929                 const QByteArray type = ns.isEmpty() ? "QWidget*" : QByteArray("'" + ns + "QWidget'*");
3930                 const QString exp = _("(*(struct %1)%2)").arg(_(type)).arg(_(addr));
3931                 // qDebug() << posNs << posWidget << pos0x << addr << ns << type;
3932                 watchHandler()->watchExpression(exp);
3933             } else {
3934                 showStatusMessage(tr("Could not find a widget."));
3935             }
3936         }
3937     }
3938 }
3939
3940
3941 struct MemoryAgentCookie
3942 {
3943     MemoryAgentCookie() : agent(0), token(0), address(0) {}
3944     MemoryAgentCookie(MemoryAgent *agent_, QObject *token_, quint64 address_)
3945         : agent(agent_), token(token_), address(address_)
3946     {}
3947     QPointer<MemoryAgent> agent;
3948     QPointer<QObject> token;
3949     quint64 address;
3950 };
3951
3952 void GdbEngine::changeMemory(MemoryAgent *agent, QObject *token,
3953         quint64 addr, const QByteArray &data)
3954 {
3955     QByteArray cmd = "-data-write-memory " + QByteArray::number(addr) + " d 1";
3956     foreach (char c, data) {
3957         cmd.append(' ');
3958         cmd.append(QByteArray::number(uint(c)));
3959     }
3960     postCommand(cmd, NeedsStop, CB(handleChangeMemory),
3961         QVariant::fromValue(MemoryAgentCookie(agent, token, addr)));
3962 }
3963
3964 void GdbEngine::handleChangeMemory(const GdbResponse &response)
3965 {
3966     Q_UNUSED(response);
3967 }
3968
3969 void GdbEngine::fetchMemory(MemoryAgent *agent, QObject *token, quint64 addr,
3970                             quint64 length)
3971 {
3972     postCommand("-data-read-memory " + QByteArray::number(addr) + " x 1 1 "
3973             + QByteArray::number(length),
3974         NeedsStop, CB(handleFetchMemory),
3975         QVariant::fromValue(MemoryAgentCookie(agent, token, addr)));
3976 }
3977
3978 void GdbEngine::handleFetchMemory(const GdbResponse &response)
3979 {
3980     // ^done,addr="0x08910c88",nr-bytes="16",total-bytes="16",
3981     // next-row="0x08910c98",prev-row="0x08910c78",next-page="0x08910c98",
3982     // prev-page="0x08910c78",memory=[{addr="0x08910c88",
3983     // data=["1","0","0","0","5","0","0","0","0","0","0","0","0","0","0","0"]}]
3984     MemoryAgentCookie ac = response.cookie.value<MemoryAgentCookie>();
3985     QTC_ASSERT(ac.agent, return);
3986     QByteArray ba;
3987     GdbMi memory = response.data.findChild("memory");
3988     QTC_ASSERT(memory.children().size() <= 1, return);
3989     if (memory.children().isEmpty())
3990         return;
3991     GdbMi memory0 = memory.children().at(0); // we asked for only one 'row'
3992     GdbMi data = memory0.findChild("data");
3993     foreach (const GdbMi &child, data.children()) {
3994         bool ok = true;
3995         unsigned char c = '?';
3996         c = child.data().toUInt(&ok, 0);
3997         QTC_ASSERT(ok, return);
3998         ba.append(c);
3999     }
4000     ac.agent->addLazyData(ac.token, ac.address, ba);
4001 }
4002
4003 class DisassemblerAgentCookie
4004 {
4005 public:
4006     DisassemblerAgentCookie() : agent(0) {}
4007     DisassemblerAgentCookie(DisassemblerAgent *agent_) : agent(agent_) {}
4008
4009 public:
4010     QPointer<DisassemblerAgent> agent;
4011 };
4012
4013 void GdbEngine::fetchDisassembler(DisassemblerAgent *agent)
4014 {
4015     // As of 7.2 the MI output is often less informative then the CLI version.
4016     // So globally fall back to CLI.
4017     if (agent->isMixed())
4018         fetchDisassemblerByCliPointMixed(agent);
4019     else
4020         fetchDisassemblerByCliPointPlain(agent);
4021 #if 0
4022     if (agent->isMixed())
4023         fetchDisassemblerByMiRangeMixed(agent)
4024     else
4025         fetchDisassemblerByMiRangePlain(agent);
4026 #endif
4027 }
4028
4029 #if 0
4030 void GdbEngine::fetchDisassemblerByMiRangePlain(const DisassemblerAgentCookie &ac0)
4031 {
4032     // Disassemble full function:
4033     const StackFrame &frame = agent->frame();
4034     DisassemblerAgentCookie ac = ac0;
4035     QTC_ASSERT(ac.agent, return);
4036     const quint64 address = ac.agent->address();
4037     QByteArray cmd = "-data-disassemble"
4038         " -f " + frame.file.toLocal8Bit() +
4039         " -l " + QByteArray::number(frame.line) + " -n -1 -- 1";
4040     postCommand(cmd, Discardable, CB(handleFetchDisassemblerByMiPointMixed),
4041         QVariant::fromValue(DisassemblerAgentCookie(agent)));
4042 }
4043 #endif
4044
4045 #if 0
4046 void GdbEngine::fetchDisassemblerByMiRangeMixed(const DisassemblerAgentCookie &ac0)
4047 {
4048     DisassemblerAgentCookie ac = ac0;
4049     QTC_ASSERT(ac.agent, return);
4050     const quint64 address = ac.agent->address();
4051     QByteArray start = QByteArray::number(address - 20, 16);
4052     QByteArray end = QByteArray::number(address + 100, 16);
4053     // -data-disassemble [ -s start-addr -e end-addr ]
4054     //  | [ -f filename -l linenum [ -n lines ] ] -- mode
4055     postCommand("-data-disassemble -s 0x" + start + " -e 0x" + end + " -- 1",
4056         Discardable, CB(handleFetchDisassemblerByMiRangeMixed),
4057         QVariant::fromValue(ac));
4058 }
4059 #endif
4060
4061 #if 0
4062 void GdbEngine::fetchDisassemblerByMiRangePlain(const DisassemblerAgentCookie &ac0)
4063 {
4064     DisassemblerAgentCookie ac = ac0;
4065     QTC_ASSERT(ac.agent, return);
4066     const quint64 address = ac.agent->address();
4067     QByteArray start = QByteArray::number(address - 20, 16);
4068     QByteArray end = QByteArray::number(address + 100, 16);
4069     // -data-disassemble [ -s start-addr -e end-addr ]
4070     //  | [ -f filename -l linenum [ -n lines ] ] -- mode
4071     postCommand("-data-disassemble -s 0x" + start + " -e 0x" + end + " -- 0",
4072         Discardable, CB(handleFetchDisassemblerByMiRangePlain),
4073         QVariant::fromValue(ac));
4074 }
4075 #endif
4076
4077 void GdbEngine::fetchDisassemblerByCliPointMixed(const DisassemblerAgentCookie &ac0)
4078 {
4079     DisassemblerAgentCookie ac = ac0;
4080     QTC_ASSERT(ac.agent, return);
4081     const quint64 address = ac.agent->address();
4082     QByteArray cmd = "disassemble /m 0x" + QByteArray::number(address, 16);
4083     postCommand(cmd, Discardable, CB(handleFetchDisassemblerByCliPointMixed),
4084         QVariant::fromValue(ac));
4085 }
4086
4087 void GdbEngine::fetchDisassemblerByCliPointPlain(const DisassemblerAgentCookie &ac0)
4088 {
4089     DisassemblerAgentCookie ac = ac0;
4090     QTC_ASSERT(ac.agent, return);
4091     const quint64 address = ac.agent->address();
4092     QByteArray cmd = "disassemble 0x" + QByteArray::number(address, 16);
4093     postCommand(cmd, Discardable, CB(handleFetchDisassemblerByCliPointPlain),
4094         QVariant::fromValue(ac));
4095 }
4096
4097 void GdbEngine::fetchDisassemblerByCliRangeMixed(const DisassemblerAgentCookie &ac0)
4098 {
4099     DisassemblerAgentCookie ac = ac0;
4100     QTC_ASSERT(ac.agent, return);
4101     const quint64 address = ac.agent->address();
4102     QByteArray start = QByteArray::number(address - 20, 16);
4103     QByteArray end = QByteArray::number(address + 100, 16);
4104     const char sep = m_disassembleUsesComma ? ',' : ' ';
4105     QByteArray cmd = "disassemble /m 0x" + start + sep + "0x" + end;
4106     postCommand(cmd, Discardable, CB(handleFetchDisassemblerByCliRangeMixed),
4107         QVariant::fromValue(ac));
4108 }
4109
4110 void GdbEngine::fetchDisassemblerByCliRangePlain(const DisassemblerAgentCookie &ac0)
4111 {
4112     DisassemblerAgentCookie ac = ac0;
4113     QTC_ASSERT(ac.agent, return);
4114     const quint64 address = ac.agent->address();
4115     QByteArray start = QByteArray::number(address - 20, 16);
4116     QByteArray end = QByteArray::number(address + 100, 16);
4117     const char sep = m_disassembleUsesComma ? ',' : ' ';
4118     QByteArray cmd = "disassemble 0x" + start + sep + "0x" + end;
4119     postCommand(cmd, Discardable, CB(handleFetchDisassemblerByCliRangePlain),
4120         QVariant::fromValue(ac));
4121 }
4122
4123 static DisassemblerLine parseLine(const GdbMi &line)
4124 {
4125     DisassemblerLine dl;
4126     QByteArray address = line.findChild("address").data();
4127     dl.address = address.toULongLong(0, 0);
4128     dl.data = _(line.findChild("inst").data());
4129     return dl;
4130 }
4131
4132 DisassemblerLines GdbEngine::parseMiDisassembler(const GdbMi &lines)
4133 {
4134     // ^done,data={asm_insns=[src_and_asm_line={line="1243",file=".../app.cpp",
4135     // line_asm_insn=[{address="0x08054857",func-name="main",offset="27",
4136     // inst="call 0x80545b0 <_Z13testQFileInfov>"}]},
4137     // src_and_asm_line={line="1244",file=".../app.cpp",
4138     // line_asm_insn=[{address="0x0805485c",func-name="main",offset="32",
4139     //inst="call 0x804cba1 <_Z11testObject1v>"}]}]}
4140     // - or - (non-Mac)
4141     // ^done,asm_insns=[
4142     // {address="0x0805acf8",func-name="...",offset="25",inst="and $0xe8,%al"},
4143     // {address="0x0805acfa",func-name="...",offset="27",inst="pop %esp"}, ..]
4144     // - or - (MAC)
4145     // ^done,asm_insns={
4146     // {address="0x0d8f69e0",func-name="...",offset="1952",inst="add $0x0,%al"},..}
4147
4148     QStringList fileContents;
4149     bool fileLoaded = false;
4150     DisassemblerLines result;
4151
4152     // FIXME: Performance?
4153     foreach (const GdbMi &child, lines.children()) {
4154         if (child.hasName("src_and_asm_line")) {
4155             // Mixed mode.
4156             if (!fileLoaded) {
4157                 QString fileName = QFile::decodeName(child.findChild("file").data());
4158                 fileName = cleanupFullName(fileName);
4159                 QFile file(fileName);
4160                 file.open(QIODevice::ReadOnly);
4161                 QTextStream ts(&file);
4162                 fileContents = ts.readAll().split(QLatin1Char('\n'));
4163                 fileLoaded = true;
4164             }
4165             int line = child.findChild("line").data().toInt();
4166             if (line >= 1 && line <= fileContents.size())
4167                 result.appendComment(fileContents.at(line - 1));
4168             GdbMi insn = child.findChild("line_asm_insn");
4169             foreach (const GdbMi &item, insn.children())
4170                 result.appendLine(parseLine(item));
4171         } else {
4172             // The non-mixed version.
4173             result.appendLine(parseLine(child));
4174         }
4175     }
4176     return result;
4177 }
4178
4179 DisassemblerLines GdbEngine::parseCliDisassembler(const GdbMi &output)
4180 {
4181     const QString someSpace = _("        ");
4182     // First line is something like
4183     // "Dump of assembler code from 0xb7ff598f to 0xb7ff5a07:"
4184     DisassemblerLines dlines;
4185     QByteArray lastFunction;
4186     foreach (const QByteArray &line0, output.data().split('\n')) {
4187         QByteArray line = line0.trimmed();
4188         if (line.startsWith("=> "))
4189             line = line.mid(3);
4190         if (line.isEmpty())
4191             continue;
4192         if (line.startsWith("Current language:"))
4193             continue;
4194         if (line.startsWith("Dump of assembler"))
4195             continue;
4196         if (line.startsWith("The current source"))
4197             continue;
4198         if (line.startsWith("End of assembler"))
4199             continue;
4200         if (line.startsWith("0x")) {
4201             int pos1 = line.indexOf('<') + 1;
4202             int pos2 = line.indexOf('+', pos1);
4203             int pos3 = line.indexOf('>', pos1);
4204             if (pos1 < pos2 && pos2 < pos3) {
4205                 QByteArray function = line.mid(pos1, pos2 - pos1);
4206                 if (function != lastFunction) {
4207                     dlines.appendComment(QString());
4208                     dlines.appendComment(_("Function: ") + _(function));
4209                     lastFunction = function;
4210                 }
4211                 line.replace(pos1, pos2 - pos1, "");
4212             }
4213             if (pos3 - pos2 == 1)
4214                 line.insert(pos2 + 1, "000");
4215             if (pos3 - pos2 == 2)
4216                 line.insert(pos2 + 1, "00");
4217             if (pos3 - pos2 == 3)
4218                 line.insert(pos2 + 1, "0");
4219             dlines.appendLine(DisassemblerLine(_(line)));
4220             continue;
4221         }
4222         dlines.appendComment(someSpace + _(line));
4223     }
4224     return dlines;
4225 }
4226
4227 DisassemblerLines GdbEngine::parseDisassembler(const GdbMi &data)
4228 {
4229     // Apple's gdb produces MI output even for CLI commands.
4230     // FIXME: Check whether wrapping this into -interpreter-exec console
4231     // (i.e. usgind the 'ConsoleCommand' GdbCommandFlag makes a
4232     // difference.
4233     GdbMi lines = data.findChild("asm_insns");
4234     if (lines.isValid())
4235         return parseMiDisassembler(lines);
4236     GdbMi output = data.findChild("consolestreamoutput");
4237     return parseCliDisassembler(output);
4238 }
4239
4240 void GdbEngine::handleDisassemblerCheck(const GdbResponse &response)
4241 {
4242     m_disassembleUsesComma = response.resultClass != GdbResultDone;
4243 }
4244
4245 void GdbEngine::handleFetchDisassemblerByCliPointMixed(const GdbResponse &response)
4246 {
4247     DisassemblerAgentCookie ac = response.cookie.value<DisassemblerAgentCookie>();
4248     QTC_ASSERT(ac.agent, return);
4249
4250     if (response.resultClass == GdbResultDone) {
4251         DisassemblerLines dlines = parseDisassembler(response.data);
4252         if (dlines.coversAddress(ac.agent->address())) {
4253             ac.agent->setContents(dlines);
4254             return;
4255         }
4256     }
4257     fetchDisassemblerByCliPointPlain(ac);
4258 }
4259
4260 void GdbEngine::handleFetchDisassemblerByCliPointPlain(const GdbResponse &response)
4261 {
4262     DisassemblerAgentCookie ac = response.cookie.value<DisassemblerAgentCookie>();
4263     QTC_ASSERT(ac.agent, return);
4264
4265     if (response.resultClass == GdbResultDone) {
4266         DisassemblerLines dlines = parseDisassembler(response.data);
4267         if (dlines.coversAddress(ac.agent->address())) {
4268             ac.agent->setContents(dlines);
4269             return;
4270         }
4271     }
4272     if (ac.agent->isMixed())
4273         fetchDisassemblerByCliRangeMixed(ac);
4274     else
4275         fetchDisassemblerByCliRangePlain(ac);
4276 }
4277
4278 void GdbEngine::handleFetchDisassemblerByCliRangeMixed(const GdbResponse &response)
4279 {
4280     DisassemblerAgentCookie ac = response.cookie.value<DisassemblerAgentCookie>();
4281     QTC_ASSERT(ac.agent, return);
4282
4283     if (response.resultClass == GdbResultDone) {
4284         DisassemblerLines dlines = parseDisassembler(response.data);
4285         if (dlines.coversAddress(ac.agent->address())) {
4286             ac.agent->setContents(dlines);
4287             return;
4288         }
4289     }
4290     fetchDisassemblerByCliRangePlain(ac);
4291 }
4292
4293 void GdbEngine::handleFetchDisassemblerByCliRangePlain(const GdbResponse &response)
4294 {
4295     DisassemblerAgentCookie ac = response.cookie.value<DisassemblerAgentCookie>();
4296     QTC_ASSERT(ac.agent, return);
4297
4298     if (response.resultClass == GdbResultDone) {
4299         DisassemblerLines dlines = parseDisassembler(response.data);
4300         if (dlines.size()) {
4301             ac.agent->setContents(dlines);
4302             return;
4303         }
4304     }
4305
4306     // Finally, give up.
4307     //76^error,msg="No function contains program counter for selected..."
4308     //76^error,msg="No function contains specified address."
4309     //>568^error,msg="Line number 0 out of range;
4310     QByteArray msg = response.data.findChild("msg").data();
4311     showStatusMessage(tr("Disassembler failed: %1")
4312         .arg(QString::fromLocal8Bit(msg)), 5000);
4313 }
4314
4315 // Binary/configuration check logic.
4316
4317 static QString gdbBinary(const DebuggerStartParameters &sp)
4318 {
4319     // 1) Environment.
4320     const QByteArray envBinary = qgetenv("QTC_DEBUGGER_PATH");
4321     if (!envBinary.isEmpty())
4322         return QString::fromLocal8Bit(envBinary);
4323     // 2) Command explicitly specified.
4324     if (!sp.debuggerCommand.isEmpty()) {
4325 #ifdef Q_OS_WIN
4326         // Do not use a CDB binary if we got started for a project with MSVC runtime.
4327         const bool abiMatch = sp.toolChainAbi.os() != ProjectExplorer::Abi::WindowsOS
4328                 || sp.toolChainAbi.osFlavor() == ProjectExplorer::Abi::WindowsMSysFlavor;
4329 #else
4330         const bool abiMatch = true;
4331 #endif
4332         if (abiMatch)
4333             return sp.debuggerCommand;
4334     }
4335     // 3) Find one from tool chains.
4336     return debuggerCore()->debuggerForAbi(sp.toolChainAbi, GdbEngineType);
4337 }
4338
4339 bool checkGdbConfiguration(const DebuggerStartParameters &sp, ConfigurationCheck *check)
4340 {
4341     const QString binary = gdbBinary(sp);
4342     if (gdbBinary(sp).isEmpty()) {
4343         check->errorDetails.push_back(msgNoGdbBinaryForToolChain(sp.toolChainAbi));
4344         check->settingsCategory = QLatin1String(ProjectExplorer::Constants::TOOLCHAIN_SETTINGS_CATEGORY);
4345         check->settingsPage = QLatin1String(ProjectExplorer::Constants::TOOLCHAIN_SETTINGS_CATEGORY);
4346         return false;
4347     }
4348 #ifdef Q_OS_WIN
4349     // See initialization below, we need an absolute path to be able to locate Python on Windows.
4350     if (!QFileInfo(binary).isAbsolute()) {
4351         check->errorDetails.push_back(GdbEngine::tr("The gdb location must be given as an "
4352                                                     "absolute path in the debugger settings (%1).").arg(binary));
4353         check->settingsCategory = QLatin1String(ProjectExplorer::Constants::TOOLCHAIN_SETTINGS_CATEGORY);
4354         check->settingsPage = QLatin1String(ProjectExplorer::Constants::TOOLCHAIN_SETTINGS_CATEGORY);
4355         return false;
4356     }
4357 #endif
4358     return true;
4359 }
4360
4361 //
4362 // Starting up & shutting down
4363 //
4364
4365 bool GdbEngine::startGdb(const QStringList &args, const QString &settingsIdHint)
4366 {
4367     gdbProc()->disconnect(); // From any previous runs
4368
4369     const DebuggerStartParameters &sp = startParameters();
4370     m_gdb = gdbBinary(sp);
4371     if (m_gdb.isEmpty()) {
4372         handleAdapterStartFailed(
4373             msgNoGdbBinaryForToolChain(sp.toolChainAbi),
4374             _(Constants::DEBUGGER_COMMON_SETTINGS_ID));
4375         return false;
4376     }
4377     QStringList gdbArgs;
4378     gdbArgs << _("-i");
4379     gdbArgs << _("mi");
4380     if (!debuggerCore()->boolSetting(LoadGdbInit))
4381         gdbArgs << _("-n");
4382     gdbArgs += args;
4383
4384 #ifdef Q_OS_WIN
4385     // Set python path. By convention, python is located below gdb executable.
4386     // Extend the environment set on the process in startAdapter().
4387     const QFileInfo fi(m_gdb);
4388     QTC_ASSERT(fi.isAbsolute(), return false; )
4389
4390     const QString winPythonVersion = _(winPythonVersionC);
4391     const QDir dir = fi.absoluteDir();
4392
4393     QProcessEnvironment environment = gdbProc()->processEnvironment();
4394     const QString pythonPathVariable = _("PYTHONPATH");
4395     QString pythonPath;
4396
4397     const QString environmentPythonPath = environment.value(pythonPathVariable);
4398     if (dir.exists(winPythonVersion)) {
4399         pythonPath = QDir::toNativeSeparators(dir.absoluteFilePath(winPythonVersion));
4400     } else if (dir.exists(_("lib"))) {
4401         // Needed for our gdb 7.2 packages
4402         pythonPath = QDir::toNativeSeparators(dir.absoluteFilePath(_("lib")));
4403     } else {
4404         pythonPath = environmentPythonPath;
4405     }
4406     if (pythonPath.isEmpty()) {
4407         const QString nativeGdb = QDir::toNativeSeparators(m_gdb);
4408         showMessage(_("GDB %1 CANNOT FIND THE PYTHON INSTALLATION.").arg(nativeGdb));
4409         showStatusMessage(_("%1 cannot find python").arg(nativeGdb));
4410         const QString msg = tr("The GDB installed at %1 cannot "
4411            "find a valid python installation in its %2 subdirectory.\n"
4412            "You may set the environment variable PYTHONPATH to point to your installation.")
4413                 .arg(nativeGdb).arg(winPythonVersion);
4414         handleAdapterStartFailed(msg, settingsIdHint);
4415         return false;
4416     }
4417     showMessage(_("Python path: %1").arg(pythonPath), LogMisc);
4418     // Apply to process
4419     if (pythonPath != environmentPythonPath) {
4420         environment.insert(pythonPathVariable, pythonPath);
4421         gdbProc()->setProcessEnvironment(environment);
4422     }
4423 #endif
4424
4425     connect(gdbProc(), SIGNAL(error(QProcess::ProcessError)),
4426         SLOT(handleGdbError(QProcess::ProcessError)));
4427     connect(gdbProc(), SIGNAL(finished(int, QProcess::ExitStatus)),
4428         SLOT(handleGdbFinished(int, QProcess::ExitStatus)));
4429     connect(gdbProc(), SIGNAL(readyReadStandardOutput()),
4430         SLOT(readGdbStandardOutput()));
4431     connect(gdbProc(), SIGNAL(readyReadStandardError()),
4432         SLOT(readGdbStandardError()));
4433
4434     showMessage(_("STARTING ") + m_gdb + _(" ") + gdbArgs.join(_(" ")));
4435     gdbProc()->start(m_gdb, gdbArgs);
4436
4437     if (!gdbProc()->waitForStarted()) {
4438         const QString msg = errorMessage(QProcess::FailedToStart);
4439         handleAdapterStartFailed(msg, settingsIdHint);
4440         return false;
4441     }
4442
4443     showMessage(_("GDB STARTED, INITIALIZING IT"));
4444     postCommand("show version", CB(handleShowVersion));
4445
4446     //postCommand("-enable-timings");
4447     //postCommand("set print static-members off"); // Seemingly doesn't work.
4448     //postCommand("set debug infrun 1");
4449     //postCommand("define hook-stop\n-thread-list-ids\n-stack-list-frames\nend");
4450     //postCommand("define hook-stop\nprint 4\nend");
4451     //postCommand("define hookpost-stop\nprint 5\nend");
4452     //postCommand("define hook-call\nprint 6\nend");
4453     //postCommand("define hookpost-call\nprint 7\nend");
4454     //postCommand("set print object on"); // works with CLI, but not MI
4455     //postCommand("set step-mode on");  // we can't work with that yes
4456     //postCommand("set exec-done-display on");
4457     //postCommand("set print pretty on");
4458     //postCommand("set confirm off");
4459     //postCommand("set pagination off");
4460
4461     // The following does not work with 6.3.50-20050815 (Apple version gdb-1344)
4462     // (Mac OS 10.6), but does so for gdb-966 (10.5):
4463     //postCommand("set print inferior-events 1");
4464
4465     postCommand("set breakpoint pending on");
4466     postCommand("set print elements 10000");
4467     // Produces a few messages during symtab loading
4468     //postCommand("set verbose on");
4469
4470     //postCommand("set substitute-path /var/tmp/qt-x11-src-4.5.0 "
4471     //    "/home/sandbox/qtsdk-2009.01/qt");
4472
4473     // one of the following is needed to prevent crashes in gdb on code like:
4474     //  template <class T> T foo() { return T(0); }
4475     //  int main() { return foo<int>(); }
4476     //  (gdb) call 'int foo<int>'()
4477     //  /build/buildd/gdb-6.8/gdb/valops.c:2069: internal-error:
4478     postCommand("set overload-resolution off");
4479     //postCommand(_("set demangle-style none"));
4480     // From the docs:
4481     //  Stop means reenter debugger if this signal happens (implies print).
4482     //  Print means print a message if this signal happens.
4483     //  Pass means let program see this signal;
4484     //  otherwise program doesn't know.
4485     //  Pass and Stop may be combined.
4486     // We need "print" as otherwise we will get no feedback whatsoever
4487     // when Custom DebuggingHelper crash (which happen regularly when accessing
4488     // uninitialized variables).
4489     postCommand("handle SIGSEGV nopass stop print");
4490
4491     // This is useful to kill the inferior whenever gdb dies.
4492     //postCommand(_("handle SIGTERM pass nostop print"));
4493
4494     postCommand("set unwindonsignal on");
4495     postCommand("pwd");
4496     postCommand("set width 0");
4497     postCommand("set height 0");
4498     postCommand("set auto-solib-add on");
4499
4500     if (debuggerCore()->boolSetting(TargetAsync)) {
4501         postCommand("set target-async on");
4502         postCommand("set non-stop on");
4503     }
4504
4505     // Work around http://bugreports.qt.nokia.com/browse/QTCREATORBUG-2004
4506     postCommand("maintenance set internal-warning quit no", ConsoleCommand);
4507     postCommand("maintenance set internal-error quit no", ConsoleCommand);
4508
4509     postCommand("disassemble 0 0", ConsoleCommand, CB(handleDisassemblerCheck));
4510
4511     loadPythonDumpers();
4512
4513     QString scriptFileName = debuggerCore()->stringSetting(GdbScriptFile);
4514     if (!scriptFileName.isEmpty()) {
4515         if (QFileInfo(scriptFileName).isReadable()) {
4516             postCommand("source " + scriptFileName.toLocal8Bit());
4517         } else {
4518             showMessageBox(QMessageBox::Warning,
4519             tr("Cannot find debugger initialization script"),
4520             tr("The debugger settings point to a script file at '%1' "
4521                "which is not accessible. If a script file is not needed, "
4522                "consider clearing that entry to avoid this warning. "
4523               ).arg(scriptFileName));
4524         }
4525     }
4526
4527     return true;
4528 }
4529
4530 void GdbEngine::loadPythonDumpers()
4531 {
4532     const QByteArray dumperSourcePath =
4533         Core::ICore::instance()->resourcePath().toLocal8Bit() + "/gdbmacros/";
4534
4535     postCommand("python execfile('" + dumperSourcePath + "dumper.py')",
4536         ConsoleCommand|NonCriticalResponse);
4537     postCommand("python execfile('" + dumperSourcePath + "gdbmacros.py')",
4538         ConsoleCommand|NonCriticalResponse);
4539     postCommand("bbsetup",
4540         ConsoleCommand, CB(handleHasPython));
4541 }
4542
4543 void GdbEngine::handleGdbError(QProcess::ProcessError error)
4544 {
4545     const QString msg = errorMessage(error);
4546     showMessage(_("HANDLE GDB ERROR: ") + msg);
4547     // Show a message box for asynchronously reported issues.
4548     switch (error) {
4549     case QProcess::FailedToStart:
4550         // This should be handled by the code trying to start the process.
4551         break;
4552     case QProcess::Crashed:
4553         // This will get a processExited() as well.
4554         break;
4555     case QProcess::ReadError:
4556     case QProcess::WriteError:
4557     case QProcess::Timedout:
4558     default:
4559         //gdbProc()->kill();
4560         //notifyEngineIll();
4561         showMessageBox(QMessageBox::Critical, tr("GDB I/O Error"), msg);
4562         break;
4563     }
4564 }
4565
4566 void GdbEngine::handleGdbFinished(int code, QProcess::ExitStatus type)
4567 {
4568     if (m_commandTimer.isActive())
4569         m_commandTimer.stop();
4570
4571     showMessage(_("GDB PROCESS FINISHED, status %1, code %2").arg(type).arg(code));
4572
4573     switch (state()) {
4574     case EngineShutdownRequested:
4575         notifyEngineShutdownOk();
4576         break;
4577     case InferiorRunOk:
4578         // This could either be a real gdb crash or a quickly exited inferior
4579         // in the terminal adapter. In this case the stub proc will die soon,
4580         // too, so there's no need to act here.
4581         showMessage(_("The gdb process exited somewhat unexpectedly."));
4582         notifyEngineSpontaneousShutdown();
4583         break;
4584     default: {
4585         notifyEngineIll(); // Initiate shutdown sequence
4586         const QString msg = type == QProcess::CrashExit ?
4587                     tr("The gdb process crashed.") :
4588                     tr("The gdb process exited unexpectedly (code %1)").arg(code);
4589         showMessageBox(QMessageBox::Critical, tr("Unexpected GDB Exit"), msg);
4590         break;
4591     }
4592     }
4593 }
4594
4595 void GdbEngine::handleAdapterStartFailed(const QString &msg,
4596     const QString &settingsIdHint)
4597 {
4598     QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
4599     showMessage(_("ADAPTER START FAILED"));
4600     if (!msg.isEmpty()) {
4601         const QString title = tr("Adapter start failed");
4602         if (settingsIdHint.isEmpty()) {
4603             Core::ICore::instance()->showWarningWithOptions(title, msg);
4604         } else {
4605             Core::ICore::instance()->showWarningWithOptions(title, msg, QString(),
4606                 _(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY), settingsIdHint);
4607         }
4608     }
4609     notifyEngineSetupFailed();
4610 }
4611
4612 void GdbEngine::handleAdapterStarted()
4613 {
4614     QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
4615     showMessage(_("ADAPTER SUCCESSFULLY STARTED"));
4616     notifyEngineSetupOk();
4617 }
4618
4619 void GdbEngine::setupInferior()
4620 {
4621     QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
4622     showStatusMessage(tr("Setting up inferior..."));
4623     m_gdbAdapter->setupInferior();
4624 }
4625
4626 void GdbEngine::notifyInferiorSetupFailed()
4627 {
4628     // FIXME: that's not enough to stop gdb from getting confused
4629     // by a timeout of the adapter.
4630     //resetCommandQueue();
4631     DebuggerEngine::notifyInferiorSetupFailed();
4632 }
4633
4634 void GdbEngine::handleInferiorPrepared()
4635 {
4636     typedef GlobalDebuggerOptions::SourcePathMap SourcePathMap;
4637     typedef SourcePathMap::const_iterator SourcePathMapIterator;
4638
4639     QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
4640
4641     // Apply source path mappings from global options.
4642     const SourcePathMap sourcePathMap =
4643             DebuggerSourcePathMappingWidget::mergePlatformQtPath(
4644                 startParameters().qtInstallPath,
4645                 debuggerCore()->globalDebuggerOptions()->sourcePathMap);
4646
4647     if (!sourcePathMap.isEmpty()) {
4648         const SourcePathMapIterator cend = sourcePathMap.constEnd();
4649         for (SourcePathMapIterator it = sourcePathMap.constBegin(); it != cend; ++it) {
4650             QByteArray command = "set substitute-path ";
4651             command += it.key().toLocal8Bit();
4652             command += ' ';
4653             command += it.value().toLocal8Bit();
4654             postCommand(command);
4655         }
4656     }
4657
4658     // Initial attempt to set breakpoints.
4659     if (startParameters().startMode != AttachCore) {
4660         showStatusMessage(tr("Setting breakpoints..."));
4661         showMessage(tr("Setting breakpoints..."));
4662         attemptBreakpointSynchronization();
4663     }
4664
4665     if (m_cookieForToken.isEmpty()) {
4666         finishInferiorSetup();
4667     } else {
4668         QTC_ASSERT(m_commandsDoneCallback == 0, /**/);
4669         m_commandsDoneCallback = &GdbEngine::finishInferiorSetup;
4670     }
4671 }
4672
4673 void GdbEngine::finishInferiorSetup()
4674 {
4675     QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
4676     // Extract Qt namespace.
4677     QString fileName;
4678     {
4679         QTemporaryFile symbols(QDir::tempPath() + _("/gdb_ns_"));
4680         symbols.open();
4681         fileName = symbols.fileName();
4682     }
4683     postCommand("maint print msymbols " + fileName.toLocal8Bit(),
4684         CB(handleNamespaceExtraction), fileName);
4685 }
4686
4687 void GdbEngine::handleNamespaceExtraction(const GdbResponse &response)
4688 {
4689     QFile file(response.cookie.toString());
4690     file.open(QIODevice::ReadOnly);
4691     QByteArray ba = file.readAll();
4692     //file.remove();
4693     int pos = ba.indexOf("7QString9fromAscii");
4694     int pos1 = pos - 1;
4695     while (pos1 > 0 && ba.at(pos1) != 'N' && ba.at(pos1) > '@')
4696         --pos1;
4697     ++pos1;
4698     const QByteArray ns = ba.mid(pos1, pos - pos1);
4699     if (ns.isEmpty()) {
4700         showMessage(_("FOUND NON-NAMESPACED QT"));
4701     } else {
4702         showMessage(_("FOUND NAMESPACED QT: " + ns));
4703         setQtNamespace(ns + "::");
4704     }
4705     postCommand("-break-insert -f '" + qtNamespace() + "qFatal'",
4706          CB(handleBreakOnQFatal));
4707 }
4708
4709 void GdbEngine::handleBreakOnQFatal(const GdbResponse &response)
4710 {
4711     if (response.resultClass == GdbResultDone) {
4712         GdbMi bkpt = response.data.findChild("bkpt");
4713         GdbMi number = bkpt.findChild("number");
4714         int bpnr = number.data().toInt();
4715         if (bpnr) {
4716             m_qFatalBreakpointNumber = bpnr;
4717             postCommand("-break-commands " + number.data() + " return");
4718         }
4719     }
4720
4721     // Continue setup.
4722     notifyInferiorSetupOk();
4723 }
4724
4725 void GdbEngine::runEngine()
4726 {
4727     QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
4728     m_gdbAdapter->runEngine();
4729 }
4730
4731 void GdbEngine::notifyInferiorSetupFailed(const QString &msg)
4732 {
4733     showStatusMessage(tr("Failed to start application: ") + msg);
4734     if (state() == EngineSetupFailed) {
4735         showMessage(_("INFERIOR START FAILED, BUT ADAPTER DIED ALREADY"));
4736         return; // Adapter crashed meanwhile, so this notification is meaningless.
4737     }
4738     showMessage(_("INFERIOR START FAILED"));
4739     showMessageBox(QMessageBox::Critical, tr("Failed to start application"), msg);
4740     DebuggerEngine::notifyInferiorSetupFailed();
4741 }
4742
4743 void GdbEngine::handleAdapterCrashed(const QString &msg)
4744 {
4745     showMessage(_("ADAPTER CRASHED"));
4746
4747     // The adapter is expected to have cleaned up after itself when we get here,
4748     // so the effect is about the same as AdapterStartFailed => use it.
4749     // Don't bother with state transitions - this can happen in any state and
4750     // the end result is always the same, so it makes little sense to find a
4751     // "path" which does not assert.
4752     if (state() == EngineSetupRequested)
4753         notifyEngineSetupFailed();
4754     else
4755         notifyEngineIll();
4756
4757     // No point in being friendly here ...
4758     gdbProc()->kill();
4759
4760     if (!msg.isEmpty())
4761         showMessageBox(QMessageBox::Critical, tr("Adapter crashed"), msg);
4762 }
4763
4764 void GdbEngine::setUseDebuggingHelpers(const QVariant &)
4765 {
4766     setTokenBarrier();
4767     updateLocals();
4768 }
4769
4770 bool GdbEngine::hasPython() const
4771 {
4772     return m_hasPython;
4773 }
4774
4775 void GdbEngine::createFullBacktrace()
4776 {
4777     postCommand("thread apply all bt full",
4778         NeedsStop|ConsoleCommand, CB(handleCreateFullBacktrace));
4779 }
4780
4781 void GdbEngine::handleCreateFullBacktrace(const GdbResponse &response)
4782 {
4783     if (response.resultClass == GdbResultDone) {
4784         debuggerCore()->openTextEditor(_("Backtrace $"),
4785             _(response.data.findChild("consolestreamoutput").data()));
4786     }
4787 }
4788
4789 void GdbEngine::resetCommandQueue()
4790 {
4791     m_commandTimer.stop();
4792     if (!m_cookieForToken.isEmpty()) {
4793         QString msg;
4794         QTextStream ts(&msg);
4795         ts << "RESETING COMMAND QUEUE. LEFT OVER TOKENS: ";
4796         foreach (const GdbCommand &cookie, m_cookieForToken)
4797             ts << "CMD:" << cookie.command << cookie.callbackName;
4798         m_cookieForToken.clear();
4799         showMessage(msg);
4800     }
4801 }
4802
4803 void GdbEngine::handleRemoteSetupDone(int gdbServerPort, int qmlPort)
4804 {
4805     m_gdbAdapter->handleRemoteSetupDone(gdbServerPort, qmlPort);
4806 }
4807
4808 void GdbEngine::handleRemoteSetupFailed(const QString &message)
4809 {
4810     m_gdbAdapter->handleRemoteSetupFailed(message);
4811 }
4812
4813 bool GdbEngine::setupQmlStep(bool on)
4814 {
4815     QTC_ASSERT(isSlaveEngine(), return false);
4816     m_qmlBreakpointNumbers.clear();
4817     //qDebug() << "CLEAR: " << m_qmlBreakpointNumbers;
4818     postCommand("tbreak '" + qtNamespace() + "QScript::FunctionWrapper::proxyCall'\n"
4819         "commands\n"
4820         "set $d=(void*)((FunctionWrapper*)callee)->data->function\n"
4821         "tbreak *$d\nprintf \"QMLBP:%d \\n\",$bpnum\ncontinue\nend",
4822         NeedsStop, CB(handleSetQmlStepBreakpoint));
4823     m_preparedForQmlBreak = on;
4824     return true;
4825 }
4826
4827 void GdbEngine::handleSetQmlStepBreakpoint(const GdbResponse &response)
4828 {
4829     //QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
4830     if (response.resultClass == GdbResultDone) {
4831         // "{logstreamoutput="tbreak 'myns::QScript::FunctionWrapper::proxyCall'\n"
4832         //,consolestreamoutput="Temporary breakpoint 1 at 0xf166e7:
4833         // file bridge/qscriptfunction.cpp, line 75.\n"}
4834         QByteArray ba = parsePlainConsoleStream(response);
4835         const int pos2 = ba.indexOf(" at 0x");
4836         const int pos1 = ba.lastIndexOf(" ", pos2 - 1) + 1;
4837         QByteArray mid = ba.mid(pos1, pos2 - pos1);
4838         const int bpnr = mid.toInt();
4839         m_qmlBreakpointNumbers[1] = bpnr;
4840         //qDebug() << "SET: " << m_qmlBreakpointNumbers;
4841     }
4842     QTC_ASSERT(masterEngine(), return);
4843     masterEngine()->readyToExecuteQmlStep();
4844 }
4845
4846 bool GdbEngine::isQmlStepBreakpoint1(int bpnr) const
4847 {
4848     //qDebug() << "CHECK 1: " << m_qmlBreakpointNumbers[1] << bpnr;
4849     return bpnr && m_qmlBreakpointNumbers[1] == bpnr;
4850 }
4851
4852 bool GdbEngine::isQmlStepBreakpoint2(int bpnr) const
4853 {
4854     //qDebug() << "CHECK 2: " << m_qmlBreakpointNumbers[2] << bpnr;
4855     return bpnr && m_qmlBreakpointNumbers[2] == bpnr;
4856 }
4857
4858 bool GdbEngine::isQFatalBreakpoint(int bpnr) const
4859 {
4860     return bpnr && m_qFatalBreakpointNumber == bpnr;
4861 }
4862
4863 //
4864 // Factory
4865 //
4866
4867 DebuggerEngine *createGdbEngine(const DebuggerStartParameters &startParameters,
4868     DebuggerEngine *masterEngine)
4869 {
4870     return new GdbEngine(startParameters, masterEngine);
4871 }
4872
4873 void addGdbOptionPages(QList<Core::IOptionsPage *> *opts)
4874 {
4875     opts->push_back(new GdbOptionsPage());
4876 }
4877
4878 } // namespace Internal
4879 } // namespace Debugger
4880
4881 Q_DECLARE_METATYPE(Debugger::Internal::MemoryAgentCookie)
4882 Q_DECLARE_METATYPE(Debugger::Internal::DisassemblerAgentCookie)
4883 Q_DECLARE_METATYPE(Debugger::Internal::GdbMi)