PageRenderTime 87ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

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

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