PageRenderTime 68ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 1ms

/src/plugins/debugger/cdb/cdbengine.cpp

https://bitbucket.org/kpozn/qt-creator-py-reborn
C++ | 3133 lines | 2646 code | 212 blank | 275 comment | 476 complexity | cd301d975e19f4cd921a1aa3b104caab MD5 | raw file
Possible License(s): LGPL-2.1

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

  1. /**************************************************************************
  2. **
  3. ** This file is part of Qt Creator
  4. **
  5. ** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
  6. **
  7. ** Contact: Nokia Corporation (qt-info@nokia.com)
  8. **
  9. **
  10. ** GNU Lesser General Public License Usage
  11. **
  12. ** This file may be used under the terms of the GNU Lesser General Public
  13. ** License version 2.1 as published by the Free Software Foundation and
  14. ** appearing in the file LICENSE.LGPL included in the packaging of this file.
  15. ** Please review the following information to ensure the GNU Lesser General
  16. ** Public License version 2.1 requirements will be met:
  17. ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  18. **
  19. ** In addition, as a special exception, Nokia gives you certain additional
  20. ** rights. These rights are described in the Nokia Qt LGPL Exception
  21. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  22. **
  23. ** Other Usage
  24. **
  25. ** Alternatively, this file may be used in accordance with the terms and
  26. ** conditions contained in a signed written agreement between you and Nokia.
  27. **
  28. ** If you have questions regarding the use of this file, please contact
  29. ** Nokia at qt-info@nokia.com.
  30. **
  31. **************************************************************************/
  32. #include "cdbengine.h"
  33. #include "breakhandler.h"
  34. #include "breakpoint.h"
  35. #include "bytearrayinputstream.h"
  36. #include "cdboptions.h"
  37. #include "cdboptionspage.h"
  38. #include "cdbparsehelpers.h"
  39. #include "debuggeractions.h"
  40. #include "debuggercore.h"
  41. #include "debuggerinternalconstants.h"
  42. #include "debuggerrunner.h"
  43. #include "debuggerstartparameters.h"
  44. #include "debuggertooltipmanager.h"
  45. #include "disassembleragent.h"
  46. #include "disassemblerlines.h"
  47. #include "memoryagent.h"
  48. #include "moduleshandler.h"
  49. #include "registerhandler.h"
  50. #include "stackframe.h"
  51. #include "stackhandler.h"
  52. #include "threadshandler.h"
  53. #include "watchhandler.h"
  54. #include "watchutils.h"
  55. #include "gdb/gdbmi.h"
  56. #include "shared/cdbsymbolpathlisteditor.h"
  57. #include "shared/hostutils.h"
  58. #include "procinterrupt.h"
  59. #include <TranslationUnit.h>
  60. #include <coreplugin/icore.h>
  61. #include <texteditor/itexteditor.h>
  62. #include <projectexplorer/abi.h>
  63. #include <projectexplorer/projectexplorerconstants.h>
  64. #include <utils/synchronousprocess.h>
  65. #include <utils/winutils.h>
  66. #include <utils/qtcassert.h>
  67. #include <utils/savedaction.h>
  68. #include <utils/consoleprocess.h>
  69. #include <utils/fileutils.h>
  70. #include <cplusplus/findcdbbreakpoint.h>
  71. #include <cplusplus/CppDocument.h>
  72. #include <cpptools/ModelManagerInterface.h>
  73. #include <QCoreApplication>
  74. #include <QFileInfo>
  75. #include <QDir>
  76. #include <QDebug>
  77. #include <QTextStream>
  78. #include <QDateTime>
  79. #include <QToolTip>
  80. #include <QMainWindow>
  81. #include <QMessageBox>
  82. #include <cctype>
  83. Q_DECLARE_METATYPE(Debugger::Internal::DisassemblerAgent*)
  84. Q_DECLARE_METATYPE(Debugger::Internal::MemoryAgent*)
  85. enum { debug = 0 };
  86. enum { debugLocals = 0 };
  87. enum { debugSourceMapping = 0 };
  88. enum { debugWatches = 0 };
  89. enum { debugBreakpoints = 0 };
  90. enum HandleLocalsFlags
  91. {
  92. PartialLocalsUpdate = 0x1,
  93. LocalsUpdateForNewFrame = 0x2
  94. };
  95. #if 0
  96. # define STATE_DEBUG(state, func, line, notifyFunc) qDebug("%s in %s at %s:%d", notifyFunc, stateName(state), func, line);
  97. #else
  98. # define STATE_DEBUG(state, func, line, notifyFunc)
  99. #endif
  100. /*!
  101. \class Debugger::Internal::CdbEngine
  102. Cdb engine version 2: Run the CDB process on pipes and parse its output.
  103. The engine relies on a CDB extension Qt Creator provides as an extension
  104. library (32/64bit), which is loaded into cdb.exe. It serves to:
  105. \list
  106. \o Notify the engine about the state of the debugging session:
  107. \list
  108. \o idle: (hooked up with .idle_cmd) debuggee stopped
  109. \o accessible: Debuggee stopped, cdb.exe accepts commands
  110. \o inaccessible: Debuggee runs, no way to post commands
  111. \o session active/inactive: Lost debuggee, terminating.
  112. \endlist
  113. \o Hook up with output/event callbacks and produce formatted output to be able
  114. to catch application output and exceptions.
  115. \o Provide some extension commands that produce output in a standardized (GDBMI)
  116. format that ends up in handleExtensionMessage(), for example:
  117. \list
  118. \o pid Return debuggee pid for interrupting.
  119. \o locals Print locals from SymbolGroup
  120. \o expandLocals Expand locals in symbol group
  121. \o registers, modules, threads
  122. \endlist
  123. \endlist
  124. Debugger commands can be posted by calling:
  125. \list
  126. \o postCommand(): Does not expect a reply
  127. \o postBuiltinCommand(): Run a builtin-command producing free-format, multiline output
  128. that is captured by enclosing it in special tokens using the 'echo' command and
  129. then invokes a callback with a CdbBuiltinCommand structure.
  130. \o postExtensionCommand(): Run a command provided by the extension producing
  131. one-line output and invoke a callback with a CdbExtensionCommand structure
  132. (output is potentially split up in chunks).
  133. \endlist
  134. Startup sequence:
  135. [Console: The console stub launches the process. On process startup,
  136. launchCDB() is called with AttachExternal].
  137. setupEngine() calls launchCDB() with the startparameters. The debuggee
  138. runs into the initial breakpoint (session idle). EngineSetupOk is
  139. notified (inferior still stopped). setupInferior() is then called
  140. which does breakpoint synchronization and issues the extension 'pid'
  141. command to obtain the inferior pid (which also hooks up the output callbacks).
  142. handlePid() notifies notifyInferiorSetupOk.
  143. runEngine() is then called which issues 'g' to continue the inferior.
  144. Shutdown mostly uses notifyEngineSpontaneousShutdown() as cdb just quits
  145. when the inferior exits (except attach modes).
  146. */
  147. using namespace ProjectExplorer;
  148. namespace Debugger {
  149. namespace Internal {
  150. static const char localsPrefixC[] = "local.";
  151. struct MemoryViewCookie
  152. {
  153. explicit MemoryViewCookie(MemoryAgent *a = 0, QObject *e = 0,
  154. quint64 addr = 0, quint64 l = 0) :
  155. agent(a), editorToken(e), address(addr), length(l)
  156. {}
  157. MemoryAgent *agent;
  158. QObject *editorToken;
  159. quint64 address;
  160. quint64 length;
  161. };
  162. struct MemoryChangeCookie
  163. {
  164. explicit MemoryChangeCookie(quint64 addr = 0, const QByteArray &d = QByteArray()) :
  165. address(addr), data(d) {}
  166. quint64 address;
  167. QByteArray data;
  168. };
  169. struct ConditionalBreakPointCookie
  170. {
  171. ConditionalBreakPointCookie(BreakpointModelId i = BreakpointModelId()) : id(i) {}
  172. BreakpointModelId id;
  173. GdbMi stopReason;
  174. };
  175. } // namespace Internal
  176. } // namespace Debugger
  177. Q_DECLARE_METATYPE(Debugger::Internal::MemoryViewCookie)
  178. Q_DECLARE_METATYPE(Debugger::Internal::MemoryChangeCookie)
  179. Q_DECLARE_METATYPE(Debugger::Internal::ConditionalBreakPointCookie)
  180. namespace Debugger {
  181. namespace Internal {
  182. static inline bool isCreatorConsole(const DebuggerStartParameters &sp, const CdbOptions &o)
  183. {
  184. return !o.cdbConsole && sp.useTerminal
  185. && (sp.startMode == StartInternal || sp.startMode == StartExternal);
  186. }
  187. static QMessageBox *
  188. nonModalMessageBox(QMessageBox::Icon icon, const QString &title, const QString &text)
  189. {
  190. QMessageBox *mb = new QMessageBox(icon, title, text, QMessageBox::Ok,
  191. debuggerCore()->mainWindow());
  192. mb->setAttribute(Qt::WA_DeleteOnClose);
  193. mb->show();
  194. return mb;
  195. }
  196. // Base data structure for command queue entries with callback
  197. struct CdbCommandBase
  198. {
  199. typedef CdbEngine::BuiltinCommandHandler CommandHandler;
  200. CdbCommandBase();
  201. CdbCommandBase(const QByteArray &cmd, int token, unsigned flags,
  202. unsigned nc, const QVariant &cookie);
  203. int token;
  204. unsigned flags;
  205. QByteArray command;
  206. QVariant cookie;
  207. // Continue with another commands as specified in CommandSequenceFlags
  208. unsigned commandSequence;
  209. };
  210. CdbCommandBase::CdbCommandBase() :
  211. token(0), flags(0), commandSequence(0)
  212. {
  213. }
  214. CdbCommandBase::CdbCommandBase(const QByteArray &cmd, int t, unsigned f,
  215. unsigned nc, const QVariant &c) :
  216. token(t), flags(f), command(cmd), cookie(c), commandSequence(nc)
  217. {
  218. }
  219. // Queue entry for builtin commands producing free-format
  220. // line-by-line output.
  221. struct CdbBuiltinCommand : public CdbCommandBase
  222. {
  223. typedef CdbEngine::BuiltinCommandHandler CommandHandler;
  224. CdbBuiltinCommand() {}
  225. CdbBuiltinCommand(const QByteArray &cmd, int token, unsigned flags,
  226. CommandHandler h,
  227. unsigned nc, const QVariant &cookie) :
  228. CdbCommandBase(cmd, token, flags, nc, cookie), handler(h)
  229. {}
  230. QByteArray joinedReply() const;
  231. CommandHandler handler;
  232. QList<QByteArray> reply;
  233. };
  234. QByteArray CdbBuiltinCommand::joinedReply() const
  235. {
  236. if (reply.isEmpty())
  237. return QByteArray();
  238. QByteArray answer;
  239. answer.reserve(120 * reply.size());
  240. foreach (const QByteArray &l, reply) {
  241. answer += l;
  242. answer += '\n';
  243. }
  244. return answer;
  245. }
  246. // Queue entry for Qt Creator extension commands producing one-line
  247. // output with success flag and error message.
  248. struct CdbExtensionCommand : public CdbCommandBase
  249. {
  250. typedef CdbEngine::ExtensionCommandHandler CommandHandler;
  251. CdbExtensionCommand() : success(false) {}
  252. CdbExtensionCommand(const QByteArray &cmd, int token, unsigned flags,
  253. CommandHandler h,
  254. unsigned nc, const QVariant &cookie) :
  255. CdbCommandBase(cmd, token, flags, nc, cookie), handler(h),success(false) {}
  256. CommandHandler handler;
  257. QByteArray reply;
  258. QByteArray errorMessage;
  259. bool success;
  260. };
  261. template <class CommandPtrType>
  262. int indexOfCommand(const QList<CommandPtrType> &l, int token)
  263. {
  264. const int count = l.size();
  265. for (int i = 0; i < count; i++)
  266. if (l.at(i)->token == token)
  267. return i;
  268. return -1;
  269. }
  270. static inline bool validMode(DebuggerStartMode sm)
  271. {
  272. switch (sm) {
  273. case NoStartMode:
  274. case StartRemoteGdb:
  275. return false;
  276. default:
  277. break;
  278. }
  279. return true;
  280. }
  281. // Accessed by RunControlFactory
  282. DebuggerEngine *createCdbEngine(const DebuggerStartParameters &sp,
  283. DebuggerEngine *masterEngine, QString *errorMessage)
  284. {
  285. #ifdef Q_OS_WIN
  286. CdbOptionsPage *op = CdbOptionsPage::instance();
  287. if (!op || !op->options()->isValid() || !validMode(sp.startMode)) {
  288. *errorMessage = QLatin1String("Internal error: Invalid start parameters passed for thre CDB engine.");
  289. return 0;
  290. }
  291. return new CdbEngine(sp, masterEngine, op->options());
  292. #else
  293. Q_UNUSED(masterEngine)
  294. Q_UNUSED(sp)
  295. #endif
  296. *errorMessage = QString::fromLatin1("Unsupported debug mode");
  297. return 0;
  298. }
  299. bool isCdbEngineEnabled()
  300. {
  301. #ifdef Q_OS_WIN
  302. return CdbOptionsPage::instance() && CdbOptionsPage::instance()->options()->isValid();
  303. #else
  304. return false;
  305. #endif
  306. }
  307. static inline QString msgNoCdbBinaryForToolChain(const Abi &tc)
  308. {
  309. return CdbEngine::tr("There is no CDB binary available for binaries in format '%1'").arg(tc.toString());
  310. }
  311. static inline bool isMsvcFlavor(Abi::OSFlavor osf)
  312. {
  313. return osf == Abi::WindowsMsvc2005Flavor
  314. || osf == Abi::WindowsMsvc2008Flavor
  315. || osf == Abi::WindowsMsvc2010Flavor;
  316. }
  317. bool checkCdbConfiguration(const DebuggerStartParameters &sp, ConfigurationCheck *check)
  318. {
  319. #ifdef Q_OS_WIN
  320. const Abi abi = sp.toolChainAbi;
  321. if (!isCdbEngineEnabled()) {
  322. check->errorDetails.push_back(CdbEngine::tr("The CDB debug engine required for %1 is currently disabled.").
  323. arg(abi.toString()));
  324. check->settingsCategory = QLatin1String(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY);
  325. check->settingsPage = CdbOptionsPage::settingsId();
  326. return false;
  327. }
  328. if (!validMode(sp.startMode)) {
  329. check->errorDetails.push_back(CdbEngine::tr("The CDB engine does not support start mode %1.").arg(sp.startMode));
  330. return false;
  331. }
  332. if (abi.binaryFormat() != Abi::PEFormat || abi.os() != Abi::WindowsOS) {
  333. check->errorDetails.push_back(CdbEngine::tr("The CDB debug engine does not support the %1 ABI.").
  334. arg(abi.toString()));
  335. return false;
  336. }
  337. if (sp.startMode == AttachCore && !isMsvcFlavor(abi.osFlavor())) {
  338. check->errorDetails.push_back(CdbEngine::tr("The CDB debug engine cannot debug gdb core files."));
  339. return false;
  340. }
  341. if (sp.debuggerCommand.isEmpty()) {
  342. check->errorDetails.push_back(msgNoCdbBinaryForToolChain(abi));
  343. check->settingsCategory = QLatin1String(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY);
  344. check->settingsPage = QLatin1String(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY);
  345. return false;
  346. }
  347. return true;
  348. #else
  349. Q_UNUSED(sp);
  350. check->errorDetails.push_back(QString::fromLatin1("Unsupported debug mode"));
  351. return false;
  352. #endif
  353. }
  354. void addCdbOptionPages(QList<Core::IOptionsPage *> *opts)
  355. {
  356. #ifdef Q_OS_WIN
  357. opts->push_back(new CdbOptionsPage);
  358. #else
  359. Q_UNUSED(opts);
  360. #endif
  361. }
  362. #define QT_CREATOR_CDB_EXT "qtcreatorcdbext"
  363. static inline Utils::SavedAction *theAssemblerAction()
  364. {
  365. return debuggerCore()->action(OperateByInstruction);
  366. }
  367. CdbEngine::CdbEngine(const DebuggerStartParameters &sp,
  368. DebuggerEngine *masterEngine, const OptionsPtr &options) :
  369. DebuggerEngine(sp, CppLanguage, masterEngine),
  370. m_creatorExtPrefix("<qtcreatorcdbext>|"),
  371. m_tokenPrefix("<token>"),
  372. m_options(options),
  373. m_effectiveStartMode(NoStartMode),
  374. m_accessible(false),
  375. m_specialStopMode(NoSpecialStop),
  376. m_nextCommandToken(0),
  377. m_currentBuiltinCommandIndex(-1),
  378. m_extensionCommandPrefixBA("!" QT_CREATOR_CDB_EXT "."),
  379. m_operateByInstructionPending(true),
  380. m_operateByInstruction(true), // Default CDB setting
  381. m_notifyEngineShutdownOnTermination(false),
  382. m_hasDebuggee(false),
  383. m_elapsedLogTime(0),
  384. m_sourceStepInto(false),
  385. m_watchPointX(0),
  386. m_watchPointY(0),
  387. m_ignoreCdbOutput(false)
  388. {
  389. connect(theAssemblerAction(), SIGNAL(triggered(bool)), this, SLOT(operateByInstructionTriggered(bool)));
  390. setObjectName(QLatin1String("CdbEngine"));
  391. connect(&m_process, SIGNAL(finished(int)), this, SLOT(processFinished()));
  392. connect(&m_process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError()));
  393. connect(&m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOut()));
  394. connect(&m_process, SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardOut()));
  395. }
  396. void CdbEngine::init()
  397. {
  398. m_effectiveStartMode = NoStartMode;
  399. notifyInferiorPid(0);
  400. m_accessible = false;
  401. m_specialStopMode = NoSpecialStop;
  402. m_nextCommandToken = 0;
  403. m_currentBuiltinCommandIndex = -1;
  404. m_operateByInstructionPending = theAssemblerAction()->isChecked();
  405. m_operateByInstruction = true; // Default CDB setting
  406. m_notifyEngineShutdownOnTermination = false;
  407. m_hasDebuggee = false;
  408. m_sourceStepInto = false;
  409. m_watchPointX = m_watchPointY = 0;
  410. m_ignoreCdbOutput = false;
  411. m_outputBuffer.clear();
  412. m_builtinCommandQueue.clear();
  413. m_extensionCommandQueue.clear();
  414. m_extensionMessageBuffer.clear();
  415. m_pendingBreakpointMap.clear();
  416. m_customSpecialStopData.clear();
  417. m_symbolAddressCache.clear();
  418. m_coreStopReason.reset();
  419. // Create local list of mappings in native separators
  420. m_sourcePathMappings.clear();
  421. const QSharedPointer<GlobalDebuggerOptions> globalOptions = debuggerCore()->globalDebuggerOptions();
  422. if (!globalOptions->sourcePathMap.isEmpty()) {
  423. typedef GlobalDebuggerOptions::SourcePathMap::const_iterator SourcePathMapIterator;
  424. m_sourcePathMappings.reserve(globalOptions->sourcePathMap.size());
  425. const SourcePathMapIterator cend = globalOptions->sourcePathMap.constEnd();
  426. for (SourcePathMapIterator it = globalOptions->sourcePathMap.constBegin(); it != cend; ++it) {
  427. m_sourcePathMappings.push_back(SourcePathMapping(QDir::toNativeSeparators(it.key()),
  428. QDir::toNativeSeparators(it.value())));
  429. }
  430. }
  431. QTC_ASSERT(m_process.state() != QProcess::Running, Utils::SynchronousProcess::stopProcess(m_process));
  432. }
  433. CdbEngine::~CdbEngine()
  434. {
  435. }
  436. void CdbEngine::operateByInstructionTriggered(bool operateByInstruction)
  437. {
  438. // To be set next time session becomes accessible
  439. m_operateByInstructionPending = operateByInstruction;
  440. if (state() == InferiorStopOk)
  441. syncOperateByInstruction(operateByInstruction);
  442. }
  443. void CdbEngine::syncOperateByInstruction(bool operateByInstruction)
  444. {
  445. if (debug)
  446. qDebug("syncOperateByInstruction current: %d new %d", m_operateByInstruction, operateByInstruction);
  447. if (m_operateByInstruction == operateByInstruction)
  448. return;
  449. QTC_ASSERT(m_accessible, return);
  450. m_operateByInstruction = operateByInstruction;
  451. postCommand(m_operateByInstruction ? QByteArray("l-t") : QByteArray("l+t"), 0);
  452. postCommand(m_operateByInstruction ? QByteArray("l-s") : QByteArray("l+s"), 0);
  453. }
  454. bool CdbEngine::setToolTipExpression(const QPoint &mousePos,
  455. TextEditor::ITextEditor *editor,
  456. const DebuggerToolTipContext &contextIn)
  457. {
  458. if (debug)
  459. qDebug() << Q_FUNC_INFO;
  460. // Need a stopped debuggee and a cpp file in a valid frame
  461. if (state() != InferiorStopOk || !isCppEditor(editor) || stackHandler()->currentIndex() < 0)
  462. return false;
  463. // Determine expression and function
  464. int line;
  465. int column;
  466. DebuggerToolTipContext context = contextIn;
  467. QString exp = cppExpressionAt(editor, context.position, &line, &column, &context.function);
  468. // Are we in the current stack frame
  469. if (context.function.isEmpty() || exp.isEmpty() || context.function != stackHandler()->currentFrame().function)
  470. return false;
  471. // No numerical or any other expressions [yet]
  472. if (!(exp.at(0).isLetter() || exp.at(0) == QLatin1Char('_')))
  473. return false;
  474. // Can this be found as a local variable?
  475. const QByteArray localsPrefix(localsPrefixC);
  476. QByteArray iname = localsPrefix + exp.toAscii();
  477. if (!watchHandler()->hasItem(iname)) {
  478. // Nope, try a 'local.this.m_foo'.
  479. exp.prepend(QLatin1String("this."));
  480. iname.insert(localsPrefix.size(), "this.");
  481. if (!watchHandler()->hasItem(iname))
  482. return false;
  483. }
  484. DebuggerToolTipWidget *tw = new DebuggerToolTipWidget;
  485. tw->setContext(context);
  486. tw->setDebuggerModel(LocalsType);
  487. tw->setExpression(exp);
  488. tw->acquireEngine(this);
  489. DebuggerToolTipManager::instance()->showToolTip(mousePos, editor, tw);
  490. return true;
  491. }
  492. // Determine full path to the CDB extension library.
  493. QString CdbEngine::extensionLibraryName(bool is64Bit)
  494. {
  495. // Determine extension lib name and path to use
  496. QString rc;
  497. QTextStream(&rc) << QFileInfo(QCoreApplication::applicationDirPath()).path()
  498. << "/lib/" << (is64Bit ? QT_CREATOR_CDB_EXT "64" : QT_CREATOR_CDB_EXT "32")
  499. << '/' << QT_CREATOR_CDB_EXT << ".dll";
  500. return rc;
  501. }
  502. // Determine environment for CDB.exe, start out with run config and
  503. // add CDB extension path merged with system value should there be one.
  504. static QStringList mergeEnvironment(QStringList runConfigEnvironment,
  505. QString cdbExtensionPath)
  506. {
  507. // Determine CDB extension path from Qt Creator
  508. static const char cdbExtensionPathVariableC[] = "_NT_DEBUGGER_EXTENSION_PATH";
  509. const QByteArray oldCdbExtensionPath = qgetenv(cdbExtensionPathVariableC);
  510. if (!oldCdbExtensionPath.isEmpty()) {
  511. cdbExtensionPath.append(QLatin1Char(';'));
  512. cdbExtensionPath.append(QString::fromLocal8Bit(oldCdbExtensionPath));
  513. }
  514. // We do not assume someone sets _NT_DEBUGGER_EXTENSION_PATH in the run
  515. // config, just to make sure, delete any existing entries
  516. const QString cdbExtensionPathVariableAssign =
  517. QLatin1String(cdbExtensionPathVariableC) + QLatin1Char('=');
  518. for (QStringList::iterator it = runConfigEnvironment.begin(); it != runConfigEnvironment.end() ; ) {
  519. if (it->startsWith(cdbExtensionPathVariableAssign)) {
  520. it = runConfigEnvironment.erase(it);
  521. break;
  522. } else {
  523. ++it;
  524. }
  525. }
  526. runConfigEnvironment.append(cdbExtensionPathVariableAssign +
  527. QDir::toNativeSeparators(cdbExtensionPath));
  528. return runConfigEnvironment;
  529. }
  530. int CdbEngine::elapsedLogTime() const
  531. {
  532. const int elapsed = m_logTime.elapsed();
  533. const int delta = elapsed - m_elapsedLogTime;
  534. m_elapsedLogTime = elapsed;
  535. return delta;
  536. }
  537. // Start the console stub with the sub process. Continue in consoleStubProcessStarted.
  538. bool CdbEngine::startConsole(const DebuggerStartParameters &sp, QString *errorMessage)
  539. {
  540. if (debug)
  541. qDebug("startConsole %s", qPrintable(sp.executable));
  542. m_consoleStub.reset(new Utils::ConsoleProcess);
  543. m_consoleStub->setMode(Utils::ConsoleProcess::Suspend);
  544. connect(m_consoleStub.data(), SIGNAL(processError(QString)),
  545. SLOT(consoleStubError(QString)));
  546. connect(m_consoleStub.data(), SIGNAL(processStarted()),
  547. SLOT(consoleStubProcessStarted()));
  548. connect(m_consoleStub.data(), SIGNAL(wrapperStopped()),
  549. SLOT(consoleStubExited()));
  550. m_consoleStub->setWorkingDirectory(sp.workingDirectory);
  551. if (sp.environment.size())
  552. m_consoleStub->setEnvironment(sp.environment);
  553. if (!m_consoleStub->start(sp.executable, sp.processArgs)) {
  554. *errorMessage = tr("The console process '%1' could not be started.").arg(sp.executable);
  555. return false;
  556. }
  557. return true;
  558. }
  559. void CdbEngine::consoleStubError(const QString &msg)
  560. {
  561. if (debug)
  562. qDebug("consoleStubProcessMessage() in %s %s", stateName(state()), qPrintable(msg));
  563. if (state() == EngineSetupRequested) {
  564. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
  565. notifyEngineSetupFailed();
  566. } else {
  567. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineIll")
  568. notifyEngineIll();
  569. }
  570. nonModalMessageBox(QMessageBox::Critical, tr("Debugger Error"), msg);
  571. }
  572. void CdbEngine::consoleStubProcessStarted()
  573. {
  574. if (debug)
  575. qDebug("consoleStubProcessStarted() PID=%lld", m_consoleStub->applicationPID());
  576. // Attach to console process.
  577. DebuggerStartParameters attachParameters = startParameters();
  578. attachParameters.executable.clear();
  579. attachParameters.processArgs.clear();
  580. attachParameters.attachPID = m_consoleStub->applicationPID();
  581. attachParameters.startMode = AttachExternal;
  582. attachParameters.useTerminal = false;
  583. showMessage(QString::fromLatin1("Attaching to %1...").arg(attachParameters.attachPID), LogMisc);
  584. QString errorMessage;
  585. if (!launchCDB(attachParameters, &errorMessage)) {
  586. showMessage(errorMessage, LogError);
  587. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
  588. notifyEngineSetupFailed();
  589. }
  590. }
  591. void CdbEngine::consoleStubExited()
  592. {
  593. }
  594. void CdbEngine::setupEngine()
  595. {
  596. if (debug)
  597. qDebug(">setupEngine");
  598. // Nag to add symbol server
  599. if (CdbSymbolPathListEditor::promptToAddSymbolServer(CdbOptions::settingsGroup(),
  600. &(m_options->symbolPaths)))
  601. m_options->toSettings(Core::ICore::settings());
  602. init();
  603. if (!m_logTime.elapsed())
  604. m_logTime.start();
  605. QString errorMessage;
  606. // Console: Launch the stub with the suspended application and attach to it
  607. // CDB in theory has a command line option '-2' that launches a
  608. // console, too, but that immediately closes when the debuggee quits.
  609. // Use the Creator stub instead.
  610. const DebuggerStartParameters &sp = startParameters();
  611. const bool launchConsole = isCreatorConsole(sp, *m_options);
  612. m_effectiveStartMode = launchConsole ? AttachExternal : sp.startMode;
  613. const bool ok = launchConsole ?
  614. startConsole(startParameters(), &errorMessage) :
  615. launchCDB(startParameters(), &errorMessage);
  616. if (debug)
  617. qDebug("<setupEngine ok=%d", ok);
  618. if (!ok) {
  619. showMessage(errorMessage, LogError);
  620. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
  621. notifyEngineSetupFailed();
  622. }
  623. }
  624. bool CdbEngine::launchCDB(const DebuggerStartParameters &sp, QString *errorMessage)
  625. {
  626. if (debug)
  627. qDebug("launchCDB startMode=%d", sp.startMode);
  628. const QChar blank(QLatin1Char(' '));
  629. // Start engine which will run until initial breakpoint:
  630. // Determine binary (force MSVC), extension lib name and path to use
  631. // The extension is passed as relative name with the path variable set
  632. //(does not work with absolute path names)
  633. const QString executable = sp.debuggerCommand;
  634. if (executable.isEmpty()) {
  635. *errorMessage = tr("There is no CDB executable specified.");
  636. return false;
  637. }
  638. const bool is64bit =
  639. #ifdef Q_OS_WIN
  640. Utils::winIs64BitBinary(executable);
  641. #else
  642. false;
  643. #endif
  644. const QFileInfo extensionFi(CdbEngine::extensionLibraryName(is64bit));
  645. if (!extensionFi.isFile()) {
  646. *errorMessage = QString::fromLatin1("Internal error: The extension %1 cannot be found.").
  647. arg(QDir::toNativeSeparators(extensionFi.absoluteFilePath()));
  648. return false;
  649. }
  650. const QString extensionFileName = extensionFi.fileName();
  651. // Prepare arguments
  652. QStringList arguments;
  653. const bool isRemote = sp.startMode == AttachToRemoteServer;
  654. if (isRemote) { // Must be first
  655. arguments << QLatin1String("-remote") << sp.remoteChannel;
  656. } else {
  657. arguments << (QLatin1String("-a") + extensionFileName);
  658. }
  659. // Source line info/No terminal breakpoint / Pull extension
  660. arguments << QLatin1String("-lines") << QLatin1String("-G")
  661. // register idle (debuggee stop) notification
  662. << QLatin1String("-c")
  663. << QLatin1String(".idle_cmd ") + QString::fromLatin1(m_extensionCommandPrefixBA) + QLatin1String("idle");
  664. if (sp.useTerminal) // Separate console
  665. arguments << QLatin1String("-2");
  666. if (!m_options->symbolPaths.isEmpty())
  667. arguments << QLatin1String("-y") << m_options->symbolPaths.join(QString(QLatin1Char(';')));
  668. if (!m_options->sourcePaths.isEmpty())
  669. arguments << QLatin1String("-srcpath") << m_options->sourcePaths.join(QString(QLatin1Char(';')));
  670. // Compile argument string preserving quotes
  671. QString nativeArguments = m_options->additionalArguments;
  672. switch (sp.startMode) {
  673. case StartInternal:
  674. case StartExternal:
  675. if (!nativeArguments.isEmpty())
  676. nativeArguments.push_back(blank);
  677. nativeArguments += QDir::toNativeSeparators(sp.executable);
  678. break;
  679. case AttachToRemoteServer:
  680. break;
  681. case AttachExternal:
  682. case AttachCrashedExternal:
  683. arguments << QLatin1String("-p") << QString::number(sp.attachPID);
  684. if (sp.startMode == AttachCrashedExternal) {
  685. arguments << QLatin1String("-e") << sp.crashParameter << QLatin1String("-g");
  686. } else {
  687. if (isCreatorConsole(startParameters(), *m_options))
  688. arguments << QLatin1String("-pr") << QLatin1String("-pb");
  689. }
  690. break;
  691. case AttachCore:
  692. arguments << QLatin1String("-z") << sp.coreFile;
  693. break;
  694. default:
  695. *errorMessage = QString::fromLatin1("Internal error: Unsupported start mode %1.").arg(sp.startMode);
  696. return false;
  697. }
  698. if (!sp.processArgs.isEmpty()) { // Complete native argument string.
  699. if (!nativeArguments.isEmpty())
  700. nativeArguments.push_back(blank);
  701. nativeArguments += sp.processArgs;
  702. }
  703. const QString msg = QString::fromLatin1("Launching %1 %2\nusing %3 of %4.").
  704. arg(QDir::toNativeSeparators(executable),
  705. arguments.join(QString(blank)) + blank + nativeArguments,
  706. QDir::toNativeSeparators(extensionFi.absoluteFilePath()),
  707. extensionFi.lastModified().toString(Qt::SystemLocaleShortDate));
  708. showMessage(msg, LogMisc);
  709. m_outputBuffer.clear();
  710. const QStringList environment = sp.environment.size() == 0 ?
  711. QProcessEnvironment::systemEnvironment().toStringList() :
  712. sp.environment.toStringList();
  713. m_process.setEnvironment(mergeEnvironment(environment, extensionFi.absolutePath()));
  714. if (!sp.workingDirectory.isEmpty())
  715. m_process.setWorkingDirectory(sp.workingDirectory);
  716. #ifdef Q_OS_WIN
  717. if (!nativeArguments.isEmpty()) // Appends
  718. m_process.setNativeArguments(nativeArguments);
  719. #endif
  720. m_process.start(executable, arguments);
  721. if (!m_process.waitForStarted()) {
  722. *errorMessage = QString::fromLatin1("Internal error: Cannot start process %1: %2").
  723. arg(QDir::toNativeSeparators(executable), m_process.errorString());
  724. return false;
  725. }
  726. #ifdef Q_OS_WIN
  727. const unsigned long pid = Utils::winQPidToPid(m_process.pid());
  728. #else
  729. const unsigned long pid = 0;
  730. #endif
  731. showMessage(QString::fromLatin1("%1 running as %2").
  732. arg(QDir::toNativeSeparators(executable)).arg(pid), LogMisc);
  733. m_hasDebuggee = true;
  734. if (isRemote) { // We do not get an 'idle' in a remote session, but are accessible
  735. m_accessible = true;
  736. const QByteArray loadCommand = QByteArray(".load ")
  737. + extensionFileName.toLocal8Bit();
  738. postCommand(loadCommand, 0);
  739. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupOk")
  740. notifyEngineSetupOk();
  741. }
  742. return true;
  743. }
  744. void CdbEngine::setupInferior()
  745. {
  746. if (debug)
  747. qDebug("setupInferior");
  748. // QmlCppEngine expects the QML engine to be connected before any breakpoints are hit
  749. // (attemptBreakpointSynchronization() will be directly called then)
  750. attemptBreakpointSynchronization();
  751. if (startParameters().breakOnMain) {
  752. const BreakpointParameters bp(BreakpointAtMain);
  753. postCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings,
  754. BreakpointModelId(quint16(-1)), true), 0);
  755. }
  756. postCommand("sxn 0x4000001f", 0); // Do not break on WowX86 exceptions.
  757. postCommand(".asm source_line", 0); // Source line in assembly
  758. postExtensionCommand("pid", QByteArray(), 0, &CdbEngine::handlePid);
  759. }
  760. void CdbEngine::runEngine()
  761. {
  762. if (debug)
  763. qDebug("runEngine");
  764. foreach (const QString &breakEvent, m_options->breakEvents)
  765. postCommand(QByteArray("sxe ") + breakEvent.toAscii(), 0);
  766. if (startParameters().startMode == AttachCore) {
  767. QTC_ASSERT(!m_coreStopReason.isNull(), return; );
  768. notifyInferiorUnrunnable();
  769. processStop(*m_coreStopReason, false);
  770. } else {
  771. postCommand("g", 0);
  772. }
  773. }
  774. bool CdbEngine::commandsPending() const
  775. {
  776. return !m_builtinCommandQueue.isEmpty() || !m_extensionCommandQueue.isEmpty();
  777. }
  778. void CdbEngine::shutdownInferior()
  779. {
  780. if (debug)
  781. qDebug("CdbEngine::shutdownInferior in state '%s', process running %d", stateName(state()),
  782. isCdbProcessRunning());
  783. if (!isCdbProcessRunning()) { // Direct launch: Terminated with process.
  784. if (debug)
  785. qDebug("notifyInferiorShutdownOk");
  786. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
  787. notifyInferiorShutdownOk();
  788. return;
  789. }
  790. if (m_accessible) { // except console.
  791. if (startParameters().startMode == AttachExternal || startParameters().startMode == AttachCrashedExternal)
  792. detachDebugger();
  793. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
  794. notifyInferiorShutdownOk();
  795. } else {
  796. // A command got stuck.
  797. if (commandsPending()) {
  798. showMessage(QLatin1String("Cannot shut down inferior due to pending commands."), LogWarning);
  799. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownFailed")
  800. notifyInferiorShutdownFailed();
  801. return;
  802. }
  803. if (!canInterruptInferior()) {
  804. showMessage(QLatin1String("Cannot interrupt the inferior."), LogWarning);
  805. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownFailed")
  806. notifyInferiorShutdownFailed();
  807. return;
  808. }
  809. interruptInferior(); // Calls us again
  810. }
  811. }
  812. /* shutdownEngine/processFinished:
  813. * Note that in the case of launching a process by the debugger, the debugger
  814. * automatically quits a short time after reporting the session becoming
  815. * inaccessible without debuggee (notifyInferiorExited). In that case,
  816. * processFinished() must not report any arbitrarily notifyEngineShutdownOk()
  817. * as not to confuse the state engine.
  818. */
  819. void CdbEngine::shutdownEngine()
  820. {
  821. if (debug)
  822. qDebug("CdbEngine::shutdownEngine in state '%s', process running %d,"
  823. "accessible=%d,commands pending=%d",
  824. stateName(state()), isCdbProcessRunning(), m_accessible,
  825. commandsPending());
  826. if (!isCdbProcessRunning()) { // Direct launch: Terminated with process.
  827. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineShutdownOk")
  828. notifyEngineShutdownOk();
  829. return;
  830. }
  831. // No longer trigger anything from messages
  832. m_ignoreCdbOutput = true;
  833. // Go for kill if there are commands pending.
  834. if (m_accessible && !commandsPending()) {
  835. // detach (except console): Wait for debugger to finish.
  836. if (startParameters().startMode == AttachExternal || startParameters().startMode == AttachCrashedExternal)
  837. detachDebugger();
  838. // Remote requires a bit more force to quit.
  839. if (m_effectiveStartMode == AttachToRemoteServer) {
  840. postCommand(m_extensionCommandPrefixBA + "shutdownex", 0);
  841. postCommand("qq", 0);
  842. } else {
  843. postCommand("q", 0);
  844. }
  845. m_notifyEngineShutdownOnTermination = true;
  846. return;
  847. } else {
  848. // Remote process. No can do, currently
  849. m_notifyEngineShutdownOnTermination = true;
  850. Utils::SynchronousProcess::stopProcess(m_process);
  851. return;
  852. }
  853. // Lost debuggee, debugger should quit anytime now
  854. if (!m_hasDebuggee) {
  855. m_notifyEngineShutdownOnTermination = true;
  856. return;
  857. }
  858. interruptInferior();
  859. }
  860. void CdbEngine::processFinished()
  861. {
  862. if (debug)
  863. qDebug("CdbEngine::processFinished %dms '%s' notify=%d (exit state=%d, ex=%d)",
  864. elapsedLogTime(), stateName(state()), m_notifyEngineShutdownOnTermination,
  865. m_process.exitStatus(), m_process.exitCode());
  866. const bool crashed = m_process.exitStatus() == QProcess::CrashExit;
  867. if (crashed) {
  868. showMessage(tr("CDB crashed"), LogError); // not in your life.
  869. } else {
  870. showMessage(tr("CDB exited (%1)").arg(m_process.exitCode()), LogMisc);
  871. }
  872. if (m_notifyEngineShutdownOnTermination) {
  873. if (crashed) {
  874. if (debug)
  875. qDebug("notifyEngineIll");
  876. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineIll")
  877. notifyEngineIll();
  878. } else {
  879. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineShutdownOk")
  880. notifyEngineShutdownOk();
  881. }
  882. } else {
  883. // The QML/CPP engine relies on the standard sequence of InferiorShutDown,etc.
  884. // Otherwise, we take a shortcut.
  885. if (isSlaveEngine()) {
  886. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorExited")
  887. notifyInferiorExited();
  888. } else {
  889. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSpontaneousShutdown")
  890. notifyEngineSpontaneousShutdown();
  891. }
  892. }
  893. }
  894. void CdbEngine::detachDebugger()
  895. {
  896. postCommand(".detach", 0);
  897. }
  898. static inline bool isWatchIName(const QByteArray &iname)
  899. {
  900. return iname.startsWith("watch");
  901. }
  902. void CdbEngine::updateWatchData(const WatchData &dataIn,
  903. const WatchUpdateFlags & flags)
  904. {
  905. if (debug || debugLocals || debugWatches)
  906. qDebug("CdbEngine::updateWatchData() %dms accessible=%d %s incr=%d: %s",
  907. elapsedLogTime(), m_accessible, stateName(state()),
  908. flags.tryIncremental,
  909. qPrintable(dataIn.toString()));
  910. if (!m_accessible) // Add watch data while running?
  911. return;
  912. // New watch item?
  913. if (isWatchIName(dataIn.iname) && dataIn.isValueNeeded()) {
  914. QByteArray args;
  915. ByteArrayInputStream str(args);
  916. str << dataIn.iname << " \"" << dataIn.exp << '"';
  917. postExtensionCommand("addwatch", args, 0,
  918. &CdbEngine::handleAddWatch, 0,
  919. qVariantFromValue(dataIn));
  920. return;
  921. }
  922. if (!dataIn.hasChildren && !dataIn.isValueNeeded()) {
  923. WatchData data = dataIn;
  924. data.setAllUnneeded();
  925. watchHandler()->insertData(data);
  926. return;
  927. }
  928. updateLocalVariable(dataIn.iname);
  929. }
  930. void CdbEngine::handleAddWatch(const CdbExtensionCommandPtr &reply)
  931. {
  932. WatchData item = qvariant_cast<WatchData>(reply->cookie);
  933. if (debugWatches)
  934. qDebug() << "handleAddWatch ok=" << reply->success << item.iname;
  935. if (reply->success) {
  936. updateLocalVariable(item.iname);
  937. } else {
  938. item.setError(tr("Unable to add expression"));
  939. watchHandler()->insertIncompleteData(item);
  940. showMessage(QString::fromLatin1("Unable to add watch item '%1'/'%2': %3").
  941. arg(QString::fromLatin1(item.iname), QString::fromLatin1(item.exp),
  942. QString::fromLocal8Bit(reply->errorMessage)), LogError);
  943. }
  944. }
  945. void CdbEngine::addLocalsOptions(ByteArrayInputStream &str) const
  946. {
  947. if (debuggerCore()->boolSetting(VerboseLog))
  948. str << blankSeparator << "-v";
  949. if (debuggerCore()->boolSetting(UseDebuggingHelpers))
  950. str << blankSeparator << "-c";
  951. const QByteArray typeFormats = watchHandler()->typeFormatRequests();
  952. if (!typeFormats.isEmpty())
  953. str << blankSeparator << "-T " << typeFormats;
  954. const QByteArray individualFormats = watchHandler()->individualFormatRequests();
  955. if (!individualFormats.isEmpty())
  956. str << blankSeparator << "-I " << individualFormats;
  957. }
  958. void CdbEngine::updateLocalVariable(const QByteArray &iname)
  959. {
  960. const bool isWatch = isWatchIName(iname);
  961. if (debugWatches)
  962. qDebug() << "updateLocalVariable watch=" << isWatch << iname;
  963. QByteArray localsArguments;
  964. ByteArrayInputStream str(localsArguments);
  965. addLocalsOptions(str);
  966. if (!isWatch) {
  967. const int stackFrame = stackHandler()->currentIndex();
  968. if (stackFrame < 0) {
  969. qWarning("Internal error; no stack frame in updateLocalVariable");
  970. return;
  971. }
  972. str << blankSeparator << stackFrame;
  973. }
  974. str << blankSeparator << iname;
  975. postExtensionCommand(isWatch ? "watches" : "locals",
  976. localsArguments, 0,
  977. &CdbEngine::handleLocals,
  978. 0, QVariant(int(PartialLocalsUpdate)));
  979. }
  980. bool CdbEngine::hasCapability(unsigned cap) const
  981. {
  982. return cap & (DisassemblerCapability | RegisterCapability
  983. | ShowMemoryCapability
  984. |WatchpointByAddressCapability|JumpToLineCapability|AddWatcherCapability|WatchWidgetsCapability
  985. |ReloadModuleCapability
  986. |BreakOnThrowAndCatchCapability // Sort-of: Can break on throw().
  987. |BreakConditionCapability|TracePointCapability
  988. |BreakModuleCapability
  989. |OperateByInstructionCapability
  990. |RunToLineCapability
  991. |MemoryAddressCapability);
  992. }
  993. void CdbEngine::executeStep()
  994. {
  995. if (!m_operateByInstruction)
  996. m_sourceStepInto = true; // See explanation at handleStackTrace().
  997. postCommand(QByteArray("t"), 0); // Step into-> t (trace)
  998. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
  999. notifyInferiorRunRequested();
  1000. }
  1001. void CdbEngine::executeStepOut()
  1002. {
  1003. postCommand(QByteArray("gu"), 0); // Step out-> gu (go up)
  1004. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
  1005. notifyInferiorRunRequested();
  1006. }
  1007. void CdbEngine::executeNext()
  1008. {
  1009. postCommand(QByteArray("p"), 0); // Step over -> p
  1010. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
  1011. notifyInferiorRunRequested();
  1012. }
  1013. void CdbEngine::executeStepI()
  1014. {
  1015. executeStep();
  1016. }
  1017. void CdbEngine::executeNextI()
  1018. {
  1019. executeNext();
  1020. }
  1021. void CdbEngine::continueInferior()
  1022. {
  1023. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
  1024. notifyInferiorRunRequested();
  1025. doContinueInferior();
  1026. }
  1027. void CdbEngine::doContinueInferior()
  1028. {
  1029. postCommand(QByteArray("g"), 0);
  1030. }
  1031. bool CdbEngine::canInterruptInferior() const
  1032. {
  1033. return m_effectiveStartMode != AttachToRemoteServer && inferiorPid();
  1034. }
  1035. void CdbEngine::interruptInferior()
  1036. {
  1037. if (debug)
  1038. qDebug() << "CdbEngine::interruptInferior()" << stateName(state());
  1039. bool ok = false;
  1040. if (!canInterruptInferior()) {
  1041. showMessage(tr("Interrupting is not possible in remote sessions."), LogError);
  1042. } else {
  1043. ok = doInterruptInferior(NoSpecialStop);
  1044. }
  1045. // Restore running state if stop failed.
  1046. if (!ok) {
  1047. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorStopOk")
  1048. notifyInferiorStopOk();
  1049. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
  1050. notifyInferiorRunRequested();
  1051. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunOk")
  1052. notifyInferiorRunOk();
  1053. }
  1054. }
  1055. void CdbEngine::doInterruptInferiorCustomSpecialStop(const QVariant &v)
  1056. {
  1057. if (m_specialStopMode == NoSpecialStop)
  1058. doInterruptInferior(CustomSpecialStop);
  1059. m_customSpecialStopData.push_back(v);
  1060. }
  1061. bool CdbEngine::doInterruptInferior(SpecialStopMode sm)
  1062. {
  1063. const SpecialStopMode oldSpecialMode = m_specialStopMode;
  1064. m_specialStopMode = sm;
  1065. showMessage(QString::fromLatin1("Interrupting process %1...").arg(inferiorPid()), LogMisc);
  1066. QString errorMessage;
  1067. const bool ok = interruptProcess(inferiorPid(), CdbEngineType, &errorMessage);
  1068. if (!ok) {
  1069. m_specialStopMode = oldSpecialMode;
  1070. showMessage(errorMessage, LogError);
  1071. }
  1072. return ok;
  1073. }
  1074. void CdbEngine::executeRunToLine(const ContextData &data)
  1075. {
  1076. // Add one-shot breakpoint
  1077. BreakpointParameters bp;
  1078. if (data.address) {
  1079. bp.type =BreakpointByAddress;
  1080. bp.address = data.address;
  1081. } else {
  1082. bp.type =BreakpointByFileAndLine;
  1083. bp.fileName = data.fileName;
  1084. bp.lineNumber = data.lineNumber;
  1085. }
  1086. postCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings, BreakpointModelId(quint16(-1)), true), 0);
  1087. continueInferior();
  1088. }
  1089. void CdbEngine::executeRunToFunction(const QString &functionName)
  1090. {
  1091. // Add one-shot breakpoint
  1092. BreakpointParameters bp(BreakpointByFunction);
  1093. bp.functionName = functionName;
  1094. postCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings, BreakpointModelId(quint16(-1)), true), 0);
  1095. continueInferior();
  1096. }
  1097. void CdbEngine::setRegisterValue(int regnr, const QString &value)
  1098. {
  1099. const Registers registers = registerHandler()->registers();
  1100. QTC_ASSERT(regnr < registers.size(), return);
  1101. // Value is decimal or 0x-hex-prefixed
  1102. QByteArray cmd;
  1103. ByteArrayInputStream str(cmd);
  1104. str << "r " << registers.at(regnr).name << '=' << value;
  1105. postCommand(cmd, 0);
  1106. reloadRegisters();
  1107. }
  1108. void CdbEngine::executeJumpToLine(const ContextData &data)
  1109. {
  1110. if (data.address) {
  1111. // Goto address directly.
  1112. jumpToAddress(data.address);
  1113. gotoLocation(Location(data.address));
  1114. } else {
  1115. // Jump to source line: Resolve source line address and go to that location
  1116. QByteArray cmd;
  1117. ByteArrayInputStream str(cmd);
  1118. str << "? `" << QDir::toNativeSeparators(data.fileName) << ':' << data.lineNumber << '`';
  1119. const QVariant cookie = qVariantFromValue(data);
  1120. postBuiltinCommand(cmd, 0, &CdbEngine::handleJumpToLineAddressResolution, 0, cookie);
  1121. }
  1122. }
  1123. void CdbEngine::jumpToAddress(quint64 address)
  1124. {
  1125. // Fake a jump to address by setting the PC register.
  1126. QByteArray registerCmd;
  1127. ByteArrayInputStream str(registerCmd);
  1128. // PC-register depending on 64/32bit.
  1129. str << "r " << (startParameters().toolChainAbi.wordWidth() == 64 ? "rip" : "eip") << '=';
  1130. str.setHexPrefix(true);
  1131. str.setIntegerBase(16);
  1132. str << address;
  1133. postCommand(registerCmd, 0);
  1134. }
  1135. void CdbEngine::handleJumpToLineAddressResolution(const CdbBuiltinCommandPtr &cmd)
  1136. {
  1137. if (cmd->reply.isEmpty())
  1138. return;
  1139. // Evaluate expression: 5365511549 = 00000001`3fcf357d
  1140. // Set register 'rip' to hex address and goto lcoation
  1141. QByteArray answer = cmd->reply.front().trimmed();
  1142. const int equalPos = answer.indexOf(" = ");
  1143. if (equalPos == -1)
  1144. return;
  1145. answer.remove(0, equalPos + 3);
  1146. const int apPos = answer.indexOf('`');
  1147. if (apPos != -1)
  1148. answer.remove(apPos, 1);
  1149. bool ok;
  1150. const quint64 address = answer.toLongLong(&ok, 16);
  1151. if (ok && address) {
  1152. QTC_ASSERT(qVariantCanConvert<ContextData>(cmd->cookie), return);
  1153. const ContextData cookie = qvariant_cast<ContextData>(cmd->cookie);
  1154. jumpToAddress(address);
  1155. gotoLocation(Location(cookie.fileName, cookie.lineNumber));
  1156. }
  1157. }
  1158. static inline bool isAsciiWord(const QString &s)
  1159. {
  1160. foreach (const QChar &c, s) {
  1161. if (!c.isLetterOrNumber() || c.toAscii() == 0)
  1162. return false;
  1163. }
  1164. return true;
  1165. }
  1166. void CdbEngine::assignValueInDebugger(const WatchData *w, const QString &expr, const QVariant &value)
  1167. {
  1168. if (debug)
  1169. qDebug() << "CdbEngine::assignValueInDebugger" << w->iname << expr << value;
  1170. if (state() != InferiorStopOk || stackHandler()->currentIndex() < 0) {
  1171. qWarning("Internal error: assignValueInDebugger: Invalid state or no stack frame.");
  1172. return;
  1173. }
  1174. QByteArray cmd;
  1175. ByteArrayInputStream str(cmd);
  1176. switch (value.type()) {
  1177. case QVariant::String: {
  1178. // Convert qstring to Utf16 data not considering endianness for Windows.
  1179. const QString s = value.toString();
  1180. if (isAsciiWord(s)) {
  1181. str << m_extensionCommandPrefixBA << "assign \"" << w->iname << '='
  1182. << s.toLatin1() << '"';
  1183. } else {
  1184. const QByteArray utf16(reinterpret_cast<const char *>(s.utf16()), 2 * s.size());
  1185. str << m_extensionCommandPrefixBA << "assign -u " << w->iname << '='
  1186. << utf16.toHex();
  1187. }
  1188. }
  1189. break;
  1190. default:
  1191. str << m_extensionCommandPrefixBA << "assign " << w->iname << '='
  1192. << value.toString();
  1193. break;
  1194. }
  1195. postCommand(cmd, 0);
  1196. // Update all locals in case we change a union or something pointed to
  1197. // that affects other variables, too.
  1198. updateLocals();
  1199. }
  1200. void CdbEngine::parseThreads(const GdbMi &data, int forceCurrentThreadId /* = -1 */)
  1201. {
  1202. int currentThreadId;
  1203. Threads threads = ThreadsHandler::parseGdbmiThreads(data, &currentThreadId);
  1204. threadsHandler()->setThreads(threads);
  1205. threadsHandler()->setCurrentThreadId(forceCurrentThreadId >= 0 ?
  1206. forceCurrentThreadId : currentThreadId);
  1207. }
  1208. void CdbEngine::handleThreads(const CdbExtensionCommandPtr &reply)
  1209. {
  1210. if (debug)
  1211. qDebug("CdbEngine::handleThreads success=%d", reply->success);
  1212. if (reply->success) {
  1213. GdbMi data;
  1214. data.fromString(reply->reply);
  1215. parseThreads(data);
  1216. // Continue sequence
  1217. postCommandSequence(reply->commandSequence);
  1218. } else {
  1219. showMessage(QString::fromLatin1(reply->errorMessage), LogError);
  1220. }
  1221. }
  1222. void CdbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages languages)
  1223. {
  1224. if (languages & CppLanguage)
  1225. postCommand(command.toLocal8Bit(), QuietCommand);
  1226. }
  1227. // Post command without callback
  1228. void CdbEngine::postCommand(const QByteArray &cmd, unsigned flags)
  1229. {
  1230. if (debug)
  1231. qDebug("CdbEngine::postCommand %dms '%s' %u %s\n",
  1232. elapsedLogTime(), cmd.constData(), flags, stateName(state()));
  1233. if (!(flags & QuietCommand))
  1234. showMessage(QString::fromLocal8Bit(cmd), LogInput);
  1235. m_process.write(cmd + '\n');
  1236. }
  1237. // Post a built-in-command producing free-format output with a callback.
  1238. // In order to catch the output, it is enclosed in 'echo' commands
  1239. // printing a specially formatted token to be identifiable in the output.
  1240. void CdbEngine::postBuiltinCommand(const QByteArray &cmd, unsigned flags,
  1241. BuiltinCommandHandler handler,
  1242. unsigned nextCommandFlag,
  1243. const QVariant &cookie)
  1244. {
  1245. if (!m_accessible) {
  1246. const QString msg = QString::fromLatin1("Attempt to issue builtin command '%1' to non-accessible session (%2)")
  1247. .arg(QString::fromLocal8Bit(cmd), QString::fromLatin1(stateName(state())));
  1248. showMessage(msg, LogError);
  1249. return;
  1250. }
  1251. if (!flags & QuietCommand)
  1252. showMessage(QString::fromLocal8Bit(cmd), LogInput);
  1253. const int token = m_nextCommandToken++;
  1254. CdbBuiltinCommandPtr pendingCommand(new CdbBuiltinCommand(cmd, token, flags, handler, nextCommandFlag, co

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