PageRenderTime 81ms CodeModel.GetById 38ms RepoModel.GetById 1ms app.codeStats 1ms

/src/plugins/debugger/gdb/gdbengine.cpp

https://bitbucket.org/kpozn/qt-creator-py-reborn
C++ | 5439 lines | 4438 code | 429 blank | 572 comment | 902 complexity | 456d16a2f4907e74a86b1b2081e849ef MD5 | raw file
Possible License(s): LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. /**************************************************************************
  2. **
  3. ** This file is part of Qt Creator
  4. **
  5. ** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
  6. **
  7. ** Contact: Nokia Corporation (qt-info@nokia.com)
  8. **
  9. **
  10. ** GNU Lesser General Public License Usage
  11. **
  12. ** This file may be used under the terms of the GNU Lesser General Public
  13. ** License version 2.1 as published by the Free Software Foundation and
  14. ** appearing in the file LICENSE.LGPL included in the packaging of this file.
  15. ** Please review the following information to ensure the GNU Lesser General
  16. ** Public License version 2.1 requirements will be met:
  17. ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  18. **
  19. ** In addition, as a special exception, Nokia gives you certain additional
  20. ** rights. These rights are described in the Nokia Qt LGPL Exception
  21. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  22. **
  23. ** Other Usage
  24. **
  25. ** Alternatively, this file may be used in accordance with the terms and
  26. ** conditions contained in a signed written agreement between you and Nokia.
  27. **
  28. ** If you have questions regarding the use of this file, please contact
  29. ** Nokia at qt-info@nokia.com.
  30. **
  31. **************************************************************************/
  32. #define QT_NO_CAST_FROM_ASCII
  33. #include "gdbengine.h"
  34. #include "debuggerstartparameters.h"
  35. #include "debuggerinternalconstants.h"
  36. #include "disassemblerlines.h"
  37. #include "attachgdbadapter.h"
  38. #include "coregdbadapter.h"
  39. #include "localplaingdbadapter.h"
  40. #include "termgdbadapter.h"
  41. #include "remotegdbserveradapter.h"
  42. #include "remoteplaingdbadapter.h"
  43. #include "codagdbadapter.h"
  44. #include "debuggeractions.h"
  45. #include "debuggerconstants.h"
  46. #include "debuggercore.h"
  47. #include "debuggerplugin.h"
  48. #include "debuggerrunner.h"
  49. #include "debuggerstringutils.h"
  50. #include "debuggertooltipmanager.h"
  51. #include "disassembleragent.h"
  52. #include "gdbmi.h"
  53. #include "gdboptionspage.h"
  54. #include "memoryagent.h"
  55. #include "watchutils.h"
  56. #include "breakhandler.h"
  57. #include "moduleshandler.h"
  58. #include "registerhandler.h"
  59. #include "snapshothandler.h"
  60. #include "sourcefileshandler.h"
  61. #include "stackhandler.h"
  62. #include "threadshandler.h"
  63. #include "watchhandler.h"
  64. #include "debuggersourcepathmappingwidget.h"
  65. #include "hostutils.h"
  66. #include "logwindow.h"
  67. #include "procinterrupt.h"
  68. #include <coreplugin/icore.h>
  69. #include <coreplugin/idocument.h>
  70. #include <extensionsystem/pluginmanager.h>
  71. #include <projectexplorer/abi.h>
  72. #include <projectexplorer/projectexplorerconstants.h>
  73. #include <projectexplorer/taskhub.h>
  74. #include <projectexplorer/itaskhandler.h>
  75. #include <texteditor/itexteditor.h>
  76. #include <utils/elfreader.h>
  77. #include <utils/qtcassert.h>
  78. #include <utils/qtcprocess.h>
  79. #include <QCoreApplication>
  80. #include <QDebug>
  81. #include <QDir>
  82. #include <QDirIterator>
  83. #include <QFileInfo>
  84. #include <QMetaObject>
  85. #include <QTime>
  86. #include <QTimer>
  87. #include <QTemporaryFile>
  88. #include <QTextStream>
  89. #include <QAction>
  90. #include <QDialogButtonBox>
  91. #include <QLabel>
  92. #include <QMainWindow>
  93. #include <QMessageBox>
  94. #include <QPushButton>
  95. #ifdef Q_OS_UNIX
  96. #include <unistd.h>
  97. #include <dlfcn.h>
  98. #endif
  99. #include <ctype.h>
  100. using namespace ProjectExplorer;
  101. using namespace Utils;
  102. namespace Debugger {
  103. namespace Internal {
  104. class GdbToolTipContext : public DebuggerToolTipContext
  105. {
  106. public:
  107. GdbToolTipContext(const DebuggerToolTipContext &c) :
  108. DebuggerToolTipContext(c), editor(0) {}
  109. QPoint mousePosition;
  110. QString expression;
  111. Core::IEditor *editor;
  112. };
  113. enum { debugPending = 0 };
  114. #define PENDING_DEBUG(s) do { if (debugPending) qDebug() << s; } while (0)
  115. #define CB(callback) &GdbEngine::callback, STRINGIFY(callback)
  116. QByteArray GdbEngine::tooltipIName(const QString &exp)
  117. {
  118. return "tooltip." + exp.toLatin1().toHex();
  119. }
  120. static bool stateAcceptsGdbCommands(DebuggerState state)
  121. {
  122. switch (state) {
  123. case EngineSetupRequested:
  124. case EngineSetupOk:
  125. case EngineSetupFailed:
  126. case InferiorUnrunnable:
  127. case InferiorSetupRequested:
  128. case InferiorSetupFailed:
  129. case EngineRunRequested:
  130. case InferiorRunRequested:
  131. case InferiorRunOk:
  132. case InferiorStopRequested:
  133. case InferiorStopOk:
  134. case InferiorShutdownRequested:
  135. case EngineShutdownRequested:
  136. case InferiorShutdownOk:
  137. case InferiorShutdownFailed:
  138. return true;
  139. case DebuggerNotReady:
  140. case InferiorStopFailed:
  141. case InferiorSetupOk:
  142. case EngineRunFailed:
  143. case InferiorExitOk:
  144. case InferiorRunFailed:
  145. case EngineShutdownOk:
  146. case EngineShutdownFailed:
  147. case DebuggerFinished:
  148. return false;
  149. }
  150. return false;
  151. }
  152. static int &currentToken()
  153. {
  154. static int token = 0;
  155. return token;
  156. }
  157. static QByteArray parsePlainConsoleStream(const GdbResponse &response)
  158. {
  159. QByteArray out = response.consoleStreamOutput;
  160. // FIXME: proper decoding needed
  161. if (out.endsWith("\\n"))
  162. out.chop(2);
  163. while (out.endsWith('\n') || out.endsWith(' '))
  164. out.chop(1);
  165. int pos = out.indexOf(" = ");
  166. return out.mid(pos + 3);
  167. }
  168. ///////////////////////////////////////////////////////////////////////
  169. //
  170. // Debuginfo Taskhandler
  171. //
  172. ///////////////////////////////////////////////////////////////////////
  173. class DebugInfoTask
  174. {
  175. public:
  176. QString command;
  177. };
  178. class DebugInfoTaskHandler : public ProjectExplorer::ITaskHandler
  179. {
  180. public:
  181. explicit DebugInfoTaskHandler(GdbEngine *engine)
  182. : m_engine(engine)
  183. {}
  184. bool canHandle(const Task &task) const
  185. {
  186. return m_debugInfoTasks.contains(task.taskId);
  187. }
  188. void handle(const Task &task)
  189. {
  190. m_engine->requestDebugInformation(m_debugInfoTasks.value(task.taskId));
  191. }
  192. void addTask(unsigned id, const DebugInfoTask &task)
  193. {
  194. m_debugInfoTasks[id] = task;
  195. }
  196. QAction *createAction(QObject *parent) const
  197. {
  198. QAction *action = new QAction(DebuggerPlugin::tr("Install &Debug Information"), parent);
  199. action->setToolTip(DebuggerPlugin::tr("This tries to install missing debug information."));
  200. return action;
  201. }
  202. private:
  203. GdbEngine *m_engine;
  204. QHash<unsigned, DebugInfoTask> m_debugInfoTasks;
  205. };
  206. ///////////////////////////////////////////////////////////////////////
  207. //
  208. // GdbEngine
  209. //
  210. ///////////////////////////////////////////////////////////////////////
  211. GdbEngine::GdbEngine(const DebuggerStartParameters &startParameters,
  212. DebuggerEngine *masterEngine)
  213. : DebuggerEngine(startParameters, CppLanguage, masterEngine)
  214. {
  215. setObjectName(_("GdbEngine"));
  216. m_busy = false;
  217. m_debuggingHelperState = DebuggingHelperUninitialized;
  218. m_gdbVersion = 100;
  219. m_gdbBuildVersion = -1;
  220. m_isMacGdb = false;
  221. m_isQnxGdb = false;
  222. m_hasBreakpointNotifications = false;
  223. m_hasPython = false;
  224. m_registerNamesListed = false;
  225. m_hasInferiorThreadList = false;
  226. m_sourcesListUpdating = false;
  227. m_oldestAcceptableToken = -1;
  228. m_nonDiscardableCount = 0;
  229. m_outputCodec = QTextCodec::codecForLocale();
  230. m_pendingBreakpointRequests = 0;
  231. m_commandsDoneCallback = 0;
  232. m_stackNeeded = false;
  233. m_preparedForQmlBreak = false;
  234. m_disassembleUsesComma = false;
  235. m_actingOnExpectedStop = false;
  236. m_fullStartDone = false;
  237. m_forceAsyncModel = false;
  238. invalidateSourcesList();
  239. m_debugInfoTaskHandler = new DebugInfoTaskHandler(this);
  240. ExtensionSystem::PluginManager::addObject(m_debugInfoTaskHandler);
  241. m_commandTimer.setSingleShot(true);
  242. connect(&m_commandTimer, SIGNAL(timeout()), SLOT(commandTimeout()));
  243. connect(debuggerCore()->action(AutoDerefPointers), SIGNAL(valueChanged(QVariant)),
  244. SLOT(reloadLocals()));
  245. connect(debuggerCore()->action(CreateFullBacktrace), SIGNAL(triggered()),
  246. SLOT(createFullBacktrace()));
  247. connect(debuggerCore()->action(UseDebuggingHelpers), SIGNAL(valueChanged(QVariant)),
  248. SLOT(reloadLocals()));
  249. connect(debuggerCore()->action(UseDynamicType), SIGNAL(valueChanged(QVariant)),
  250. SLOT(reloadLocals()));
  251. }
  252. GdbEngine::~GdbEngine()
  253. {
  254. ExtensionSystem::PluginManager::removeObject(m_debugInfoTaskHandler);
  255. delete m_debugInfoTaskHandler;
  256. m_debugInfoTaskHandler = 0;
  257. // Prevent sending error messages afterwards.
  258. disconnect();
  259. }
  260. DebuggerStartMode GdbEngine::startMode() const
  261. {
  262. return startParameters().startMode;
  263. }
  264. QString GdbEngine::errorMessage(QProcess::ProcessError error)
  265. {
  266. switch (error) {
  267. case QProcess::FailedToStart:
  268. return tr("The gdb process failed to start. Either the "
  269. "invoked program '%1' is missing, or you may have insufficient "
  270. "permissions to invoke the program.\n%2")
  271. .arg(m_gdb, gdbProc()->errorString());
  272. case QProcess::Crashed:
  273. if (targetState() == DebuggerFinished)
  274. return tr("The gdb process crashed some time after starting "
  275. "successfully.");
  276. else
  277. return tr("The gdb process was ended forcefully");
  278. case QProcess::Timedout:
  279. return tr("The last waitFor...() function timed out. "
  280. "The state of QProcess is unchanged, and you can try calling "
  281. "waitFor...() again.");
  282. case QProcess::WriteError:
  283. return tr("An error occurred when attempting to write "
  284. "to the gdb process. For example, the process may not be running, "
  285. "or it may have closed its input channel.");
  286. case QProcess::ReadError:
  287. return tr("An error occurred when attempting to read from "
  288. "the gdb process. For example, the process may not be running.");
  289. default:
  290. return tr("An unknown error in the gdb process occurred. ");
  291. }
  292. }
  293. #if 0
  294. static void dump(const char *first, const char *middle, const QString & to)
  295. {
  296. QByteArray ba(first, middle - first);
  297. Q_UNUSED(to)
  298. // note that qDebug cuts off output after a certain size... (bug?)
  299. qDebug("\n>>>>> %s\n%s\n====\n%s\n<<<<<\n",
  300. qPrintable(currentTime()),
  301. qPrintable(QString(ba).trimmed()),
  302. qPrintable(to.trimmed()));
  303. //qDebug() << "";
  304. //qDebug() << qPrintable(currentTime())
  305. // << " Reading response: " << QString(ba).trimmed() << "\n";
  306. }
  307. #endif
  308. // Parse "~:gdb: unknown target exception 0xc0000139 at 0x77bef04e\n"
  309. // and return an exception message
  310. static inline QString msgWinException(const QByteArray &data)
  311. {
  312. const int exCodePos = data.indexOf("0x");
  313. const int blankPos = exCodePos != -1 ? data.indexOf(' ', exCodePos + 1) : -1;
  314. const int addressPos = blankPos != -1 ? data.indexOf("0x", blankPos + 1) : -1;
  315. if (addressPos < 0)
  316. return GdbEngine::tr("An exception was triggered.");
  317. const unsigned exCode = data.mid(exCodePos, blankPos - exCodePos).toUInt(0, 0);
  318. const quint64 address = data.mid(addressPos).trimmed().toULongLong(0, 0);
  319. QString rc;
  320. QTextStream str(&rc);
  321. str << GdbEngine::tr("An exception was triggered: ");
  322. #ifdef Q_OS_WIN
  323. formatWindowsException(exCode, address, 0, 0, 0, str);
  324. #else
  325. Q_UNUSED(exCode)
  326. Q_UNUSED(address)
  327. #endif
  328. str << '.';
  329. return rc;
  330. }
  331. void GdbEngine::readDebugeeOutput(const QByteArray &data)
  332. {
  333. QString msg = m_outputCodec->toUnicode(data.constData(), data.length(),
  334. &m_outputCodecState);
  335. showMessage(msg, AppOutput);
  336. }
  337. static bool isNameChar(char c)
  338. {
  339. // could be 'stopped' or 'shlibs-added'
  340. return (c >= 'a' && c <= 'z') || c == '-';
  341. }
  342. static bool contains(const QByteArray &message, const char *pattern, int size)
  343. {
  344. const int s = message.size();
  345. if (s < size)
  346. return false;
  347. const int pos = message.indexOf(pattern);
  348. if (pos == -1)
  349. return false;
  350. const bool beginFits = pos == 0 || message.at(pos - 1) == '\n';
  351. const bool endFits = pos + size == s || message.at(pos + size) == '\n';
  352. return beginFits && endFits;
  353. }
  354. static bool isGdbConnectionError(const QByteArray &message)
  355. {
  356. // Handle messages gdb client produces when the target exits (gdbserver)
  357. //
  358. // we get this as response either to a specific command, e.g.
  359. // 31^error,msg="Remote connection closed"
  360. // or as informative output:
  361. // &Remote connection closed
  362. const char msg1[] = "Remote connection closed";
  363. const char msg2[] = "Remote communication error. Target disconnected.: No error.";
  364. const char msg3[] = "Quit";
  365. return contains(message, msg1, sizeof(msg1) - 1)
  366. || contains(message, msg2, sizeof(msg2) - 1)
  367. || contains(message, msg3, sizeof(msg3) - 1);
  368. }
  369. void GdbEngine::handleResponse(const QByteArray &buff)
  370. {
  371. showMessage(QString::fromLocal8Bit(buff, buff.length()), LogOutput);
  372. if (buff.isEmpty() || buff == "(gdb) ")
  373. return;
  374. const char *from = buff.constData();
  375. const char *to = from + buff.size();
  376. const char *inner;
  377. int token = -1;
  378. // Token is a sequence of numbers.
  379. for (inner = from; inner != to; ++inner)
  380. if (*inner < '0' || *inner > '9')
  381. break;
  382. if (from != inner) {
  383. token = QByteArray(from, inner - from).toInt();
  384. from = inner;
  385. }
  386. // Next char decides kind of response.
  387. const char c = *from++;
  388. switch (c) {
  389. case '*':
  390. case '+':
  391. case '=': {
  392. QByteArray asyncClass;
  393. for (; from != to; ++from) {
  394. const char c = *from;
  395. if (!isNameChar(c))
  396. break;
  397. asyncClass += *from;
  398. }
  399. GdbMi result;
  400. while (from != to) {
  401. GdbMi data;
  402. if (*from != ',') {
  403. // happens on archer where we get
  404. // 23^running <NL> *running,thread-id="all" <NL> (gdb)
  405. result.m_type = GdbMi::Tuple;
  406. break;
  407. }
  408. ++from; // skip ','
  409. data.parseResultOrValue(from, to);
  410. if (data.isValid()) {
  411. //qDebug() << "parsed result:" << data.toString();
  412. result.m_children += data;
  413. result.m_type = GdbMi::Tuple;
  414. }
  415. }
  416. if (asyncClass == "stopped") {
  417. handleStopResponse(result);
  418. m_pendingLogStreamOutput.clear();
  419. m_pendingConsoleStreamOutput.clear();
  420. } else if (asyncClass == "running") {
  421. // Archer has 'thread-id="all"' here
  422. } else if (asyncClass == "library-loaded") {
  423. // Archer has 'id="/usr/lib/libdrm.so.2",
  424. // target-name="/usr/lib/libdrm.so.2",
  425. // host-name="/usr/lib/libdrm.so.2",
  426. // symbols-loaded="0"
  427. // id="/lib/i386-linux-gnu/libc.so.6"
  428. // target-name="/lib/i386-linux-gnu/libc.so.6"
  429. // host-name="/lib/i386-linux-gnu/libc.so.6"
  430. // symbols-loaded="0",thread-group="i1"
  431. QByteArray id = result.findChild("id").data();
  432. if (!id.isEmpty())
  433. showStatusMessage(tr("Library %1 loaded").arg(_(id)), 1000);
  434. progressPing();
  435. invalidateSourcesList();
  436. Module module;
  437. module.startAddress = 0;
  438. module.endAddress = 0;
  439. module.hostPath = _(result.findChild("host-name").data());
  440. module.modulePath = _(result.findChild("target-name").data());
  441. module.moduleName = QFileInfo(module.hostPath).baseName();
  442. modulesHandler()->updateModule(module);
  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. progressPing();
  449. showStatusMessage(tr("Library %1 unloaded").arg(_(id)), 1000);
  450. invalidateSourcesList();
  451. } else if (asyncClass == "thread-group-added") {
  452. // 7.1-symbianelf has "{id="i1"}"
  453. } else if (asyncClass == "thread-group-created"
  454. || asyncClass == "thread-group-started") {
  455. // Archer had only "{id="28902"}" at some point of 6.8.x.
  456. // *-started seems to be standard in 7.1, but in early
  457. // 7.0.x, there was a *-created instead.
  458. progressPing();
  459. // 7.1.50 has thread-group-started,id="i1",pid="3529"
  460. QByteArray id = result.findChild("id").data();
  461. showStatusMessage(tr("Thread group %1 created").arg(_(id)), 1000);
  462. int pid = id.toInt();
  463. if (!pid) {
  464. id = result.findChild("pid").data();
  465. pid = id.toInt();
  466. }
  467. if (pid)
  468. notifyInferiorPid(pid);
  469. handleThreadGroupCreated(result);
  470. } else if (asyncClass == "thread-created") {
  471. //"{id="1",group-id="28902"}"
  472. QByteArray id = result.findChild("id").data();
  473. showStatusMessage(tr("Thread %1 created").arg(_(id)), 1000);
  474. } else if (asyncClass == "thread-group-exited") {
  475. // Archer has "{id="28902"}"
  476. QByteArray id = result.findChild("id").data();
  477. showStatusMessage(tr("Thread group %1 exited").arg(_(id)), 1000);
  478. handleThreadGroupExited(result);
  479. } else if (asyncClass == "thread-exited") {
  480. //"{id="1",group-id="28902"}"
  481. QByteArray id = result.findChild("id").data();
  482. QByteArray groupid = result.findChild("group-id").data();
  483. showStatusMessage(tr("Thread %1 in group %2 exited")
  484. .arg(_(id)).arg(_(groupid)), 1000);
  485. } else if (asyncClass == "thread-selected") {
  486. QByteArray id = result.findChild("id").data();
  487. showStatusMessage(tr("Thread %1 selected").arg(_(id)), 1000);
  488. //"{id="2"}"
  489. } else if (m_isMacGdb && asyncClass == "shlibs-updated") {
  490. // Apple's gdb announces updated libs.
  491. invalidateSourcesList();
  492. } else if (m_isMacGdb && asyncClass == "shlibs-added") {
  493. // Apple's gdb announces added libs.
  494. // {shlib-info={num="2", name="libmathCommon.A_debug.dylib",
  495. // kind="-", dyld-addr="0x7f000", reason="dyld", requested-state="Y",
  496. // state="Y", path="/usr/lib/system/libmathCommon.A_debug.dylib",
  497. // description="/usr/lib/system/libmathCommon.A_debug.dylib",
  498. // loaded_addr="0x7f000", slide="0x7f000", prefix=""}}
  499. invalidateSourcesList();
  500. } else if (m_isMacGdb && asyncClass == "resolve-pending-breakpoint") {
  501. // Apple's gdb announces resolved breakpoints.
  502. // new_bp="1",pended_bp="1",new_expr="\"gdbengine.cpp\":1584",
  503. // bkpt={number="1",type="breakpoint",disp="keep",enabled="y",
  504. // addr="0x0000000115cc3ddf",func="foo()",file="../foo.cpp",
  505. // line="1584",shlib="/../libFoo_debug.dylib",times="0"}
  506. const GdbMi bkpt = result.findChild("bkpt");
  507. const BreakpointResponseId rid(bkpt.findChild("number").data());
  508. if (!isQmlStepBreakpoint(rid)) {
  509. BreakHandler *handler = breakHandler();
  510. BreakpointModelId id = handler->findBreakpointByResponseId(rid);
  511. BreakpointResponse br = handler->response(id);
  512. updateResponse(br, bkpt);
  513. handler->setResponse(id, br);
  514. attemptAdjustBreakpointLocation(id);
  515. }
  516. } else if (asyncClass == "breakpoint-modified") {
  517. // New in FSF gdb since 2011-04-27.
  518. // "{bkpt={number="3",type="breakpoint",disp="keep",
  519. // enabled="y",addr="<MULTIPLE>",times="1",
  520. // original-location="\\",simple_gdbtest_app.cpp\\":135"},
  521. // {number="3.1",enabled="y",addr="0x0805ff68",
  522. // func="Vector<int>::Vector(int)",
  523. // file="simple_gdbtest_app.cpp",
  524. // fullname="/data/...line="135"},{number="3.2"...}}"
  525. // Note the leading comma in original-location. Filter it out.
  526. // We don't need the field anyway.
  527. QByteArray ba = result.toString();
  528. ba = '[' + ba.mid(6, ba.size() - 7) + ']';
  529. const int pos1 = ba.indexOf(",original-location");
  530. const int pos2 = ba.indexOf("\":", pos1 + 2);
  531. const int pos3 = ba.indexOf('"', pos2 + 2);
  532. ba.remove(pos1, pos3 - pos1 + 1);
  533. result = GdbMi();
  534. result.fromString(ba);
  535. BreakHandler *handler = breakHandler();
  536. BreakpointModelId id;
  537. BreakpointResponse br;
  538. foreach (const GdbMi &bkpt, result.children()) {
  539. const QByteArray nr = bkpt.findChild("number").data();
  540. BreakpointResponseId rid(nr);
  541. if (!isHiddenBreakpoint(rid)) {
  542. if (nr.contains('.')) {
  543. // A sub-breakpoint.
  544. BreakpointResponse sub;
  545. updateResponse(sub, bkpt);
  546. sub.id = rid;
  547. sub.type = br.type;
  548. handler->insertSubBreakpoint(id, sub);
  549. } else {
  550. // A primary breakpoint.
  551. id = handler->findBreakpointByResponseId(rid);
  552. //qDebug() << "NR: " << nr << "RID: " << rid
  553. // << "ID: " << id;
  554. //BreakpointModelId id =
  555. // handler->findBreakpointByResponseId(rid);
  556. br = handler->response(id);
  557. updateResponse(br, bkpt);
  558. handler->setResponse(id, br);
  559. }
  560. }
  561. }
  562. m_hasBreakpointNotifications = true;
  563. } else if (asyncClass == "breakpoint-created") {
  564. // "{bkpt={number="1",type="breakpoint",disp="del",enabled="y",
  565. // addr="<PENDING>",pending="main",times="0",
  566. // original-location="main"}}" -- or --
  567. // {bkpt={number="2",type="hw watchpoint",disp="keep",enabled="y",
  568. // what="*0xbfffed48",times="0",original-location="*0xbfffed48"
  569. BreakHandler *handler = breakHandler();
  570. foreach (const GdbMi &bkpt, result.children()) {
  571. BreakpointResponse br;
  572. br.type = BreakpointByFileAndLine;
  573. updateResponse(br, bkpt);
  574. handler->handleAlienBreakpoint(br, this);
  575. }
  576. } else if (asyncClass == "breakpoint-deleted") {
  577. // "breakpoint-deleted" "{id="1"}"
  578. // New in FSF gdb since 2011-04-27.
  579. BreakHandler *handler = breakHandler();
  580. QByteArray nr = result.findChild("id").data();
  581. BreakpointResponseId rid(nr);
  582. BreakpointModelId id = handler->findBreakpointByResponseId(rid);
  583. if (id.isValid())
  584. handler->removeAlienBreakpoint(id);
  585. } else {
  586. qDebug() << "IGNORED ASYNC OUTPUT"
  587. << asyncClass << result.toString();
  588. }
  589. break;
  590. }
  591. case '~': {
  592. QByteArray data = GdbMi::parseCString(from, to);
  593. m_pendingConsoleStreamOutput += data;
  594. // Parse pid from noise.
  595. if (!inferiorPid()) {
  596. // Linux/Mac gdb: [New [Tt]hread 0x545 (LWP 4554)]
  597. static QRegExp re1(_("New .hread 0x[0-9a-f]+ \\(LWP ([0-9]*)\\)"));
  598. // MinGW 6.8: [New thread 2437.0x435345]
  599. static QRegExp re2(_("New .hread ([0-9]+)\\.0x[0-9a-f]*"));
  600. // Mac: [Switching to process 9294 local thread 0x2e03] or
  601. // [Switching to process 31773]
  602. static QRegExp re3(_("Switching to process ([0-9]+)"));
  603. QTC_ASSERT(re1.isValid() && re2.isValid(), return);
  604. if (re1.indexIn(_(data)) != -1)
  605. maybeHandleInferiorPidChanged(re1.cap(1));
  606. else if (re2.indexIn(_(data)) != -1)
  607. maybeHandleInferiorPidChanged(re2.cap(1));
  608. else if (re3.indexIn(_(data)) != -1)
  609. maybeHandleInferiorPidChanged(re3.cap(1));
  610. }
  611. // Show some messages to give the impression something happens.
  612. if (data.startsWith("Reading symbols from ")) {
  613. showStatusMessage(tr("Reading %1...").arg(_(data.mid(21))), 1000);
  614. progressPing();
  615. invalidateSourcesList();
  616. } else if (data.startsWith("[New ") || data.startsWith("[Thread ")) {
  617. if (data.endsWith('\n'))
  618. data.chop(1);
  619. progressPing();
  620. showStatusMessage(_(data), 1000);
  621. } else if (data.startsWith("gdb: unknown target exception 0x")) {
  622. // [Windows, most likely some DLL/Entry point not found]:
  623. // "gdb: unknown target exception 0xc0000139 at 0x77bef04e"
  624. // This may be fatal and cause the target to exit later
  625. m_lastWinException = msgWinException(data);
  626. showMessage(m_lastWinException, LogMisc);
  627. }
  628. if (data.startsWith("QMLBP:")) {
  629. int pos1 = 6;
  630. int pos2 = data.indexOf(' ', pos1);
  631. m_qmlBreakpointResponseId2 = BreakpointResponseId(data.mid(pos1, pos2 - pos1));
  632. //qDebug() << "FOUND QMLBP: " << m_qmlBreakpointNumbers[2];
  633. //qDebug() << "CURRENT: " << m_qmlBreakpointNumbers;
  634. }
  635. break;
  636. }
  637. case '@': {
  638. readDebugeeOutput(GdbMi::parseCString(from, to));
  639. break;
  640. }
  641. case '&': {
  642. QByteArray data = GdbMi::parseCString(from, to);
  643. m_pendingLogStreamOutput += data;
  644. // On Windows, the contents seem to depend on the debugger
  645. // version and/or OS version used.
  646. if (data.startsWith("warning:"))
  647. showMessage(_(data.mid(9)), AppStuff); // Cut "warning: "
  648. if (isGdbConnectionError(data)) {
  649. notifyInferiorExited();
  650. break;
  651. }
  652. // From SuSE's gdb: >&"Missing separate debuginfo for ...\n"
  653. // ">&"Try: zypper install -C \"debuginfo(build-id)=c084ee5876ed1ac12730181c9f07c3e027d8e943\"\n"
  654. if (data.startsWith("Missing separate debuginfo for ")) {
  655. m_lastMissingDebugInfo = QString::fromLocal8Bit(data.mid(32));
  656. } else if (data.startsWith("Try: zypper")) {
  657. QString cmd = QString::fromLocal8Bit(data.mid(4));
  658. Task task(Task::Warning,
  659. tr("Missing debug information for %1\nTry: %2")
  660. .arg(m_lastMissingDebugInfo).arg(cmd),
  661. FileName(), 0, Core::Id("Debuginfo"));
  662. taskHub()->addTask(task);
  663. DebugInfoTask dit;
  664. dit.command = cmd;
  665. m_debugInfoTaskHandler->addTask(task.taskId, dit);
  666. }
  667. break;
  668. }
  669. case '^': {
  670. GdbResponse response;
  671. response.token = token;
  672. for (inner = from; inner != to; ++inner)
  673. if (*inner < 'a' || *inner > 'z')
  674. break;
  675. QByteArray resultClass = QByteArray::fromRawData(from, inner - from);
  676. if (resultClass == "done") {
  677. response.resultClass = GdbResultDone;
  678. } else if (resultClass == "running") {
  679. response.resultClass = GdbResultRunning;
  680. } else if (resultClass == "connected") {
  681. response.resultClass = GdbResultConnected;
  682. } else if (resultClass == "error") {
  683. response.resultClass = GdbResultError;
  684. } else if (resultClass == "exit") {
  685. response.resultClass = GdbResultExit;
  686. } else {
  687. response.resultClass = GdbResultUnknown;
  688. }
  689. from = inner;
  690. if (from != to) {
  691. if (*from == ',') {
  692. ++from;
  693. response.data.parseTuple_helper(from, to);
  694. response.data.m_type = GdbMi::Tuple;
  695. response.data.m_name = "data";
  696. } else {
  697. // Archer has this.
  698. response.data.m_type = GdbMi::Tuple;
  699. response.data.m_name = "data";
  700. }
  701. }
  702. //qDebug() << "\nLOG STREAM:" + m_pendingLogStreamOutput;
  703. //qDebug() << "\nCONSOLE STREAM:" + m_pendingConsoleStreamOutput;
  704. response.logStreamOutput = m_pendingLogStreamOutput;
  705. response.consoleStreamOutput = m_pendingConsoleStreamOutput;
  706. m_pendingLogStreamOutput.clear();
  707. m_pendingConsoleStreamOutput.clear();
  708. handleResultRecord(&response);
  709. break;
  710. }
  711. default: {
  712. qDebug() << "UNKNOWN RESPONSE TYPE '" << c << "'. REST: " << from;
  713. break;
  714. }
  715. }
  716. }
  717. void GdbEngine::readGdbStandardError()
  718. {
  719. QByteArray err = gdbProc()->readAllStandardError();
  720. showMessage(_("UNEXPECTED GDB STDERR: " + err));
  721. if (err == "Undefined command: \"bb\". Try \"help\".\n")
  722. return;
  723. if (err.startsWith("BFD: reopening"))
  724. return;
  725. qWarning() << "Unexpected GDB stderr:" << err;
  726. }
  727. void GdbEngine::readGdbStandardOutput()
  728. {
  729. m_commandTimer.start(); // Restart timer.
  730. int newstart = 0;
  731. int scan = m_inbuffer.size();
  732. QByteArray out = gdbProc()->readAllStandardOutput();
  733. m_inbuffer.append(out);
  734. // This can trigger when a dialog starts a nested event loop.
  735. if (m_busy)
  736. return;
  737. while (newstart < m_inbuffer.size()) {
  738. int start = newstart;
  739. int end = m_inbuffer.indexOf('\n', scan);
  740. if (end < 0) {
  741. m_inbuffer.remove(0, start);
  742. return;
  743. }
  744. newstart = end + 1;
  745. scan = newstart;
  746. if (end == start)
  747. continue;
  748. if (m_inbuffer.at(end - 1) == '\r') {
  749. --end;
  750. if (end == start)
  751. continue;
  752. }
  753. m_busy = true;
  754. QByteArray ba = QByteArray::fromRawData(m_inbuffer.constData() + start, end - start);
  755. handleResponse(ba);
  756. m_busy = false;
  757. }
  758. m_inbuffer.clear();
  759. }
  760. void GdbEngine::interruptInferior()
  761. {
  762. QTC_ASSERT(state() == InferiorStopRequested,
  763. qDebug() << "INTERRUPT INFERIOR: " << state(); return);
  764. if (usesExecInterrupt()) {
  765. postCommand("-exec-interrupt", Immediate);
  766. } else {
  767. showStatusMessage(tr("Stop requested..."), 5000);
  768. showMessage(_("TRYING TO INTERRUPT INFERIOR"));
  769. interruptInferior2();
  770. }
  771. }
  772. void GdbEngine::interruptInferiorTemporarily()
  773. {
  774. foreach (const GdbCommand &cmd, m_commandsToRunOnTemporaryBreak) {
  775. if (cmd.flags & LosesChild) {
  776. notifyInferiorIll();
  777. return;
  778. }
  779. }
  780. requestInterruptInferior();
  781. }
  782. void GdbEngine::maybeHandleInferiorPidChanged(const QString &pid0)
  783. {
  784. const qint64 pid = pid0.toLongLong();
  785. if (pid == 0) {
  786. showMessage(_("Cannot parse PID from %1").arg(pid0));
  787. return;
  788. }
  789. if (pid == inferiorPid())
  790. return;
  791. showMessage(_("FOUND PID %1").arg(pid));
  792. notifyInferiorPid(pid);
  793. }
  794. void GdbEngine::postCommand(const QByteArray &command, GdbCommandCallback callback,
  795. const char *callbackName, const QVariant &cookie)
  796. {
  797. postCommand(command, NoFlags, callback, callbackName, cookie);
  798. }
  799. void GdbEngine::postCommand(const QByteArray &command, GdbCommandFlags flags,
  800. GdbCommandCallback callback, const char *callbackName,
  801. const QVariant &cookie)
  802. {
  803. GdbCommand cmd;
  804. cmd.command = command;
  805. cmd.flags = flags;
  806. cmd.callback = callback;
  807. cmd.callbackName = callbackName;
  808. cmd.cookie = cookie;
  809. postCommandHelper(cmd);
  810. }
  811. void GdbEngine::postCommandHelper(const GdbCommand &cmd)
  812. {
  813. if (!stateAcceptsGdbCommands(state())) {
  814. PENDING_DEBUG(_("NO GDB PROCESS RUNNING, CMD IGNORED: " + cmd.command));
  815. showMessage(_("NO GDB PROCESS RUNNING, CMD IGNORED: %1 %2")
  816. .arg(_(cmd.command)).arg(state()));
  817. return;
  818. }
  819. if (cmd.flags & RebuildBreakpointModel) {
  820. ++m_pendingBreakpointRequests;
  821. PENDING_DEBUG(" BRWAKPOINT MODEL:" << cmd.command << "=>" << cmd.callbackName
  822. << "INCREMENTS PENDING TO" << m_pendingBreakpointRequests);
  823. } else {
  824. PENDING_DEBUG(" OTHER (IN):" << cmd.command << "=>" << cmd.callbackName
  825. << "LEAVES PENDING WATCH AT" << m_uncompleted.size()
  826. << "LEAVES PENDING BREAKPOINT AT" << m_pendingBreakpointRequests);
  827. }
  828. if (!(cmd.flags & Discardable))
  829. ++m_nonDiscardableCount;
  830. // FIXME: clean up logic below
  831. if (cmd.flags & Immediate) {
  832. // This should always be sent.
  833. flushCommand(cmd);
  834. } else if ((cmd.flags & NeedsStop)
  835. || !m_commandsToRunOnTemporaryBreak.isEmpty()) {
  836. if (state() == InferiorStopOk || state() == InferiorUnrunnable
  837. || state() == InferiorSetupRequested || state() == EngineSetupOk
  838. || state() == InferiorShutdownRequested) {
  839. // Can be safely sent now.
  840. flushCommand(cmd);
  841. } else {
  842. // Queue the commands that we cannot send at once.
  843. showMessage(_("QUEUING COMMAND " + cmd.command));
  844. m_commandsToRunOnTemporaryBreak.append(cmd);
  845. if (state() == InferiorStopRequested) {
  846. if (cmd.flags & LosesChild) {
  847. notifyInferiorIll();
  848. }
  849. showMessage(_("CHILD ALREADY BEING INTERRUPTED. STILL HOPING."));
  850. // Calling shutdown() here breaks all situations where two
  851. // NeedsStop commands are issued in quick succession.
  852. } else if (state() == InferiorRunOk) {
  853. showStatusMessage(tr("Stopping temporarily"), 1000);
  854. interruptInferiorTemporarily();
  855. } else {
  856. qDebug() << "ATTEMPTING TO QUEUE COMMAND "
  857. << cmd.command << "IN INAPPROPRIATE STATE" << state();
  858. }
  859. }
  860. } else if (!cmd.command.isEmpty()) {
  861. flushCommand(cmd);
  862. }
  863. }
  864. void GdbEngine::flushQueuedCommands()
  865. {
  866. showStatusMessage(tr("Processing queued commands"), 1000);
  867. while (!m_commandsToRunOnTemporaryBreak.isEmpty()) {
  868. GdbCommand cmd = m_commandsToRunOnTemporaryBreak.takeFirst();
  869. showMessage(_("RUNNING QUEUED COMMAND " + cmd.command + ' '
  870. + (cmd.callbackName ? cmd.callbackName : "<unnamed callback>")));
  871. flushCommand(cmd);
  872. }
  873. }
  874. void GdbEngine::flushCommand(const GdbCommand &cmd0)
  875. {
  876. if (!stateAcceptsGdbCommands(state())) {
  877. showMessage(_(cmd0.command), LogInput);
  878. showMessage(_("GDB PROCESS ACCEPTS NO CMD IN STATE %1 ").arg(state()));
  879. return;
  880. }
  881. QTC_ASSERT(gdbProc()->state() == QProcess::Running, return);
  882. const int token = ++currentToken();
  883. GdbCommand cmd = cmd0;
  884. cmd.postTime = QTime::currentTime();
  885. m_cookieForToken[token] = cmd;
  886. if (cmd.flags & ConsoleCommand)
  887. cmd.command = "-interpreter-exec console \"" + cmd.command + '"';
  888. cmd.command = QByteArray::number(token) + cmd.command;
  889. showMessage(_(cmd.command), LogInput);
  890. if (m_scheduledTestResponses.contains(token)) {
  891. // Fake response for test cases.
  892. QByteArray buffer = m_scheduledTestResponses.value(token);
  893. buffer.replace("@TOKEN@", QByteArray::number(token));
  894. m_scheduledTestResponses.remove(token);
  895. showMessage(_("FAKING TEST RESPONSE (TOKEN: %2, RESPONSE: '%3')")
  896. .arg(token).arg(_(buffer)));
  897. QMetaObject::invokeMethod(this, "handleResponse",
  898. Q_ARG(QByteArray, buffer));
  899. } else {
  900. write(cmd.command + "\r\n");
  901. // Start Watchdog.
  902. if (m_commandTimer.interval() <= 20000)
  903. m_commandTimer.setInterval(commandTimeoutTime());
  904. // The process can die for external reason between the "-gdb-exit" was
  905. // sent and a response could be retrieved. We don't want the watchdog
  906. // to bark in that case since the only possible outcome is a dead
  907. // process anyway.
  908. if (!cmd.command.endsWith("-gdb-exit"))
  909. m_commandTimer.start();
  910. //if (cmd.flags & LosesChild)
  911. // notifyInferiorIll();
  912. }
  913. }
  914. int GdbEngine::commandTimeoutTime() const
  915. {
  916. int time = debuggerCore()->action(GdbWatchdogTimeout)->value().toInt();
  917. return 1000 * qMax(40, time);
  918. }
  919. void GdbEngine::commandTimeout()
  920. {
  921. QList<int> keys = m_cookieForToken.keys();
  922. qSort(keys);
  923. bool killIt = false;
  924. foreach (int key, keys) {
  925. const GdbCommand &cmd = m_cookieForToken.value(key);
  926. if (!(cmd.flags & NonCriticalResponse))
  927. killIt = true;
  928. QByteArray msg = QByteArray::number(key);
  929. msg += ": " + cmd.command + " => ";
  930. msg += cmd.callbackName ? cmd.callbackName : "<unnamed callback>";
  931. showMessage(_(msg));
  932. }
  933. if (killIt) {
  934. QStringList commands;
  935. foreach (const GdbCommand &cookie, m_cookieForToken)
  936. commands << QString(_("\"%1\"")).arg(
  937. QString::fromLatin1(cookie.command));
  938. showMessage(_("TIMED OUT WAITING FOR GDB REPLY. "
  939. "COMMANDS STILL IN PROGRESS: ") + commands.join(_(", ")));
  940. int timeOut = m_commandTimer.interval();
  941. //m_commandTimer.stop();
  942. const QString msg = tr("The gdb process has not responded "
  943. "to a command within %n second(s). This could mean it is stuck "
  944. "in an endless loop or taking longer than expected to perform "
  945. "the operation.\nYou can choose between waiting "
  946. "longer or abort debugging.", 0, timeOut / 1000);
  947. QMessageBox *mb = showMessageBox(QMessageBox::Critical,
  948. tr("GDB not responding"), msg,
  949. QMessageBox::Ok | QMessageBox::Cancel);
  950. mb->button(QMessageBox::Cancel)->setText(tr("Give GDB more time"));
  951. mb->button(QMessageBox::Ok)->setText(tr("Stop debugging"));
  952. if (mb->exec() == QMessageBox::Ok) {
  953. showMessage(_("KILLING DEBUGGER AS REQUESTED BY USER"));
  954. // This is an undefined state, so we just pull the emergency brake.
  955. gdbProc()->kill();
  956. } else {
  957. showMessage(_("CONTINUE DEBUGGER AS REQUESTED BY USER"));
  958. }
  959. } else {
  960. showMessage(_("\nNON-CRITICAL TIMEOUT\n"));
  961. }
  962. }
  963. void GdbEngine::handleResultRecord(GdbResponse *response)
  964. {
  965. //qDebug() << "TOKEN:" << response->token
  966. // << " ACCEPTABLE:" << m_oldestAcceptableToken;
  967. //qDebug() << "\nRESULT" << response->token << response->toString();
  968. int token = response->token;
  969. if (token == -1)
  970. return;
  971. if (!m_cookieForToken.contains(token)) {
  972. // In theory this should not happen (rather the error should be
  973. // reported in the "first" response to the command) in practice it
  974. // does. We try to handle a few situations we are aware of gracefully.
  975. // Ideally, this code should not be present at all.
  976. showMessage(_("COOKIE FOR TOKEN %1 ALREADY EATEN (%2). "
  977. "TWO RESPONSES FOR ONE COMMAND?").arg(token).
  978. arg(QString::fromLatin1(stateName(state()))));
  979. if (response->resultClass == GdbResultError) {
  980. QByteArray msg = response->data.findChild("msg").data();
  981. if (msg == "Cannot find new threads: generic error") {
  982. // Handle a case known to occur on Linux/gdb 6.8 when debugging moc
  983. // with helpers enabled. In this case we get a second response with
  984. // msg="Cannot find new threads: generic error"
  985. showMessage(_("APPLYING WORKAROUND #1"));
  986. showMessageBox(QMessageBox::Critical,
  987. tr("Executable failed"), QString::fromLocal8Bit(msg));
  988. showStatusMessage(tr("Process failed to start"));
  989. //shutdown();
  990. notifyInferiorIll();
  991. } else if (msg == "\"finish\" not meaningful in the outermost frame.") {
  992. // Handle a case known to appear on GDB 6.4 symbianelf when
  993. // the stack is cut due to access to protected memory.
  994. //showMessage(_("APPLYING WORKAROUND #2"));
  995. notifyInferiorStopOk();
  996. } else if (msg.startsWith("Cannot find bounds of current function")) {
  997. // Happens when running "-exec-next" in a function for which
  998. // there is no debug information. Divert to "-exec-next-step"
  999. showMessage(_("APPLYING WORKAROUND #3"));
  1000. notifyInferiorStopOk();
  1001. executeNextI();
  1002. } else if (msg.startsWith("Couldn't get registers: No such process.")) {
  1003. // Happens on archer-tromey-python 6.8.50.20090910-cvs
  1004. // There might to be a race between a process shutting down
  1005. // and library load messages.
  1006. showMessage(_("APPLYING WORKAROUND #4"));
  1007. notifyInferiorStopOk();
  1008. //notifyInferiorIll();
  1009. //showStatusMessage(tr("Executable failed: %1")
  1010. // .arg(QString::fromLocal8Bit(msg)));
  1011. //shutdown();
  1012. //showMessageBox(QMessageBox::Critical,
  1013. // tr("Executable failed"), QString::fromLocal8Bit(msg));
  1014. } else if (msg.contains("Cannot insert breakpoint")) {
  1015. // For breakpoints set by address to non-existent addresses we
  1016. // might get something like "6^error,msg="Warning:\nCannot insert
  1017. // breakpoint 3.\nError accessing memory address 0x34592327:
  1018. // Input/output error.\nCannot insert breakpoint 4.\nError
  1019. // accessing memory address 0x34592335: Input/output error.\n".
  1020. // This should not stop us from proceeding.
  1021. // Most notably, that happens after a "6^running" and "*running"
  1022. // We are probably sitting at _start and can't proceed as
  1023. // long as the breakpoints are enabled.
  1024. // FIXME: Should we silently disable the offending breakpoints?
  1025. showMessage(_("APPLYING WORKAROUND #5"));
  1026. showMessageBox(QMessageBox::Critical,
  1027. tr("Setting breakpoints failed"), QString::fromLocal8Bit(msg));
  1028. QTC_CHECK(state() == InferiorRunOk);
  1029. notifyInferiorSpontaneousStop();
  1030. notifyEngineIll();
  1031. } else if (isGdbConnectionError(msg)) {
  1032. notifyInferiorExited();
  1033. } else {
  1034. // Windows: Some DLL or some function not found. Report
  1035. // the exception now in a box.
  1036. if (msg.startsWith("During startup program exited with"))
  1037. notifyInferiorExited();
  1038. QString logMsg;
  1039. if (!m_lastWinException.isEmpty())
  1040. logMsg = m_lastWinException + QLatin1Char('\n');
  1041. logMsg += QString::fromLocal8Bit(msg);
  1042. showMessageBox(QMessageBox::Critical, tr("Executable Failed"), logMsg);
  1043. showStatusMessage(tr("Executable failed: %1").arg(logMsg));
  1044. }
  1045. }
  1046. return;
  1047. }
  1048. GdbCommand cmd = m_cookieForToken.take(token);
  1049. if (debuggerCore()->boolSetting(LogTimeStamps)) {
  1050. showMessage(_("Response time: %1: %2 s")
  1051. .arg(_(cmd.command))
  1052. .arg(cmd.postTime.msecsTo(QTime::currentTime()) / 1000.),
  1053. LogTime);
  1054. }
  1055. if (response->token < m_oldestAcceptableToken && (cmd.flags & Discardable)) {
  1056. //showMessage(_("### SKIPPING OLD RESULT") + response.toString());
  1057. return;
  1058. }
  1059. response->cookie = cmd.cookie;
  1060. bool isExpectedResult =
  1061. (response->resultClass == GdbResultError) // Can always happen.
  1062. || (response->resultClass == GdbResultRunning && (cmd.flags & RunRequest))
  1063. || (response->resultClass == GdbResultExit && (cmd.flags & ExitRequest))
  1064. || (response->resultClass == GdbResultDone);
  1065. // GdbResultDone can almost "always" happen. Known examples are:
  1066. // (response->resultClass == GdbResultDone && cmd.command == "continue")
  1067. // Happens with some incarnations of gdb 6.8 for "jump to line"
  1068. // (response->resultClass == GdbResultDone && cmd.command.startsWith("jump"))
  1069. // (response->resultClass == GdbResultDone && cmd.command.startsWith("detach"))
  1070. // Happens when stepping finishes very quickly and issues *stopped and ^done
  1071. // instead of ^running and *stopped
  1072. // (response->resultClass == GdbResultDone && (cmd.flags & RunRequest));
  1073. if (!isExpectedResult) {
  1074. const DebuggerStartParameters &sp = startParameters();
  1075. Abi abi = sp.toolChainAbi;
  1076. if (abi.os() == Abi::WindowsOS
  1077. && cmd.command.startsWith("attach")
  1078. && (sp.startMode == AttachExternal || sp.useTerminal))
  1079. {
  1080. // Ignore spurious 'running' responses to 'attach'.
  1081. } else {
  1082. QByteArray rsp = GdbResponse::stringFromResultClass(response->resultClass);
  1083. rsp = "UNEXPECTED RESPONSE '" + rsp + "' TO COMMAND '" + cmd.command + "'";
  1084. qWarning() << rsp << " AT " __FILE__ ":" STRINGIFY(__LINE__);
  1085. showMessage(_(rsp));
  1086. }
  1087. }
  1088. if (!(cmd.flags & Discardable))
  1089. --m_nonDiscardableCount;
  1090. if (cmd.callback)
  1091. (this->*cmd.callback)(*response);
  1092. if (cmd.flags & RebuildBreakpointModel) {
  1093. --m_pendingBreakpointRequests;
  1094. PENDING_DEBUG(" BREAKPOINT" << cmd.command << "=>" << cmd.callbackName
  1095. << "DECREMENTS PENDING TO" << m_uncompleted.size());
  1096. if (m_pendingBreakpointRequests <= 0) {
  1097. PENDING_DEBUG("\n\n ... AND TRIGGERS BREAKPOINT MODEL UPDATE\n");
  1098. attemptBreakpointSynchronization();
  1099. }
  1100. } else {
  1101. PENDING_DEBUG(" OTHER (OUT):" << cmd.command << "=>" << cmd.callbackName
  1102. << "LEAVES PENDING WATCH AT" << m_uncompleted.size()
  1103. << "LEAVES PENDING BREAKPOINT AT" << m_pendingBreakpointRequests);
  1104. }
  1105. // Commands were queued, but we were in RunningRequested state, so the interrupt
  1106. // was postponed.
  1107. // This is done after the command callbacks so the running-requesting commands
  1108. // can assert on the right state.
  1109. if (state() == InferiorRunOk && !m_commandsToRunOnTemporaryBreak.isEmpty())
  1110. interruptInferiorTemporarily();
  1111. // Continue only if there are no commands wire anymore, so this will
  1112. // be fully synchronous.
  1113. // This is somewhat inefficient, as it makes the last command synchronous.
  1114. // An optimization would be requesting the continue immediately when the
  1115. // event loop is entered, and let individual commands have a flag to suppress
  1116. // that behavior.
  1117. if (m_commandsDoneCallback && m_cookieForToken.isEmpty()) {
  1118. showMessage(_("ALL COMMANDS DONE; INVOKING CALLBACK"));
  1119. CommandsDoneCallback cont = m_commandsDoneCallback;
  1120. m_commandsDoneCallback = 0;
  1121. (this->*cont)();
  1122. } else {
  1123. PENDING_DEBUG("MISSING TOKENS: " << m_cookieForToken.keys());
  1124. }
  1125. if (m_cookieForToken.isEmpty())
  1126. m_commandTimer.stop();
  1127. }
  1128. bool GdbEngine::acceptsDebuggerCommands() const
  1129. {
  1130. return state() == InferiorStopOk
  1131. || state() == InferiorUnrunnable;
  1132. }
  1133. void GdbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages languages)
  1134. {
  1135. if (!(languages & CppLanguage))
  1136. return;
  1137. QTC_CHECK(acceptsDebuggerCommands());
  1138. GdbCommand cmd;
  1139. cmd.command = command.toLatin1();
  1140. flushCommand(cmd);
  1141. }
  1142. // This is called from CoreAdapter and AttachAdapter.
  1143. void GdbEngine::updateAll()
  1144. {
  1145. if (hasPython())
  1146. updateAllPython();
  1147. else
  1148. updateAllClassic();
  1149. }
  1150. void GdbEngine::handleQuerySources(const GdbResponse &response)
  1151. {
  1152. m_sourcesListUpdating = false;
  1153. if (response.resultClass == GdbResultDone) {
  1154. QMap<QString, QString> oldShortToFull = m_shortToFullName;
  1155. m_shortToFullName.clear();
  1156. m_fullToShortName.clear();
  1157. // "^done,files=[{file="../../../../bin/dumper/dumper.cpp",
  1158. // fullname="/data5/dev/ide/main/bin/dumper/dumper.cpp"},
  1159. GdbMi files = response.data.findChild("files");
  1160. foreach (const GdbMi &item, files.children()) {
  1161. GdbMi fileName = item.findChild("file");
  1162. if (fileName.data().endsWith("<built-in>"))
  1163. continue;
  1164. GdbMi fullName = item.findChild("fullname");
  1165. QString file = QSt

Large files files are truncated, but you can click here to view the full file