OSDN Git Service

always clear pending command queue before posting shutdown commands
[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) 2009 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** Commercial Usage
10 **
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
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 ** If you are unsure which license is appropriate for your use, please
26 ** contact the sales department at http://qt.nokia.com/contact.
27 **
28 **************************************************************************/
29
30 #define QT_NO_CAST_FROM_ASCII
31
32 #include "gdbengine.h"
33 #include "gdboptionspage.h"
34 #include "trkoptions.h"
35 #include "trkoptionspage.h"
36
37 #include "attachgdbadapter.h"
38 #include "coregdbadapter.h"
39 #include "plaingdbadapter.h"
40 #include "termgdbadapter.h"
41 #include "remotegdbadapter.h"
42 #include "trkgdbadapter.h"
43
44 #include "watchutils.h"
45 #include "debuggeractions.h"
46 #include "debuggeragents.h"
47 #include "debuggerconstants.h"
48 #include "debuggermanager.h"
49 #include "debuggertooltip.h"
50 #include "debuggerstringutils.h"
51 #include "gdbmi.h"
52
53 #include "breakhandler.h"
54 #include "moduleshandler.h"
55 #include "registerhandler.h"
56 #include "stackhandler.h"
57 #include "watchhandler.h"
58 #include "sourcefileswindow.h"
59
60 #include "debuggerdialogs.h"
61
62 #include <utils/qtcassert.h>
63 #include <utils/fancymainwindow.h>
64 #include <texteditor/itexteditor.h>
65 #include <projectexplorer/toolchain.h>
66 #include <coreplugin/icore.h>
67
68 #include <QtCore/QDebug>
69 #include <QtCore/QDir>
70 #include <QtCore/QFileInfo>
71 #include <QtCore/QMetaObject>
72 #include <QtCore/QTime>
73 #include <QtCore/QTimer>
74 #include <QtCore/QTextStream>
75
76 #include <QtGui/QAction>
77 #include <QtCore/QCoreApplication>
78 #include <QtGui/QLabel>
79 #include <QtGui/QMainWindow>
80 #include <QtGui/QMessageBox>
81 #include <QtGui/QDialogButtonBox>
82 #include <QtGui/QPushButton>
83 #ifdef Q_OS_WIN
84 #    include "shared/sharedlibraryinjector.h"
85 #endif
86
87 #ifdef Q_OS_UNIX
88 #include <unistd.h>
89 #include <dlfcn.h>
90 #endif
91 #include <ctype.h>
92
93 namespace Debugger {
94 namespace Internal {
95
96 //#define DEBUG_PENDING  1
97 //#define DEBUG_SUBITEM  1
98
99 #if DEBUG_PENDING
100 #   define PENDING_DEBUG(s) qDebug() << s
101 #else
102 #   define PENDING_DEBUG(s)
103 #endif
104 #define PENDING_DEBUGX(s) qDebug() << s
105
106 #define CB(callback) &GdbEngine::callback, STRINGIFY(callback)
107
108 static bool stateAcceptsGdbCommands(DebuggerState state)
109 {
110     switch (state) {
111     case AdapterStarting:
112     case AdapterStarted:
113     case AdapterStartFailed:
114     case InferiorUnrunnable:
115     case InferiorStarting:
116     case InferiorStartFailed:
117     case InferiorRunningRequested:
118     case InferiorRunningRequested_Kill:
119     case InferiorRunning:
120     case InferiorStopping:
121     case InferiorStopping_Kill:
122     case InferiorStopped:
123     case InferiorShuttingDown:
124     case InferiorShutDown:
125     case InferiorShutdownFailed:
126         return true;
127     case DebuggerNotReady:
128     case EngineStarting:
129     case InferiorStopFailed:
130     case EngineShuttingDown:
131         break;
132     }
133     return false;
134 }
135
136 static int &currentToken()
137 {
138     static int token = 0;
139     return token;
140 }
141
142 // reads a MI-encoded item frome the consolestream
143 static bool parseConsoleStream(const GdbResponse &response, GdbMi *contents)
144 {
145     GdbMi output = response.data.findChild("consolestreamoutput");
146     QByteArray out = output.data();
147
148     int markerPos = out.indexOf('"') + 1; // position of 'success marker'
149     if (markerPos == 0 || out.at(markerPos) == 'f') {  // 't' or 'f'
150         // custom dumper produced no output
151         return false;
152     }
153
154     out = out.mid(markerPos +  1);
155     out = out.left(out.lastIndexOf('"'));
156     // optimization: dumper output never needs real C unquoting
157     out.replace('\\', "");
158     out = "dummy={" + out + "}";
159
160     contents->fromString(out);
161     //qDebug() << "CONTENTS" << contents->toString(true);
162     return contents->isValid();
163 }
164
165 static QByteArray parsePlainConsoleStream(const GdbResponse &response)
166 {
167     GdbMi output = response.data.findChild("consolestreamoutput");
168     QByteArray out = output.data();
169     // FIXME: proper decoding needed
170     if (out.endsWith("\\n"))
171         out.chop(2);
172     while (out.endsWith('\n') || out.endsWith(' '))
173         out.chop(1);
174     int pos = out.indexOf(" = ");
175     return out.mid(pos + 3);
176 }
177
178 ///////////////////////////////////////////////////////////////////////
179 //
180 // GdbEngine
181 //
182 ///////////////////////////////////////////////////////////////////////
183
184 GdbEngine::GdbEngine(DebuggerManager *manager) :
185     IDebuggerEngine(manager),
186 #ifdef Q_OS_WIN // Do injection loading with MinGW (call loading does not work with 64bit)
187     m_dumperInjectionLoad(true)
188 #else
189     m_dumperInjectionLoad(false)
190 #endif
191 {
192     m_trkOptions = QSharedPointer<TrkOptions>(new TrkOptions);
193     m_trkOptions->fromSettings(Core::ICore::instance()->settings());
194     m_gdbAdapter = 0;
195
196     m_commandTimer = new QTimer(this);
197     m_commandTimer->setSingleShot(true);
198     m_commandTimer->setInterval(COMMAND_TIMEOUT);
199     connect(m_commandTimer, SIGNAL(timeout()), SLOT(commandTimeout()));
200
201     // Needs no resetting in initializeVariables()
202     m_busy = false;
203
204     connect(theDebuggerAction(AutoDerefPointers), SIGNAL(valueChanged(QVariant)),
205             this, SLOT(setAutoDerefPointers(QVariant)));
206 }
207
208 void GdbEngine::connectDebuggingHelperActions()
209 {
210     connect(theDebuggerAction(UseDebuggingHelpers), SIGNAL(valueChanged(QVariant)),
211             this, SLOT(setUseDebuggingHelpers(QVariant)));
212     connect(theDebuggerAction(DebugDebuggingHelpers), SIGNAL(valueChanged(QVariant)),
213             this, SLOT(setDebugDebuggingHelpers(QVariant)));
214     connect(theDebuggerAction(RecheckDebuggingHelpers), SIGNAL(triggered()),
215             this, SLOT(recheckDebuggingHelperAvailability()));
216 }
217    
218 void GdbEngine::disconnectDebuggingHelperActions()
219 {
220     disconnect(theDebuggerAction(UseDebuggingHelpers), 0, this, 0);
221     disconnect(theDebuggerAction(DebugDebuggingHelpers), 0, this, 0);
222     disconnect(theDebuggerAction(RecheckDebuggingHelpers), 0, this, 0);
223 }
224
225 DebuggerStartMode GdbEngine::startMode() const
226 {
227     QTC_ASSERT(!m_startParameters.isNull(), return NoStartMode);
228     return m_startParameters->startMode;
229 }
230
231 QMainWindow *GdbEngine::mainWindow() const
232 {
233     return m_manager->mainWindow();
234 }
235
236 GdbEngine::~GdbEngine()
237 {
238     // prevent sending error messages afterwards
239     disconnect(&m_gdbProc, 0, this, 0);
240     delete m_gdbAdapter;
241     m_gdbAdapter = 0;
242 }
243
244 void GdbEngine::connectAdapter()
245 {
246     connect(m_gdbAdapter, SIGNAL(adapterStarted()),
247         this, SLOT(handleAdapterStarted()));
248     connect(m_gdbAdapter, SIGNAL(adapterStartFailed(QString,QString)),
249         this, SLOT(handleAdapterStartFailed(QString,QString)));
250
251     connect(m_gdbAdapter, SIGNAL(inferiorPrepared()),
252         this, SLOT(handleInferiorPrepared()));
253
254     connect(m_gdbAdapter, SIGNAL(inferiorStartFailed(QString)),
255         this, SLOT(handleInferiorStartFailed(QString)));
256
257     connect(m_gdbAdapter, SIGNAL(adapterCrashed(QString)),
258         this, SLOT(handleAdapterCrashed(QString)));
259 }
260
261 void GdbEngine::initializeVariables()
262 {
263     m_debuggingHelperState = DebuggingHelperUninitialized;
264     m_gdbVersion = 100;
265     m_gdbBuildVersion = -1;
266     m_isMacGdb = false;
267     m_isSynchroneous = false;
268     m_registerNamesListed = false;
269
270     m_fullToShortName.clear();
271     m_shortToFullName.clear();
272     m_varToType.clear();
273
274     m_modulesListOutdated = m_sourcesListOutdated = true;
275     m_sourcesListUpdating = false;
276     m_oldestAcceptableToken = -1;
277     m_outputCodec = QTextCodec::codecForLocale();
278     m_pendingRequests = 0;
279     m_commandsDoneCallback = 0;
280     m_commandsToRunOnTemporaryBreak.clear();
281     m_cookieForToken.clear();
282
283     m_pendingConsoleStreamOutput.clear();
284     m_pendingLogStreamOutput.clear();
285
286     m_inbuffer.clear();
287
288     m_commandTimer->stop();
289
290     // ConverterState has no reset() function.
291     m_outputCodecState.~ConverterState();
292     new (&m_outputCodecState) QTextCodec::ConverterState();
293
294     m_currentFunctionArgs.clear();
295     m_currentFrame.clear();
296     m_dumperHelper.clear();
297 #ifdef Q_OS_LINUX
298     m_entryPoint.clear();
299 #endif
300 }
301
302 QString GdbEngine::errorMessage(QProcess::ProcessError error)
303 {
304     switch (error) {
305         case QProcess::FailedToStart:
306             return tr("The Gdb process failed to start. Either the "
307                 "invoked program '%1' is missing, or you may have insufficient "
308                 "permissions to invoke the program.")
309                 .arg(theDebuggerStringSetting(GdbLocation));
310         case QProcess::Crashed:
311             return tr("The Gdb process crashed some time after starting "
312                 "successfully.");
313         case QProcess::Timedout:
314             return tr("The last waitFor...() function timed out. "
315                 "The state of QProcess is unchanged, and you can try calling "
316                 "waitFor...() again.");
317         case QProcess::WriteError:
318             return tr("An error occurred when attempting to write "
319                 "to the Gdb process. For example, the process may not be running, "
320                 "or it may have closed its input channel.");
321         case QProcess::ReadError:
322             return tr("An error occurred when attempting to read from "
323                 "the Gdb process. For example, the process may not be running.");
324         default:
325             return tr("An unknown error in the Gdb process occurred. ");
326     }
327 }
328
329 #if 0
330 static void dump(const char *first, const char *middle, const QString & to)
331 {
332     QByteArray ba(first, middle - first);
333     Q_UNUSED(to)
334     // note that qDebug cuts off output after a certain size... (bug?)
335     qDebug("\n>>>>> %s\n%s\n====\n%s\n<<<<<\n",
336         qPrintable(currentTime()),
337         qPrintable(QString(ba).trimmed()),
338         qPrintable(to.trimmed()));
339     //qDebug() << "";
340     //qDebug() << qPrintable(currentTime())
341     //    << " Reading response:  " << QString(ba).trimmed() << "\n";
342 }
343 #endif
344
345 void GdbEngine::readDebugeeOutput(const QByteArray &data)
346 {
347     m_manager->showApplicationOutput(m_outputCodec->toUnicode(
348             data.constData(), data.length(), &m_outputCodecState));
349 }
350
351 void GdbEngine::debugMessage(const QString &msg)
352 {
353     gdbOutputAvailable(LogDebug, msg);
354 }
355
356 void GdbEngine::handleResponse(const QByteArray &buff)
357 {
358     static QTime lastTime;
359
360     if (theDebuggerBoolSetting(LogTimeStamps))
361         gdbOutputAvailable(LogTime, currentTime());
362     gdbOutputAvailable(LogOutput, QString::fromLocal8Bit(buff, buff.length()));
363
364 #if 0
365     qDebug() // << "#### start response handling #### "
366         << currentTime()
367         << lastTime.msecsTo(QTime::currentTime()) << "ms,"
368         << "buf:" << buff.left(1500) << "..."
369         //<< "buf:" << buff
370         << "size:" << buff.size();
371 #else
372     //qDebug() << "buf:" << buff;
373 #endif
374
375     lastTime = QTime::currentTime();
376
377     if (buff.isEmpty() || buff == "(gdb) ")
378         return;
379
380     const char *from = buff.constData();
381     const char *to = from + buff.size();
382     const char *inner;
383
384     int token = -1;
385     // token is a sequence of numbers
386     for (inner = from; inner != to; ++inner)
387         if (*inner < '0' || *inner > '9')
388             break;
389     if (from != inner) {
390         token = QByteArray(from, inner - from).toInt();
391         from = inner;
392         //qDebug() << "found token" << token;
393     }
394
395     // next char decides kind of response
396     const char c = *from++;
397     //qDebug() << "CODE:" << c;
398     switch (c) {
399         case '*':
400         case '+':
401         case '=': {
402             QByteArray asyncClass;
403             for (; from != to; ++from) {
404                 const char c = *from;
405                 if (!isNameChar(c))
406                     break;
407                 asyncClass += *from;
408             }
409             //qDebug() << "ASYNCCLASS" << asyncClass;
410
411             GdbMi result;
412             while (from != to) {
413                 GdbMi data;
414                 if (*from != ',') {
415                     // happens on archer where we get 
416                     // 23^running <NL> *running,thread-id="all" <NL> (gdb) 
417                     result.m_type = GdbMi::Tuple;
418                     break;
419                 }
420                 ++from; // skip ','
421                 data.parseResultOrValue(from, to);
422                 if (data.isValid()) {
423                     //qDebug() << "parsed result:" << data.toString();
424                     result.m_children += data;
425                     result.m_type = GdbMi::Tuple;
426                 }
427             }
428             if (asyncClass == "stopped") {
429                 handleStopResponse(result);
430                 m_pendingLogStreamOutput.clear();
431                 m_pendingConsoleStreamOutput.clear();
432             } else if (asyncClass == "running") {
433                 // Archer has 'thread-id="all"' here
434             } else if (asyncClass == "library-loaded") {
435                 // Archer has 'id="/usr/lib/libdrm.so.2",
436                 // target-name="/usr/lib/libdrm.so.2",
437                 // host-name="/usr/lib/libdrm.so.2",
438                 // symbols-loaded="0"
439                 QByteArray id = result.findChild("id").data();
440                 if (!id.isEmpty())
441                     showStatusMessage(tr("Library %1 loaded.").arg(_(id)));
442                 m_modulesListOutdated = m_sourcesListOutdated = true;
443             } else if (asyncClass == "library-unloaded") {
444                 // Archer has 'id="/usr/lib/libdrm.so.2",
445                 // target-name="/usr/lib/libdrm.so.2",
446                 // host-name="/usr/lib/libdrm.so.2"
447                 QByteArray id = result.findChild("id").data();
448                 showStatusMessage(tr("Library %1 unloaded.").arg(_(id)));
449                 m_modulesListOutdated = m_sourcesListOutdated = true;
450             } else if (asyncClass == "thread-group-created") {
451                 // Archer has "{id="28902"}" 
452                 QByteArray id = result.findChild("id").data();
453                 showStatusMessage(tr("Thread group %1 created.").arg(_(id)));
454                 int pid = id.toInt();
455                 if (pid != inferiorPid())
456                     handleInferiorPidChanged(pid);
457             } else if (asyncClass == "thread-created") {
458                 //"{id="1",group-id="28902"}" 
459                 QByteArray id = result.findChild("id").data();
460                 showStatusMessage(tr("Thread %1 created.").arg(_(id)));
461             } else if (asyncClass == "thread-group-exited") {
462                 // Archer has "{id="28902"}" 
463                 QByteArray id = result.findChild("id").data();
464                 showStatusMessage(tr("Thread group %1 exited.").arg(_(id)));
465             } else if (asyncClass == "thread-exited") {
466                 //"{id="1",group-id="28902"}" 
467                 QByteArray id = result.findChild("id").data();
468                 QByteArray groupid = result.findChild("group-id").data();
469                 showStatusMessage(tr("Thread %1 in group %2 exited.")
470                     .arg(_(id)).arg(_(groupid)));
471             } else if (asyncClass == "thread-selected") {
472                 QByteArray id = result.findChild("id").data();
473                 showStatusMessage(tr("Thread %1 selected.").arg(_(id)));
474                 //"{id="2"}" 
475             #if defined(Q_OS_MAC)
476             } else if (asyncClass == "shlibs-updated") {
477                 // MAC announces updated libs
478                 m_modulesListOutdated = m_sourcesListOutdated = true;
479             } else if (asyncClass == "shlibs-added") {
480                 // MAC announces added libs
481                 // {shlib-info={num="2", name="libmathCommon.A_debug.dylib",
482                 // kind="-", dyld-addr="0x7f000", reason="dyld", requested-state="Y",
483                 // state="Y", path="/usr/lib/system/libmathCommon.A_debug.dylib",
484                 // description="/usr/lib/system/libmathCommon.A_debug.dylib",
485                 // loaded_addr="0x7f000", slide="0x7f000", prefix=""}}
486                 m_modulesListOutdated = m_sourcesListOutdated = true;
487             #endif
488             } else {
489                 qDebug() << "IGNORED ASYNC OUTPUT"
490                     << asyncClass << result.toString();
491             }
492             break;
493         }
494
495         case '~': {
496             QByteArray data = GdbMi::parseCString(from, to);
497             m_pendingConsoleStreamOutput += data;
498
499             // Parse pid from noise.
500             if (!inferiorPid()) {
501                 // Linux/Mac gdb: [New [Tt]hread 0x545 (LWP 4554)]
502                 static QRegExp re1(_("New .hread 0x[0-9a-f]+ \\(LWP ([0-9]*)\\)"));
503                 // MinGW 6.8: [New thread 2437.0x435345]
504                 static QRegExp re2(_("New .hread ([0-9]+)\\.0x[0-9a-f]*"));
505                 // Mac: [Switching to process 9294 local thread 0x2e03] or
506                 // [Switching to process 31773]
507                 static QRegExp re3(_("Switching to process ([0-9]+)"));
508                 QTC_ASSERT(re1.isValid() && re2.isValid(), return);
509                 if (re1.indexIn(_(data)) != -1)
510                     maybeHandleInferiorPidChanged(re1.cap(1));
511                 else if (re2.indexIn(_(data)) != -1)
512                     maybeHandleInferiorPidChanged(re2.cap(1));
513                 else if (re3.indexIn(_(data)) != -1)
514                     maybeHandleInferiorPidChanged(re3.cap(1));
515             }
516
517             // Show some messages to give the impression something happens.
518             if (data.startsWith("Reading symbols from ")) {
519                 showStatusMessage(tr("Reading %1...").arg(_(data.mid(21))), 1000);
520                 m_modulesListOutdated = m_sourcesListOutdated = true;
521             } else if (data.startsWith("[New ") || data.startsWith("[Thread ")) {
522                 if (data.endsWith('\n'))
523                     data.chop(1);
524                 showStatusMessage(_(data), 1000);
525             }
526             break;
527         }
528
529         case '@': {
530             readDebugeeOutput(GdbMi::parseCString(from, to));
531             break;
532         }
533
534         case '&': {
535             QByteArray data = GdbMi::parseCString(from, to);
536             m_pendingLogStreamOutput += data;
537             // On Windows, the contents seem to depend on the debugger
538             // version and/or OS version used.
539             if (data.startsWith("warning:"))
540                 manager()->showApplicationOutput(_(data.mid(9))); // cut "warning: "
541             break;
542         }
543
544         case '^': {
545             GdbResponse response;
546
547             response.token = token;
548
549             for (inner = from; inner != to; ++inner)
550                 if (*inner < 'a' || *inner > 'z')
551                     break;
552
553             QByteArray resultClass = QByteArray::fromRawData(from, inner - from);
554             if (resultClass == "done") {
555                 response.resultClass = GdbResultDone;
556             } else if (resultClass == "running") {
557                 if (state() == InferiorStopped) { // Result of manual command.
558                     m_manager->resetLocation();
559                     setTokenBarrier();
560                     setState(InferiorRunningRequested);
561                 }
562                 setState(InferiorRunning);
563                 showStatusMessage(tr("Running..."));
564                 response.resultClass = GdbResultRunning;
565             } else if (resultClass == "connected") {
566                 response.resultClass = GdbResultConnected;
567             } else if (resultClass == "error") {
568                 response.resultClass = GdbResultError;
569             } else if (resultClass == "exit") {
570                 response.resultClass = GdbResultExit;
571             } else {
572                 response.resultClass = GdbResultUnknown;
573             }
574
575             from = inner;
576             if (from != to) {
577                 if (*from == ',') {
578                     ++from;
579                     response.data.parseTuple_helper(from, to);
580                     response.data.m_type = GdbMi::Tuple;
581                     response.data.m_name = "data";
582                 } else {
583                     // Archer has this
584                     response.data.m_type = GdbMi::Tuple;
585                     response.data.m_name = "data";
586                 }
587             }
588
589             //qDebug() << "\nLOG STREAM:" + m_pendingLogStreamOutput;
590             //qDebug() << "\nCONSOLE STREAM:" + m_pendingConsoleStreamOutput;
591             response.data.setStreamOutput("logstreamoutput",
592                 m_pendingLogStreamOutput);
593             response.data.setStreamOutput("consolestreamoutput",
594                 m_pendingConsoleStreamOutput);
595             m_pendingLogStreamOutput.clear();
596             m_pendingConsoleStreamOutput.clear();
597
598             handleResultRecord(&response);
599             break;
600         }
601         default: {
602             qDebug() << "UNKNOWN RESPONSE TYPE" << c;
603             break;
604         }
605     }
606 }
607
608 void GdbEngine::readGdbStandardError()
609 {
610     QByteArray err = m_gdbProc.readAllStandardError();
611     if (err == "Undefined command: \"bb\".  Try \"help\".\n")
612         return;
613     qWarning() << "Unexpected gdb stderr:" << err;
614 }
615
616 void GdbEngine::readGdbStandardOutput()
617 {
618     if (m_commandTimer->isActive())
619         m_commandTimer->start(); // Retrigger
620
621     int newstart = 0;
622     int scan = m_inbuffer.size();
623
624     m_inbuffer.append(m_gdbProc.readAllStandardOutput());
625
626     // This can trigger when a dialog starts a nested event loop
627     if (m_busy)
628         return;
629
630     while (newstart < m_inbuffer.size()) {
631         int start = newstart;
632         int end = m_inbuffer.indexOf('\n', scan);
633         if (end < 0) {
634             m_inbuffer.remove(0, start);
635             return;
636         }
637         newstart = end + 1;
638         scan = newstart;
639         if (end == start)
640             continue;
641         #if defined(Q_OS_WIN)
642         if (m_inbuffer.at(end - 1) == '\r') {
643             --end;
644             if (end == start)
645                 continue;
646         }
647         #endif
648         m_busy = true;
649         handleResponse(QByteArray::fromRawData(m_inbuffer.constData() + start, end - start));
650         m_busy = false;
651     }
652     m_inbuffer.clear();
653 }
654
655 void GdbEngine::interruptInferior()
656 {
657     QTC_ASSERT(state() == InferiorRunning, qDebug() << state(); return);
658
659     setState(InferiorStopping);
660     showStatusMessage(tr("Stop requested..."), 5000);
661
662     debugMessage(_("TRYING TO INTERRUPT INFERIOR"));
663     m_gdbAdapter->interruptInferior();
664 }
665
666 void GdbEngine::interruptInferiorTemporarily()
667 {
668     interruptInferior();
669     foreach (const GdbCommand &cmd, m_commandsToRunOnTemporaryBreak)
670         if (cmd.flags & LosesChild) {
671             setState(InferiorStopping_Kill);
672             break;
673         }
674 }
675
676 void GdbEngine::maybeHandleInferiorPidChanged(const QString &pid0)
677 {
678     const qint64 pid = pid0.toLongLong();
679     if (pid == 0) {
680         debugMessage(_("Cannot parse PID from %1").arg(pid0));
681         return;
682     }
683     if (pid == inferiorPid())
684         return;
685     debugMessage(_("FOUND PID %1").arg(pid));    
686
687     handleInferiorPidChanged(pid);
688     if (m_dumperInjectionLoad)
689         tryLoadDebuggingHelpers();
690 }
691
692 void GdbEngine::postCommand(const QString &command, AdapterCallback callback,
693                             const char *callbackName, const QVariant &cookie)
694 {
695     postCommand(command, NoFlags, callback, callbackName, cookie);
696 }
697
698 void GdbEngine::postCommand(const QString &command, GdbCommandFlags flags,
699                             AdapterCallback callback,
700                             const char *callbackName, const QVariant &cookie)
701 {
702     GdbCommand cmd;
703     cmd.command = command;
704     cmd.flags = flags;
705     cmd.adapterCallback = callback;
706     cmd.callbackName = callbackName;
707     cmd.cookie = cookie;
708     postCommandHelper(cmd);
709 }
710
711 void GdbEngine::postCommand(const QString &command, GdbCommandCallback callback,
712                             const char *callbackName, const QVariant &cookie)
713 {
714     postCommand(command, NoFlags, callback, callbackName, cookie);
715 }
716
717 void GdbEngine::postCommand(const QString &command, GdbCommandFlags flags,
718                             GdbCommandCallback callback, const char *callbackName,
719                             const QVariant &cookie)
720 {
721     GdbCommand cmd;
722     cmd.command = command;
723     cmd.flags = flags;
724     cmd.callback = callback;
725     cmd.callbackName = callbackName;
726     cmd.cookie = cookie;
727     postCommandHelper(cmd);
728 }
729
730 void GdbEngine::postCommandHelper(const GdbCommand &cmd)
731 {
732     if (!stateAcceptsGdbCommands(state())) {
733         PENDING_DEBUG(_("NO GDB PROCESS RUNNING, CMD IGNORED: ") + cmd.command);
734         debugMessage(_("NO GDB PROCESS RUNNING, CMD IGNORED: %1 %2")
735             .arg(cmd.command).arg(state()));
736         return;
737     }
738
739     if (cmd.flags & RebuildModel) {
740         ++m_pendingRequests;
741         PENDING_DEBUG("   MODEL:" << cmd.command << "=>" << cmd.callbackName
742                       << "INCREMENTS PENDING TO" << m_pendingRequests);
743     } else {
744         PENDING_DEBUG("   OTHER (IN):" << cmd.command << "=>" << cmd.callbackName
745                       << "LEAVES PENDING AT" << m_pendingRequests);
746     }
747
748     if ((cmd.flags & NeedsStop) || !m_commandsToRunOnTemporaryBreak.isEmpty()) {
749         if (state() == InferiorStopped || state() == InferiorUnrunnable
750             || state() == InferiorStarting || state() == AdapterStarted) {
751             // Can be safely sent now.
752             flushCommand(cmd);
753         } else {
754             // Queue the commands that we cannot send at once.
755             debugMessage(_("QUEUING COMMAND ") + cmd.command);
756             m_commandsToRunOnTemporaryBreak.append(cmd);
757             if (state() == InferiorStopping) {
758                 if (cmd.flags & LosesChild)
759                     setState(InferiorStopping_Kill);
760                 debugMessage(_("CHILD ALREADY BEING INTERRUPTED"));
761             } else if (state() == InferiorStopping_Kill) {
762                 debugMessage(_("CHILD ALREADY BEING INTERRUPTED (KILL PENDING)"));
763             } else if (state() == InferiorRunningRequested) {
764                 if (cmd.flags & LosesChild)
765                     setState(InferiorRunningRequested_Kill);
766                 debugMessage(_("RUNNING REQUESTED; POSTPONING INTERRUPT"));
767             } else if (state() == InferiorRunningRequested_Kill) {
768                 debugMessage(_("RUNNING REQUESTED; POSTPONING INTERRUPT (KILL PENDING)"));
769             } else if (state() == InferiorRunning) {
770                 showStatusMessage(tr("Stopping temporarily."), 1000);
771                 interruptInferiorTemporarily();
772             } else {
773                 qDebug() << "ATTEMPTING TO QUEUE COMMAND IN INAPPROPRIATE STATE" << state();
774             }
775         }
776     } else if (!cmd.command.isEmpty()) {
777         flushCommand(cmd);
778     }
779 }
780
781 void GdbEngine::flushQueuedCommands()
782 {
783     showStatusMessage(tr("Processing queued commands."), 1000);
784     while (!m_commandsToRunOnTemporaryBreak.isEmpty()) {
785         GdbCommand cmd = m_commandsToRunOnTemporaryBreak.takeFirst();
786         debugMessage(_("RUNNING QUEUED COMMAND %1 %2")
787             .arg(cmd.command).arg(_(cmd.callbackName)));
788         flushCommand(cmd);
789     }
790 }
791
792 void GdbEngine::flushCommand(const GdbCommand &cmd0)
793 {
794     GdbCommand cmd = cmd0;
795     if (state() == DebuggerNotReady) {
796         gdbInputAvailable(LogInput, cmd.command);
797         debugMessage(_("GDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: ") + cmd.command);
798         return;
799     }
800
801     ++currentToken();
802     cmd.postTime = QTime::currentTime();
803     m_cookieForToken[currentToken()] = cmd;
804     cmd.command = QString::number(currentToken()) + cmd.command;
805     if (cmd.flags & EmbedToken)
806         cmd.command = cmd.command.arg(currentToken());
807     gdbInputAvailable(LogInput, cmd.command);
808
809     m_gdbAdapter->write(cmd.command.toLatin1() + "\r\n");
810
811     m_commandTimer->start();
812
813     if (cmd.flags & LosesChild)
814         setState(InferiorShuttingDown);
815 }
816
817 void GdbEngine::commandTimeout()
818 {
819     // FIXME this needs a proper message box
820     debugMessage(_("TIMED OUT WAITING FOR GDB REPLY. COMMANDS STILL IN PROGRESS:"));
821     QList<int> keys = m_cookieForToken.keys();
822     qSort(keys);
823     foreach (int key, keys) {
824         const GdbCommand &cmd = m_cookieForToken[key];
825         debugMessage(_("  %1: %2 => %3").arg(key).arg(cmd.command).arg(_(cmd.callbackName)));
826     }
827     // This is an entirely undefined state, so we just pull the emergency brake.
828     setState(EngineShuttingDown, true);
829     m_gdbProc.kill();
830 }
831
832 void GdbEngine::handleResultRecord(GdbResponse *response)
833 {
834     //qDebug() << "TOKEN:" << response.token
835     //    << " ACCEPTABLE:" << m_oldestAcceptableToken;
836     //qDebug() << "\nRESULT" << response.token << response.toString();
837
838     int token = response->token;
839     if (token == -1)
840         return;
841
842     if (!m_cookieForToken.contains(token)) {
843         // In theory this should not happen (rather the error should be
844         // reported in the "first" response to the command) in practice it
845         // does. We try to handle a few situations we are aware of gracefully.
846         // Ideally, this code should not be present at all.
847         debugMessage(_("COOKIE FOR TOKEN %1 ALREADY EATEN. "
848             "TWO RESPONSES FOR ONE COMMAND?").arg(token));
849         if (response->resultClass == GdbResultError) {
850             QByteArray msg = response->data.findChild("msg").data();
851             if (msg == "Cannot find new threads: generic error") {
852                 // Handle a case known to occur on Linux/gdb 6.8 when debugging moc
853                 // with helpers enabled. In this case we get a second response with
854                 // msg="Cannot find new threads: generic error"
855                 debugMessage(_("APPLYING WORKAROUND #1"));
856                 showMessageBox(QMessageBox::Critical,
857                     tr("Executable failed"), QString::fromLocal8Bit(msg));
858                 showStatusMessage(tr("Process failed to start."));
859                 shutdown();
860             } else if (msg == "\"finish\" not meaningful in the outermost frame.") { 
861                 // Handle a case known to appear on gdb 6.4 symbianelf when
862                 // the stack is cut due to access to protected memory.
863                 debugMessage(_("APPLYING WORKAROUND #2"));
864                 setState(InferiorStopping);
865                 setState(InferiorStopped);
866             } else if (msg.startsWith("Cannot find bounds of current function")) {
867                 // Happens when running "-exec-next" in a function for which
868                 // there is no debug information. Divert to "-exec-next-step"
869                 debugMessage(_("APPLYING WORKAROUND #3"));
870                 setState(InferiorStopping);
871                 setState(InferiorStopped);
872                 nextIExec();
873             } else if (msg.startsWith("Couldn't get registers: No such process.")) {
874                 // Happens on archer-tromey-python 6.8.50.20090910-cvs
875                 // There might to be a race between a process shutting down
876                 // and library load messages.
877                 debugMessage(_("APPLYING WORKAROUND #4"));
878                 setState(InferiorStopping);
879                 setState(InferiorStopped);
880                 setState(InferiorShuttingDown);
881                 setState(InferiorShutDown);
882                 showStatusMessage(tr("Executable failed: %1")
883                     .arg(QString::fromLocal8Bit(msg)));
884                 shutdown();
885                 showMessageBox(QMessageBox::Critical,
886                     tr("Executable failed"), QString::fromLocal8Bit(msg));
887             } else {
888                 showMessageBox(QMessageBox::Critical,
889                     tr("Executable failed"), QString::fromLocal8Bit(msg));
890                 showStatusMessage(tr("Executable failed: %1")
891                     .arg(QString::fromLocal8Bit(msg)));
892             }
893         }
894         return;
895     }
896
897     GdbCommand cmd = m_cookieForToken.take(token);
898     if (theDebuggerBoolSetting(LogTimeStamps)) {
899         gdbOutputAvailable(LogTime, _("Response time: %1: %2 s")
900             .arg(cmd.command)
901             .arg(cmd.postTime.msecsTo(QTime::currentTime()) / 1000.));
902     }
903
904     if (response->token < m_oldestAcceptableToken && (cmd.flags & Discardable)) {
905         //debugMessage(_("### SKIPPING OLD RESULT") + response.toString());
906         return;
907     }
908
909     response->cookie = cmd.cookie;
910
911     if (response->resultClass != GdbResultError &&
912         response->resultClass != ((cmd.flags & RunRequest) ? GdbResultRunning :
913                                   (cmd.flags & ExitRequest) ? GdbResultExit :
914                                   GdbResultDone)) {
915         QString rsp = _(GdbResponse::stringFromResultClass(response->resultClass));
916         qWarning() << "UNEXPECTED RESPONSE " << rsp << " TO COMMAND" << cmd.command << " AT " __FILE__ ":" STRINGIFY(__LINE__);
917         debugMessage(_("UNEXPECTED RESPONSE %1 TO COMMAND %2").arg(rsp).arg(cmd.command));
918     } else {
919         if (cmd.callback)
920             (this->*cmd.callback)(*response);
921         else if (cmd.adapterCallback)
922             (m_gdbAdapter->*cmd.adapterCallback)(*response);
923     }
924
925     if (cmd.flags & RebuildModel) {
926         --m_pendingRequests;
927         PENDING_DEBUG("   WATCH" << cmd.command << "=>" << cmd.callbackName
928                       << "DECREMENTS PENDING TO" << m_pendingRequests);
929         if (m_pendingRequests <= 0) {
930             PENDING_DEBUG("\n\n ... AND TRIGGERS MODEL UPDATE\n");
931             rebuildModel();
932         }
933     } else {
934         PENDING_DEBUG("   OTHER (OUT):" << cmd.command << "=>" << cmd.callbackName
935                       << "LEAVES PENDING AT" << m_pendingRequests);
936     }
937
938     // Commands were queued, but we were in RunningRequested state, so the interrupt
939     // was postponed.
940     // This is done after the command callbacks so the running-requesting commands
941     // can assert on the right state.
942     if (state() == InferiorRunning && !m_commandsToRunOnTemporaryBreak.isEmpty())
943         interruptInferiorTemporarily();
944
945     // Continue only if there are no commands wire anymore, so this will
946     // be fully synchroneous.
947     // This is somewhat inefficient, as it makes the last command synchronous.
948     // An optimization would be requesting the continue immediately when the
949     // event loop is entered, and let individual commands have a flag to suppress
950     // that behavior.
951     if (m_commandsDoneCallback && m_cookieForToken.isEmpty()) {
952         debugMessage(_("ALL COMMANDS DONE; INVOKING CALLBACK"));
953         CommandsDoneCallback cont = m_commandsDoneCallback;
954         m_commandsDoneCallback = 0;
955         (this->*cont)();
956     } else {
957         PENDING_DEBUG("MISSING TOKENS: " << m_cookieForToken.keys());
958     }
959
960     if (m_cookieForToken.isEmpty())
961         m_commandTimer->stop();
962 }
963
964 void GdbEngine::executeDebuggerCommand(const QString &command)
965 {
966     if (state() == DebuggerNotReady) {
967         debugMessage(_("GDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: ") + command);
968         return;
969     }
970
971     m_gdbAdapter->write(command.toLatin1() + "\r\n");
972 }
973
974 // Called from CoreAdapter and AttachAdapter
975 void GdbEngine::updateAll()
976 {
977     QTC_ASSERT(state() == InferiorUnrunnable || state() == InferiorStopped, /**/);
978     tryLoadDebuggingHelpers();
979     reloadModulesInternal();
980     postCommand(_("-stack-list-frames"), WatchUpdate, CB(handleStackListFrames),
981         QVariant::fromValue<StackCookie>(StackCookie(false, true)));
982     manager()->stackHandler()->setCurrentIndex(0);
983     if (supportsThreads())
984         postCommand(_("-thread-list-ids"), WatchUpdate, CB(handleStackListThreads), 0);
985     manager()->reloadRegisters();
986     updateLocals(); 
987 }
988
989 void GdbEngine::handleQuerySources(const GdbResponse &response)
990 {
991     if (response.resultClass == GdbResultDone) {
992         QMap<QString, QString> oldShortToFull = m_shortToFullName;
993         m_shortToFullName.clear();
994         m_fullToShortName.clear();
995         // "^done,files=[{file="../../../../bin/gdbmacros/gdbmacros.cpp",
996         // fullname="/data5/dev/ide/main/bin/gdbmacros/gdbmacros.cpp"},
997         GdbMi files = response.data.findChild("files");
998         foreach (const GdbMi &item, files.children()) {
999             GdbMi fullName = item.findChild("fullname");
1000             if (fullName.isValid()) {
1001                 QString full = cleanupFullName(QString::fromLocal8Bit(fullName.data()));
1002                 QString fileName = QString::fromLocal8Bit(item.findChild("file").data());
1003                 m_shortToFullName[fileName] = full;
1004                 m_fullToShortName[full] = fileName;
1005             }
1006         }
1007         if (m_shortToFullName != oldShortToFull)
1008             manager()->sourceFileWindow()->setSourceFiles(m_shortToFullName);
1009     }
1010 }
1011
1012 #if 0
1013 void GdbEngine::handleExecJumpToLine(const GdbResponse &response)
1014 {
1015     // FIXME: remove this special case as soon as 'jump'
1016     // is supported by MI
1017     // "&"jump /home/apoenitz/dev/work/test1/test1.cpp:242"
1018     // ~"Continuing at 0x4058f3."
1019     // ~"run1 (argc=1, argv=0x7fffb213a478) at test1.cpp:242"
1020     // ~"242\t x *= 2;"
1021     //109^done"
1022     setState(InferiorStopped);
1023     showStatusMessage(tr("Jumped. Stopped."));
1024     QByteArray output = response.data.findChild("logstreamoutput").data();
1025     if (output.isEmpty())
1026         return;
1027     int idx1 = output.indexOf(' ') + 1;
1028     if (idx1 > 0) {
1029         int idx2 = output.indexOf(':', idx1);
1030         if (idx2 > 0) {
1031             QString file = QString::fromLocal8Bit(output.mid(idx1, idx2 - idx1));
1032             int line = output.mid(idx2 + 1).toInt();
1033             gotoLocation(file, line, true);
1034         }
1035     }
1036 }
1037 #endif
1038
1039 //void GdbEngine::handleExecRunToFunction(const GdbResponse &response)
1040 //{
1041 //    // FIXME: remove this special case as soon as there's a real
1042 //    // reason given when the temporary breakpoint is hit.
1043 //    // reight now we get:
1044 //    // 14*stopped,thread-id="1",frame={addr="0x0000000000403ce4",
1045 //    // func="foo",args=[{name="str",value="@0x7fff0f450460"}],
1046 //    // file="main.cpp",fullname="/tmp/g/main.cpp",line="37"}
1047 //    QTC_ASSERT(state() == InferiorStopping, qDebug() << state())
1048 //    setState(InferiorStopped);
1049 //    showStatusMessage(tr("Function reached. Stopped."));
1050 //    GdbMi frame = response.data.findChild("frame");
1051 //    StackFrame f = parseStackFrame(frame, 0);
1052 //    gotoLocation(f, true);
1053 //}
1054
1055 static bool isExitedReason(const QByteArray &reason)
1056 {
1057     return reason == "exited-normally"   // inferior exited normally
1058         || reason == "exited-signalled"  // inferior exited because of a signal
1059         //|| reason == "signal-received" // inferior received signal
1060         || reason == "exited";           // inferior exited
1061 }
1062
1063 #if 0
1064 void GdbEngine::handleAqcuiredInferior()
1065 {
1066     // Reverse debugging. FIXME: Should only be used when available.
1067     //if (theDebuggerBoolSetting(EnableReverseDebugging))
1068     //    postCommand(_("target response"));
1069
1070     tryLoadDebuggingHelpers();
1071
1072     #ifndef Q_OS_MAC
1073     // intentionally after tryLoadDebuggingHelpers(),
1074     // otherwise we'd interupt solib loading.
1075     if (theDebuggerBoolSetting(AllPluginBreakpoints)) {
1076         postCommand(_("set auto-solib-add on"));
1077         postCommand(_("set stop-on-solib-events 0"));
1078         postCommand(_("sharedlibrary .*"));
1079     } else if (theDebuggerBoolSetting(SelectedPluginBreakpoints)) {
1080         postCommand(_("set auto-solib-add on"));
1081         postCommand(_("set stop-on-solib-events 1"));
1082         postCommand(_("sharedlibrary ")
1083           + theDebuggerStringSetting(SelectedPluginBreakpointsPattern));
1084     } else if (theDebuggerBoolSetting(NoPluginBreakpoints)) {
1085         // should be like that already
1086         if (!m_dumperInjectionLoad)
1087             postCommand(_("set auto-solib-add off"));
1088         postCommand(_("set stop-on-solib-events 0"));
1089     }
1090     #endif
1091
1092     // It's nicer to see a bit of the world we live in.
1093     reloadModulesInternal();
1094     attemptBreakpointSynchronization();
1095 }
1096 #endif
1097
1098 void GdbEngine::handleStopResponse(const GdbMi &data)
1099 {
1100     // This is gdb 7+'s initial *stopped in response to attach.
1101     // For consistency, we just discard it.
1102     if (state() == InferiorStarting)
1103         return;
1104
1105     const QByteArray reason = data.findChild("reason").data();
1106
1107     if (isExitedReason(reason)) {
1108         if (state() == InferiorRunning) {
1109             setState(InferiorStopping);
1110         } else {
1111             // The user triggered a stop, but meanwhile the app simply exited ...
1112             QTC_ASSERT(state() == InferiorStopping || state() == InferiorStopping_Kill,
1113                        qDebug() << state());
1114         }
1115         setState(InferiorStopped);
1116         QString msg;
1117         if (reason == "exited") {
1118             msg = tr("Program exited with exit code %1.")
1119                 .arg(_(data.findChild("exit-code").toString()));
1120         } else if (reason == "exited-signalled" || reason == "signal-received") {
1121             msg = tr("Program exited after receiving signal %1.")
1122                 .arg(_(data.findChild("signal-name").toString()));
1123         } else {
1124             msg = tr("Program exited normally.");
1125         }
1126         showStatusMessage(msg);
1127         setState(InferiorShuttingDown);
1128         setState(InferiorShutDown);
1129         shutdown();
1130         return;
1131     }
1132
1133     if (!m_commandsToRunOnTemporaryBreak.isEmpty()) {
1134         QTC_ASSERT(state() == InferiorStopping || state() == InferiorStopping_Kill,
1135                    qDebug() << state())
1136         setState(InferiorStopped);
1137         flushQueuedCommands();
1138         if (state() == InferiorStopped) {
1139             QTC_ASSERT(m_commandsDoneCallback == 0, /**/);
1140             m_commandsDoneCallback = &GdbEngine::autoContinueInferior;
1141         } else {
1142             QTC_ASSERT(state() == InferiorShuttingDown, qDebug() << state())
1143         }
1144         return;
1145     }
1146
1147     if (state() == InferiorRunning) {
1148         // Stop triggered by a breakpoint or otherwise not directly
1149         // initiated by the user.
1150         setState(InferiorStopping);
1151     } else {
1152         QTC_ASSERT(state() == InferiorStopping, qDebug() << state());
1153     }
1154     setState(InferiorStopped);
1155
1156     // Due to LD_PRELOADing the dumpers, these events can occur even before
1157     // reaching the entry point. So handle it before the entry point hacks below.
1158     if (reason.isEmpty() && m_gdbVersion < 70000 && !m_isMacGdb) {
1159         // On Linux it reports "Stopped due to shared library event\n", but
1160         // on Windows it simply forgets about it. Thus, we identify the response
1161         // based on it having no frame information.
1162         if (!data.findChild("frame").isValid()) {
1163             m_modulesListOutdated = m_sourcesListOutdated = true;
1164             // Each stop causes a roundtrip and button flicker, so prevent
1165             // a flood of useless stops. Will be automatically re-enabled.
1166             postCommand(_("set stop-on-solib-events 0"));
1167 #if 0
1168             // The related code (handleAqcuiredInferior()) is disabled as well.
1169             if (theDebuggerBoolSetting(SelectedPluginBreakpoints)) {
1170                 QString dataStr = _(data.toString());
1171                 debugMessage(_("SHARED LIBRARY EVENT: ") + dataStr);
1172                 QString pat = theDebuggerStringSetting(SelectedPluginBreakpointsPattern);
1173                 debugMessage(_("PATTERN: ") + pat);
1174                 postCommand(_("sharedlibrary ") + pat);
1175                 showStatusMessage(tr("Loading %1...").arg(dataStr));
1176             }
1177 #endif
1178             continueInferiorInternal();
1179             return;
1180         }
1181     }
1182
1183 #ifdef Q_OS_LINUX
1184     if (!m_entryPoint.isEmpty()) {
1185         GdbMi frameData = data.findChild("frame");
1186         if (frameData.findChild("addr").data() == m_entryPoint) {
1187             // There are two expected reasons for getting here:
1188             // 1) For some reason, attaching to a stopped process causes *two* SIGSTOPs
1189             //    when trying to continue (kernel i386 2.6.24-23-ubuntu, gdb 6.8).
1190             //    Interestingly enough, on MacOSX no signal is delivered at all.
1191             // 2) The explicit tbreak at the entry point we set to query the PID.
1192             //    Gdb <= 6.8 reports a frame but no reason, 6.8.50+ reports everything.
1193             // The case of the user really setting a breakpoint at _start is simply
1194             // unsupported.
1195             if (!inferiorPid()) // For programs without -pthread under gdb <= 6.8.
1196                 postCommand(_("info proc"), CB(handleInfoProc));
1197             continueInferiorInternal();
1198             return;
1199         }
1200         // We are past the initial stop(s). No need to waste time on further checks.
1201         m_entryPoint.clear();
1202     }
1203 #endif
1204
1205     // seen on XP after removing a breakpoint while running
1206     //  >945*stopped,reason="signal-received",signal-name="SIGTRAP",
1207     //  signal-meaning="Trace/breakpoint trap",thread-id="2",
1208     //  frame={addr="0x7c91120f",func="ntdll!DbgUiConnectToDbg",
1209     //  args=[],from="C:\\WINDOWS\\system32\\ntdll.dll"}
1210     //if (reason == "signal-received"
1211     //      && data.findChild("signal-name").data() == "SIGTRAP") {
1212     //    continueInferiorInternal();
1213     //    return;
1214     //}
1215
1216     // jump over well-known frames
1217     static int stepCounter = 0;
1218     if (theDebuggerBoolSetting(SkipKnownFrames)) {
1219         if (reason == "end-stepping-range" || reason == "function-finished") {
1220             GdbMi frame = data.findChild("frame");
1221             //debugMessage(frame.toString());
1222             QString funcName = _(frame.findChild("func").data());
1223             QString fileName = QString::fromLocal8Bit(frame.findChild("file").data());
1224             if (isLeavableFunction(funcName, fileName)) {
1225                 //debugMessage(_("LEAVING ") + funcName);
1226                 ++stepCounter;
1227                 m_manager->stepOutExec();
1228                 //stepExec();
1229                 return;
1230             }
1231             if (isSkippableFunction(funcName, fileName)) {
1232                 //debugMessage(_("SKIPPING ") + funcName);
1233                 ++stepCounter;
1234                 m_manager->stepExec();
1235                 return;
1236             }
1237             //if (stepCounter)
1238             //    qDebug() << "STEPCOUNTER:" << stepCounter;
1239             stepCounter = 0;
1240         }
1241     }
1242
1243     bool initHelpers = m_debuggingHelperState == DebuggingHelperUninitialized
1244                        || m_debuggingHelperState == DebuggingHelperLoadTried;
1245     // Don't load helpers on stops triggered by signals unless it's
1246     // an intentional trap.
1247     if (initHelpers && reason == "signal-received"
1248             && data.findChild("signal-name").data() != "SIGTRAP")
1249         initHelpers = false;
1250     if (isSynchroneous())
1251         initHelpers = false;
1252     if (initHelpers) {
1253         tryLoadDebuggingHelpers();
1254         QVariant var = QVariant::fromValue<GdbMi>(data);
1255         postCommand(_("p 4"), CB(handleStop1), var);  // dummy
1256     } else {
1257         handleStop1(data);
1258     }
1259     // Dumper loading is sequenced, as otherwise the display functions
1260     // will start requesting data without knowing that dumpers are available.
1261 }
1262
1263 void GdbEngine::handleStop1(const GdbResponse &response)
1264 {
1265     handleStop1(response.cookie.value<GdbMi>());
1266 }
1267
1268 void GdbEngine::handleStop1(const GdbMi &data)
1269 {
1270     if (m_modulesListOutdated)
1271         reloadModulesInternal(); // This is for display only
1272     if (m_sourcesListOutdated)
1273         reloadSourceFilesInternal(); // This needs to be done before fullName() may need it
1274
1275     QByteArray reason = data.findChild("reason").data();
1276     if (reason == "breakpoint-hit") {
1277         showStatusMessage(tr("Stopped at breakpoint."));
1278     } else {
1279         if (reason == "signal-received"
1280             && theDebuggerBoolSetting(UseMessageBoxForSignals)) {
1281             QByteArray name = data.findChild("signal-name").data();
1282             // Ignore SIGTRAP as they are showing up regularily when
1283             // stopping debugging.
1284             if (name != "SIGTRAP") {
1285                 QByteArray meaning = data.findChild("signal-meaning").data();
1286                 QString msg = tr("<p>The inferior stopped because it received a "
1287                     "signal from the Operating System.<p>"
1288                     "<table><tr><td>Signal name : </td><td>%1</td></tr>"
1289                     "<tr><td>Signal meaning : </td><td>%2</td></tr></table>")
1290                     .arg(name.isEmpty() ? tr(" <Unknown> ", "name") : _(name))
1291                     .arg(meaning.isEmpty() ? tr(" <Unknown> ", "meaning") : _(meaning));
1292                 showMessageBox(QMessageBox::Information,
1293                     tr("Signal received"), msg);
1294             }
1295         }
1296
1297         if (reason.isEmpty())
1298             showStatusMessage(tr("Stopped."));
1299         else
1300             showStatusMessage(tr("Stopped: \"%1\"").arg(_(reason)));
1301     }
1302
1303     const GdbMi gdbmiFrame = data.findChild("frame");
1304
1305     m_currentFrame = _(gdbmiFrame.findChild("addr").data() + '%' +
1306          gdbmiFrame.findChild("func").data() + '%');
1307
1308     // Quick shot: Jump to stack frame #0.
1309     StackFrame frame;
1310     if (gdbmiFrame.isValid()) {
1311         frame = parseStackFrame(gdbmiFrame, 0);
1312         gotoLocation(frame, true);
1313     }
1314
1315     //
1316     // Stack
1317     //
1318     manager()->stackHandler()->setCurrentIndex(0);
1319     updateLocals(qVariantFromValue(frame)); // Quick shot
1320
1321     reloadStack(false);
1322
1323     if (supportsThreads()) {
1324         int currentId = data.findChild("thread-id").data().toInt();
1325         postCommand(_("-thread-list-ids"), WatchUpdate,
1326             CB(handleStackListThreads), currentId);
1327     }
1328
1329     //
1330     // Registers
1331     //
1332     manager()->reloadRegisters();
1333 }
1334
1335 #ifdef Q_OS_LINUX
1336 void GdbEngine::handleInfoProc(const GdbResponse &response)
1337 {
1338     if (response.resultClass == GdbResultDone) {
1339         static QRegExp re(_("\\bprocess ([0-9]+)\n"));
1340         QTC_ASSERT(re.isValid(), return);
1341         if (re.indexIn(_(response.data.findChild("consolestreamoutput").data())) != -1)
1342             maybeHandleInferiorPidChanged(re.cap(1));
1343     }
1344 }
1345 #endif
1346
1347 void GdbEngine::handleShowVersion(const GdbResponse &response)
1348 {
1349     //qDebug () << "VERSION 2:" << response.data.findChild("consolestreamoutput").data();
1350     //qDebug () << "VERSION:" << response.toString();
1351     debugMessage(_("VERSION: " + response.toString()));
1352     if (response.resultClass == GdbResultDone) {
1353         m_gdbVersion = 100;
1354         m_gdbBuildVersion = -1;
1355         m_isMacGdb = false;
1356         QString msg = QString::fromLocal8Bit(response.data.findChild("consolestreamoutput").data());
1357         QRegExp supported(_("GNU gdb(.*) (\\d+)\\.(\\d+)(\\.(\\d+))?(-(\\d+))?"));
1358         if (supported.indexIn(msg) == -1) {
1359             debugMessage(_("UNSUPPORTED GDB VERSION ") + msg);
1360 #if 0
1361             QStringList list = msg.split(_c('\n'));
1362             while (list.size() > 2)
1363                 list.removeLast();
1364             msg = tr("The debugger you are using identifies itself as:")
1365                 + _("<p><p>") + list.join(_("<br>")) + _("<p><p>")
1366                 + tr("This version is not officially supported by Qt Creator.\n"
1367                      "Debugging will most likely not work well.\n"
1368                      "Using gdb 6.7 or later is strongly recommended.");
1369 #if 0
1370             // ugly, but 'Show again' check box...
1371             static QErrorMessage *err = new QErrorMessage(mainWindow());
1372             err->setMinimumSize(400, 300);
1373             err->showMessage(msg);
1374 #else
1375             //showMessageBox(QMessageBox::Information, tr("Warning"), msg);
1376 #endif
1377 #endif
1378         } else {
1379             m_gdbVersion = 10000 * supported.cap(2).toInt()
1380                          +   100 * supported.cap(3).toInt()
1381                          +     1 * supported.cap(5).toInt();
1382             m_gdbBuildVersion = supported.cap(7).toInt();
1383             m_isMacGdb = msg.contains(__("Apple version"));
1384             debugMessage(_("GDB VERSION: %1, BUILD: %2%3").arg(m_gdbVersion)
1385                 .arg(m_gdbBuildVersion).arg(_(m_isMacGdb ? " (APPLE)" : "")));
1386         }
1387         //qDebug () << "VERSION 3:" << m_gdbVersion << m_gdbBuildVersion;
1388     }
1389 }
1390
1391 void GdbEngine::handleIsSynchroneous(const GdbResponse &response)
1392 {
1393     Q_UNUSED(response);
1394     if (response.resultClass == GdbResultDone) {
1395         m_isSynchroneous = true;
1396     } else {
1397         m_isSynchroneous = false;
1398     }
1399 }
1400
1401 void GdbEngine::handleExecContinue(const GdbResponse &response)
1402 {
1403     if (response.resultClass == GdbResultRunning) {
1404         // The "running" state is picked up in handleResponse()
1405         QTC_ASSERT(state() == InferiorRunning, /**/);
1406     } else {
1407         if (state() == InferiorRunningRequested_Kill) {
1408             setState(InferiorStopped);
1409             shutdown();
1410             return;
1411         }
1412         QTC_ASSERT(state() == InferiorRunningRequested, /**/);
1413         setState(InferiorStopped);
1414         QByteArray msg = response.data.findChild("msg").data();
1415         if (msg.startsWith("Cannot find bounds of current function")) {
1416             if (!m_commandsToRunOnTemporaryBreak.isEmpty())
1417                 flushQueuedCommands();
1418             showStatusMessage(tr("Stopped."), 5000);
1419             //showStatusMessage(tr("No debug information available. "
1420             //  "Leaving function..."));
1421             //stepOutExec();
1422         } else {
1423             showMessageBox(QMessageBox::Critical, tr("Execution Error"),
1424                            tr("Cannot continue debugged process:\n") + QString::fromLocal8Bit(msg));
1425             shutdown();
1426         }
1427     }
1428 }
1429
1430 QString GdbEngine::fullName(const QString &fileName)
1431 {
1432     if (fileName.isEmpty())
1433         return QString();
1434     QTC_ASSERT(!m_sourcesListOutdated, /* */)
1435     QTC_ASSERT(!m_sourcesListUpdating, /* */)
1436     return m_shortToFullName.value(fileName, QString());
1437 }
1438
1439 #ifdef Q_OS_WIN
1440 QString GdbEngine::cleanupFullName(const QString &fileName)
1441 {
1442     QTC_ASSERT(!fileName.isEmpty(), return QString())
1443     // Gdb on windows often delivers "fullnames" which
1444     // a) have no drive letter and b) are not normalized.
1445     QFileInfo fi(fileName);
1446     if (!fi.isReadable())
1447         return QString();
1448     return QDir::cleanPath(fi.absoluteFilePath());
1449 }
1450 #endif
1451
1452 void GdbEngine::shutdown()
1453 {
1454     debugMessage(_("INITIATE GDBENGINE SHUTDOWN"));
1455     switch (state()) {
1456     case DebuggerNotReady: // Nothing to do! :)
1457     case EngineStarting: // We can't get here, really
1458     case InferiorShuttingDown: // Will auto-trigger further shutdown steps
1459     case EngineShuttingDown: // Do not disturb! :)
1460     case InferiorRunningRequested_Kill:
1461     case InferiorStopping_Kill:
1462         break;
1463     case AdapterStarting: // GDB is up, adapter is "doing something"
1464         setState(AdapterStartFailed);
1465         m_gdbAdapter->shutdown();
1466         // fall-through
1467     case AdapterStartFailed: // Adapter "did something", but it did not help
1468         if (m_gdbProc.state() == QProcess::Running) {
1469             m_commandsToRunOnTemporaryBreak.clear();
1470             postCommand(_("-gdb-exit"), GdbEngine::ExitRequest, CB(handleGdbExit));
1471         } else {
1472             setState(DebuggerNotReady);
1473         }
1474         break;
1475     case InferiorRunningRequested:
1476     case InferiorRunning:
1477     case InferiorStopping:
1478     case InferiorStopped:
1479         m_commandsToRunOnTemporaryBreak.clear();
1480         postCommand(_(m_gdbAdapter->inferiorShutdownCommand()),
1481                     NeedsStop | LosesChild, CB(handleInferiorShutdown));
1482         break;
1483     case AdapterStarted: // We can't get here, really
1484     case InferiorStartFailed:
1485     case InferiorShutDown:
1486     case InferiorShutdownFailed: // Whatever
1487     case InferiorUnrunnable:
1488         m_commandsToRunOnTemporaryBreak.clear();
1489         postCommand(_("-gdb-exit"), GdbEngine::ExitRequest, CB(handleGdbExit));
1490         setState(EngineShuttingDown); // Do it after posting the command!
1491         break;
1492     case InferiorStarting: // This may take some time, so just short-circuit it
1493         setState(InferiorStartFailed);
1494         // fall-through
1495     case InferiorStopFailed: // Tough luck, I guess. But unreachable as of now anyway.
1496         setState(EngineShuttingDown);
1497         m_gdbProc.kill();
1498         break;
1499     }
1500 }
1501
1502 void GdbEngine::handleInferiorShutdown(const GdbResponse &response)
1503 {
1504     QTC_ASSERT(state() == InferiorShuttingDown, qDebug() << state());
1505     if (response.resultClass == GdbResultDone) {
1506         debugMessage(_("INFERIOR SUCCESSFULLY SHUT DOWN"));
1507         setState(InferiorShutDown);
1508     } else {
1509         debugMessage(_("INFERIOR SHUTDOWN FAILED"));
1510         setState(InferiorShutdownFailed);
1511         QString msg = m_gdbAdapter->msgInferiorStopFailed(_(response.data.findChild("msg").data()));
1512         showMessageBox(QMessageBox::Critical, tr("Inferior shutdown failed"), msg);
1513     }
1514     shutdown(); // re-iterate...
1515 }
1516
1517 void GdbEngine::handleGdbExit(const GdbResponse &response)
1518 {
1519     if (response.resultClass == GdbResultExit) {
1520         debugMessage(_("GDB CLAIMS EXIT; WAITING"));
1521         m_commandsDoneCallback = 0;
1522         // don't set state here, this will be handled in handleGdbFinished()
1523     } else {
1524         QString msg = m_gdbAdapter->msgGdbStopFailed(_(response.data.findChild("msg").data()));
1525         debugMessage(_("GDB WON'T EXIT (%1); KILLING IT").arg(msg));
1526         m_gdbProc.kill();
1527     }
1528 }
1529
1530 void GdbEngine::detachDebugger()
1531 {
1532     QTC_ASSERT(state() == InferiorStopped, /**/);
1533     QTC_ASSERT(startMode() != AttachCore, /**/);
1534     postCommand(_("detach")); 
1535     setState(InferiorShuttingDown);
1536     setState(InferiorShutDown);
1537     shutdown();
1538 }
1539
1540 void GdbEngine::exitDebugger() // called from the manager
1541 {
1542     disconnectDebuggingHelperActions();
1543     shutdown();
1544 }
1545
1546 int GdbEngine::currentFrame() const
1547 {
1548     return manager()->stackHandler()->currentIndex();
1549 }
1550
1551 bool GdbEngine::checkConfiguration(int toolChain, QString *errorMessage, QString *settingsPage) const
1552 {
1553     switch (toolChain) {
1554     case ProjectExplorer::ToolChain::WINSCW: // S60
1555     case ProjectExplorer::ToolChain::GCCE:
1556     case ProjectExplorer::ToolChain::RVCT_ARMV5:
1557     case ProjectExplorer::ToolChain::RVCT_ARMV6:
1558         if (!m_trkOptions->check(errorMessage)) {
1559             if (settingsPage)
1560                 *settingsPage = TrkOptionsPage::settingsId();
1561             return false;
1562         }
1563     default:
1564         break;
1565     }
1566     return true;
1567 }
1568
1569 AbstractGdbAdapter *GdbEngine::createAdapter(const DebuggerStartParametersPtr &sp)
1570 {
1571     switch (sp->toolChainType) {
1572     case ProjectExplorer::ToolChain::WINSCW: // S60
1573     case ProjectExplorer::ToolChain::GCCE:
1574     case ProjectExplorer::ToolChain::RVCT_ARMV5:
1575     case ProjectExplorer::ToolChain::RVCT_ARMV6:
1576         return new TrkGdbAdapter(this, m_trkOptions);
1577     default:
1578         break;
1579     }
1580     // @todo: remove testing hack
1581     if (sp->processArgs.size() == 3 && sp->processArgs.at(0) == _("@sym@"))
1582         return new TrkGdbAdapter(this, m_trkOptions);
1583     switch (sp->startMode) {
1584     case AttachCore:
1585         return new CoreGdbAdapter(this);
1586     case StartRemote:
1587         return new RemoteGdbAdapter(this, sp->toolChainType);
1588     case AttachExternal:
1589         return new AttachGdbAdapter(this);
1590     default:
1591         if (sp->useTerminal)
1592             return new TermGdbAdapter(this);
1593         return new PlainGdbAdapter(this);
1594     }
1595 }
1596
1597 void GdbEngine::startDebugger(const DebuggerStartParametersPtr &sp)
1598 {
1599     QTC_ASSERT(state() == EngineStarting, qDebug() << state());
1600     // This should be set by the constructor or in exitDebugger() 
1601     // via initializeVariables()
1602     //QTC_ASSERT(m_debuggingHelperState == DebuggingHelperUninitialized,
1603     //    initializeVariables());
1604     //QTC_ASSERT(m_gdbAdapter == 0, delete m_gdbAdapter; m_gdbAdapter = 0);
1605
1606     initializeVariables();
1607
1608     m_startParameters = sp;
1609
1610     delete m_gdbAdapter;
1611     m_gdbAdapter = createAdapter(sp);
1612     connectAdapter();
1613
1614     if (m_gdbAdapter->dumperHandling() != AbstractGdbAdapter::DumperNotAvailable)
1615         connectDebuggingHelperActions();
1616
1617     m_gdbAdapter->startAdapter();
1618 }
1619
1620 void GdbEngine::continueInferiorInternal()
1621 {
1622     QTC_ASSERT(state() == InferiorStopped || state() == InferiorStarting,
1623                qDebug() << state());
1624     setState(InferiorRunningRequested);
1625     postCommand(_("-exec-continue"), RunRequest, CB(handleExecContinue));
1626 }
1627
1628 void GdbEngine::autoContinueInferior()
1629 {
1630     continueInferiorInternal();
1631     showStatusMessage(tr("Continuing after temporary stop..."), 1000);
1632 }
1633
1634 void GdbEngine::continueInferior()
1635 {
1636     m_manager->resetLocation();
1637     setTokenBarrier();
1638     continueInferiorInternal();
1639     showStatusMessage(tr("Running requested..."), 5000);
1640 }
1641
1642 void GdbEngine::stepExec()
1643 {
1644     QTC_ASSERT(state() == InferiorStopped, qDebug() << state());
1645     setTokenBarrier();
1646     setState(InferiorRunningRequested);
1647     showStatusMessage(tr("Step requested..."), 5000);
1648     if (manager()->isReverseDebugging())
1649         postCommand(_("-reverse-step"), RunRequest, CB(handleExecContinue));
1650     else
1651         postCommand(_("-exec-step"), RunRequest, CB(handleExecContinue));
1652 }
1653
1654 void GdbEngine::stepIExec()
1655 {
1656     QTC_ASSERT(state() == InferiorStopped, qDebug() << state());
1657     setTokenBarrier();
1658     setState(InferiorRunningRequested);
1659     showStatusMessage(tr("Step by instruction requested..."), 5000);
1660     if (manager()->isReverseDebugging())
1661         postCommand(_("-reverse-stepi"), RunRequest, CB(handleExecContinue));
1662     else
1663         postCommand(_("-exec-step-instruction"), RunRequest, CB(handleExecContinue));
1664 }
1665
1666 void GdbEngine::stepOutExec()
1667 {
1668     QTC_ASSERT(state() == InferiorStopped, qDebug() << state());
1669     setTokenBarrier();
1670     setState(InferiorRunningRequested);
1671     showStatusMessage(tr("Finish function requested..."), 5000);
1672     postCommand(_("-exec-finish"), RunRequest, CB(handleExecContinue));
1673 }
1674
1675 void GdbEngine::nextExec()
1676 {
1677     QTC_ASSERT(state() == InferiorStopped, qDebug() << state());
1678     setTokenBarrier();
1679     setState(InferiorRunningRequested);
1680     showStatusMessage(tr("Step next requested..."), 5000);
1681     if (manager()->isReverseDebugging())
1682         postCommand(_("-reverse-next"), RunRequest, CB(handleExecContinue));
1683     else {
1684 #if 1
1685         postCommand(_("-exec-next"), RunRequest, CB(handleExecContinue));
1686 #else
1687         postCommand(_("tbreak \"%2\":%1").arg(lastLine + 1).arg(breakLocation(lastFile)));
1688         postCommand(_("-exec-continue"), RunRequest, CB(handleExecContinue));
1689 #endif
1690     }
1691 }
1692
1693 void GdbEngine::nextIExec()
1694 {
1695     QTC_ASSERT(state() == InferiorStopped, qDebug() << state());
1696     setTokenBarrier();
1697     setState(InferiorRunningRequested);
1698     showStatusMessage(tr("Step next instruction requested..."), 5000);
1699     if (manager()->isReverseDebugging())
1700         postCommand(_("-reverse-nexti"), RunRequest, CB(handleExecContinue));
1701     else
1702         postCommand(_("-exec-next-instruction"), RunRequest, CB(handleExecContinue));
1703 }
1704
1705 void GdbEngine::runToLineExec(const QString &fileName, int lineNumber)
1706 {
1707     QTC_ASSERT(state() == InferiorStopped, qDebug() << state());
1708     setTokenBarrier();
1709     setState(InferiorRunningRequested);
1710     showStatusMessage(tr("Run to line %1 requested...").arg(lineNumber), 5000);
1711     postCommand(_("-exec-until \"%2\":%1").arg(lineNumber).arg(breakLocation(fileName)),
1712                 RunRequest, CB(handleExecContinue));
1713 }
1714
1715 void GdbEngine::runToFunctionExec(const QString &functionName)
1716 {
1717     QTC_ASSERT(state() == InferiorStopped, qDebug() << state());
1718     setTokenBarrier();
1719     postCommand(_("-break-insert -t ") + functionName);
1720     continueInferiorInternal();
1721     //setState(InferiorRunningRequested);
1722     //postCommand(_("-exec-continue"), handleExecRunToFunction);
1723     showStatusMessage(tr("Run to function %1 requested...").arg(functionName), 5000);
1724 }
1725
1726 void GdbEngine::jumpToLineExec(const QString &fileName, int lineNumber)
1727 {
1728     QTC_ASSERT(state() == InferiorStopped, qDebug() << state());
1729     StackFrame frame;
1730     frame.file = fileName;
1731     frame.line = lineNumber;
1732 #if 1
1733     QString loc = breakLocation(fileName);
1734     postCommand(_("tbreak \"%2\":%1").arg(lineNumber).arg(loc));
1735     setState(InferiorRunningRequested);
1736     postCommand(_("jump \"%2\":%1").arg(lineNumber).arg(loc), RunRequest);
1737     // will produce something like
1738     //  &"jump \"/home/apoenitz/dev/work/test1/test1.cpp\":242"
1739     //  ~"Continuing at 0x4058f3."
1740     //  ~"run1 (argc=1, argv=0x7fffbf1f5538) at test1.cpp:242"
1741     //  ~"242\t x *= 2;"
1742     //  23^done"
1743     gotoLocation(frame, true);
1744     //setBreakpoint();
1745     //postCommand(_("jump ") + fileName + ':' + QString::number(lineNumber));
1746 #else
1747     gotoLocation(frame,  true);
1748     setBreakpoint(fileName, lineNumber);
1749     setState(InferiorRunningRequested);
1750     postCommand(_("jump ") + fileName + ':' + QString::number(lineNumber), RunRequest);
1751 #endif
1752 }
1753
1754 /*!
1755     \fn void GdbEngine::setTokenBarrier()
1756     \brief Discard the results of all pending watch-updating commands.
1757
1758     This method is called at the beginning of all step/next/finish etc.
1759     debugger functions.
1760     If non-watch-updating commands with call-backs are still in the pipe,
1761     it will complain.
1762 */
1763
1764 void GdbEngine::setTokenBarrier()
1765 {
1766     foreach (const GdbCommand &cookie, m_cookieForToken) {
1767         QTC_ASSERT(!cookie.callback || (cookie.flags & Discardable),
1768             qDebug() << "CMD:" << cookie.command << " CALLBACK:" << cookie.callbackName;
1769             return
1770         );
1771     }
1772     PENDING_DEBUG("\n--- token barrier ---\n");
1773     gdbInputAvailable(LogMisc, _("--- token barrier ---"));
1774     m_oldestAcceptableToken = currentToken();
1775 }
1776
1777 void GdbEngine::setDebugDebuggingHelpers(const QVariant &on)
1778 {
1779     if (on.toBool()) {
1780         debugMessage(_("SWITCHING ON DUMPER DEBUGGING"));
1781         postCommand(_("set unwindonsignal off"));
1782         m_manager->breakByFunction(_("qDumpObjectData440"));
1783         //updateLocals();
1784     } else {
1785         debugMessage(_("SWITCHING OFF DUMPER DEBUGGING"));
1786         postCommand(_("set unwindonsignal on"));
1787     }
1788 }
1789
1790
1791 //////////////////////////////////////////////////////////////////////
1792 //
1793 // Breakpoint specific stuff
1794 //
1795 //////////////////////////////////////////////////////////////////////
1796
1797 void GdbEngine::breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt)
1798 {
1799     if (!bkpt.isValid())
1800         return;
1801     if (!data)
1802         return;
1803     data->pending = false;
1804     data->bpMultiple = false;
1805     data->bpEnabled = true;
1806     data->bpCondition.clear();
1807     QByteArray file, fullName;
1808     foreach (const GdbMi &child, bkpt.children()) {
1809         if (child.hasName("number")) {
1810             data->bpNumber = _(child.data());
1811         } else if (child.hasName("func")) {
1812             data->bpFuncName = _(child.data());
1813         } else if (child.hasName("addr")) {
1814             // <MULTIPLE> happens in constructors. In this case there are
1815             // _two_ fields named "addr" in the response. On Linux that is...
1816             if (child.data() == "<MULTIPLE>")
1817                 data->bpMultiple = true;
1818             else
1819                 data->bpAddress = _(child.data());
1820         } else if (child.hasName("file")) {
1821             file = child.data();
1822         } else if (child.hasName("fullname")) {
1823             fullName = child.data();
1824         } else if (child.hasName("line")) {
1825             data->bpLineNumber = _(child.data());
1826             if (child.data().toInt())
1827                 data->markerLineNumber = child.data().toInt();
1828         } else if (child.hasName("cond")) {
1829             data->bpCondition = _(child.data());
1830             // gdb 6.3 likes to "rewrite" conditions. Just accept that fact.
1831             if (data->bpCondition != data->condition && data->conditionsMatch())
1832                 data->condition = data->bpCondition;
1833         } else if (child.hasName("enabled")) {
1834             data->bpEnabled = (child.data() == "y");
1835         } else if (child.hasName("pending")) {
1836             data->pending = true;
1837             // Any content here would be interesting only if we did accept
1838             // spontaneously appearing breakpoints (user using gdb commands).
1839         } else if (child.hasName("at")) {
1840             // Happens with (e.g.?) gdb 6.4 symbianelf
1841             QByteArray ba = child.data();
1842             if (ba.startsWith('<') && ba.endsWith('>'))
1843                 ba = ba.mid(1, ba.size() - 2);
1844             data->bpFuncName = _(ba);
1845         }
1846     }
1847     // This field is not present.  Contents needs to be parsed from
1848     // the plain "ignore" response.
1849     //else if (child.hasName("ignore"))
1850     //    data->bpIgnoreCount = child.data();
1851
1852     QString name;
1853     if (!fullName.isEmpty()) {
1854         name = cleanupFullName(QFile::decodeName(fullName));
1855         if (data->markerFileName.isEmpty())
1856             data->markerFileName = name;
1857     } else {
1858         name = QFile::decodeName(file);
1859         // Use fullName() once we have a mapping which is more complete than gdb's own ...
1860         // No point in assigning markerFileName for now.
1861     }
1862     data->bpFileName = name;
1863 }
1864
1865 QString GdbEngine::breakLocation(const QString &file) const
1866 {
1867     QTC_ASSERT(!m_sourcesListOutdated, /* */)
1868     QTC_ASSERT(!m_sourcesListUpdating, /* */)
1869     QString where = m_fullToShortName.value(file);
1870     if (where.isEmpty())
1871         return QFileInfo(file).fileName();
1872     return where;
1873 }
1874
1875 void GdbEngine::sendInsertBreakpoint(int index)
1876 {
1877     const BreakpointData *data = manager()->breakHandler()->at(index);
1878     QString where;
1879     if (data->funcName.isEmpty()) {
1880         where = data->useFullPath ? data->fileName : breakLocation(data->fileName);
1881         // The argument is simply a C-quoted version of the argument to the
1882         // non-MI "break" command, including the "original" quoting it wants.
1883         where = _("\"\\\"%2\\\":%1\"").arg(data->lineNumber).arg(GdbMi::escapeCString(where));
1884     } else {
1885         where = data->funcName;
1886     }
1887
1888     // set up fallback in case of pending breakpoints which aren't handled
1889     // by the MI interface
1890     QString cmd;
1891     if (m_isMacGdb)
1892         cmd = _("-break-insert -l -1 -f ");
1893     else if (m_gdbVersion >= 60800) // Probably some earlier version would work as well ...
1894         cmd = _("-break-insert -f ");
1895     else
1896         cmd = _("-break-insert ");
1897     //if (!data->condition.isEmpty())
1898     //    cmd += _("-c ") + data->condition + _c(' ');
1899     cmd += where;
1900     postCommand(cmd, NeedsStop, CB(handleBreakInsert), index);
1901 }
1902
1903 void GdbEngine::handleBreakList(const GdbResponse &response)
1904 {
1905     m_sourcesListUpdating = false;
1906
1907     // 45^done,BreakpointTable={nr_rows="2",nr_cols="6",hdr=[
1908     // {width="3",alignment="-1",col_name="number",colhdr="Num"}, ...
1909     // body=[bkpt={number="1",type="breakpoint",disp="keep",enabled="y",
1910     //  addr="0x000000000040109e",func="main",file="app.cpp",
1911     //  fullname="/home/apoenitz/dev/work/plugintest/app/app.cpp",
1912     //  line="11",times="1"},
1913     //  bkpt={number="2",type="breakpoint",disp="keep",enabled="y",
1914     //  addr="<PENDING>",pending="plugin.cpp:7",times="0"}] ... }
1915
1916     if (response.resultClass == GdbResultDone) {
1917         GdbMi table = response.data.findChild("BreakpointTable");
1918         if (table.isValid())
1919             handleBreakList(table);
1920     }
1921 }
1922
1923 void GdbEngine::handleBreakList(const GdbMi &table)
1924 {
1925     GdbMi body = table.findChild("body");
1926     QList<GdbMi> bkpts;
1927     if (body.isValid()) {
1928         // Non-Mac
1929         bkpts = body.children();
1930     } else {
1931         // Mac
1932         bkpts = table.children();
1933         // Remove the 'hdr' and artificial items.
1934         for (int i = bkpts.size(); --i >= 0; ) {
1935             int num = bkpts.at(i).findChild("number").data().toInt();
1936             if (num <= 0)
1937                 bkpts.removeAt(i);
1938         }
1939         //qDebug() << "LEFT" << bkpts.size() << "BREAKPOINTS";
1940     }
1941
1942     BreakHandler *handler = manager()->breakHandler();
1943     for (int index = 0; index != bkpts.size(); ++index) {
1944         BreakpointData temp(handler);
1945         breakpointDataFromOutput(&temp, bkpts.at(index));
1946         int found = handler->findBreakpoint(temp);
1947         if (found != -1)
1948             breakpointDataFromOutput(handler->at(found), bkpts.at(index));
1949         //else
1950             //qDebug() << "CANNOT HANDLE RESPONSE" << bkpts.at(index).toString();
1951     }
1952
1953     attemptBreakpointSynchronization();
1954 }
1955
1956 void GdbEngine::handleBreakIgnore(const GdbResponse &response)
1957 {
1958     int index = response.cookie.toInt();
1959     // gdb 6.8:
1960     // ignore 2 0:
1961     // ~"Will stop next time breakpoint 2 is reached.\n"
1962     // 28^done
1963     // ignore 2 12:
1964     // &"ignore 2 12\n"
1965     // ~"Will ignore next 12 crossings of breakpoint 2.\n"
1966     // 29^done
1967     //
1968     // gdb 6.3 does not produce any console output
1969     BreakHandler *handler = manager()->breakHandler();
1970     if (response.resultClass == GdbResultDone && index < handler->size()) {
1971         QString msg = _(response.data.findChild("consolestreamoutput").data());
1972         BreakpointData *data = handler->at(index);
1973         //if (msg.contains(__("Will stop next time breakpoint"))) {
1974         //    data->bpIgnoreCount = _("0");
1975         //} else if (msg.contains(__("Will ignore next"))) {
1976         //    data->bpIgnoreCount = data->ignoreCount;
1977         //}
1978         // FIXME: this assumes it is doing the right thing...
1979         data->bpIgnoreCount = data->ignoreCount;
1980         handler->updateMarkers();
1981     }
1982 }
1983
1984 void GdbEngine::handleBreakCondition(const GdbResponse &response)
1985 {
1986     int index = response.cookie.toInt();
1987     BreakHandler *handler = manager()->breakHandler();
1988     if (response.resultClass == GdbResultDone) {
1989         // We just assume it was successful. Otherwise we had to parse
1990         // the output stream data.
1991         BreakpointData *data = handler->at(index);
1992         //qDebug() << "HANDLE BREAK CONDITION" << index << data->condition;
1993         data->bpCondition = data->condition;
1994     } else {
1995         QByteArray msg = response.data.findChild("msg").data();
1996         // happens on Mac
1997         if (1 || msg.startsWith("Error parsing breakpoint condition. "
1998                 " Will try again when we hit the breakpoint.")) {
1999             BreakpointData *data = handler->at(index);
2000             //qDebug() << "ERROR BREAK CONDITION" << index << data->condition;
2001             data->bpCondition = data->condition;
2002         }
2003     }
2004     handler->updateMarkers();
2005 }
2006
2007 void GdbEngine::handleBreakInsert(const GdbResponse &response)
2008 {
2009     int index = response.cookie.toInt();
2010     BreakHandler *handler = manager()->breakHandler();
2011     if (response.resultClass == GdbResultDone) {
2012 //#if defined(Q_OS_MAC)
2013         // Interesting only on Mac?
2014         BreakpointData *data = handler->at(index);
2015         GdbMi bkpt = response.data.findChild("bkpt");
2016         breakpointDataFromOutput(data, bkpt);
2017 //#endif
2018         attemptBreakpointSynchronization();
2019     } else {
2020         if (m_gdbVersion < 60800 && !m_isMacGdb) {
2021             // This gdb version doesn't "do" pending breakpoints.
2022         } else {
2023             QTC_ASSERT(false, /**/);
2024         }
2025     }
2026 }
2027
2028 void GdbEngine::extractDataFromInfoBreak(const QString &output, BreakpointData *data)
2029 {
2030     data->bpFileName = _("<MULTIPLE>");
2031
2032     //qDebug() << output;
2033     if (output.isEmpty())
2034         return;
2035     // "Num     Type           Disp Enb Address            What
2036     // 4       breakpoint     keep y   <MULTIPLE>         0x00000000004066ad
2037     // 4.1                         y     0x00000000004066ad in CTorTester
2038     //  at /data5/dev/ide/main/tests/manual/gdbdebugger/simple/app.cpp:124
2039     // - or -
2040     // everything on a single line on Windows for constructors of classes
2041     // within namespaces.
2042     // Sometimes the path is relative too.
2043
2044     // 2    breakpoint     keep y   <MULTIPLE> 0x0040168e
2045     // 2.1    y     0x0040168e in MainWindow::MainWindow(QWidget*) at mainwindow.cpp:7
2046     // 2.2    y     0x00401792 in MainWindow::MainWindow(QWidget*) at mainwindow.cpp:7
2047
2048     // tested in ../../../tests/auto/debugger/
2049     QRegExp re(_("MULTIPLE.*(0x[0-9a-f]+) in (.*)\\s+at (.*):([\\d]+)([^\\d]|$)"));
2050     re.setMinimal(true);
2051
2052     if (re.indexIn(output) != -1) {
2053         data->bpAddress = re.cap(1);
2054         data->bpFuncName = re.cap(2).trimmed();
2055         data->bpLineNumber = re.cap(4);
2056         QString full = fullName(re.cap(3));
2057         if (full.isEmpty()) {
2058             qDebug() << "NO FULL NAME KNOWN FOR" << re.cap(3);
2059             full = cleanupFullName(re.cap(3));
2060             if (full.isEmpty()) {
2061                 qDebug() << "FILE IS NOT RESOLVABLE" << re.cap(3);
2062                 full = re.cap(3); // FIXME: wrong, but prevents recursion
2063             }
2064         }
2065         data->markerLineNumber = data->bpLineNumber.toInt();
2066         data->markerFileName = full;
2067         data->bpFileName = full;
2068     } else {
2069         qDebug() << "COULD NOT MATCH " << re.pattern() << " AND " << output;
2070         data->bpNumber = _("<unavailable>");
2071     }
2072 }
2073
2074 void GdbEngine::handleBreakInfo(const GdbResponse &response)
2075 {
2076     int bpNumber = response.cookie.toInt();
2077     BreakHandler *handler = manager()->breakHandler();
2078     if (response.resultClass == GdbResultDone) {
2079         // Old-style output for multiple breakpoints, presumably in a
2080         // constructor
2081         int found = handler->findBreakpoint(bpNumber);
2082         if (found != -1) {
2083             QString str = QString::fromLocal8Bit(response.data.findChild("consolestreamoutput").data());
2084             extractDataFromInfoBreak(str, handler->at(found));
2085             attemptBreakpointSynchronization(); // trigger "ready"
2086         }
2087     }
2088 }
2089
2090 void GdbEngine::handleBreakInsert1(const GdbResponse &response)
2091 {
2092     int index = response.cookie.toInt();
2093     BreakHandler *handler = manager()->breakHandler();
2094     if (response.resultClass == GdbResultDone) {
2095         // Pending breakpoints in dylibs on Mac only?
2096         BreakpointData *data = handler->at(index);
2097         GdbMi bkpt = response.data.findChild("bkpt");
2098         breakpointDataFromOutput(data, bkpt);
2099     } else {
2100         qDebug() << "INSERTING BREAKPOINT WITH BASE NAME FAILED. GIVING UP";
2101         BreakpointData *data = handler->at(index);
2102         data->bpNumber = _("<unavailable>");
2103     }
2104     attemptBreakpointSynchronization(); // trigger "ready"
2105 }
2106
2107 void GdbEngine::attemptBreakpointSynchronization()
2108 {
2109     switch (state()) {
2110     case InferiorStarting:
2111     case InferiorRunningRequested:
2112     case InferiorRunning:
2113     case InferiorStopping:
2114     case InferiorStopped:
2115         break;
2116     default:
2117         //qDebug() << "attempted breakpoint sync in state" << state();
2118         return;
2119     }
2120
2121     // For best results, we rely on an up-to-date fullname mapping.
2122     // The listing completion will retrigger us, so no futher action is needed.
2123     if (m_sourcesListOutdated) {
2124         reloadSourceFilesInternal();
2125         return;
2126     } else if (m_sourcesListUpdating) {
2127         return;
2128     }
2129
2130     BreakHandler *handler = manager()->breakHandler();
2131
2132     foreach (BreakpointData *data, handler->takeDisabledBreakpoints()) {
2133         QString bpNumber = data->bpNumber;
2134         if (!bpNumber.trimmed().isEmpty()) {
2135             postCommand(_("-break-disable ") + bpNumber, NeedsStop);
2136             data->bpEnabled = false;
2137         }
2138     }
2139
2140     foreach (BreakpointData *data, handler->takeEnabledBreakpoints()) {
2141         QString bpNumber = data->bpNumber;
2142         if (!bpNumber.trimmed().isEmpty()) {
2143             postCommand(_("-break-enable ") + bpNumber, NeedsStop);
2144             data->bpEnabled = true;
2145         }
2146     }
2147
2148     foreach (BreakpointData *data, handler->takeRemovedBreakpoints()) {
2149         QString bpNumber = data->bpNumber;
2150         debugMessage(_("DELETING BP %1 IN %2").arg(bpNumber)
2151             .arg(data->markerFileName));
2152         if (!bpNumber.trimmed().isEmpty())
2153             postCommand(_("-break-delete ") + bpNumber, NeedsStop);
2154         delete data;
2155     }
2156
2157     for (int index = 0; index != handler->size(); ++index) {
2158         BreakpointData *data = handler->at(index);
2159         if (data->bpNumber.isEmpty()) { // unset breakpoint?
2160             data->bpNumber = _(" "); // Sent, but no feedback yet
2161             sendInsertBreakpoint(index);
2162         } else if (data->bpNumber.toInt()) {
2163             if (data->bpMultiple && data->bpFileName.isEmpty()) {
2164                 postCommand(_("info break %1").arg(data->bpNumber),
2165                     CB(handleBreakInfo), data->bpNumber.toInt());
2166                 continue;
2167             }
2168             // update conditions if needed
2169             if (data->condition != data->bpCondition && !data->conditionsMatch())
2170                 postCommand(_("condition %1 %2").arg(data->bpNumber).arg(data->condition),
2171                             CB(handleBreakCondition), index);
2172             // update ignorecount if needed
2173             if (data->ignoreCount != data->bpIgnoreCount)
2174                 postCommand(_("ignore %1 %2").arg(data->bpNumber).arg(data->ignoreCount),
2175                             CB(handleBreakIgnore), index);
2176             if (!data->enabled && data->bpEnabled) {
2177                 postCommand(_("-break-disable ") + data->bpNumber, NeedsStop);
2178                 data->bpEnabled = false;
2179             }
2180         }
2181     }
2182
2183     handler->updateMarkers();
2184 }
2185
2186
2187 //////////////////////////////////////////////////////////////////////
2188 //
2189 // Modules specific stuff
2190 //
2191 //////////////////////////////////////////////////////////////////////
2192
2193 void GdbEngine::loadSymbols(const QString &moduleName)
2194 {
2195     // FIXME: gdb does not understand quoted names here (tested with 6.8)
2196     postCommand(_("sharedlibrary ") + dotEscape(moduleName));
2197     reloadModulesInternal();
2198 }
2199
2200 void GdbEngine::loadAllSymbols()
2201 {
2202     postCommand(_("sharedlibrary .*"));
2203     reloadModulesInternal();
2204 }
2205
2206 QList<Symbol> GdbEngine::moduleSymbols(const QString &moduleName)
2207 {
2208     QList<Symbol> rc;
2209     bool success = false;
2210     QString errorMessage;
2211     do {
2212         const QString nmBinary = _("nm");
2213         QProcess proc;
2214         proc.start(nmBinary, QStringList() << _("-D") << moduleName);
2215         if (!proc.waitForFinished()) {
2216             errorMessage = tr("Unable to run '%1': %2").arg(nmBinary, proc.errorString());
2217             break;
2218         }
2219         const QString contents = QString::fromLocal8Bit(proc.readAllStandardOutput());
2220         const QRegExp re(_("([0-9a-f]+)?\\s+([^\\s]+)\\s+([^\\s]+)"));
2221         Q_ASSERT(re.isValid());
2222         foreach (const QString &line, contents.split(_c('\n'))) {
2223             if (re.indexIn(line) != -1) {
2224                 Symbol symbol;
2225                 symbol.address = re.cap(1);
2226                 symbol.state = re.cap(2);
2227                 symbol.name = re.cap(3);
2228                 rc.push_back(symbol);
2229             } else {
2230                 qWarning("moduleSymbols: unhandled: %s", qPrintable(line));
2231             }
2232         }
2233         success = true;
2234     } while (false);
2235     if (!success)
2236         qWarning("moduleSymbols: %s\n", qPrintable(errorMessage));
2237     return rc;
2238 }
2239
2240 void GdbEngine::reloadModules()
2241 {
2242     if (state() == InferiorRunning || state() == InferiorStopped)
2243         reloadModulesInternal();
2244 }
2245
2246 void GdbEngine::reloadModulesInternal()
2247 {
2248     m_modulesListOutdated = false;
2249     postCommand(_("info shared"), NeedsStop, CB(handleModulesList));
2250     if (m_gdbVersion < 70000 && !m_isMacGdb)
2251         postCommand(_("set stop-on-solib-events 1"));
2252 }
2253
2254 void GdbEngine::handleModulesList(const GdbResponse &response)
2255 {
2256     QList<Module> modules;
2257     if (response.resultClass == GdbResultDone) {
2258         // That's console-based output, likely Linux or Windows,
2259         // but we can avoid the #ifdef here.
2260         QString data = QString::fromLocal8Bit(response.data.findChild("consolestreamoutput").data());
2261         QTextStream ts(&data, QIODevice::ReadOnly);
2262         while (!ts.atEnd()) {
2263             QString line = ts.readLine();
2264             Module module;
2265             QString symbolsRead;
2266             QTextStream ts(&line, QIODevice::ReadOnly);
2267             if (line.startsWith(__("0x"))) {
2268                 ts >> module.startAddress >> module.endAddress >> symbolsRead;
2269                 module.moduleName = ts.readLine().trimmed();
2270                 module.symbolsRead = (symbolsRead == __("Yes"));
2271                 modules.append(module);
2272             } else if (line.trimmed().startsWith(__("No"))) {
2273                 // gdb 6.4 symbianelf
2274                 ts >> symbolsRead;
2275                 QTC_ASSERT(symbolsRead == __("No"), continue);
2276                 module.moduleName = ts.readLine().trimmed();
2277                 modules.append(module);
2278             }
2279         }
2280         if (modules.isEmpty()) {
2281             // Mac has^done,shlib-info={num="1",name="dyld",kind="-",
2282             // dyld-addr="0x8fe00000",reason="dyld",requested-state="Y",
2283             // state="Y",path="/usr/lib/dyld",description="/usr/lib/dyld",
2284             // loaded_addr="0x8fe00000",slide="0x0",prefix="__dyld_"},
2285             // shlib-info={...}...
2286             foreach (const GdbMi &item, response.data.children()) {
2287                 Module module;
2288                 module.moduleName = QString::fromLocal8Bit(item.findChild("path").data());
2289                 module.symbolsRead = (item.findChild("state").data() == "Y");
2290                 module.startAddress = _(item.findChild("loaded_addr").data());
2291                 //: End address of loaded module
2292                 module.endAddress = tr("<unknown>", "address");
2293                 modules.append(module);
2294             }
2295         }
2296     }
2297     manager()->modulesHandler()->setModules(modules);
2298 }
2299
2300
2301 //////////////////////////////////////////////////////////////////////
2302 //
2303 // Source files specific stuff
2304 //
2305 //////////////////////////////////////////////////////////////////////
2306
2307 void GdbEngine::reloadSourceFiles()
2308 {
2309     if ((state() == InferiorRunning || state() == InferiorStopped)
2310         && !m_sourcesListUpdating)
2311         reloadSourceFilesInternal();
2312 }
2313
2314 void GdbEngine::reloadSourceFilesInternal()
2315 {
2316     m_sourcesListUpdating = true;
2317     m_sourcesListOutdated = false;
2318     postCommand(_("-file-list-exec-source-files"), NeedsStop, CB(handleQuerySources));
2319     postCommand(_("-break-list"), CB(handleBreakList));
2320     if (m_gdbVersion < 70000 && !m_isMacGdb)
2321         postCommand(_("set stop-on-solib-events 1"));
2322 }
2323
2324
2325 //////////////////////////////////////////////////////////////////////
2326 //
2327 // Stack specific stuff
2328 //
2329 //////////////////////////////////////////////////////////////////////
2330
2331 void GdbEngine::selectThread(int index)
2332 {
2333     ThreadsHandler *threadsHandler = manager()->threadsHandler();
2334     threadsHandler->setCurrentThread(index);
2335
2336     QList<ThreadData> threads = threadsHandler->threads();
2337     QTC_ASSERT(index < threads.size(), return);
2338     int id = threads.at(index).id;
2339     showStatusMessage(tr("Retrieving data for stack view..."), 10000);
2340     postCommand(_("-thread-select %1").arg(id), CB(handleStackSelectThread));
2341 }
2342
2343 void GdbEngine::handleStackSelectThread(const GdbResponse &)
2344 {
2345     QTC_ASSERT(state() == InferiorUnrunnable || state() == InferiorStopped, /**/);
2346     //qDebug("FIXME: StackHandler::handleOutput: SelectThread");
2347     showStatusMessage(tr("Retrieving data for stack view..."), 3000);
2348     manager()->reloadRegisters();
2349     reloadStack(true);
2350     updateLocals(); 
2351 }
2352
2353 void GdbEngine::reloadFullStack()
2354 {
2355     QString cmd = _("-stack-list-frames");
2356     postCommand(cmd, WatchUpdate, CB(handleStackListFrames),
2357         QVariant::fromValue<StackCookie>(StackCookie(true, true)));
2358 }
2359
2360 void GdbEngine::reloadStack(bool forceGotoLocation)
2361 {
2362     QString cmd = _("-stack-list-frames");
2363     int stackDepth = theDebuggerAction(MaximalStackDepth)->value().toInt();
2364     if (stackDepth && !m_gdbAdapter->isTrkAdapter())
2365         cmd += _(" 0 ") + QString::number(stackDepth);
2366     // FIXME: gdb 6.4 symbianelf likes to be asked twice. The first time it
2367     // returns with "^error,msg="Previous frame identical to this frame
2368     // (corrupt stack?)". Might be related to the fact that we can't
2369     // access the memory belonging to the lower frames. But as we know
2370     // this sometimes happens, ask the second time immediately instead
2371     // of waiting for the first request to fail.
2372     if (m_gdbAdapter->isTrkAdapter())
2373         postCommand(cmd, WatchUpdate);
2374     postCommand(cmd, WatchUpdate, CB(handleStackListFrames),
2375         QVariant::fromValue<StackCookie>(StackCookie(false, forceGotoLocation)));
2376 }
2377
2378 StackFrame GdbEngine::parseStackFrame(const GdbMi &frameMi, int level)
2379 {
2380     //qDebug() << "HANDLING FRAME:" << frameMi.toString();
2381     StackFrame frame;
2382     frame.level = level;
2383     GdbMi fullName = frameMi.findChild("fullname");
2384     if (fullName.isValid())
2385         frame.file = cleanupFullName(QFile::decodeName(fullName.data()));
2386     else
2387         frame.file = QFile::decodeName(frameMi.findChild("file").data());
2388     frame.function = _(frameMi.findChild("func").data());
2389     frame.from = _(frameMi.findChild("from").data());
2390     frame.line = frameMi.findChild("line").data().toInt();
2391     frame.address = _(frameMi.findChild("addr").data());
2392     return frame;
2393 }
2394
2395 void GdbEngine::handleStackListFrames(const GdbResponse &response)
2396 {
2397     bool handleIt = (m_isMacGdb || response.resultClass == GdbResultDone);
2398     if (!handleIt) {
2399         // That always happens on symbian gdb with
2400         // ^error,data={msg="Previous frame identical to this frame (corrupt stack?)"
2401         // logstreamoutput="Previous frame identical to this frame (corrupt stack?)\n"
2402         //qDebug() << "LISTING STACK FAILED: " << response.toString();
2403         return;
2404     }
2405
2406     StackCookie cookie = response.cookie.value<StackCookie>();
2407     QList<StackFrame> stackFrames;
2408
2409     GdbMi stack = response.data.findChild("stack");
2410     if (!stack.isValid()) {
2411         qDebug() << "FIXME: stack:" << stack.toString();
2412         return;
2413     }
2414
2415     int targetFrame = -1;
2416
2417     int n = stack.childCount();
2418     for (int i = 0; i != n; ++i) {
2419         stackFrames.append(parseStackFrame(stack.childAt(i), i));
2420         const StackFrame &frame = stackFrames.back();
2421
2422         #if defined(Q_OS_WIN)
2423         const bool isBogus =
2424             // Assume this is wrong and points to some strange stl_algobase
2425             // implementation. Happens on Karsten's XP system with Gdb 5.50
2426             (frame.file.endsWith(__("/bits/stl_algobase.h")) && frame.line == 150)
2427             // Also wrong. Happens on Vista with Gdb 5.50
2428                || (frame.function == __("operator new") && frame.line == 151);
2429
2430         // Immediately leave bogus frames.
2431         if (targetFrame == -1 && isBogus) {
2432             setTokenBarrier();
2433             setState(InferiorRunningRequested);
2434             postCommand(_("-exec-finish"), RunRequest, CB(handleExecContinue));
2435             showStatusMessage(tr("Jumping out of bogus frame..."), 1000);
2436             return;
2437         }
2438         #endif
2439
2440         // Initialize top frame to the first valid frame.
2441         const bool isValid = frame.isUsable() && !frame.function.isEmpty();
2442         if (isValid && targetFrame == -1)
2443             targetFrame = i;
2444     }
2445
2446     bool canExpand = !cookie.isFull 
2447         && (n >= theDebuggerAction(MaximalStackDepth)->value().toInt());
2448     theDebuggerAction(ExpandStack)->setEnabled(canExpand);
2449     manager()->stackHandler()->setFrames(stackFrames, canExpand);
2450
2451     // We can't jump to any file if we don't have any frames.
2452     if (stackFrames.isEmpty())
2453         return;
2454
2455     // targetFrame contains the top most frame for which we have source
2456     // information. That's typically the frame we'd like to jump to, with
2457     // a few exceptions:
2458
2459     // Always jump to frame #0 when stepping by instruction.
2460     if (theDebuggerBoolSetting(OperateByInstruction))
2461         targetFrame = 0;
2462
2463     // If there is no frame with source, jump to frame #0.
2464     if (targetFrame == -1)
2465         targetFrame = 0;
2466
2467     // Mac gdb does not add the location to the "stopped" message,
2468     // so the early gotoLocation() was not triggered. Force it here.
2469     // For targetFrame == 0 we already issued a 'gotoLocation'
2470     // when reading the *stopped message.
2471     bool jump = (m_isMacGdb || targetFrame != 0);
2472   
2473     manager()->stackHandler()->setCurrentIndex(targetFrame);
2474     if (jump || cookie.gotoLocation) {
2475         const StackFrame &frame = manager()->stackHandler()->currentFrame();
2476         //qDebug() << "GOTO, 2ND ATTEMPT: " << frame.toString() << targetFrame;
2477         gotoLocation(frame, true);
2478     }
2479 }
2480
2481 void GdbEngine::activateFrame(int frameIndex)
2482 {
2483     m_manager->resetLocation();
2484     if (state() != InferiorStopped && state() != InferiorUnrunnable)
2485         return;
2486
2487     StackHandler *stackHandler = manager()->stackHandler();
2488     int oldIndex = stackHandler->currentIndex();
2489
2490     if (frameIndex == stackHandler->stackSize()) {
2491         reloadFullStack();
2492         return;
2493     }
2494
2495     QTC_ASSERT(frameIndex < stackHandler->stackSize(), return);
2496
2497     if (oldIndex != frameIndex) {
2498         setTokenBarrier();
2499
2500         // Assuming the command always succeeds this saves a roundtrip.
2501         // Otherwise the lines below would need to get triggered
2502         // after a response to this -stack-select-frame here.
2503         postCommand(_("-stack-select-frame ") + QString::number(frameIndex));
2504
2505         stackHandler->setCurrentIndex(frameIndex);
2506         updateLocals();
2507         reloadRegisters();
2508     }
2509
2510     gotoLocation(stackHandler->currentFrame(), true);
2511 }
2512
2513 void GdbEngine::handleStackListThreads(const GdbResponse &response)
2514 {
2515     int id = response.cookie.toInt();
2516     // "72^done,{thread-ids={thread-id="2",thread-id="1"},number-of-threads="2"}
2517     const QList<GdbMi> items = response.data.findChild("thread-ids").children();
2518     QList<ThreadData> threads;
2519     int currentIndex = -1;
2520     for (int index = 0, n = items.size(); index != n; ++index) {
2521         ThreadData thread;
2522         thread.id = items.at(index).data().toInt();
2523         threads.append(thread);
2524         if (thread.id == id) {
2525             //qDebug() << "SETTING INDEX TO:" << index << " ID:"
2526             // << id << " RECOD:" << response.toString();
2527             currentIndex = index;
2528         }
2529     }
2530     ThreadsHandler *threadsHandler = manager()->threadsHandler();
2531     threadsHandler->setThreads(threads);
2532     threadsHandler->setCurrentThread(currentIndex);
2533 }
2534
2535
2536 //////////////////////////////////////////////////////////////////////
2537 //
2538 // Register specific stuff
2539 //
2540 //////////////////////////////////////////////////////////////////////
2541
2542 void GdbEngine::reloadRegisters()
2543 {
2544     if (!m_registerNamesListed) {
2545         postCommand(_("-data-list-register-names"), CB(handleRegisterListNames));
2546         m_registerNamesListed = true;
2547     }
2548
2549     if (m_gdbAdapter->isTrkAdapter()) {
2550         // FIXME: remove that special case. This is only to prevent
2551         // gdb from asking for the values of the fixed point registers
2552         postCommand(_("-data-list-register-values x 0 1 2 3 4 5 6 7 8 9 "
2553                       "10 11 12 13 14 15 25"),
2554                     Discardable, CB(handleRegisterListValues));
2555     } else {
2556         postCommand(_("-data-list-register-values x"),
2557                     Discardable, CB(handleRegisterListValues));
2558     }
2559 }
2560
2561 void GdbEngine::setRegisterValue(int nr, const QString &value)
2562 {
2563     Register reg = manager()->registerHandler()->registers().at(nr);
2564     //qDebug() << "NOT IMPLEMENTED: CHANGE REGISTER " << nr << reg.name << ":"
2565     //    << value;
2566     postCommand(_("-var-delete \"R@\""));
2567     postCommand(_("-var-create \"R@\" * $%1").arg(reg.name));
2568     postCommand(_("-var-assign \"R@\" %1").arg(value));
2569     postCommand(_("-var-delete \"R@\""));
2570     //postCommand(_("-data-list-register-values d"),
2571     //            Discardable, CB(handleRegisterListValues));
2572     reloadRegisters();
2573 }
2574
2575 void GdbEngine::handleRegisterListNames(const GdbResponse &response)
2576 {
2577     if (response.resultClass != GdbResultDone) {
2578         m_registerNamesListed = false;
2579         return;
2580     }
2581
2582     QList<Register> registers;
2583     foreach (const GdbMi &item, response.data.findChild("register-names").children())
2584         registers.append(Register(_(item.data())));
2585
2586     manager()->registerHandler()->setRegisters(registers);
2587 }
2588
2589 void GdbEngine::handleRegisterListValues(const GdbResponse &response)
2590 {
2591     if (response.resultClass != GdbResultDone)
2592         return;
2593
2594     QList<Register> registers = manager()->registerHandler()->registers();
2595
2596     // 24^done,register-values=[{number="0",value="0xf423f"},...]
2597     foreach (const GdbMi &item, response.data.findChild("register-values").children()) {
2598         int index = item.findChild("number").data().toInt();
2599         if (index < registers.size()) {
2600             Register &reg = registers[index];
2601             QString value = _(item.findChild("value").data());
2602             reg.changed = (value != reg.value);
2603             if (reg.changed)
2604                 reg.value = value;
2605         }
2606     }
2607     manager()->registerHandler()->setRegisters(registers);
2608 }
2609
2610
2611 //////////////////////////////////////////////////////////////////////
2612 //
2613 // Thread specific stuff
2614 //
2615 //////////////////////////////////////////////////////////////////////
2616
2617 bool GdbEngine::supportsThreads() const
2618 {
2619     // FSF gdb 6.3 crashes happily on -thread-list-ids. So don't use it.
2620     // The test below is a semi-random pick, 6.8 works fine
2621     return m_isMacGdb || m_gdbVersion > 60500;
2622 }
2623
2624
2625 //////////////////////////////////////////////////////////////////////
2626 //
2627 // Tooltip specific stuff
2628 //
2629 //////////////////////////////////////////////////////////////////////
2630
2631 static QString m_toolTipExpression;
2632 static QPoint m_toolTipPos;
2633
2634 static QString tooltipINameForExpression(const QString &exp)
2635 {
2636     // FIXME: 'exp' can contain illegal characters
2637     //return QLatin1String("tooltip.") + exp;
2638     Q_UNUSED(exp)
2639     return QLatin1String("tooltip.x");
2640 }
2641
2642 bool GdbEngine::showToolTip()
2643 {
2644     WatchHandler *handler = manager()->watchHandler();
2645     WatchModel *model = handler->model(TooltipsWatch);
2646     QString iname = tooltipINameForExpression(m_toolTipExpression);
2647     WatchItem *item = model->findItem(iname, model->rootItem());
2648     if (!item) {
2649         hideDebuggerToolTip();
2650         return false;
2651     }
2652     QModelIndex index = model->watchIndex(item);
2653     showDebuggerToolTip(m_toolTipPos, model, index, m_toolTipExpression);
2654     return true;
2655 }
2656
2657 void GdbEngine::setToolTipExpression(const QPoint &mousePos,
2658     TextEditor::ITextEditor *editor, int cursorPos)
2659 {
2660     if (state() != InferiorStopped || !isCppEditor(editor)) {
2661         //qDebug() << "SUPPRESSING DEBUGGER TOOLTIP, INFERIOR NOT STOPPED/Non Cpp editor";
2662         return;
2663     }
2664
2665     if (theDebuggerBoolSetting(DebugDebuggingHelpers)) {
2666         // minimize interference
2667         return;
2668     }
2669
2670     m_toolTipPos = mousePos;
2671     int line, column;
2672     QString exp = cppExpressionAt(editor, cursorPos, &line, &column);
2673     m_toolTipExpression = exp;
2674
2675     // FIXME: enable caching
2676     //if (showToolTip())
2677     //    return;
2678
2679     if (exp.isEmpty() || exp.startsWith(_c('#')))  {
2680         //QToolTip::hideText();
2681         return;
2682     }
2683
2684     if (!hasLetterOrNumber(exp)) {
2685         //QToolTip::showText(m_toolTipPos,
2686         //    tr("'%1' contains no identifier").arg(exp));
2687         return;
2688     }
2689
2690     if (isKeyWord(exp))
2691         return;
2692
2693     if (exp.startsWith(_c('"')) && exp.endsWith(_c('"')))  {
2694         //QToolTip::showText(m_toolTipPos, tr("String literal %1").arg(exp));
2695         return;
2696     }
2697
2698     if (exp.startsWith(__("++")) || exp.startsWith(__("--")))
2699         exp = exp.mid(2);
2700
2701     if (exp.endsWith(__("++")) || exp.endsWith(__("--")))
2702         exp = exp.mid(2);
2703
2704     if (exp.startsWith(_c('<')) || exp.startsWith(_c('[')))
2705         return;
2706
2707     if (hasSideEffects(exp)) {
2708         //QToolTip::showText(m_toolTipPos,
2709         //    tr("Cowardly refusing to evaluate expression '%1' "
2710         //       "with potential side effects").arg(exp));
2711         return;
2712     }
2713
2714     // Gdb crashes when creating a variable object with the name
2715     // of the type of 'this'
2716 /*
2717     for (int i = 0; i != m_currentLocals.childCount(); ++i) {
2718         if (m_currentLocals.childAt(i).exp == "this") {
2719             qDebug() << "THIS IN ROW" << i;
2720             if (m_currentLocals.childAt(i).type.startsWith(exp)) {
2721                 QToolTip::showText(m_toolTipPos,
2722                     tr("%1: type of current 'this'").arg(exp));
2723                 qDebug() << " TOOLTIP CRASH SUPPRESSED";
2724                 return;
2725             }
2726             break;
2727         }
2728     }
2729 */
2730
2731     WatchData toolTip;
2732     toolTip.exp = exp;
2733     toolTip.name = exp;
2734     toolTip.iname = tooltipINameForExpression(exp);
2735     manager()->watchHandler()->removeData(toolTip.iname);
2736     manager()->watchHandler()->insertData(toolTip);
2737 }
2738
2739
2740 //////////////////////////////////////////////////////////////////////
2741 //
2742 // Watch specific stuff
2743 //
2744 //////////////////////////////////////////////////////////////////////
2745
2746 static void setWatchDataValue(WatchData &data, const GdbMi &mi,
2747     int encoding = 0)
2748 {
2749     if (mi.isValid())
2750         data.setValue(decodeData(mi.data(), encoding));
2751     else
2752         data.setValueNeeded();
2753 }
2754
2755 static void setWatchDataEditValue(WatchData &data, const GdbMi &mi)
2756 {
2757     if (mi.isValid())
2758         data.editvalue = mi.data();
2759 }
2760
2761 static void setWatchDataValueToolTip(WatchData &data, const GdbMi &mi,
2762         int encoding = 0)
2763 {
2764     if (mi.isValid())
2765         data.setValueToolTip(decodeData(mi.data(), encoding));
2766 }
2767
2768 static void setWatchDataChildCount(WatchData &data, const GdbMi &mi)
2769 {
2770     if (mi.isValid())
2771         data.setHasChildren(mi.data().toInt() > 0);
2772 }
2773
2774 static void setWatchDataValueEnabled(WatchData &data, const GdbMi &mi)
2775 {
2776     if (mi.data() == "true")
2777         data.valueEnabled = true;
2778     else if (mi.data() == "false")
2779         data.valueEnabled = false;
2780 }
2781
2782 static void setWatchDataValueEditable(WatchData &data, const GdbMi &mi)
2783 {
2784     if (mi.data() == "true")
2785         data.valueEditable = true;
2786     else if (mi.data() == "false")
2787         data.valueEditable = false;
2788 }
2789
2790 static void setWatchDataExpression(WatchData &data, const GdbMi &mi)
2791 {
2792     if (mi.isValid())
2793         data.exp = _('(' + mi.data() + ')');
2794 }
2795
2796 static void setWatchDataAddress(WatchData &data, const GdbMi &mi)
2797 {
2798     if (mi.isValid()) {
2799         data.addr = _(mi.data());
2800         if (data.exp.isEmpty() && !data.addr.startsWith(_("$")))
2801             data.exp = _("(*(") + gdbQuoteTypes(data.type) + _("*)") + data.addr + _c(')');
2802     }
2803 }
2804
2805 static void setWatchDataSAddress(WatchData &data, const GdbMi &mi)
2806 {
2807     if (mi.isValid())
2808         data.saddr = _(mi.data());
2809 }
2810
2811 void GdbEngine::setUseDebuggingHelpers(const QVariant &on)
2812 {
2813     //qDebug() << "SWITCHING ON/OFF DUMPER DEBUGGING:" << on;
2814     Q_UNUSED(on)
2815     setTokenBarrier();
2816     updateLocals();
2817 }
2818
2819 void GdbEngine::setAutoDerefPointers(const QVariant &on)
2820 {
2821     Q_UNUSED(on)
2822     setTokenBarrier();
2823     updateLocals();
2824 }
2825
2826 bool GdbEngine::hasDebuggingHelperForType(const QString &type) const
2827 {
2828     if (!theDebuggerBoolSetting(UseDebuggingHelpers))
2829         return false;
2830
2831     if (m_gdbAdapter->dumperHandling() == AbstractGdbAdapter::DumperNotAvailable) {
2832         // "call" is not possible in gdb when looking at core files
2833         return type == __("QString") || type.endsWith(__("::QString"))
2834             || type == __("QStringList") || type.endsWith(__("::QStringList"));
2835     }
2836
2837     if (theDebuggerBoolSetting(DebugDebuggingHelpers)
2838             && manager()->stackHandler()->isDebuggingDebuggingHelpers())
2839         return false;
2840
2841     if (m_debuggingHelperState != DebuggingHelperAvailable)
2842         return false;
2843
2844     // simple types
2845     return m_dumperHelper.type(type) != QtDumperHelper::UnknownType;
2846 }
2847
2848 static inline QString msgRetrievingWatchData(int pending)
2849 {
2850     return GdbEngine::tr("Retrieving data for watch view (%n requests pending)...", 0, pending);
2851 }
2852
2853 void GdbEngine::runDirectDebuggingHelper(const WatchData &data, bool dumpChildren)
2854 {
2855     Q_UNUSED(dumpChildren)
2856     QString type = data.type;
2857     QString cmd;
2858
2859     if (type == __("QString") || type.endsWith(__("::QString")))
2860         cmd = _("qdumpqstring (&") + data.exp + _c(')');
2861     else if (type == __("QStringList") || type.endsWith(__("::QStringList")))
2862         cmd = _("qdumpqstringlist (&") + data.exp + _c(')');
2863
2864     QVariant var;
2865     var.setValue(data);
2866     postCommand(cmd, WatchUpdate, CB(handleDebuggingHelperValue3), var);
2867
2868     showStatusMessage(msgRetrievingWatchData(m_pendingRequests + 1), 10000);
2869 }
2870
2871 void GdbEngine::runDebuggingHelper(const WatchData &data0, bool dumpChildren)
2872 {
2873     if (m_debuggingHelperState != DebuggingHelperAvailable) {
2874         runDirectDebuggingHelper(data0, dumpChildren);
2875         return;
2876     }
2877     WatchData data = data0;
2878
2879     // Avoid endless loops created by faulty dumpers.
2880     QString processedName = QString(_("%1-%2").arg(dumpChildren).arg(data.iname));
2881     if (m_processedNames.contains(processedName)) {
2882         gdbInputAvailable(LogStatus,
2883             _("<Breaking endless loop for %1>").arg(data.iname));
2884         data.setAllUnneeded();
2885         data.setValue(_("<unavailable>"));
2886         data.setHasChildren(false);
2887         insertData(data);
2888         return; 
2889     }
2890     m_processedNames.insert(processedName);
2891
2892     QByteArray params;
2893     QStringList extraArgs;
2894     const QtDumperHelper::TypeData td = m_dumperHelper.typeData(data0.type);
2895     m_dumperHelper.evaluationParameters(data, td, QtDumperHelper::GdbDebugger, &params, &extraArgs);
2896
2897     //int protocol = (data.iname.startsWith("watch") && data.type == "QImage") ? 3 : 2;
2898     //int protocol = data.iname.startsWith("watch") ? 3 : 2;
2899     const int protocol = 2;
2900     //int protocol = isDisplayedIName(data.iname) ? 3 : 2;
2901
2902     QString addr;
2903     if (data.addr.startsWith(__("0x")))
2904         addr = _("(void*)") + data.addr;
2905     else if (data.exp.isEmpty()) // happens e.g. for QAbstractItem
2906         addr = _("0");
2907     else
2908         addr = _("&(") + data.exp + _c(')');
2909
2910     sendWatchParameters(params);
2911
2912     QString cmd;
2913     QTextStream(&cmd) << "call " << "(void*)qDumpObjectData440(" <<
2914             protocol << ',' << "%1+1"                // placeholder for token
2915             <<',' <<  addr << ',' << (dumpChildren ? "1" : "0")
2916             << ',' << extraArgs.join(QString(_c(','))) <<  ')';
2917
2918     postCommand(cmd, WatchUpdate | EmbedToken);
2919
2920     showStatusMessage(msgRetrievingWatchData(m_pendingRequests + 1), 10000);
2921
2922     // retrieve response
2923     postCommand(_("p (char*)&qDumpOutBuffer"), WatchUpdate,
2924         CB(handleDebuggingHelperValue2), qVariantFromValue(data));
2925 }
2926
2927 void GdbEngine::createGdbVariable(const WatchData &data)
2928 {
2929     if (data.iname == _("local.flist.0")) {
2930         int i = 1;
2931         Q_UNUSED(i);
2932     }
2933     postCommand(_("-var-delete \"%1\"").arg(data.iname), WatchUpdate);
2934     QString exp = data.exp;
2935     if (exp.isEmpty() && data.addr.startsWith(__("0x")))
2936         exp = _("*(") + gdbQuoteTypes(data.type) + _("*)") + data.addr;
2937     QVariant val = QVariant::fromValue<WatchData>(data);
2938     postCommand(_("-var-create \"%1\" * \"%2\"").arg(data.iname).arg(exp),
2939         WatchUpdate, CB(handleVarCreate), val);
2940 }
2941
2942 void GdbEngine::updateSubItem(const WatchData &data0)
2943 {
2944     WatchData data = data0;
2945     #if DEBUG_SUBITEM
2946     qDebug() << "UPDATE SUBITEM:" << data.toString();
2947     #endif
2948     QTC_ASSERT(data.isValid(), return);
2949
2950     // in any case we need the type first
2951     if (data.isTypeNeeded()) {
2952         // This should only happen if we don't have a variable yet.
2953         // Let's play safe, though.
2954         if (!data.variable.isEmpty()) {
2955             // Update: It does so for out-of-scope watchers.
2956             #if 1
2957             qDebug() << "FIXME: GdbEngine::updateSubItem:"
2958                  << data.toString() << "should not happen";
2959             #else
2960             data.setType(WatchData::msgNotInScope());
2961             data.setValue(WatchData::msgNotInScope());
2962             data.setHasChildren(false);
2963             insertData(data);
2964             return;
2965             #endif
2966         }
2967         // The WatchVarCreate handler will receive type information
2968         // and re-insert a WatchData item with correct type, so
2969         // we will not re-enter this bit.
2970         // FIXME: Concurrency issues?
2971         createGdbVariable(data);
2972         return;
2973     }
2974
2975     // we should have a type now. this is relied upon further below
2976     QTC_ASSERT(!data.type.isEmpty(), return);
2977
2978     // a common case that can be easily solved
2979     if (data.isChildrenNeeded() && isPointerType(data.type)
2980         && !hasDebuggingHelperForType(data.type)) {
2981         // We sometimes know what kind of children pointers have
2982         #if DEBUG_SUBITEM
2983         qDebug() << "IT'S A POINTER";
2984         #endif
2985     
2986         if (theDebuggerBoolSetting(AutoDerefPointers)) {
2987             // Try automatic dereferentiation
2988             data.exp = _("(*(") + data.exp + _("))");
2989             data.type = data.type + _("."); // FIXME: fragile HACK to avoid recursion
2990             insertData(data);
2991         } else {
2992             data.setChildrenUnneeded();
2993             insertData(data);
2994             WatchData data1;
2995             data1.iname = data.iname + QLatin1String(".*");
2996             data1.name = QLatin1Char('*') + data.name;
2997             data1.exp = QLatin1String("(*(") + data.exp + QLatin1String("))");
2998             data1.type = stripPointerType(data.type);
2999             data1.setValueNeeded();
3000             data1.setChildrenUnneeded();
3001             insertData(data1);
3002         }
3003         return;
3004     }
3005
3006     if (data.isValueNeeded() && hasDebuggingHelperForType(data.type)) {
3007         #if DEBUG_SUBITEM
3008         qDebug() << "UPDATE SUBITEM: CUSTOMVALUE";
3009         #endif
3010         runDebuggingHelper(data, manager()->watchHandler()->isExpandedIName(data.iname));
3011         return;
3012     }
3013
3014 /*
3015     if (data.isValueNeeded() && data.exp.isEmpty()) {
3016         #if DEBUG_SUBITEM
3017         qDebug() << "UPDATE SUBITEM: NO EXPRESSION?";
3018         #endif
3019         data.setError("<no expression given>");
3020         insertData(data);
3021         return;
3022     }
3023 */
3024
3025     if (data.isValueNeeded() && data.variable.isEmpty()) {
3026         #if DEBUG_SUBITEM
3027         qDebug() << "UPDATE SUBITEM: VARIABLE NEEDED FOR VALUE";
3028         #endif
3029         createGdbVariable(data);
3030         // the WatchVarCreate handler will re-insert a WatchData
3031         // item, with valueNeeded() set.
3032         return;
3033     }
3034
3035     if (data.isValueNeeded()) {
3036         QTC_ASSERT(!data.variable.isEmpty(), return); // tested above
3037         #if DEBUG_SUBITEM
3038         qDebug() << "UPDATE SUBITEM: VALUE";
3039         #endif
3040         QString cmd = _("-var-evaluate-expression \"") + data.iname + _c('"');
3041         postCommand(cmd, WatchUpdate, CB(handleEvaluateExpression),
3042             QVariant::fromValue(data));
3043         return;
3044     }
3045
3046     if (data.isChildrenNeeded() && hasDebuggingHelperForType(data.type)) {
3047         #if DEBUG_SUBITEM
3048         qDebug() << "UPDATE SUBITEM: CUSTOMVALUE WITH CHILDREN";
3049         #endif
3050         runDebuggingHelper(data, true);
3051         return;
3052     }
3053
3054     if (data.isChildrenNeeded() && data.variable.isEmpty()) {
3055         #if DEBUG_SUBITEM
3056         qDebug() << "UPDATE SUBITEM: VARIABLE NEEDED FOR CHILDREN";
3057         #endif
3058         createGdbVariable(data);
3059         // the WatchVarCreate handler will re-insert a WatchData
3060         // item, with childrenNeeded() set.
3061         return;
3062     }
3063
3064     if (data.isChildrenNeeded()) {
3065         QTC_ASSERT(!data.variable.isEmpty(), return); // tested above
3066         QString cmd = _("-var-list-children --all-values \"") + data.variable + _c('"');
3067         postCommand(cmd, WatchUpdate, CB(handleVarListChildren), QVariant::fromValue(data));
3068         return;
3069     }
3070
3071     if (data.isHasChildrenNeeded() && hasDebuggingHelperForType(data.type)) {
3072         #if DEBUG_SUBITEM
3073         qDebug() << "UPDATE SUBITEM: CUSTOMVALUE WITH CHILDREN";
3074         #endif
3075         runDebuggingHelper(data, manager()->watchHandler()->isExpandedIName(data.iname));
3076         return;
3077     }
3078
3079 //#if !X
3080     if (data.isHasChildrenNeeded() && data.variable.isEmpty()) {
3081         #if DEBUG_SUBITEM
3082         qDebug() << "UPDATE SUBITEM: VARIABLE NEEDED FOR CHILDCOUNT";
3083         #endif
3084         createGdbVariable(data);
3085         // the WatchVarCreate handler will re-insert a WatchData
3086         // item, with childrenNeeded() set.
3087         return;
3088     }
3089 //#endif
3090
3091     if (data.isHasChildrenNeeded()) {
3092         QTC_ASSERT(!data.variable.isEmpty(), return); // tested above
3093         QString cmd = _("-var-list-children --all-values \"") + data.variable + _c('"');
3094         postCommand(cmd, Discardable, CB(handleVarListChildren), QVariant::fromValue(data));
3095         return;
3096     }
3097
3098     qDebug() << "FIXME: UPDATE SUBITEM:" << data.toString();
3099     QTC_ASSERT(false, return);
3100 }
3101
3102 void GdbEngine::updateWatchData(const WatchData &data)
3103 {
3104     if (isSynchroneous()) {
3105         // This should only be called for fresh expanded items, not for
3106         // items that had their children retrieved earlier.
3107         //qDebug() << "\nUPDATE WATCH DATA: " << data.toString() << "\n";
3108 #if 0
3109         WatchData data1 = data;
3110         data1.setAllUnneeded();
3111         insertData(data1);
3112         rebuildModel();
3113 #else
3114         if (data.iname.endsWith(_(".")))
3115             return;
3116
3117         // Avoid endless loops created by faulty dumpers.
3118         QString processedName = QString(_("%1-%2").arg(1).arg(data.iname));
3119         //qDebug() << "PROCESSED NAMES: " << processedName << m_processedNames;
3120         if (m_processedNames.contains(processedName)) {
3121             WatchData data1 = data;
3122             gdbInputAvailable(LogStatus,
3123                 _("<Breaking endless loop for %1>").arg(data1.iname));
3124             data1.setAllUnneeded();
3125             data1.setValue(_("<unavailable>"));
3126             data1.setHasChildren(false);
3127             insertData(data1);
3128             return; 
3129         }
3130         m_processedNames.insert(processedName);
3131
3132         updateLocals();
3133 #endif
3134     } else {
3135         // Bump requests to avoid model rebuilding during the nested
3136         // updateWatchModel runs.
3137         ++m_pendingRequests;
3138         PENDING_DEBUG("UPDATE WATCH BUMPS PENDING UP TO " << m_pendingRequests);
3139 #if 1
3140         QMetaObject::invokeMethod(this, "updateWatchDataHelper",
3141             Qt::QueuedConnection, Q_ARG(WatchData, data));
3142 #else
3143         updateWatchDataHelper(data);
3144 #endif
3145     }
3146 }
3147
3148 void GdbEngine::updateWatchDataHelper(const WatchData &data)
3149 {
3150     //m_pendingRequests = 0;
3151     PENDING_DEBUG("UPDATE WATCH DATA");
3152     #if DEBUG_PENDING
3153     //qDebug() << "##############################################";
3154     qDebug() << "UPDATE MODEL, FOUND INCOMPLETE:";
3155     //qDebug() << data.toString();
3156     #endif
3157
3158     updateSubItem(data);
3159     //PENDING_DEBUG("INTERNAL TRIGGERING UPDATE WATCH MODEL");
3160     --m_pendingRequests;
3161     PENDING_DEBUG("UPDATE WATCH DONE BUMPS PENDING DOWN TO " << m_pendingRequests);
3162     if (m_pendingRequests <= 0)
3163         rebuildModel();
3164 }
3165
3166 void GdbEngine::rebuildModel()
3167 {
3168     static int count = 0;
3169     ++count;
3170     if (!isSynchroneous())
3171         m_processedNames.clear();
3172     PENDING_DEBUG("REBUILDING MODEL" << count);
3173     gdbInputAvailable(LogStatus, _("<Rebuild Watchmodel %1>").arg(count));
3174     showStatusMessage(tr("Finished retrieving data."), 400);
3175     manager()->watchHandler()->endCycle();
3176     showToolTip();
3177 }
3178
3179 static inline double getDumperVersion(const GdbMi &contents)
3180 {
3181     const GdbMi dumperVersionG = contents.findChild("dumperversion");
3182     if (dumperVersionG.type() != GdbMi::Invalid) {
3183         bool ok;
3184         const double v = QString::fromAscii(dumperVersionG.data()).toDouble(&ok);
3185         if (ok)
3186             return v;
3187     }
3188     return 1.0;
3189 }
3190
3191 void GdbEngine::handleQueryDebuggingHelper(const GdbResponse &response)
3192 {
3193     const double dumperVersionRequired = 1.0;
3194     //qDebug() << "DATA DUMPER TRIAL:" << response.toString();
3195
3196     GdbMi contents;
3197     QTC_ASSERT(parseConsoleStream(response, &contents), qDebug() << response.toString());
3198     const bool ok = m_dumperHelper.parseQuery(contents, QtDumperHelper::GdbDebugger)
3199         && m_dumperHelper.typeCount();
3200     if (ok) {
3201         // Get version and sizes from dumpers. Expression cache
3202         // currently causes errors.
3203         const double dumperVersion = getDumperVersion(contents);
3204         if (dumperVersion < dumperVersionRequired) {
3205             manager()->showQtDumperLibraryWarning(
3206                 QtDumperHelper::msgDumperOutdated(dumperVersionRequired, dumperVersion));
3207             m_debuggingHelperState = DebuggingHelperUnavailable;
3208             return;
3209         }
3210         m_debuggingHelperState = DebuggingHelperAvailable;
3211         const QString successMsg = tr("Dumper version %1, %n custom dumpers found.",
3212             0, m_dumperHelper.typeCount()).arg(dumperVersion);
3213         showStatusMessage(successMsg);
3214     } else {
3215         if (!m_dumperInjectionLoad) // Retry if thread has not terminated yet.
3216             m_debuggingHelperState = DebuggingHelperUnavailable;
3217         showStatusMessage(tr("Debugging helpers not found."));
3218     }
3219     //qDebug() << m_dumperHelper.toString(true);
3220     //qDebug() << m_availableSimpleDebuggingHelpers << "DATA DUMPERS AVAILABLE";
3221 }
3222
3223 static inline QString arrayFillCommand(const char *array, const QByteArray &params)
3224 {
3225     char buf[50];
3226     sprintf(buf, "set {char[%d]} &%s = {", params.size(), array);
3227     QByteArray encoded;
3228     encoded.append(buf);
3229     const int size = params.size();
3230     for (int i = 0; i != size; ++i) {
3231         sprintf(buf, "%d,", int(params[i]));
3232         encoded.append(buf);
3233     }
3234     encoded[encoded.size() - 1] = '}';
3235     return _(encoded);
3236 }
3237
3238 void GdbEngine::sendWatchParameters(const QByteArray &params0)
3239 {
3240     QByteArray params = params0;
3241     params.append('\0');
3242     const QString inBufferCmd = arrayFillCommand("qDumpInBuffer", params);
3243
3244     params.replace('\0','!');
3245     gdbInputAvailable(LogMisc, QString::fromUtf8(params));
3246
3247     params.clear();
3248     params.append('\0');
3249     const QString outBufferCmd = arrayFillCommand("qDumpOutBuffer", params);
3250
3251     postCommand(inBufferCmd);
3252     postCommand(outBufferCmd);
3253 }
3254
3255 void GdbEngine::handleVarAssign(const GdbResponse &)
3256 {
3257     // Everything might have changed, force re-evaluation.
3258     // FIXME: Speed this up by re-using variables and only
3259     // marking values as 'unknown'
3260     setTokenBarrier();
3261     updateLocals();
3262 }
3263
3264 // Find the "type" and "displayedtype" children of root and set up type.
3265 void GdbEngine::setWatchDataType(WatchData &data, const GdbMi &item)
3266 {
3267     if (item.isValid()) {
3268         const QString miData = _(item.data());
3269         if (!data.framekey.isEmpty())
3270             m_varToType[data.framekey] = miData;
3271         data.setType(miData);
3272     } else if (data.type.isEmpty()) {
3273         data.setTypeNeeded();
3274     }
3275 }
3276
3277 void GdbEngine::setWatchDataDisplayedType(WatchData &data, const GdbMi &item)
3278 {
3279     if (item.isValid())
3280         data.displayedType = _(item.data());
3281 }
3282
3283 void GdbEngine::handleVarCreate(const GdbResponse &response)
3284 {
3285     WatchData data = response.cookie.value<WatchData>();
3286     // happens e.g. when we already issued a var-evaluate command
3287     if (!data.isValid())
3288         return;
3289     //qDebug() << "HANDLE VARIABLE CREATION:" << data.toString();
3290     if (response.resultClass == GdbResultDone) {
3291         data.variable = data.iname;
3292         setWatchDataType(data, response.data.findChild("type"));
3293         if (manager()->watchHandler()->isExpandedIName(data.iname)
3294                 && !response.data.findChild("children").isValid())
3295             data.setChildrenNeeded();
3296         else
3297             data.setChildrenUnneeded();
3298         setWatchDataChildCount(data, response.data.findChild("numchild"));
3299         insertData(data);
3300     } else {
3301         data.setError(QString::fromLocal8Bit(response.data.findChild("msg").data()));
3302         if (data.isWatcher()) {
3303             data.value = WatchData::msgNotInScope();
3304             data.type = _(" ");
3305             data.setAllUnneeded();
3306             data.setHasChildren(false);
3307             data.valueEnabled = false;
3308             data.valueEditable = false;
3309             insertData(data);
3310         }
3311     }
3312 }
3313
3314 void GdbEngine::handleEvaluateExpression(const GdbResponse &response)
3315 {
3316     WatchData data = response.cookie.value<WatchData>();
3317     QTC_ASSERT(data.isValid(), qDebug() << "HUH?");
3318     if (response.resultClass == GdbResultDone) {
3319         //if (col == 0)
3320         //    data.name = response.data.findChild("value").data();
3321         //else
3322             setWatchDataValue(data, response.data.findChild("value"));
3323     } else {
3324         data.setError(QString::fromLocal8Bit(response.data.findChild("msg").data()));
3325     }
3326     //qDebug() << "HANDLE EVALUATE EXPRESSION:" << data.toString();
3327     insertData(data);
3328     //updateWatchModel2();
3329 }
3330
3331 void GdbEngine::handleDebuggingHelperSetup(const GdbResponse &response)
3332 {
3333     //qDebug() << "CUSTOM SETUP RESULT:" << response.toString();
3334     if (response.resultClass == GdbResultDone) {
3335     } else {
3336         QString msg = QString::fromLocal8Bit(response.data.findChild("msg").data());
3337         //qDebug() << "CUSTOM DUMPER SETUP ERROR MESSAGE:" << msg;
3338         showStatusMessage(tr("Custom dumper setup: %1").arg(msg), 10000);
3339     }
3340 }
3341
3342 void GdbEngine::handleDebuggingHelperValue2(const GdbResponse &response)
3343 {
3344     WatchData data = response.cookie.value<WatchData>();
3345     QTC_ASSERT(data.isValid(), return);
3346
3347     //qDebug() << "CUSTOM VALUE RESULT:" << response.toString();
3348     //qDebug() << "FOR DATA:" << data.toString() << response.resultClass;
3349     if (response.resultClass != GdbResultDone) {
3350         qDebug() << "STRANGE CUSTOM DUMPER RESULT DATA:" << data.toString();
3351         return;
3352     }
3353
3354     GdbMi contents;
3355     if (!parseConsoleStream(response, &contents)) {
3356         data.setError(WatchData::msgNotInScope());
3357         insertData(data);
3358         return;
3359     }
3360
3361     setWatchDataType(data, response.data.findChild("type"));
3362     setWatchDataDisplayedType(data, response.data.findChild("displaytype"));
3363     QList<WatchData> list;
3364     handleChildren(data, contents, &list);
3365     //for (int i = 0; i != list.size(); ++i)
3366     //    qDebug() << "READ: " << list.at(i).toString();
3367     manager()->watchHandler()->insertBulkData(list);
3368 }
3369
3370 void GdbEngine::handleChildren(const WatchData &data0, const GdbMi &item,
3371     QList<WatchData> *list)
3372 {
3373     //qDebug() << "HANDLE CHILDREN: " << data0.toString() << item.toString();
3374     WatchData data = data0;
3375     if (!manager()->watchHandler()->isExpandedIName(data.iname))
3376         data.setChildrenUnneeded();
3377
3378     GdbMi children = item.findChild("children");
3379     if (children.isValid() || !manager()->watchHandler()->isExpandedIName(data.iname))
3380         data.setChildrenUnneeded();
3381
3382     if (manager()->watchHandler()->isDisplayedIName(data.iname)) {
3383         GdbMi editvalue = item.findChild("editvalue");
3384         if (editvalue.isValid()) {
3385             setWatchDataEditValue(data, editvalue);
3386             manager()->watchHandler()->showEditValue(data);
3387         }
3388     }
3389     setWatchDataType(data, item.findChild("type"));
3390     setWatchDataEditValue(data, item.findChild("editvalue"));
3391     setWatchDataExpression(data, item.findChild("exp"));
3392     setWatchDataChildCount(data, item.findChild("numchild"));
3393     setWatchDataValue(data, item.findChild("value"),
3394         item.findChild("valueencoded").data().toInt());
3395     setWatchDataAddress(data, item.findChild("addr"));
3396     setWatchDataSAddress(data, item.findChild("saddr"));
3397     setWatchDataValueToolTip(data, item.findChild("valuetooltip"),
3398         item.findChild("valuetooltipencoded").data().toInt());
3399     setWatchDataValueEnabled(data, item.findChild("valueenabled"));
3400     setWatchDataValueEditable(data, item.findChild("valueeditable"));
3401     //qDebug() << "\nAPPEND TO LIST: " << data.toString() << "\n";
3402     list->append(data);
3403
3404     // try not to repeat data too often
3405     WatchData childtemplate;
3406     setWatchDataType(childtemplate, item.findChild("childtype"));
3407     setWatchDataChildCount(childtemplate, item.findChild("childnumchild"));
3408     //qDebug() << "CHILD TEMPLATE:" << childtemplate.toString();
3409
3410     int i = 0;
3411     foreach (GdbMi child, children.children()) {
3412         WatchData data1 = childtemplate;
3413         GdbMi name = child.findChild("name");
3414         if (name.isValid())
3415             data1.name = _(name.data());
3416         else
3417             data1.name = QString::number(i);
3418         data1.iname = data.iname + _c('.') + data1.name;
3419         if (!data1.name.isEmpty() && data1.name.at(0).isDigit())
3420             data1.name = _c('[') + data1.name + _c(']');
3421         QByteArray key = child.findChild("key").data();
3422         if (!key.isEmpty()) {
3423             int encoding = child.findChild("keyencoded").data().toInt();
3424             QString skey = decodeData(key, encoding);
3425             if (skey.size() > 13) {
3426                 skey = skey.left(12);
3427                 skey += _("...");
3428             }
3429             //data1.name += " (" + skey + ")";
3430             data1.name = skey;
3431         }
3432         handleChildren(data1, child, list);
3433         ++i;
3434     }
3435 }
3436
3437 void GdbEngine::handleDebuggingHelperValue3(const GdbResponse &response)
3438 {
3439     if (response.resultClass == GdbResultDone) {
3440         WatchData data = response.cookie.value<WatchData>();
3441         QByteArray out = response.data.findChild("consolestreamoutput").data();
3442         while (out.endsWith(' ') || out.endsWith('\n'))
3443             out.chop(1);
3444         QList<QByteArray> list = out.split(' ');
3445         //qDebug() << "RECEIVED" << response.toString() << "FOR" << data0.toString()
3446         //    <<  " STREAM:" << out;
3447         if (list.isEmpty()) {
3448             //: Value for variable
3449             data.setError(WatchData::msgNotInScope());
3450             data.setAllUnneeded();
3451             insertData(data);
3452         } else if (data.type == __("QString")
3453                 || data.type.endsWith(__("::QString"))) {
3454             QList<QByteArray> list = out.split(' ');
3455             QString str;
3456             int l = out.isEmpty() ? 0 : list.size();
3457             for (int i = 0; i < l; ++i)
3458                  str.append(list.at(i).toInt());
3459             data.setValue(_c('"') + str + _c('"'));
3460             data.setHasChildren(false);
3461             data.setAllUnneeded();
3462             insertData(data);
3463         } else if (data.type == __("QStringList")
3464                 || data.type.endsWith(__("::QStringList"))) {
3465             if (out.isEmpty()) {
3466                 data.setValue(tr("<0 items>"));
3467                 data.setHasChildren(false);
3468                 data.setAllUnneeded();
3469                 insertData(data);
3470             } else {
3471                 int l = list.size();
3472                 //: In string list
3473                 data.setValue(tr("<%n items>", 0, l));
3474                 data.setHasChildren(!list.empty());
3475                 data.setAllUnneeded();
3476                 insertData(data);
3477                 for (int i = 0; i < l; ++i) {
3478                     WatchData data1;
3479                     data1.name = _("[%1]").arg(i);
3480                     data1.type = data.type.left(data.type.size() - 4);
3481                     data1.iname = data.iname + _(".%1").arg(i);
3482                     data1.addr = _(list.at(i));
3483                     data1.exp = _("((") + gdbQuoteTypes(data1.type) + _("*)") + data1.addr + _c(')');
3484                     data1.setHasChildren(false);
3485                     data1.setValueNeeded();
3486                     QString cmd = _("qdumpqstring (") + data1.exp + _c(')');
3487                     QVariant var;
3488                     var.setValue(data1);
3489                     postCommand(cmd, WatchUpdate, CB(handleDebuggingHelperValue3), var);
3490                 }
3491             }
3492         } else {
3493             //: Value for variable
3494             data.setError(WatchData::msgNotInScope());
3495             data.setAllUnneeded();
3496             insertData(data);
3497         }
3498     } else {
3499         WatchData data = response.cookie.value<WatchData>();
3500         data.setError(WatchData::msgNotInScope());
3501         data.setAllUnneeded();
3502         insertData(data);
3503     }
3504 }
3505
3506 void GdbEngine::updateLocals(const QVariant &cookie)
3507 {
3508     m_pendingRequests = 0;
3509     if (isSynchroneous()) {
3510         m_processedNames.clear();
3511         manager()->watchHandler()->beginCycle();
3512         m_toolTipExpression.clear();
3513         QStringList expanded = m_manager->watchHandler()->expandedINames().toList();
3514         postCommand(_("-interpreter-exec console \"bb %1 %2\"")
3515                 .arg(int(theDebuggerBoolSetting(UseDebuggingHelpers)))
3516                 .arg(expanded.join(_(","))),
3517             CB(handleStackFrame));
3518     } else {
3519         m_processedNames.clear();
3520
3521         PENDING_DEBUG("\nRESET PENDING");
3522         //m_toolTipCache.clear();
3523         m_toolTipExpression.clear();
3524         manager()->watchHandler()->beginCycle();
3525
3526         // Asynchronous load of injected library, initialize in first stop
3527         if (m_dumperInjectionLoad && m_debuggingHelperState == DebuggingHelperLoadTried
3528                 && m_dumperHelper.typeCount() == 0
3529                 && inferiorPid() > 0)
3530             tryQueryDebuggingHelpers();
3531
3532         QString level = QString::number(currentFrame());
3533         // '2' is 'list with type and value'
3534         QString cmd = _("-stack-list-arguments 2 ") + level + _c(' ') + level;
3535         postCommand(cmd, WatchUpdate, CB(handleStackListArguments));
3536         // '2' is 'list with type and value'
3537         postCommand(_("-stack-list-locals 2"), WatchUpdate,
3538             CB(handleStackListLocals), cookie); // stage 2/2
3539     }
3540 }
3541
3542 void GdbEngine::handleStackFrame(const GdbResponse &response)
3543 {
3544     if (response.resultClass == GdbResultDone) {
3545         QByteArray out = response.data.findChild("consolestreamoutput").data();
3546         while (out.endsWith(' ') || out.endsWith('\n'))
3547             out.chop(1);
3548         //qDebug() << "SECOND CHUNK: " << out;
3549         int pos = out.indexOf("locals=");
3550         if (pos != 0) {
3551             qDebug() << "DISCARDING JUNK AT BEGIN OF RESPONSE: "
3552                 << out.left(pos);
3553             out = out.mid(pos);
3554         }
3555         GdbMi all("[" + out + "]");
3556         //GdbMi all(out);
3557         
3558         //qDebug() << "\n\n\nALL: " << all.toString() << "\n";
3559         GdbMi locals = all.findChild("locals");
3560         //qDebug() << "\n\n\nLOCALS: " << locals.toString() << "\n";
3561         WatchData *data = manager()->watchHandler()->findItem(_("local"));
3562         QTC_ASSERT(data, return);
3563
3564         QList<WatchData> list;
3565         //foreach (const GdbMi &local, locals.children)
3566         //   handleChildren(*data, local, &list);
3567         handleChildren(*data, locals, &list);
3568         //for (int i = 0; i != list.size(); ++i)
3569         //    qDebug() << "READ: " << list.at(i).toString();
3570         manager()->watchHandler()->insertBulkData(list);
3571
3572         // FIXME:
3573         //manager()->watchHandler()->updateWatchers();
3574         PENDING_DEBUG("AFTER handleStackFrame()");
3575         // FIXME: This should only be used when updateLocals() was
3576         // triggered by expanding an item in the view.
3577         if (m_pendingRequests <= 0) {
3578             PENDING_DEBUG("\n\n ....  AND TRIGGERS MODEL UPDATE\n");
3579             rebuildModel();
3580         }
3581     } else {
3582         QTC_ASSERT(false, /**/);
3583     }
3584 }
3585
3586 void GdbEngine::handleStackListArguments(const GdbResponse &response)
3587 {
3588     // stage 1/2
3589
3590     // Linux:
3591     // 12^done,stack-args=
3592     //   [frame={level="0",args=[
3593     //     {name="argc",type="int",value="1"},
3594     //     {name="argv",type="char **",value="(char **) 0x7..."}]}]
3595     // Mac:
3596     // 78^done,stack-args=
3597     //    {frame={level="0",args={
3598     //      varobj=
3599     //        {exp="this",value="0x38a2fab0",name="var21",numchild="3",
3600     //             type="CurrentDocumentFind *  const",typecode="PTR",
3601     //             dynamic_type="",in_scope="true",block_start_addr="0x3938e946",
3602     //             block_end_addr="0x3938eb2d"},
3603     //      varobj=
3604     //         {exp="before",value="@0xbfffb9f8: {d = 0x3a7f2a70}",
3605     //              name="var22",numchild="1",type="const QString  ...} }}}
3606     //
3607     // In both cases, iterating over the children of stack-args/frame/args
3608     // is ok.
3609     m_currentFunctionArgs.clear();
3610     if (response.resultClass == GdbResultDone) {
3611         const GdbMi list = response.data.findChild("stack-args");
3612         const GdbMi frame = list.findChild("frame");
3613         const GdbMi args = frame.findChild("args");
3614         m_currentFunctionArgs = args.children();
3615     } else {
3616         qDebug() << "FIXME: GdbEngine::handleStackListArguments: should not happen"
3617             << response.toString();
3618     }
3619 }
3620
3621 void GdbEngine::handleStackListLocals(const GdbResponse &response)
3622 {
3623     // stage 2/2
3624
3625     // There could be shadowed variables
3626     QList<GdbMi> locals = response.data.findChild("locals").children();
3627     locals += m_currentFunctionArgs;
3628     QMap<QByteArray, int> seen;
3629     // If desired, retrieve list of uninitialized variables looking at
3630     // the current frame. This is invoked first time after a stop from
3631     // handleStop1, which passes on the frame as cookie. The whole stack
3632     // is not known at this point.
3633     QStringList uninitializedVariables;
3634     if (theDebuggerAction(UseCodeModel)->isChecked()) {
3635         const StackFrame frame = qVariantCanConvert<Debugger::Internal::StackFrame>(response.cookie) ?
3636                                  qVariantValue<Debugger::Internal::StackFrame>(response.cookie) :
3637                                  m_manager->stackHandler()->currentFrame();
3638         if (frame.isUsable())
3639             getUninitializedVariables(m_manager->cppCodeModelSnapshot(),
3640                                       frame.function, frame.file, frame.line,
3641                                       &uninitializedVariables);
3642     }
3643     QList<WatchData> list;
3644     foreach (const GdbMi &item, locals) {
3645         const WatchData data = localVariable(item, uninitializedVariables, &seen);
3646         if (data.isValid())
3647             list.push_back(data);
3648     }
3649     manager()->watchHandler()->insertBulkData(list);
3650     manager()->watchHandler()->updateWatchers();
3651 }
3652
3653 // Parse a local variable from GdbMi
3654 WatchData GdbEngine::localVariable(const GdbMi &item,
3655                                    const QStringList &uninitializedVariables,
3656                                    QMap<QByteArray, int> *seen)
3657 {
3658     // Local variables of inlined code are reported as
3659     // 26^done,locals={varobj={exp="this",value="",name="var4",exp="this",
3660     // numchild="1",type="const QtSharedPointer::Basic<CPlusPlus::..."}}
3661     // We do not want these at all. Current hypotheses is that those
3662     // "spurious" locals have _two_ "exp" field. Try to filter them:
3663     QByteArray name;
3664     if (m_isMacGdb) {
3665         int numExps = 0;
3666         foreach (const GdbMi &child, item.children())
3667             numExps += int(child.name() == "exp");
3668         if (numExps > 1)
3669             return WatchData();
3670         name = item.findChild("exp").data();
3671     } else {
3672         name = item.findChild("name").data();
3673     }
3674     const QMap<QByteArray, int>::iterator it  = seen->find(name);
3675     if (it != seen->end()) {
3676         const int n = it.value();
3677         ++(it.value());
3678         WatchData data;
3679         QString nam = _(name);
3680         data.iname = _("local.") + nam + QString::number(n + 1);
3681         //: Variable %1 is the variable name, %2 is a simple count
3682         data.name = WatchData::shadowedName(nam, n);
3683         if (uninitializedVariables.contains(data.name)) {
3684             data.setError(WatchData::msgNotInScope());
3685             return data;
3686         }
3687         //: Type of local variable or parameter shadowed by another        
3688         //: variable of the same name in a nested block.
3689         setWatchDataValue(data, item.findChild("value"));
3690         data.setType(GdbEngine::tr("<shadowed>"));        
3691         data.setHasChildren(false);
3692         return data;
3693     }
3694     seen->insert(name, 1);
3695     WatchData data;
3696     QString nam = _(name);
3697     data.iname = _("local.") + nam;
3698     data.name = nam;
3699     data.exp = nam;
3700     data.framekey = m_currentFrame + data.name;
3701     setWatchDataType(data, item.findChild("type"));
3702     if (uninitializedVariables.contains(data.name)) {
3703         data.setError(WatchData::msgNotInScope());
3704         return data;
3705     }
3706     if (isSynchroneous()) {
3707         setWatchDataValue(data, item.findChild("value"),
3708                           item.findChild("valueencoded").data().toInt());
3709         // We know that the complete list of children is
3710         // somewhere in the response.
3711         data.setChildrenUnneeded();
3712     } else {
3713         // set value only directly if it is simple enough, otherwise
3714         // pass through the insertData() machinery
3715         if (isIntOrFloatType(data.type) || isPointerType(data.type))
3716             setWatchDataValue(data, item.findChild("value"));
3717         if (isSymbianIntType(data.type)) {
3718             setWatchDataValue(data, item.findChild("value"));
3719             data.setHasChildren(false);
3720         }
3721     }
3722
3723     if (!m_manager->watchHandler()->isExpandedIName(data.iname))
3724         data.setChildrenUnneeded();
3725     if (isPointerType(data.type) || data.name == __("this"))
3726         data.setHasChildren(true);
3727     return data;
3728 }
3729
3730 void GdbEngine::insertData(const WatchData &data0)
3731 {
3732     PENDING_DEBUG("INSERT DATA" << data0.toString());
3733     WatchData data = data0;
3734     if (data.value.startsWith(__("mi_cmd_var_create:"))) {
3735         qDebug() << "BOGUS VALUE:" << data.toString();
3736         return;
3737     }
3738     manager()->watchHandler()->insertData(data);
3739 }
3740
3741 void GdbEngine::handleVarListChildrenHelper(const GdbMi &item,
3742     const WatchData &parent)
3743 {
3744     //qDebug() <<  "VAR_LIST_CHILDREN: PARENT" << parent.toString();
3745     //qDebug() <<  "VAR_LIST_CHILDREN: ITEM" << item.toString();
3746     QByteArray exp = item.findChild("exp").data();
3747     QByteArray name = item.findChild("name").data();
3748     if (isAccessSpecifier(_(exp))) {
3749         // suppress 'private'/'protected'/'public' level
3750         WatchData data;
3751         data.variable = _(name);
3752         data.iname = parent.iname;
3753         //data.iname = data.variable;
3754         data.exp = parent.exp;
3755         data.setTypeUnneeded();
3756         data.setValueUnneeded();
3757         data.setHasChildrenUnneeded();
3758         data.setChildrenUnneeded();
3759         //qDebug() << "DATA" << data.toString();
3760         QString cmd = _("-var-list-children --all-values \"") + data.variable + _c('"');
3761         //iname += '.' + exp;
3762         postCommand(cmd, WatchUpdate,
3763             CB(handleVarListChildren), QVariant::fromValue(data));
3764     } else if (item.findChild("numchild").data() == "0") {
3765         // happens for structs without data, e.g. interfaces.
3766         WatchData data;
3767         data.name = _(exp);
3768         data.iname = parent.iname + _c('.') + data.name;
3769         data.variable = _(name);
3770         setWatchDataType(data, item.findChild("type"));
3771         setWatchDataValue(data, item.findChild("value"));
3772         setWatchDataAddress(data, item.findChild("addr"));
3773         setWatchDataSAddress(data, item.findChild("saddr"));
3774         data.setHasChildren(false);
3775         insertData(data);
3776     } else if (parent.iname.endsWith(_c('.'))) {
3777         // Happens with anonymous unions
3778         WatchData data;
3779         data.iname = _(name);
3780         QString cmd = _("-var-list-children --all-values \"") + data.variable + _c('"');
3781         postCommand(cmd, WatchUpdate,
3782             CB(handleVarListChildren), QVariant::fromValue(data));
3783     } else if (exp == "staticMetaObject") {
3784         //    && item.findChild("type").data() == "const QMetaObject")
3785         // FIXME: Namespaces?
3786         // { do nothing }    FIXME: make configurable?
3787         // special "clever" hack to avoid clutter in the GUI.
3788         // I am not sure this is a good idea...
3789     } else {
3790         WatchData data;
3791         data.iname = parent.iname + _c('.') + __(exp);
3792         data.variable = _(name);
3793         setWatchDataType(data, item.findChild("type"));
3794         setWatchDataValue(data, item.findChild("value"));
3795         setWatchDataAddress(data, item.findChild("addr"));
3796         setWatchDataSAddress(data, item.findChild("saddr"));
3797         setWatchDataChildCount(data, item.findChild("numchild"));
3798         if (!manager()->watchHandler()->isExpandedIName(data.iname))
3799             data.setChildrenUnneeded();
3800
3801         data.name = _(exp);
3802         if (data.type == data.name) {
3803             if (isPointerType(parent.type)) {
3804                 data.exp = _("*(") + parent.exp + _c(')');
3805                 data.name = _("*") + parent.name;
3806             } else {
3807                 // A type we derive from? gdb crashes when creating variables here
3808                 data.exp = parent.exp;
3809             }
3810         } else if (exp.startsWith("*")) {
3811             // A pointer
3812             data.exp = _("*(") + parent.exp + _c(')');
3813         } else if (startsWithDigit(data.name)) {
3814             // An array. No variables needed?
3815             data.name = _c('[') + data.name + _c(']');
3816             data.exp = parent.exp + _('[' + exp + ']');
3817         } else if (0 && parent.name.endsWith(_c('.'))) {
3818             // Happens with anonymous unions
3819             data.exp = parent.exp + data.name;
3820             //data.name = "<anonymous union>";
3821         } else if (exp.isEmpty()) {
3822             // Happens with anonymous unions
3823             data.exp = parent.exp;
3824             data.name = tr("<n/a>");
3825             data.iname = parent.iname + _(".@");
3826             data.type = tr("<anonymous union>");
3827         } else {
3828             // A structure. Hope there's nothing else...
3829             data.exp = parent.exp + _c('.') + data.name;
3830         }
3831
3832         if (hasDebuggingHelperForType(data.type)) {
3833             // we do not trust gdb if we have a custom dumper
3834             data.setValueNeeded();
3835             data.setHasChildrenNeeded();
3836         }
3837
3838         //qDebug() <<  "VAR_LIST_CHILDREN: PARENT 3" << parent.toString();
3839         //qDebug() <<  "VAR_LIST_CHILDREN: APPENDEE" << data.toString();
3840         insertData(data);
3841     }
3842 }
3843
3844 void GdbEngine::handleVarListChildren(const GdbResponse &response)
3845 {
3846     //WatchResultCounter dummy(this, WatchVarListChildren);
3847     WatchData data = response.cookie.value<WatchData>();
3848     if (!data.isValid())
3849         return;
3850     if (response.resultClass == GdbResultDone) {
3851         //qDebug() <<  "VAR_LIST_CHILDREN: PARENT" << data.toString();
3852         GdbMi children = response.data.findChild("children");
3853
3854         foreach (const GdbMi &child, children.children())
3855             handleVarListChildrenHelper(child, data);
3856
3857         if (children.children().isEmpty()) {
3858             // happens e.g. if no debug information is present or
3859             // if the class really has no children
3860             WatchData data1;
3861             data1.iname = data.iname + _(".child");
3862             //: About variable's value
3863             data1.value = tr("<no information>");
3864             data1.hasChildren = false;
3865             data1.setAllUnneeded();
3866             insertData(data1);
3867             data.setAllUnneeded();
3868             insertData(data);
3869         } else if (!isAccessSpecifier(data.variable.split(_c('.')).last())) {
3870             data.setChildrenUnneeded();
3871             insertData(data);
3872         } else {
3873             // this skips the spurious "public", "private" etc levels
3874             // gdb produces
3875         }
3876     } else {
3877         data.setError(QString::fromLocal8Bit(response.data.findChild("msg").data()));
3878     }
3879 }
3880
3881 #if 0
3882 void GdbEngine::handleChangedItem(QStandardItem *item)
3883 {
3884     // HACK: Just store the item for the slot
3885     //  handleChangedItem(QWidget *widget) below.
3886     QModelIndex index = item->index().sibling(item->index().row(), 0);
3887     //WatchData data = m_currentSet.takeData(iname);
3888     //m_editedData = inameFromItem(m_model.itemFromIndex(index)).exp;
3889     //qDebug() << "HANDLE CHANGED EXPRESSION:" << m_editedData;
3890 }
3891 #endif
3892
3893 void GdbEngine::assignValueInDebugger(const QString &expression, const QString &value)
3894 {
3895     postCommand(_("-var-delete assign"));
3896     postCommand(_("-var-create assign * ") + expression);
3897     postCommand(_("-var-assign assign ") + value, Discardable, CB(handleVarAssign));
3898 }
3899
3900 QString GdbEngine::qtDumperLibraryName() const
3901 {
3902     return m_manager->qtDumperLibraryName();
3903 }
3904
3905 bool GdbEngine::checkDebuggingHelpers()
3906 {
3907     if (!manager()->qtDumperLibraryEnabled())
3908         return false;
3909     const QString lib = qtDumperLibraryName();
3910     //qDebug() << "DUMPERLIB:" << lib;
3911     const QFileInfo fi(lib);
3912     if (!fi.exists()) {
3913         const QStringList &locations = manager()->qtDumperLibraryLocations();
3914         const QString loc = locations.join(QLatin1String(", "));
3915         const QString msg = tr("The debugging helper library was not found at %1.").arg(loc);
3916         debugMessage(msg);
3917         manager()->showQtDumperLibraryWarning(msg);
3918         return false;
3919     }
3920     return true;
3921 }
3922
3923 void GdbEngine::setDebuggingHelperState(DebuggingHelperState s)
3924 {
3925     m_debuggingHelperState = s;
3926 }
3927
3928 void GdbEngine::tryLoadDebuggingHelpers()
3929 {
3930     if (isSynchroneous())
3931         return;
3932     switch (m_debuggingHelperState) {
3933     case DebuggingHelperUninitialized:
3934         break;
3935     case DebuggingHelperLoadTried:
3936         tryQueryDebuggingHelpers();
3937         return;
3938     case DebuggingHelperAvailable:
3939     case DebuggingHelperUnavailable:
3940         return;
3941     }
3942
3943     if (m_gdbAdapter->dumperHandling() == AbstractGdbAdapter::DumperNotAvailable) {
3944         // Load at least gdb macro based dumpers.
3945         QFile file(_(":/gdb/gdbmacros.txt"));
3946         file.open(QIODevice::ReadOnly);
3947         QByteArray contents = file.readAll(); 
3948         m_debuggingHelperState = DebuggingHelperLoadTried;
3949         postCommand(_(contents));
3950         return;
3951     }
3952     if (m_dumperInjectionLoad && inferiorPid() <= 0) // Need PID to inject
3953         return;
3954
3955     PENDING_DEBUG("TRY LOAD CUSTOM DUMPERS");
3956     m_debuggingHelperState = DebuggingHelperUnavailable;
3957     if (!checkDebuggingHelpers())
3958         return;
3959
3960     m_debuggingHelperState = DebuggingHelperLoadTried;
3961     const QString lib = manager()->qtDumperLibraryName();
3962 #if defined(Q_OS_WIN)
3963     if (m_dumperInjectionLoad) {
3964         /// Launch asynchronous remote thread to load.
3965         SharedLibraryInjector injector(inferiorPid());
3966         QString errorMessage;
3967         if (injector.remoteInject(lib, false, &errorMessage)) {
3968             debugMessage(_("Dumper injection loading triggered (%1)...").arg(lib));
3969         } else {
3970             debugMessage(_("Dumper loading (%1) failed: %2").arg(lib, errorMessage));
3971             manager()->showQtDumperLibraryWarning(errorMessage);
3972             m_debuggingHelperState = DebuggingHelperUnavailable;
3973             return;
3974         }
3975     } else {
3976         debugMessage(_("Loading dumpers via debugger call (%1)...").arg(lib));
3977         postCommand(_("sharedlibrary .*")); // for LoadLibraryA
3978         //postCommand(_("handle SIGSEGV pass stop print"));
3979         //postCommand(_("set unwindonsignal off"));
3980         postCommand(_("call LoadLibraryA(\"") + GdbMi::escapeCString(lib) + _("\")"),
3981                     CB(handleDebuggingHelperSetup));
3982         postCommand(_("sharedlibrary ") + dotEscape(lib));
3983     }
3984 #elif defined(Q_OS_MAC)
3985     //postCommand(_("sharedlibrary libc")); // for malloc
3986     //postCommand(_("sharedlibrary libdl")); // for dlopen
3987     postCommand(_("call (void)dlopen(\"") + GdbMi::escapeCString(lib) + _("\", " STRINGIFY(RTLD_NOW) ")"),
3988         CB(handleDebuggingHelperSetup));
3989     //postCommand(_("sharedlibrary ") + dotEscape(lib));
3990 #else
3991     //postCommand(_("p dlopen"));
3992     postCommand(_("sharedlibrary libc")); // for malloc
3993     postCommand(_("sharedlibrary libdl")); // for dlopen
3994     postCommand(_("call (void*)dlopen(\"") + GdbMi::escapeCString(lib) + _("\", " STRINGIFY(RTLD_NOW) ")"),
3995         CB(handleDebuggingHelperSetup));
3996     // some older systems like CentOS 4.6 prefer this:
3997     postCommand(_("call (void*)__dlopen(\"") + GdbMi::escapeCString(lib) + _("\", " STRINGIFY(RTLD_NOW) ")"),
3998         CB(handleDebuggingHelperSetup));
3999     postCommand(_("sharedlibrary ") + dotEscape(lib));
4000 #endif
4001     if (!m_dumperInjectionLoad)
4002         tryQueryDebuggingHelpers();
4003 }
4004
4005 void GdbEngine::tryQueryDebuggingHelpers()
4006 {
4007     // retrieve list of dumpable classes
4008     postCommand(_("call (void*)qDumpObjectData440(1,%1+1,0,0,0,0,0,0)"), EmbedToken);
4009     postCommand(_("p (char*)&qDumpOutBuffer"), CB(handleQueryDebuggingHelper));
4010 }
4011
4012 void GdbEngine::recheckDebuggingHelperAvailability()
4013 {
4014     if (m_gdbAdapter->dumperHandling() != AbstractGdbAdapter::DumperNotAvailable) {
4015         // retreive list of dumpable classes
4016         postCommand(_("call (void*)qDumpObjectData440(1,%1+1,0,0,0,0,0,0)"), EmbedToken);
4017         postCommand(_("p (char*)&qDumpOutBuffer"), CB(handleQueryDebuggingHelper));
4018     }
4019 }
4020
4021 void GdbEngine::watchPoint(const QPoint &pnt)
4022 {
4023     //qDebug() << "WATCH " << pnt;
4024     postCommand(_("call (void*)watchPoint(%1,%2)").arg(pnt.x()).arg(pnt.y()),
4025         NeedsStop, CB(handleWatchPoint));
4026 }
4027
4028 void GdbEngine::handleWatchPoint(const GdbResponse &response)
4029 {
4030     //qDebug() << "HANDLE WATCH POINT:" << response.toString();
4031     if (response.resultClass == GdbResultDone) {
4032         GdbMi contents = response.data.findChild("consolestreamoutput");
4033         // "$5 = (void *) 0xbfa7ebfc\n"
4034         QString str = _(parsePlainConsoleStream(response));
4035         // "(void *) 0xbfa7ebfc"
4036         QString addr = str.mid(9);
4037         QString ns = m_dumperHelper.qtNamespace();
4038         QString type = ns.isEmpty() ? _("QWidget*") : _("'%1QWidget'*").arg(ns);
4039         QString exp = _("(*(%1)%2)").arg(type).arg(addr);
4040         theDebuggerAction(WatchExpression)->trigger(exp);
4041     }
4042 }
4043
4044
4045 struct MemoryAgentCookie
4046 {
4047     MemoryAgentCookie() : agent(0), address(0) {}
4048     MemoryAgentCookie(MemoryViewAgent *agent_, quint64 address_)
4049         : agent(agent_), address(address_)
4050     {}
4051     QPointer<MemoryViewAgent> agent;
4052     quint64 address;
4053 };
4054
4055 void GdbEngine::fetchMemory(MemoryViewAgent *agent, quint64 addr, quint64 length)
4056 {
4057     //qDebug() << "GDB MEMORY FETCH" << agent << addr << length;
4058     postCommand(_("-data-read-memory %1 x 1 1 %2").arg(addr).arg(length),
4059         NeedsStop, CB(handleFetchMemory),
4060         QVariant::fromValue(MemoryAgentCookie(agent, addr)));
4061 }
4062
4063 void GdbEngine::handleFetchMemory(const GdbResponse &response)
4064 {
4065     // ^done,addr="0x08910c88",nr-bytes="16",total-bytes="16",
4066     // next-row="0x08910c98",prev-row="0x08910c78",next-page="0x08910c98",
4067     // prev-page="0x08910c78",memory=[{addr="0x08910c88",
4068     // data=["1","0","0","0","5","0","0","0","0","0","0","0","0","0","0","0"]}]
4069     MemoryAgentCookie ac = response.cookie.value<MemoryAgentCookie>();
4070     QTC_ASSERT(ac.agent, return);
4071     QByteArray ba;
4072     GdbMi memory = response.data.findChild("memory");
4073     QTC_ASSERT(memory.children().size() <= 1, return);
4074     if (memory.children().isEmpty())
4075         return;
4076     GdbMi memory0 = memory.children().at(0); // we asked for only one 'row'
4077     GdbMi data = memory0.findChild("data");
4078     foreach (const GdbMi &child, data.children()) {
4079         bool ok = true;
4080         unsigned char c = '?';
4081         c = child.data().toUInt(&ok, 0);
4082         QTC_ASSERT(ok, return);
4083         ba.append(c);
4084     }
4085     ac.agent->addLazyData(ac.address, ba);
4086 }
4087
4088
4089 struct DisassemblerAgentCookie
4090 {
4091     DisassemblerAgentCookie() : agent(0) {}
4092     DisassemblerAgentCookie(DisassemblerViewAgent *agent_)
4093         : agent(agent_)
4094     {}
4095     QPointer<DisassemblerViewAgent> agent;
4096 };
4097
4098 void GdbEngine::fetchDisassembler(DisassemblerViewAgent *agent,
4099     const StackFrame &frame)
4100 {
4101     if (frame.file.isEmpty()) {
4102         fetchDisassemblerByAddress(agent, true);
4103     } else {
4104         // Disassemble full function:
4105         QString cmd = _("-data-disassemble -f %1 -l %2 -n -1 -- 1");
4106         postCommand(cmd.arg(frame.file).arg(frame.line),
4107             Discardable, CB(handleFetchDisassemblerByLine),
4108             QVariant::fromValue(DisassemblerAgentCookie(agent)));
4109     }
4110 }
4111
4112 void GdbEngine::fetchDisassemblerByAddress(DisassemblerViewAgent *agent,
4113     bool useMixedMode)
4114 {
4115     QTC_ASSERT(agent, return);
4116     bool ok = true;
4117     quint64 address = agent->address().toULongLong(&ok, 0);
4118     QTC_ASSERT(ok, qDebug() << "ADDRESS: " << agent->address() << address; return);
4119     QString start = QString::number(address - 20, 16);
4120     QString end = QString::number(address + 100, 16);
4121     // -data-disassemble [ -s start-addr -e end-addr ]
4122     //  | [ -f filename -l linenum [ -n lines ] ] -- mode
4123     if (useMixedMode) 
4124         postCommand(_("-data-disassemble -s 0x%1 -e 0x%2 -- 1").arg(start).arg(end),
4125             Discardable, CB(handleFetchDisassemblerByAddress1),
4126             QVariant::fromValue(DisassemblerAgentCookie(agent)));
4127     else
4128         postCommand(_("-data-disassemble -s 0x%1 -e 0x%2 -- 0").arg(start).arg(end),
4129             Discardable, CB(handleFetchDisassemblerByAddress0),
4130             QVariant::fromValue(DisassemblerAgentCookie(agent)));
4131 }
4132
4133 static QByteArray parseLine(const GdbMi &line)
4134 {
4135     QByteArray ba;
4136     ba.reserve(200);
4137     QByteArray address = line.findChild("address").data();
4138     //QByteArray funcName = line.findChild("func-name").data();
4139     //QByteArray offset = line.findChild("offset").data();
4140     QByteArray inst = line.findChild("inst").data();
4141     ba += address + QByteArray(15 - address.size(), ' ');
4142     //ba += funcName + "+" + offset + "  ";
4143     //ba += QByteArray(30 - funcName.size() - offset.size(), ' ');
4144     ba += inst;
4145     ba += '\n';
4146     return ba;
4147 }
4148
4149 QString GdbEngine::parseDisassembler(const GdbMi &lines)
4150 {
4151     // ^done,data={asm_insns=[src_and_asm_line={line="1243",file=".../app.cpp",
4152     // line_asm_insn=[{address="0x08054857",func-name="main",offset="27",
4153     // inst="call 0x80545b0 <_Z13testQFileInfov>"}]},
4154     // src_and_asm_line={line="1244",file=".../app.cpp",
4155     // line_asm_insn=[{address="0x0805485c",func-name="main",offset="32",
4156     //inst="call 0x804cba1 <_Z11testObject1v>"}]}]}
4157     // - or -
4158     // ^done,asm_insns=[
4159     // {address="0x0805acf8",func-name="...",offset="25",inst="and $0xe8,%al"},
4160     // {address="0x0805acfa",func-name="...",offset="27",inst="pop %esp"},
4161
4162     QList<QByteArray> fileContents;
4163     bool fileLoaded = false;
4164     QByteArray ba;
4165     ba.reserve(200 * lines.children().size());
4166
4167     // FIXME: Performance?
4168     foreach (const GdbMi &child, lines.children()) {
4169         if (child.hasName("src_and_asm_line")) {
4170             // mixed mode
4171             if (!fileLoaded) {
4172                 QString fileName = QFile::decodeName(child.findChild("file").data());
4173                 QFile file(fullName(fileName));
4174                 file.open(QIODevice::ReadOnly);
4175                 fileContents = file.readAll().split('\n');
4176                 fileLoaded = true;
4177             }
4178             int line = child.findChild("line").data().toInt();
4179             if (line >= 0 && line < fileContents.size())
4180                 ba += "    " + fileContents.at(line) + '\n';
4181             GdbMi insn = child.findChild("line_asm_insn");
4182             foreach (const GdbMi &line, insn.children()) 
4183                 ba += parseLine(line);
4184         } else {
4185             // the non-mixed version
4186             ba += parseLine(child);
4187         }
4188     }
4189     return _(ba);
4190 }
4191
4192 void GdbEngine::handleFetchDisassemblerByLine(const GdbResponse &response)
4193 {
4194     DisassemblerAgentCookie ac = response.cookie.value<DisassemblerAgentCookie>();
4195     QTC_ASSERT(ac.agent, return);
4196
4197     if (response.resultClass == GdbResultDone) {
4198         GdbMi lines = response.data.findChild("asm_insns");
4199         if (lines.children().isEmpty())
4200             fetchDisassemblerByAddress(ac.agent, true);
4201         else if (lines.children().size() == 1
4202                     && lines.childAt(0).findChild("line").data() == "0")
4203             fetchDisassemblerByAddress(ac.agent, true);
4204         else
4205             ac.agent->setContents(parseDisassembler(lines));
4206     } else {
4207         // 536^error,msg="mi_cmd_disassemble: Invalid line number"
4208         QByteArray msg = response.data.findChild("msg").data();
4209         if (msg == "mi_cmd_disassemble: Invalid line number")
4210             fetchDisassemblerByAddress(ac.agent, true);
4211         else
4212             showStatusMessage(tr("Disassembler failed: %1").arg(_(msg)), 5000);
4213     }
4214 }
4215
4216 void GdbEngine::handleFetchDisassemblerByAddress1(const GdbResponse &response)
4217 {
4218     DisassemblerAgentCookie ac = response.cookie.value<DisassemblerAgentCookie>();
4219     QTC_ASSERT(ac.agent, return);
4220
4221     if (response.resultClass == GdbResultDone) {
4222         GdbMi lines = response.data.findChild("asm_insns");
4223         if (lines.children().isEmpty())
4224             fetchDisassemblerByAddress(ac.agent, false);
4225         else {
4226             QString contents = parseDisassembler(lines);
4227             if (ac.agent->contentsCoversAddress(contents)) {
4228                 ac.agent->setContents(parseDisassembler(lines));
4229             } else {
4230                 debugMessage(_("FALL BACK TO NON-MIXED"));
4231                 fetchDisassemblerByAddress(ac.agent, false);
4232             }
4233         }
4234     } else {
4235         // 26^error,msg="Cannot access memory at address 0x801ca308"
4236         QByteArray msg = response.data.findChild("msg").data();
4237         showStatusMessage(tr("Disassembler failed: %1").arg(_(msg)), 5000);
4238     }
4239 }
4240
4241 void GdbEngine::handleFetchDisassemblerByAddress0(const GdbResponse &response)
4242 {
4243     DisassemblerAgentCookie ac = response.cookie.value<DisassemblerAgentCookie>();
4244     QTC_ASSERT(ac.agent, return);
4245
4246     if (response.resultClass == GdbResultDone) {
4247         GdbMi lines = response.data.findChild("asm_insns");
4248         ac.agent->setContents(parseDisassembler(lines));
4249     } else {
4250         QByteArray msg = response.data.findChild("msg").data();
4251         showStatusMessage(tr("Disassembler failed: %1").arg(_(msg)), 5000);
4252     }
4253 }
4254
4255 void GdbEngine::gotoLocation(const StackFrame &frame, bool setMarker)
4256 {
4257     // qDebug() << "GOTO " << frame << setMarker;
4258     m_manager->gotoLocation(frame, setMarker);
4259 }
4260
4261 //
4262 // Starting up & shutting down
4263 //
4264
4265 bool GdbEngine::startGdb(const QStringList &args, const QString &gdb, const QString &settingsIdHint)
4266 {
4267     debugMessage(_("STARTING GDB ") + gdb);
4268
4269     m_gdbProc.disconnect(); // From any previous runs
4270
4271     QString location = gdb;
4272     const QByteArray env = qgetenv("QTC_DEBUGGER_PATH");
4273     if (!env.isEmpty())
4274         location = QString::fromLatin1(env);
4275     if (location.isEmpty())
4276         location = theDebuggerStringSetting(GdbLocation);
4277     QStringList gdbArgs;
4278     gdbArgs << _("-i");
4279     gdbArgs << _("mi");
4280     gdbArgs += args;
4281     m_gdbProc.start(location, gdbArgs);
4282
4283     if (!m_gdbProc.waitForStarted()) {
4284         const QString msg = tr("Unable to start gdb '%1': %2").arg(location, m_gdbProc.errorString());
4285         handleAdapterStartFailed(msg, settingsIdHint);
4286         return false;
4287     }
4288
4289     // Do this only after the process is running, so we get no needless error notifications
4290     connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)),
4291         SLOT(handleGdbError(QProcess::ProcessError)));
4292     connect(&m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)),
4293         SLOT(handleGdbFinished(int, QProcess::ExitStatus)));
4294     connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()),
4295         SLOT(readGdbStandardOutput()));
4296     connect(&m_gdbProc, SIGNAL(readyReadStandardError()),
4297         SLOT(readGdbStandardError()));
4298
4299     debugMessage(_("GDB STARTED, INITIALIZING IT"));
4300
4301     postCommand(_("show version"), CB(handleShowVersion));
4302     postCommand(_("-interpreter-exec console \"help bb\""),
4303         CB(handleIsSynchroneous));
4304     //postCommand(_("-enable-timings");
4305     postCommand(_("set print static-members off")); // Seemingly doesn't work.
4306     //postCommand(_("set debug infrun 1"));
4307     //postCommand(_("define hook-stop\n-thread-list-ids\n-stack-list-frames\nend"));
4308     //postCommand(_("define hook-stop\nprint 4\nend"));
4309     //postCommand(_("define hookpost-stop\nprint 5\nend"));
4310     //postCommand(_("define hook-call\nprint 6\nend"));
4311     //postCommand(_("define hookpost-call\nprint 7\nend"));
4312     //postCommand(_("set print object on")); // works with CLI, but not MI
4313     //postCommand(_("set step-mode on"));  // we can't work with that yes
4314     //postCommand(_("set exec-done-display on"));
4315     //postCommand(_("set print pretty on"));
4316     //postCommand(_("set confirm off"));
4317     //postCommand(_("set pagination off"));
4318
4319     // The following does not work with 6.3.50-20050815 (Apple version gdb-1344)
4320     // (Mac OS 10.6), but does so for gdb-966 (10.5):
4321     //postCommand(_("set print inferior-events 1"));
4322
4323     postCommand(_("set breakpoint pending on"));
4324     postCommand(_("set print elements 10000"));
4325
4326     //postCommand(_("set substitute-path /var/tmp/qt-x11-src-4.5.0 "
4327     //    "/home/sandbox/qtsdk-2009.01/qt"));
4328
4329     // one of the following is needed to prevent crashes in gdb on code like:
4330     //  template <class T> T foo() { return T(0); }
4331     //  int main() { return foo<int>(); }
4332     //  (gdb) call 'int foo<int>'()
4333     //  /build/buildd/gdb-6.8/gdb/valops.c:2069: internal-error:
4334     postCommand(_("set overload-resolution off"));
4335     //postCommand(_("set demangle-style none"));
4336     // From the docs:
4337     //  Stop means reenter debugger if this signal happens (implies print).
4338     //  Print means print a message if this signal happens.
4339     //  Pass means let program see this signal;
4340     //  otherwise program doesn't know.
4341     //  Pass and Stop may be combined.
4342     // We need "print" as otherwise we would get no feedback whatsoever
4343     // Custom DebuggingHelper crashs which happen regularily for when accessing
4344     // uninitialized variables.
4345     postCommand(_("handle SIGSEGV nopass stop print"));
4346
4347     // This is useful to kill the inferior whenever gdb dies.
4348     //postCommand(_("handle SIGTERM pass nostop print"));
4349
4350     postCommand(_("set unwindonsignal on"));
4351     //postCommand(_("pwd"));
4352     postCommand(_("set width 0"));
4353     postCommand(_("set height 0"));
4354
4355     if (m_isMacGdb) {
4356         postCommand(_("-gdb-set inferior-auto-start-cfm off"));
4357         postCommand(_("-gdb-set sharedLibrary load-rules "
4358             "dyld \".*libSystem.*\" all "
4359             "dyld \".*libauto.*\" all "
4360             "dyld \".*AppKit.*\" all "
4361             "dyld \".*PBGDBIntrospectionSupport.*\" all "
4362             "dyld \".*Foundation.*\" all "
4363             "dyld \".*CFDataFormatters.*\" all "
4364             "dyld \".*libobjc.*\" all "
4365             "dyld \".*CarbonDataFormatters.*\" all"));
4366     }
4367
4368     QString scriptFileName = theDebuggerStringSetting(GdbScriptFile);
4369     if (!scriptFileName.isEmpty()) {
4370         if (QFileInfo(scriptFileName).isReadable()) {
4371             postCommand(_("source ") + scriptFileName);
4372         } else {
4373             showMessageBox(QMessageBox::Warning,
4374             tr("Cannot find debugger initialization script"),
4375             tr("The debugger settings point to a script file at '%1' "
4376                "which is not accessible. If a script file is not needed, "
4377                "consider clearing that entry to avoid this warning. "
4378               ).arg(scriptFileName));
4379         }
4380     }
4381     if (m_gdbAdapter->dumperHandling() == AbstractGdbAdapter::DumperLoadedByGdbPreload
4382         && checkDebuggingHelpers()) {        
4383         QString cmd = _("set environment ");
4384         cmd += _(Debugger::Constants::Internal::LD_PRELOAD_ENV_VAR);
4385         cmd += _c(' ');
4386         cmd += manager()->qtDumperLibraryName();
4387         postCommand(cmd);
4388         m_debuggingHelperState = DebuggingHelperLoadTried;
4389     }
4390     return true;
4391 }
4392
4393 void GdbEngine::handleGdbError(QProcess::ProcessError error)
4394 {
4395     debugMessage(_("HANDLE GDB ERROR"));
4396     switch (error) {
4397     case QProcess::Crashed:
4398         break; // will get a processExited() as well
4399     // impossible case QProcess::FailedToStart:
4400     case QProcess::ReadError:
4401     case QProcess::WriteError:
4402     case QProcess::Timedout:
4403     default:
4404         m_gdbProc.kill();
4405         setState(EngineShuttingDown, true);
4406         showMessageBox(QMessageBox::Critical, tr("Gdb I/O Error"),
4407                        errorMessage(error));
4408         break;
4409     }
4410 }
4411
4412 void GdbEngine::handleGdbFinished(int code, QProcess::ExitStatus type)
4413 {
4414     debugMessage(_("GDB PROCESS FINISHED, status %1, code %2").arg(type).arg(code));
4415     if (!m_gdbAdapter)
4416         return;
4417     if (state() == EngineShuttingDown) {
4418         m_gdbAdapter->shutdown();
4419     } else if (state() != AdapterStartFailed) {
4420         showMessageBox(QMessageBox::Critical, tr("Unexpected Gdb Exit"),
4421                        tr("The gdb process exited unexpectedly (%1).")
4422                        .arg((type == QProcess::CrashExit)
4423                             ? tr("crashed") : tr("code %1").arg(code)));
4424         m_gdbAdapter->shutdown();
4425     }
4426     initializeVariables();
4427     setState(DebuggerNotReady, true);
4428 }
4429
4430 void GdbEngine::handleAdapterStartFailed(const QString &msg, const QString &settingsIdHint)
4431 {
4432     setState(AdapterStartFailed);
4433     debugMessage(_("ADAPTER START FAILED"));
4434     const QString title = tr("Adapter start failed");
4435     if (settingsIdHint.isEmpty()) {
4436         Core::ICore::instance()->showWarningWithOptions(title, msg);
4437     } else {
4438         Core::ICore::instance()->showWarningWithOptions(title, msg, QString(),
4439                     _(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY),
4440                     settingsIdHint);
4441     }
4442     shutdown();
4443 }
4444
4445 void GdbEngine::handleAdapterStarted()
4446 {
4447     setState(AdapterStarted);
4448     debugMessage(_("ADAPTER SUCCESSFULLY STARTED"));
4449
4450     showStatusMessage(tr("Starting inferior..."));
4451     setState(InferiorStarting);
4452     m_gdbAdapter->startInferior();
4453 }
4454
4455 void GdbEngine::handleInferiorPrepared()
4456 {
4457     const QString qtInstallPath = m_startParameters->qtInstallPath;
4458     if (!qtInstallPath.isEmpty()) {
4459         QString qtBuildPath =
4460         #if defined(Q_OS_WIN)
4461             _("C:/qt-greenhouse/Trolltech/Code_less_create_more/Trolltech/Code_less_create_more/Troll/4.6/qt");
4462         #elif defined(Q_OS_MAC)
4463             QString();
4464         #else    
4465             _("/var/tmp/qt-x11-src-4.6.0");
4466         #endif
4467         if (!qtBuildPath.isEmpty())
4468         postCommand(_("set substitute-path %1 %2")
4469             .arg(qtBuildPath).arg(qtInstallPath));
4470     }
4471
4472     // Initial attempt to set breakpoints
4473     showStatusMessage(tr("Setting breakpoints..."));
4474     attemptBreakpointSynchronization();
4475
4476     if (m_cookieForToken.isEmpty()) {
4477         startInferiorPhase2();
4478     } else {
4479         QTC_ASSERT(m_commandsDoneCallback == 0, /**/);
4480         m_commandsDoneCallback = &GdbEngine::startInferiorPhase2;
4481     }
4482 }
4483
4484 void GdbEngine::startInferiorPhase2()
4485 {
4486     debugMessage(_("BREAKPOINTS SET, CONTINUING INFERIOR STARTUP"));
4487     m_gdbAdapter->startInferiorPhase2();
4488 }
4489
4490 void GdbEngine::handleInferiorStartFailed(const QString &msg)
4491 {
4492     if (state() == AdapterStartFailed)
4493         return; // Adapter crashed meanwhile, so this notification is meaningless.
4494     debugMessage(_("INFERIOR START FAILED"));
4495     showMessageBox(QMessageBox::Critical, tr("Inferior start failed"), msg);
4496     setState(InferiorStartFailed);
4497     shutdown();
4498 }
4499
4500 void GdbEngine::handleAdapterCrashed(const QString &msg)
4501 {
4502     debugMessage(_("ADAPTER CRASHED"));
4503
4504     // The adapter is expected to have cleaned up after itself when we get here,
4505     // so the effect is about the same as AdapterStartFailed => use it.
4506     // Don't bother with state transitions - this can happen in any state and
4507     // the end result is always the same, so it makes little sense to find a
4508     // "path" which does not assert.
4509     setState(AdapterStartFailed, true);
4510
4511     // No point in being friendly here ...
4512     m_gdbProc.kill();
4513
4514     if (!msg.isEmpty())
4515         showMessageBox(QMessageBox::Critical, tr("Adapter crashed"), msg);
4516 }
4517
4518 void GdbEngine::addOptionPages(QList<Core::IOptionsPage*> *opts) const
4519 {
4520     opts->push_back(new GdbOptionsPage);
4521     opts->push_back(new TrkOptionsPage(m_trkOptions));
4522 }
4523
4524 void GdbEngine::showMessageBox(int icon, const QString &title, const QString &text)
4525 {
4526     m_manager->showMessageBox(icon, title, text);
4527 }
4528
4529 bool GdbEngine::isSynchroneous() const
4530 {
4531     return m_isSynchroneous;
4532 }
4533
4534 //
4535 // Factory
4536 //
4537
4538 IDebuggerEngine *createGdbEngine(DebuggerManager *manager)
4539 {
4540     return new GdbEngine(manager);
4541 }
4542
4543 } // namespace Internal
4544 } // namespace Debugger
4545
4546 Q_DECLARE_METATYPE(Debugger::Internal::MemoryAgentCookie);
4547 Q_DECLARE_METATYPE(Debugger::Internal::DisassemblerAgentCookie);
4548 Q_DECLARE_METATYPE(Debugger::Internal::GdbMi);