PageRenderTime 64ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

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

https://bitbucket.org/kyanha/qt-creator
C++ | 3132 lines | 2653 code | 203 blank | 276 comment | 464 complexity | e07a8c59db8e025772f646a7c0206d3e MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1

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

  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 "cdbengine.h"
  30. #include "breakhandler.h"
  31. #include "breakpoint.h"
  32. #include "bytearrayinputstream.h"
  33. #include "cdboptions.h"
  34. #include "cdboptionspage.h"
  35. #include "cdbparsehelpers.h"
  36. #include "debuggeractions.h"
  37. #include "debuggercore.h"
  38. #include "debuggerinternalconstants.h"
  39. #include "debuggerrunner.h"
  40. #include "debuggerstartparameters.h"
  41. #include "debuggertooltipmanager.h"
  42. #include "disassembleragent.h"
  43. #include "disassemblerlines.h"
  44. #include "memoryagent.h"
  45. #include "moduleshandler.h"
  46. #include "registerhandler.h"
  47. #include "stackframe.h"
  48. #include "stackhandler.h"
  49. #include "threadshandler.h"
  50. #include "watchhandler.h"
  51. #include "watchutils.h"
  52. #include "gdb/gdbmi.h"
  53. #include "shared/cdbsymbolpathlisteditor.h"
  54. #include "shared/hostutils.h"
  55. #include "procinterrupt.h"
  56. #include <TranslationUnit.h>
  57. #include <coreplugin/icore.h>
  58. #include <texteditor/itexteditor.h>
  59. #include <projectexplorer/abi.h>
  60. #include <projectexplorer/projectexplorerconstants.h>
  61. #include <projectexplorer/task.h>
  62. #include <projectexplorer/taskhub.h>
  63. #include <utils/synchronousprocess.h>
  64. #include <utils/qtcprocess.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, QString *errorMessage)
  283. {
  284. #ifdef Q_OS_WIN
  285. CdbOptionsPage *op = CdbOptionsPage::instance();
  286. if (!op || !op->options()->isValid() || !validMode(sp.startMode)) {
  287. *errorMessage = QLatin1String("Internal error: Invalid start parameters passed for thre CDB engine.");
  288. return 0;
  289. }
  290. return new CdbEngine(sp, op->options());
  291. #else
  292. Q_UNUSED(sp)
  293. #endif
  294. *errorMessage = QString::fromLatin1("Unsupported debug mode");
  295. return 0;
  296. }
  297. void addCdbOptionPages(QList<Core::IOptionsPage *> *opts)
  298. {
  299. #ifdef Q_OS_WIN
  300. opts->push_back(new CdbOptionsPage);
  301. #else
  302. Q_UNUSED(opts);
  303. #endif
  304. }
  305. #define QT_CREATOR_CDB_EXT "qtcreatorcdbext"
  306. static inline Utils::SavedAction *theAssemblerAction()
  307. {
  308. return debuggerCore()->action(OperateByInstruction);
  309. }
  310. CdbEngine::CdbEngine(const DebuggerStartParameters &sp, const OptionsPtr &options) :
  311. DebuggerEngine(sp),
  312. m_creatorExtPrefix("<qtcreatorcdbext>|"),
  313. m_tokenPrefix("<token>"),
  314. m_options(options),
  315. m_effectiveStartMode(NoStartMode),
  316. m_accessible(false),
  317. m_specialStopMode(NoSpecialStop),
  318. m_nextCommandToken(0),
  319. m_currentBuiltinCommandIndex(-1),
  320. m_extensionCommandPrefixBA("!" QT_CREATOR_CDB_EXT "."),
  321. m_operateByInstructionPending(true),
  322. m_operateByInstruction(true), // Default CDB setting
  323. m_notifyEngineShutdownOnTermination(false),
  324. m_hasDebuggee(false),
  325. m_cdbIs64Bit(false),
  326. m_elapsedLogTime(0),
  327. m_sourceStepInto(false),
  328. m_watchPointX(0),
  329. m_watchPointY(0),
  330. m_ignoreCdbOutput(false)
  331. {
  332. connect(theAssemblerAction(), SIGNAL(triggered(bool)), this, SLOT(operateByInstructionTriggered(bool)));
  333. setObjectName(QLatin1String("CdbEngine"));
  334. connect(&m_process, SIGNAL(finished(int)), this, SLOT(processFinished()));
  335. connect(&m_process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError()));
  336. connect(&m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOut()));
  337. connect(&m_process, SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardOut()));
  338. }
  339. void CdbEngine::init()
  340. {
  341. m_effectiveStartMode = NoStartMode;
  342. notifyInferiorPid(0);
  343. m_accessible = false;
  344. m_specialStopMode = NoSpecialStop;
  345. m_nextCommandToken = 0;
  346. m_currentBuiltinCommandIndex = -1;
  347. m_operateByInstructionPending = theAssemblerAction()->isChecked();
  348. m_operateByInstruction = true; // Default CDB setting
  349. m_notifyEngineShutdownOnTermination = false;
  350. m_hasDebuggee = false;
  351. m_sourceStepInto = false;
  352. m_watchPointX = m_watchPointY = 0;
  353. m_ignoreCdbOutput = false;
  354. m_watchInameToName.clear();
  355. m_outputBuffer.clear();
  356. m_builtinCommandQueue.clear();
  357. m_extensionCommandQueue.clear();
  358. m_extensionMessageBuffer.clear();
  359. m_pendingBreakpointMap.clear();
  360. m_customSpecialStopData.clear();
  361. m_symbolAddressCache.clear();
  362. m_coreStopReason.reset();
  363. // Create local list of mappings in native separators
  364. m_sourcePathMappings.clear();
  365. const QSharedPointer<GlobalDebuggerOptions> globalOptions = debuggerCore()->globalDebuggerOptions();
  366. if (!globalOptions->sourcePathMap.isEmpty()) {
  367. typedef GlobalDebuggerOptions::SourcePathMap::const_iterator SourcePathMapIterator;
  368. m_sourcePathMappings.reserve(globalOptions->sourcePathMap.size());
  369. const SourcePathMapIterator cend = globalOptions->sourcePathMap.constEnd();
  370. for (SourcePathMapIterator it = globalOptions->sourcePathMap.constBegin(); it != cend; ++it) {
  371. m_sourcePathMappings.push_back(SourcePathMapping(QDir::toNativeSeparators(it.key()),
  372. QDir::toNativeSeparators(it.value())));
  373. }
  374. }
  375. QTC_ASSERT(m_process.state() != QProcess::Running, Utils::SynchronousProcess::stopProcess(m_process));
  376. }
  377. CdbEngine::~CdbEngine()
  378. {
  379. }
  380. void CdbEngine::operateByInstructionTriggered(bool operateByInstruction)
  381. {
  382. // To be set next time session becomes accessible
  383. m_operateByInstructionPending = operateByInstruction;
  384. if (state() == InferiorStopOk)
  385. syncOperateByInstruction(operateByInstruction);
  386. }
  387. void CdbEngine::syncOperateByInstruction(bool operateByInstruction)
  388. {
  389. if (debug)
  390. qDebug("syncOperateByInstruction current: %d new %d", m_operateByInstruction, operateByInstruction);
  391. if (m_operateByInstruction == operateByInstruction)
  392. return;
  393. QTC_ASSERT(m_accessible, return);
  394. m_operateByInstruction = operateByInstruction;
  395. postCommand(m_operateByInstruction ? QByteArray("l-t") : QByteArray("l+t"), 0);
  396. postCommand(m_operateByInstruction ? QByteArray("l-s") : QByteArray("l+s"), 0);
  397. }
  398. bool CdbEngine::setToolTipExpression(const QPoint &mousePos,
  399. TextEditor::ITextEditor *editor,
  400. const DebuggerToolTipContext &contextIn)
  401. {
  402. if (debug)
  403. qDebug() << Q_FUNC_INFO;
  404. // Need a stopped debuggee and a cpp file in a valid frame
  405. if (state() != InferiorStopOk || !isCppEditor(editor) || stackHandler()->currentIndex() < 0)
  406. return false;
  407. // Determine expression and function
  408. int line;
  409. int column;
  410. DebuggerToolTipContext context = contextIn;
  411. QString exp = fixCppExpression(cppExpressionAt(editor, context.position, &line, &column, &context.function));
  412. // Are we in the current stack frame
  413. if (context.function.isEmpty() || exp.isEmpty() || context.function != stackHandler()->currentFrame().function)
  414. return false;
  415. // Show tooltips of local variables only. Anything else can slow debugging down.
  416. const WatchData *localVariable = watchHandler()->findCppLocalVariable(exp);
  417. if (!localVariable)
  418. return false;
  419. DebuggerToolTipWidget *tw = new DebuggerToolTipWidget;
  420. tw->setContext(context);
  421. tw->setIname(localVariable->iname);
  422. tw->acquireEngine(this);
  423. DebuggerToolTipManager::instance()->showToolTip(mousePos, editor, tw);
  424. return true;
  425. }
  426. // Determine full path to the CDB extension library.
  427. QString CdbEngine::extensionLibraryName(bool is64Bit)
  428. {
  429. // Determine extension lib name and path to use
  430. QString rc;
  431. QTextStream(&rc) << QFileInfo(QCoreApplication::applicationDirPath()).path()
  432. << "/lib/" << (is64Bit ? QT_CREATOR_CDB_EXT "64" : QT_CREATOR_CDB_EXT "32")
  433. << '/' << QT_CREATOR_CDB_EXT << ".dll";
  434. return rc;
  435. }
  436. // Determine environment for CDB.exe, start out with run config and
  437. // add CDB extension path merged with system value should there be one.
  438. static QStringList mergeEnvironment(QStringList runConfigEnvironment,
  439. QString cdbExtensionPath)
  440. {
  441. // Determine CDB extension path from Qt Creator
  442. static const char cdbExtensionPathVariableC[] = "_NT_DEBUGGER_EXTENSION_PATH";
  443. const QByteArray oldCdbExtensionPath = qgetenv(cdbExtensionPathVariableC);
  444. if (!oldCdbExtensionPath.isEmpty()) {
  445. cdbExtensionPath.append(QLatin1Char(';'));
  446. cdbExtensionPath.append(QString::fromLocal8Bit(oldCdbExtensionPath));
  447. }
  448. // We do not assume someone sets _NT_DEBUGGER_EXTENSION_PATH in the run
  449. // config, just to make sure, delete any existing entries
  450. const QString cdbExtensionPathVariableAssign =
  451. QLatin1String(cdbExtensionPathVariableC) + QLatin1Char('=');
  452. for (QStringList::iterator it = runConfigEnvironment.begin(); it != runConfigEnvironment.end() ; ) {
  453. if (it->startsWith(cdbExtensionPathVariableAssign)) {
  454. it = runConfigEnvironment.erase(it);
  455. break;
  456. } else {
  457. ++it;
  458. }
  459. }
  460. runConfigEnvironment.append(cdbExtensionPathVariableAssign +
  461. QDir::toNativeSeparators(cdbExtensionPath));
  462. return runConfigEnvironment;
  463. }
  464. int CdbEngine::elapsedLogTime() const
  465. {
  466. const int elapsed = m_logTime.elapsed();
  467. const int delta = elapsed - m_elapsedLogTime;
  468. m_elapsedLogTime = elapsed;
  469. return delta;
  470. }
  471. // Start the console stub with the sub process. Continue in consoleStubProcessStarted.
  472. bool CdbEngine::startConsole(const DebuggerStartParameters &sp, QString *errorMessage)
  473. {
  474. if (debug)
  475. qDebug("startConsole %s", qPrintable(sp.executable));
  476. m_consoleStub.reset(new Utils::ConsoleProcess);
  477. m_consoleStub->setMode(Utils::ConsoleProcess::Suspend);
  478. connect(m_consoleStub.data(), SIGNAL(processError(QString)),
  479. SLOT(consoleStubError(QString)));
  480. connect(m_consoleStub.data(), SIGNAL(processStarted()),
  481. SLOT(consoleStubProcessStarted()));
  482. connect(m_consoleStub.data(), SIGNAL(wrapperStopped()),
  483. SLOT(consoleStubExited()));
  484. m_consoleStub->setWorkingDirectory(sp.workingDirectory);
  485. if (sp.environment.size())
  486. m_consoleStub->setEnvironment(sp.environment);
  487. if (!m_consoleStub->start(sp.executable, sp.processArgs)) {
  488. *errorMessage = tr("The console process '%1' could not be started.").arg(sp.executable);
  489. return false;
  490. }
  491. return true;
  492. }
  493. void CdbEngine::consoleStubError(const QString &msg)
  494. {
  495. if (debug)
  496. qDebug("consoleStubProcessMessage() in %s %s", stateName(state()), qPrintable(msg));
  497. if (state() == EngineSetupRequested) {
  498. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
  499. notifyEngineSetupFailed();
  500. } else {
  501. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineIll")
  502. notifyEngineIll();
  503. }
  504. nonModalMessageBox(QMessageBox::Critical, tr("Debugger Error"), msg);
  505. }
  506. void CdbEngine::consoleStubProcessStarted()
  507. {
  508. if (debug)
  509. qDebug("consoleStubProcessStarted() PID=%lld", m_consoleStub->applicationPID());
  510. // Attach to console process.
  511. DebuggerStartParameters attachParameters = startParameters();
  512. attachParameters.executable.clear();
  513. attachParameters.processArgs.clear();
  514. attachParameters.attachPID = m_consoleStub->applicationPID();
  515. attachParameters.startMode = AttachExternal;
  516. attachParameters.useTerminal = false;
  517. showMessage(QString::fromLatin1("Attaching to %1...").arg(attachParameters.attachPID), LogMisc);
  518. QString errorMessage;
  519. if (!launchCDB(attachParameters, &errorMessage)) {
  520. showMessage(errorMessage, LogError);
  521. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
  522. notifyEngineSetupFailed();
  523. }
  524. }
  525. void CdbEngine::consoleStubExited()
  526. {
  527. }
  528. void CdbEngine::setupEngine()
  529. {
  530. if (debug)
  531. qDebug(">setupEngine");
  532. // Nag to add symbol server
  533. if (CdbSymbolPathListEditor::promptToAddSymbolServer(CdbOptions::settingsGroup(),
  534. &(m_options->symbolPaths)))
  535. m_options->toSettings(Core::ICore::settings());
  536. init();
  537. if (!m_logTime.elapsed())
  538. m_logTime.start();
  539. QString errorMessage;
  540. // Console: Launch the stub with the suspended application and attach to it
  541. // CDB in theory has a command line option '-2' that launches a
  542. // console, too, but that immediately closes when the debuggee quits.
  543. // Use the Creator stub instead.
  544. const DebuggerStartParameters &sp = startParameters();
  545. const bool launchConsole = isCreatorConsole(sp, *m_options);
  546. m_effectiveStartMode = launchConsole ? AttachExternal : sp.startMode;
  547. const bool ok = launchConsole ?
  548. startConsole(startParameters(), &errorMessage) :
  549. launchCDB(startParameters(), &errorMessage);
  550. if (debug)
  551. qDebug("<setupEngine ok=%d", ok);
  552. if (!ok) {
  553. showMessage(errorMessage, LogError);
  554. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
  555. notifyEngineSetupFailed();
  556. }
  557. const QString normalFormat = tr("Normal");
  558. const QStringList stringFormats = QStringList()
  559. << normalFormat << tr("Separate Window");
  560. WatchHandler *wh = watchHandler();
  561. wh->addTypeFormats("QString", stringFormats);
  562. wh->addTypeFormats("QString *", stringFormats);
  563. wh->addTypeFormats("QByteArray", stringFormats);
  564. wh->addTypeFormats("QByteArray *", stringFormats);
  565. wh->addTypeFormats("std__basic_string", stringFormats); // Python dumper naming convention for std::[w]string
  566. const QStringList imageFormats = QStringList()
  567. << normalFormat << tr("Image");
  568. wh->addTypeFormats("QImage", imageFormats);
  569. wh->addTypeFormats("QImage *", imageFormats);
  570. }
  571. bool CdbEngine::launchCDB(const DebuggerStartParameters &sp, QString *errorMessage)
  572. {
  573. if (debug)
  574. qDebug("launchCDB startMode=%d", sp.startMode);
  575. const QChar blank(QLatin1Char(' '));
  576. // Start engine which will run until initial breakpoint:
  577. // Determine binary (force MSVC), extension lib name and path to use
  578. // The extension is passed as relative name with the path variable set
  579. //(does not work with absolute path names)
  580. const QString executable = sp.debuggerCommand;
  581. if (executable.isEmpty()) {
  582. *errorMessage = tr("There is no CDB executable specified.");
  583. return false;
  584. }
  585. m_cdbIs64Bit =
  586. #ifdef Q_OS_WIN
  587. Utils::winIs64BitBinary(executable);
  588. #else
  589. false;
  590. #endif
  591. const QFileInfo extensionFi(CdbEngine::extensionLibraryName(m_cdbIs64Bit));
  592. if (!extensionFi.isFile()) {
  593. *errorMessage = QString::fromLatin1("Internal error: The extension %1 cannot be found.").
  594. arg(QDir::toNativeSeparators(extensionFi.absoluteFilePath()));
  595. return false;
  596. }
  597. const QString extensionFileName = extensionFi.fileName();
  598. // Prepare arguments
  599. QStringList arguments;
  600. const bool isRemote = sp.startMode == AttachToRemoteServer;
  601. if (isRemote) { // Must be first
  602. arguments << QLatin1String("-remote") << sp.remoteChannel;
  603. } else {
  604. arguments << (QLatin1String("-a") + extensionFileName);
  605. }
  606. // Source line info/No terminal breakpoint / Pull extension
  607. arguments << QLatin1String("-lines") << QLatin1String("-G")
  608. // register idle (debuggee stop) notification
  609. << QLatin1String("-c")
  610. << QLatin1String(".idle_cmd ") + QString::fromLatin1(m_extensionCommandPrefixBA) + QLatin1String("idle");
  611. if (sp.useTerminal) // Separate console
  612. arguments << QLatin1String("-2");
  613. if (m_options->ignoreFirstChanceAccessViolation)
  614. arguments << QLatin1String("-x");
  615. if (!m_options->symbolPaths.isEmpty())
  616. arguments << QLatin1String("-y") << m_options->symbolPaths.join(QString(QLatin1Char(';')));
  617. if (!m_options->sourcePaths.isEmpty())
  618. arguments << QLatin1String("-srcpath") << m_options->sourcePaths.join(QString(QLatin1Char(';')));
  619. // Compile argument string preserving quotes
  620. QString nativeArguments = m_options->additionalArguments;
  621. switch (sp.startMode) {
  622. case StartInternal:
  623. case StartExternal:
  624. if (!nativeArguments.isEmpty())
  625. nativeArguments.push_back(blank);
  626. Utils::QtcProcess::addArgs(&nativeArguments,
  627. QStringList(QDir::toNativeSeparators(sp.executable)));
  628. break;
  629. case AttachToRemoteServer:
  630. break;
  631. case AttachExternal:
  632. case AttachCrashedExternal:
  633. arguments << QLatin1String("-p") << QString::number(sp.attachPID);
  634. if (sp.startMode == AttachCrashedExternal) {
  635. arguments << QLatin1String("-e") << sp.crashParameter << QLatin1String("-g");
  636. } else {
  637. if (isCreatorConsole(startParameters(), *m_options))
  638. arguments << QLatin1String("-pr") << QLatin1String("-pb");
  639. }
  640. break;
  641. case AttachCore:
  642. arguments << QLatin1String("-z") << sp.coreFile;
  643. break;
  644. default:
  645. *errorMessage = QString::fromLatin1("Internal error: Unsupported start mode %1.").arg(sp.startMode);
  646. return false;
  647. }
  648. if (!sp.processArgs.isEmpty()) { // Complete native argument string.
  649. if (!nativeArguments.isEmpty())
  650. nativeArguments.push_back(blank);
  651. nativeArguments += sp.processArgs;
  652. }
  653. const QString msg = QString::fromLatin1("Launching %1 %2\nusing %3 of %4.").
  654. arg(QDir::toNativeSeparators(executable),
  655. arguments.join(QString(blank)) + blank + nativeArguments,
  656. QDir::toNativeSeparators(extensionFi.absoluteFilePath()),
  657. extensionFi.lastModified().toString(Qt::SystemLocaleShortDate));
  658. showMessage(msg, LogMisc);
  659. m_outputBuffer.clear();
  660. const QStringList environment = sp.environment.size() == 0 ?
  661. QProcessEnvironment::systemEnvironment().toStringList() :
  662. sp.environment.toStringList();
  663. m_process.setEnvironment(mergeEnvironment(environment, extensionFi.absolutePath()));
  664. if (!sp.workingDirectory.isEmpty())
  665. m_process.setWorkingDirectory(sp.workingDirectory);
  666. #ifdef Q_OS_WIN
  667. if (!nativeArguments.isEmpty()) // Appends
  668. m_process.setNativeArguments(nativeArguments);
  669. #endif
  670. m_process.start(executable, arguments);
  671. if (!m_process.waitForStarted()) {
  672. *errorMessage = QString::fromLatin1("Internal error: Cannot start process %1: %2").
  673. arg(QDir::toNativeSeparators(executable), m_process.errorString());
  674. return false;
  675. }
  676. #ifdef Q_OS_WIN
  677. const unsigned long pid = Utils::winQPidToPid(m_process.pid());
  678. #else
  679. const unsigned long pid = 0;
  680. #endif
  681. showMessage(QString::fromLatin1("%1 running as %2").
  682. arg(QDir::toNativeSeparators(executable)).arg(pid), LogMisc);
  683. m_hasDebuggee = true;
  684. if (isRemote) { // We do not get an 'idle' in a remote session, but are accessible
  685. m_accessible = true;
  686. const QByteArray loadCommand = QByteArray(".load ")
  687. + extensionFileName.toLocal8Bit();
  688. postCommand(loadCommand, 0);
  689. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupOk")
  690. notifyEngineSetupOk();
  691. }
  692. return true;
  693. }
  694. void CdbEngine::setupInferior()
  695. {
  696. if (debug)
  697. qDebug("setupInferior");
  698. // QmlCppEngine expects the QML engine to be connected before any breakpoints are hit
  699. // (attemptBreakpointSynchronization() will be directly called then)
  700. attemptBreakpointSynchronization();
  701. if (startParameters().breakOnMain) {
  702. const BreakpointParameters bp(BreakpointAtMain);
  703. postCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings,
  704. BreakpointModelId(quint16(-1)), true), 0);
  705. }
  706. postCommand("sxn 0x4000001f", 0); // Do not break on WowX86 exceptions.
  707. postCommand(".asm source_line", 0); // Source line in assembly
  708. postExtensionCommand("pid", QByteArray(), 0, &CdbEngine::handlePid);
  709. }
  710. static QByteArray msvcRunTime(const Abi::OSFlavor flavour)
  711. {
  712. switch (flavour) {
  713. case Abi::WindowsMsvc2005Flavor:
  714. return "MSVCR80";
  715. case Abi::WindowsMsvc2008Flavor:
  716. return "MSVCR90";
  717. case Abi::WindowsMsvc2010Flavor:
  718. return "MSVCR100";
  719. case Abi::WindowsMsvc2012Flavor:
  720. return "MSVCR110"; // #FIXME: VS2012 beta, will probably be 12 in final?
  721. default:
  722. break;
  723. }
  724. return "MSVCRT"; // MinGW, others.
  725. }
  726. static QByteArray breakAtFunctionCommand(const QByteArray &function,
  727. const QByteArray &module = QByteArray())
  728. {
  729. QByteArray result = "bu ";
  730. if (!module.isEmpty()) {
  731. result += module;
  732. result += '!';
  733. }
  734. result += function;
  735. return result;
  736. }
  737. void CdbEngine::runEngine()
  738. {
  739. if (debug)
  740. qDebug("runEngine");
  741. foreach (const QString &breakEvent, m_options->breakEvents)
  742. postCommand(QByteArray("sxe ") + breakEvent.toLatin1(), 0);
  743. // Break functions: each function must be fully qualified,
  744. // else the debugger will slow down considerably.
  745. foreach (const QString &breakFunctionS, m_options->breakFunctions) {
  746. const QByteArray breakFunction = breakFunctionS.toLatin1();
  747. if (breakFunction == CdbOptions::crtDbgReport) {
  748. // CrtDbgReport(): Add MSVC runtime (debug, release)
  749. // and stop at Wide character version as well
  750. const QByteArray module = msvcRunTime(startParameters().toolChainAbi.osFlavor());
  751. const QByteArray debugModule = module + 'D';
  752. const QByteArray wideFunc = breakFunction + 'W';
  753. postCommand(breakAtFunctionCommand(breakFunction, module), 0);
  754. postCommand(breakAtFunctionCommand(wideFunc, module), 0);
  755. postCommand(breakAtFunctionCommand(breakFunction, debugModule), 0);
  756. postCommand(breakAtFunctionCommand(wideFunc, debugModule), 0);
  757. } else {
  758. postCommand(breakAtFunctionCommand(breakFunction), 0);
  759. }
  760. }
  761. if (debuggerCore()->boolSetting(BreakOnWarning)) {
  762. postCommand("bm /( QtCored4!qWarning", 0); // 'bm': All overloads.
  763. postCommand("bm /( Qt5Cored!QMessageLogger::warning", 0);
  764. }
  765. if (debuggerCore()->boolSetting(BreakOnFatal)) {
  766. postCommand("bm /( QtCored4!qFatal", 0); // 'bm': All overloads.
  767. postCommand("bm /( Qt5Cored!QMessageLogger::fatal", 0);
  768. }
  769. if (startParameters().startMode == AttachCore) {
  770. QTC_ASSERT(!m_coreStopReason.isNull(), return; );
  771. notifyInferiorUnrunnable();
  772. processStop(*m_coreStopReason, false);
  773. } else {
  774. postCommand("g", 0);
  775. }
  776. }
  777. bool CdbEngine::commandsPending() const
  778. {
  779. return !m_builtinCommandQueue.isEmpty() || !m_extensionCommandQueue.isEmpty();
  780. }
  781. void CdbEngine::shutdownInferior()
  782. {
  783. if (debug)
  784. qDebug("CdbEngine::shutdownInferior in state '%s', process running %d", stateName(state()),
  785. isCdbProcessRunning());
  786. if (!isCdbProcessRunning()) { // Direct launch: Terminated with process.
  787. if (debug)
  788. qDebug("notifyInferiorShutdownOk");
  789. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
  790. notifyInferiorShutdownOk();
  791. return;
  792. }
  793. if (m_accessible) { // except console.
  794. if (startParameters().startMode == AttachExternal || startParameters().startMode == AttachCrashedExternal)
  795. detachDebugger();
  796. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
  797. notifyInferiorShutdownOk();
  798. } else {
  799. // A command got stuck.
  800. if (commandsPending()) {
  801. showMessage(QLatin1String("Cannot shut down inferior due to pending commands."), LogWarning);
  802. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownFailed")
  803. notifyInferiorShutdownFailed();
  804. return;
  805. }
  806. if (!canInterruptInferior()) {
  807. showMessage(QLatin1String("Cannot interrupt the inferior."), LogWarning);
  808. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownFailed")
  809. notifyInferiorShutdownFailed();
  810. return;
  811. }
  812. interruptInferior(); // Calls us again
  813. }
  814. }
  815. /* shutdownEngine/processFinished:
  816. * Note that in the case of launching a process by the debugger, the debugger
  817. * automatically quits a short time after reporting the session becoming
  818. * inaccessible without debuggee (notifyInferiorExited). In that case,
  819. * processFinished() must not report any arbitrarily notifyEngineShutdownOk()
  820. * as not to confuse the state engine.
  821. */
  822. void CdbEngine::shutdownEngine()
  823. {
  824. if (debug)
  825. qDebug("CdbEngine::shutdownEngine in state '%s', process running %d,"
  826. "accessible=%d,commands pending=%d",
  827. stateName(state()), isCdbProcessRunning(), m_accessible,
  828. commandsPending());
  829. if (!isCdbProcessRunning()) { // Direct launch: Terminated with process.
  830. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineShutdownOk")
  831. notifyEngineShutdownOk();
  832. return;
  833. }
  834. // No longer trigger anything from messages
  835. m_ignoreCdbOutput = true;
  836. // Go for kill if there are commands pending.
  837. if (m_accessible && !commandsPending()) {
  838. // detach (except console): Wait for debugger to finish.
  839. if (startParameters().startMode == AttachExternal || startParameters().startMode == AttachCrashedExternal)
  840. detachDebugger();
  841. // Remote requires a bit more force to quit.
  842. if (m_effectiveStartMode == AttachToRemoteServer) {
  843. postCommand(m_extensionCommandPrefixBA + "shutdownex", 0);
  844. postCommand("qq", 0);
  845. } else {
  846. postCommand("q", 0);
  847. }
  848. m_notifyEngineShutdownOnTermination = true;
  849. return;
  850. } else {
  851. // Remote process. No can do, currently
  852. m_notifyEngineShutdownOnTermination = true;
  853. Utils::SynchronousProcess::stopProcess(m_process);
  854. return;
  855. }
  856. // Lost debuggee, debugger should quit anytime now
  857. if (!m_hasDebuggee) {
  858. m_notifyEngineShutdownOnTermination = true;
  859. return;
  860. }
  861. interruptInferior();
  862. }
  863. void CdbEngine::processFinished()
  864. {
  865. if (debug)
  866. qDebug("CdbEngine::processFinished %dms '%s' notify=%d (exit state=%d, ex=%d)",
  867. elapsedLogTime(), stateName(state()), m_notifyEngineShutdownOnTermination,
  868. m_process.exitStatus(), m_process.exitCode());
  869. const bool crashed = m_process.exitStatus() == QProcess::CrashExit;
  870. if (crashed)
  871. showMessage(tr("CDB crashed"), LogError); // not in your life.
  872. else
  873. showMessage(tr("CDB exited (%1)").arg(m_process.exitCode()), LogMisc);
  874. if (m_notifyEngineShutdownOnTermination) {
  875. if (crashed) {
  876. if (debug)
  877. qDebug("notifyEngineIll");
  878. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineIll")
  879. notifyEngineIll();
  880. } else {
  881. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineShutdownOk")
  882. notifyEngineShutdownOk();
  883. }
  884. } else {
  885. // The QML/CPP engine relies on the standard sequence of InferiorShutDown,etc.
  886. // Otherwise, we take a shortcut.
  887. if (isSlaveEngine()) {
  888. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorExited")
  889. notifyInferiorExited();
  890. } else {
  891. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSpontaneousShutdown")
  892. notifyEngineSpontaneousShutdown();
  893. }
  894. }
  895. }
  896. void CdbEngine::detachDebugger()
  897. {
  898. postCommand(".detach", 0);
  899. }
  900. static inline bool isWatchIName(const QByteArray &iname)
  901. {
  902. return iname.startsWith("watch");
  903. }
  904. void CdbEngine::updateWatchData(const WatchData &dataIn,
  905. const WatchUpdateFlags & flags)
  906. {
  907. if (debug || debugLocals || debugWatches)
  908. qDebug("CdbEngine::updateWatchData() %dms accessible=%d %s incr=%d: %s",
  909. elapsedLogTime(), m_accessible, stateName(state()),
  910. flags.tryIncremental,
  911. qPrintable(dataIn.toString()));
  912. if (!m_accessible) // Add watch data while running?
  913. return;
  914. // New watch item?
  915. if (isWatchIName(dataIn.iname) && dataIn.isValueNeeded()) {
  916. QByteArray args;
  917. ByteArrayInputStream str(args);
  918. str << dataIn.iname << " \"" << dataIn.exp << '"';
  919. // Store the name since the CDB extension library
  920. // does not maintain the names of watches.
  921. if (!dataIn.name.isEmpty() && dataIn.name != QLatin1String(dataIn.exp))
  922. m_watchInameToName.insert(dataIn.iname, dataIn.name);
  923. postExtensionCommand("addwatch", args, 0,
  924. &CdbEngine::handleAddWatch, 0,
  925. qVariantFromValue(dataIn));
  926. return;
  927. }
  928. if (!dataIn.hasChildren && !dataIn.isValueNeeded()) {
  929. WatchData data = dataIn;
  930. data.setAllUnneeded();
  931. watchHandler()->insertData(data);
  932. return;
  933. }
  934. updateLocalVariable(dataIn.iname);
  935. }
  936. void CdbEngine::handleAddWatch(const CdbExtensionCommandPtr &reply)
  937. {
  938. WatchData item = qvariant_cast<WatchData>(reply->cookie);
  939. if (debugWatches)
  940. qDebug() << "handleAddWatch ok=" << reply->success << item.iname;
  941. if (reply->success) {
  942. updateLocalVariable(item.iname);
  943. } else {
  944. item.setError(tr("Unable to add expression"));
  945. watchHandler()->insertIncompleteData(item);
  946. showMessage(QString::fromLatin1("Unable to add watch item '%1'/'%2': %3").
  947. arg(QString::fromLatin1(item.iname), QString::fromLatin1(item.exp),
  948. QString::fromLocal8Bit(reply->errorMessage)), LogError);
  949. }
  950. }
  951. void CdbEngine::addLocalsOptions(ByteArrayInputStream &str) const
  952. {
  953. if (debuggerCore()->boolSetting(VerboseLog))
  954. str << blankSeparator << "-v";
  955. if (debuggerCore()->boolSetting(UseDebuggingHelpers))
  956. str << blankSeparator << "-c";
  957. const QByteArray typeFormats = watchHandler()->typeFormatRequests();
  958. if (!typeFormats.isEmpty())
  959. str << blankSeparator << "-T " << typeFormats;
  960. const QByteArray individualFormats = watchHandler()->individualFormatRequests();
  961. if (!individualFormats.isEmpty())
  962. str << blankSeparator << "-I " << individualFormats;
  963. }
  964. void CdbEngine::updateLocalVariable(const QByteArray &iname)
  965. {
  966. const bool isWatch = isWatchIName(iname);
  967. if (debugWatches)
  968. qDebug() << "updateLocalVariable watch=" << isWatch << iname;
  969. QByteArray localsArguments;
  970. ByteArrayInputStream str(localsArguments);
  971. addLocalsOptions(str);
  972. if (!isWatch) {
  973. const int stackFrame = stackHandler()->currentIndex();
  974. if (stackFrame < 0) {
  975. qWarning("Internal error; no stack frame in updateLocalVariable");
  976. return;
  977. }
  978. str << blankSeparator << stackFrame;
  979. }
  980. str << blankSeparator << iname;
  981. postExtensionCommand(isWatch ? "watches" : "locals",
  982. localsArguments, 0,
  983. &CdbEngine::handleLocals,
  984. 0, QVariant(int(PartialLocalsUpdate)));
  985. }
  986. bool CdbEngine::hasCapability(unsigned cap) const
  987. {
  988. return cap & (DisassemblerCapability | RegisterCapability
  989. | ShowMemoryCapability
  990. |WatchpointByAddressCapability|JumpToLineCapability|AddWatcherCapability|WatchWidgetsCapability
  991. |ReloadModuleCapability
  992. |BreakOnThrowAndCatchCapability // Sort-of: Can break on throw().
  993. |BreakConditionCapability|TracePointCapability
  994. |BreakModuleCapability
  995. |OperateByInstructionCapability
  996. |RunToLineCapability
  997. |MemoryAddressCapability);
  998. }
  999. void CdbEngine::executeStep()
  1000. {
  1001. if (!m_operateByInstruction)
  1002. m_sourceStepInto = true; // See explanation at handleStackTrace().
  1003. postCommand(QByteArray("t"), 0); // Step into-> t (trace)
  1004. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
  1005. notifyInferiorRunRequested();
  1006. }
  1007. void CdbEngine::executeStepOut()
  1008. {
  1009. postCommand(QByteArray("gu"), 0); // Step out-> gu (go up)
  1010. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
  1011. notifyInferiorRunRequested();
  1012. }
  1013. void CdbEngine::executeNext()
  1014. {
  1015. postCommand(QByteArray("p"), 0); // Step over -> p
  1016. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
  1017. notifyInferiorRunRequested();
  1018. }
  1019. void CdbEngine::executeStepI()
  1020. {
  1021. executeStep();
  1022. }
  1023. void CdbEngine::executeNextI()
  1024. {
  1025. executeNext();
  1026. }
  1027. void CdbEngine::continueInferior()
  1028. {
  1029. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
  1030. notifyInferiorRunRequested();
  1031. doContinueInferior();
  1032. }
  1033. void CdbEngine::doContinueInferior()
  1034. {
  1035. postCommand(QByteArray("g"), 0);
  1036. }
  1037. bool CdbEngine::canInterruptInferior() const
  1038. {
  1039. return m_effectiveStartMode != AttachToRemoteServer && inferiorPid();
  1040. }
  1041. void CdbEngine::interruptInferior()
  1042. {
  1043. if (debug)
  1044. qDebug() << "CdbEngine::interruptInferior()" << stateName(state());
  1045. bool ok = false;
  1046. if (!canInterruptInferior())
  1047. showMessage(tr("Interrupting is not possible in remote sessions."), LogError);
  1048. else
  1049. ok = doInterruptInferior(NoSpecialStop);
  1050. // Restore running state if stop failed.
  1051. if (!ok) {
  1052. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorStopOk")
  1053. notifyInferiorStopOk();
  1054. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
  1055. notifyInferiorRunRequested();
  1056. STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunOk")
  1057. notifyInferiorRunOk();
  1058. }
  1059. }
  1060. void CdbEngine::doInterruptInferiorCustomSpecialStop(const QVariant &v)
  1061. {
  1062. if (m_specialStopMode == NoSpecialStop)
  1063. doInterruptInferior(CustomSpecialStop);
  1064. m_customSpecialStopData.push_back(v);
  1065. }
  1066. bool CdbEngine::doInterruptInferior(SpecialStopMode sm)
  1067. {
  1068. const SpecialStopMode oldSpecialMode = m_specialStopMode;
  1069. m_specialStopMode = sm;
  1070. showMessage(QString::fromLatin1("Interrupting process %1...").arg(inferiorPid()), LogMisc);
  1071. QString errorMessage;
  1072. const bool ok = interruptProcess(inferiorPid(), CdbEngineType,
  1073. &errorMessage, m_cdbIs64Bit);
  1074. if (!ok) {
  1075. m_specialStopMode = oldSpecialMode;
  1076. showMessage(errorMessage, LogError);
  1077. }
  1078. return ok;
  1079. }
  1080. void CdbEngine::executeRunToLine(const ContextData &data)
  1081. {
  1082. // Add one-shot breakpoint
  1083. BreakpointParameters bp;
  1084. if (data.address) {
  1085. bp.type =BreakpointByAddress;
  1086. bp.address = data.address;
  1087. } else {
  1088. bp.type =BreakpointByFileAndLine;
  1089. bp.fileName = data.fileName;
  1090. bp.lineNumber = data.lineNumber;
  1091. }
  1092. postCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings, BreakpointModelId(), true), 0);
  1093. continueInferior();
  1094. }
  1095. void CdbEngine::executeRunToFunction(const QString &functionName)
  1096. {
  1097. // Add one-shot breakpoint
  1098. BreakpointParameters bp(BreakpointByFunction);
  1099. bp.functionName = functionName;
  1100. postCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings, BreakpointModelId(), true), 0);
  1101. continueInferior();
  1102. }
  1103. void CdbEngine::setRegisterValue(int regnr, const QString &value)
  1104. {
  1105. const Registers registers = registerHandler()->registers();
  1106. QTC_ASSERT(regnr < registers.size(), return);
  1107. // Value is decimal or 0x-hex-prefixed
  1108. QByteArray cmd;
  1109. ByteArrayInputStream str(cmd);
  1110. str << "r " << registers.at(regnr).name << '=' << value;
  1111. postCommand(cmd, 0);
  1112. reloadRegisters();
  1113. }
  1114. void CdbEngine::executeJumpToLine(const ContextData &data)
  1115. {
  1116. if (data.address) {
  1117. // Goto address directly.
  1118. jumpToAddress(data.address);
  1119. gotoLocation(Location(data.address));
  1120. } else {
  1121. // Jump to source line: Resolve source line address and go to that location
  1122. QByteArray cmd;
  1123. ByteArrayInputStream str(cmd);
  1124. str << "? `" << QDir::toNativeSeparators(data.fileName) << ':' << data.lineNumber << '`';
  1125. const QVariant cookie = qVariantFromValue(data);
  1126. postBuiltinCommand(cmd, 0, &CdbEngine::handleJumpToLineAddressResolution, 0, cookie);
  1127. }
  1128. }
  1129. void CdbEngine::jumpToAddress(quint64 address)
  1130. {
  1131. // Fake a jump to address by setting the PC register.
  1132. QByteArray registerCmd;
  1133. ByteArrayInputStream str(registerCmd);
  1134. // PC-register depending on 64/32bit.
  1135. str << "r " << (startParameters().toolChainAbi.wordWidth() == 64 ? "rip" : "eip") << '=';
  1136. str.setHexPrefix(true);
  1137. str.setIntegerBase(16);
  1138. str << address;
  1139. postCommand(registerCmd, 0);
  1140. }
  1141. void CdbEngine::handleJumpToLineAddressResolution(const CdbBuiltinCommandPtr &cmd)
  1142. {
  1143. if (cmd->reply.isEmpty())
  1144. return;
  1145. // Evaluate expression: 5365511549 = 00000001`3fcf357d
  1146. // Set register 'rip' to hex address and goto lcoation
  1147. QByteArray answer = cmd->reply.front().trimmed();
  1148. const int equalPos = answer.indexOf(" = ");
  1149. if (equalPos == -1)
  1150. return;
  1151. answer.remove(0, equalPos + 3);
  1152. const int apPos = answer.indexOf('`');
  1153. if (apPos != -1)
  1154. answer.remove(apPos, 1);
  1155. bool ok;
  1156. const quint64 address = answer.toLongLong(&ok, 16);
  1157. if (ok && address) {
  1158. QTC_ASSERT(cmd->cookie.canConvert<ContextData>(), return);
  1159. const ContextData cookie = qvariant_cast<ContextData>(cmd->cookie);
  1160. jumpToAddress(address);
  1161. gotoLocation(Location(cookie.fileName, cookie.lineNumber));
  1162. }
  1163. }
  1164. static inline bool isAsciiWord(const QString &s)
  1165. {
  1166. foreach (const QChar &c, s) {
  1167. if (!c.isLetterOrNumber() || c.toLatin1() == 0)
  1168. return false;
  1169. }
  1170. return true;
  1171. }
  1172. void CdbEngine::assignValueInDebugger(const WatchData *w, const QString &expr, const QVariant &value)
  1173. {
  1174. if (debug)
  1175. qDebug() << "CdbEngine::assignValueInDebugger" << w->iname << expr << value;
  1176. if (state() != InferiorStopOk || stackHandler()->currentIndex() < 0) {
  1177. qWarning("Internal error: assignValueInDebugger: Invalid state or no stack frame.");
  1178. return;
  1179. }
  1180. QByteArray cmd;
  1181. ByteArrayInputStream str(cmd);
  1182. switch (value.type()) {
  1183. case QVariant::String: {
  1184. // Convert qstring to Utf16 data not considering endianness for Windows.
  1185. const QString s = value.toString();
  1186. if (isAsciiWord(s)) {
  1187. str << m_extensionCommandPrefixBA << "assign \"" << w->iname << '='
  1188. << s.toLatin1() << '"';
  1189. } else {
  1190. const QByteArray utf16(reinterpret_cast<const char *>(s.utf16()), 2 * s.size());
  1191. str << m_extensionCommandPrefixBA << "assign -u " << w->iname << '='
  1192. << utf16.toHex();
  1193. }
  1194. }
  1195. break;
  1196. default:
  1197. str << m_extensionCommandPrefixBA << "assign " << w->iname << '='
  1198. << value.toString();
  1199. break;
  1200. }
  1201. postCommand(cmd, 0);
  1202. // Update all locals in case we change a union or something pointed to
  1203. // that affects other variables, too.
  1204. updateLocals();
  1205. }
  1206. void CdbEngine::handleThreads(const CdbExtensionCommandPtr &reply)
  1207. {
  1208. if (debug)
  1209. qDebug("CdbEngine::handleThreads success=%d", reply->success);
  1210. if (reply->success) {
  1211. GdbMi data;
  1212. data.fromString(reply->reply);
  1213. threadsHandler()->updateThreads(data);
  1214. // Continue sequence
  1215. postCommandSequence(reply->commandSequence);
  1216. } else {
  1217. showMessage(QString::fromLatin1(reply->errorMessage), LogError);
  1218. }
  1219. }
  1220. void CdbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages languages)
  1221. {
  1222. if (languages & CppLanguage)
  1223. postCommand(command.toLocal8Bit(), QuietCommand);
  1224. }
  1225. // Post command without callback
  1226. void CdbEngine::postCommand(const QByteArray &cmd, unsigned flags)
  1227. {
  1228. if (debug)
  1229. qDebug("CdbEngine::postCommand %dms '%s' %u %s\n",
  1230. elapsedLogTime(), cmd.constData(), flags, stateName(state()));
  1231. if (!(flags & QuietCommand))
  1232. showMessage(QString::fromLocal8Bit(cmd), LogInput);
  1233. m_process.write(cmd + '\n');
  1234. }
  1235. // Post a built-in-command producing free-format output with a callback.
  1236. // In order to catch the output, it is enclosed in 'echo' commands
  1237. // printing a specially formatted token to be identifiable in the output.
  1238. void CdbEngine::postBuiltinCommand(const QByteArray &cmd, unsigned flags,
  1239. BuiltinCommandHandler handler,
  1240. unsigned nextCommandFlag,

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