1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights. These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
32 **************************************************************************/
34 #ifndef DEBUGGER_GDBENGINE_H
35 #define DEBUGGER_GDBENGINE_H
37 #include "debuggerengine.h"
39 #include "stackframe.h"
40 #include "watchutils.h"
42 #include <QtCore/QByteArray>
43 #include <QtCore/QProcess>
44 #include <QtCore/QHash>
45 #include <QtCore/QMap>
46 #include <QtCore/QMultiMap>
47 #include <QtCore/QObject>
48 #include <QtCore/QPoint>
49 #include <QtCore/QSet>
50 #include <QtCore/QTextCodec>
51 #include <QtCore/QTime>
52 #include <QtCore/QTimer>
53 #include <QtCore/QVariant>
59 class AbstractGdbAdapter;
60 class AbstractGdbProcess;
65 class DisassemblerAgentCookie;
66 class DisassemblerLines;
68 class AttachGdbAdapter;
70 class LocalPlainGdbAdapter;
71 class RemoteGdbServerAdapter;
74 enum DebuggingHelperState
76 DebuggingHelperUninitialized,
77 DebuggingHelperLoadTried,
78 DebuggingHelperAvailable,
79 DebuggingHelperUnavailable
83 class GdbEngine : public Debugger::DebuggerEngine
88 explicit GdbEngine(const DebuggerStartParameters &startParameters);
90 AbstractGdbAdapter *gdbAdapter() const { return m_gdbAdapter; }
93 friend class AbstractGdbAdapter;
94 friend class AbstractPlainGdbAdapter;
95 friend class AttachGdbAdapter;
96 friend class CoreGdbAdapter;
97 friend class LocalPlainGdbAdapter;
98 friend class TermGdbAdapter;
99 friend class RemoteGdbServerAdapter;
100 friend class RemotePlainGdbAdapter;
101 friend class TrkGdbAdapter;
102 friend class TcfTrkGdbAdapter;
104 private: ////////// General Interface //////////
106 virtual void setupEngine();
107 virtual void setupInferior();
108 virtual void runEngine();
110 virtual unsigned debuggerCapabilities() const;
111 virtual void detachDebugger();
112 virtual void shutdownEngine();
113 virtual void shutdownInferior();
114 virtual void notifyInferiorSetupFailed();
116 virtual void executeDebuggerCommand(const QString &command);
117 virtual QByteArray qtNamespace() const { return m_dumperHelper.qtNamespace(); }
119 private: ////////// General State //////////
121 DebuggerStartMode startMode() const;
122 Q_SLOT void reloadLocals();
124 bool m_registerNamesListed;
126 private: ////////// Gdb Process Management //////////
128 AbstractGdbAdapter *createAdapter();
129 bool startGdb(const QStringList &args = QStringList(),
130 const QString &gdb = QString(),
131 const QString &settingsIdHint = QString());
132 void handleInferiorShutdown(const GdbResponse &response);
133 void handleGdbExit(const GdbResponse &response);
134 void handleRemoteSetupDone(int gdbServerPort, int qmlPort);
135 void handleRemoteSetupFailed(const QString &message);
137 void handleAdapterStarted();
138 void defaultInferiorShutdown(const char *cmd);
139 void loadPythonDumpers();
140 void pythonDumpersFailed();
142 // Something went wrong with the adapter *before* adapterStarted() was emitted.
143 // Make sure to clean up everything before emitting this signal.
144 void handleAdapterStartFailed(const QString &msg,
145 const QString &settingsIdHint = QString());
147 // This triggers the initial breakpoint synchronization and causes
148 // finishInferiorSetup() being called once done.
149 void handleInferiorPrepared();
150 // This notifies the base of a successful inferior setup.
151 void finishInferiorSetup();
153 // The adapter is still running just fine, but it failed to acquire a debuggee.
154 void notifyInferiorSetupFailed(const QString &msg);
156 void notifyAdapterShutdownOk();
157 void notifyAdapterShutdownFailed();
159 // Something went wrong with the adapter *after* adapterStarted() was emitted.
160 // Make sure to clean up everything before emitting this signal.
161 void handleAdapterCrashed(const QString &msg);
164 void handleGdbFinished(int, QProcess::ExitStatus status);
165 void handleGdbError(QProcess::ProcessError error);
166 void readGdbStandardOutput();
167 void readGdbStandardError();
168 void readDebugeeOutput(const QByteArray &data);
171 QTextCodec *m_outputCodec;
172 QTextCodec::ConverterState m_outputCodecState;
174 QByteArray m_inbuffer;
177 AbstractGdbAdapter *m_gdbAdapter;
179 // Name of the convenience variable containing the last
180 // known function return value.
181 QByteArray m_resultVarName;
183 private: ////////// Gdb Command Management //////////
185 public: // Otherwise the Qt flag macros are unhappy.
186 enum GdbCommandFlag {
188 // The command needs a stopped inferior.
190 // No need to wait for the reply before continuing inferior.
192 // Trigger watch model rebuild when no such commands are pending anymore.
193 RebuildWatchModel = 4,
194 WatchUpdate = Discardable | RebuildWatchModel,
195 // We can live without receiving an answer.
196 NonCriticalResponse = 8,
197 // Callback expects GdbResultRunning instead of GdbResultDone.
199 // Callback expects GdbResultExit instead of GdbResultDone.
201 // Auto-set inferior shutdown related states.
203 // Trigger breakpoint model rebuild when no such commands are pending anymore.
204 RebuildBreakpointModel = 128,
205 // This command needs to be send immediately.
207 // This is a command that needs to be wrapped into -interpreter-exec console
210 Q_DECLARE_FLAGS(GdbCommandFlags, GdbCommandFlag)
213 typedef void (GdbEngine::*GdbCommandCallback)
214 (const GdbResponse &response);
215 typedef void (AbstractGdbAdapter::*AdapterCallback)
216 (const GdbResponse &response);
221 : flags(0), callback(0), adapterCallback(0), callbackName(0)
225 GdbCommandCallback callback;
226 AdapterCallback adapterCallback;
227 const char *callbackName;
233 // Type and cookie are sender-internal data, opaque for the "event
234 // queue". resultNeeded == true increments m_pendingResults on
235 // send and decrements on receipt, effectively preventing
236 // watch model updates before everything is finished.
237 void flushCommand(const GdbCommand &cmd);
238 void postCommand(const QByteArray &command,
239 GdbCommandFlags flags,
240 GdbCommandCallback callback = 0,
241 const char *callbackName = 0,
242 const QVariant &cookie = QVariant());
243 void postCommand(const QByteArray &command,
244 GdbCommandCallback callback = 0,
245 const char *callbackName = 0,
246 const QVariant &cookie = QVariant());
247 void postCommand(const QByteArray &command,
248 AdapterCallback callback,
249 const char *callbackName,
250 const QVariant &cookie = QVariant());
251 void postCommand(const QByteArray &command,
252 GdbCommandFlags flags,
253 AdapterCallback callback,
254 const char *callbackName,
255 const QVariant &cookie = QVariant());
256 void postCommandHelper(const GdbCommand &cmd);
257 void flushQueuedCommands();
258 Q_SLOT void commandTimeout();
259 void setTokenBarrier();
261 QHash<int, GdbCommand> m_cookieForToken;
262 int commandTimeoutTime() const;
263 QTimer m_commandTimer;
265 QByteArray m_pendingConsoleStreamOutput;
266 QByteArray m_pendingLogStreamOutput;
268 // This contains the first token number for the current round
269 // of evaluation. Responses with older tokens are considers
270 // out of date and discarded.
271 int m_oldestAcceptableToken;
273 int m_pendingWatchRequests; // Watch updating commands in flight
274 int m_pendingBreakpointRequests; // Watch updating commands in flight
276 typedef void (GdbEngine::*CommandsDoneCallback)();
277 // This function is called after all previous responses have been received.
278 CommandsDoneCallback m_commandsDoneCallback;
280 QList<GdbCommand> m_commandsToRunOnTemporaryBreak;
281 int gdbVersion() const { return m_gdbVersion; }
283 private: ////////// Gdb Output, State & Capability Handling //////////
285 void handleResponse(const QByteArray &buff);
286 void handleStopResponse(const GdbMi &data);
287 void handleResultRecord(GdbResponse *response);
288 void handleStop0(const GdbMi &data);
289 void handleStop1(const GdbResponse &response);
290 void handleStop1(const GdbMi &data);
291 Q_SLOT void handleStop2();
292 StackFrame parseStackFrame(const GdbMi &mi, int level);
293 void resetCommandQueue();
295 bool isSynchronous() const { return hasPython(); }
296 virtual bool hasPython() const;
297 bool supportsThreads() const;
299 // Gdb initialization sequence
300 void handleShowVersion(const GdbResponse &response);
301 void handleHasPython(const GdbResponse &response);
303 int m_gdbVersion; // 6.8.0 is 60800
304 int m_gdbBuildVersion; // MAC only?
307 bool m_hasInferiorThreadList;
309 private: ////////// Inferior Management //////////
311 // This should be always the last call in a function.
312 bool stateAcceptsBreakpointChanges() const;
313 bool acceptsBreakpoint(BreakpointId id) const;
314 void insertBreakpoint(BreakpointId id);
315 void removeBreakpoint(BreakpointId id);
316 void changeBreakpoint(BreakpointId id);
319 void executeStepOut();
324 void continueInferiorInternal();
325 void autoContinueInferior();
326 void continueInferior();
327 void interruptInferior();
328 void interruptInferiorTemporarily();
330 void executeRunToLine(const QString &fileName, int lineNumber);
331 void executeRunToFunction(const QString &functionName);
332 void executeJumpToLine(const QString &fileName, int lineNumber);
333 void executeReturn();
335 void handleExecuteContinue(const GdbResponse &response);
336 void handleExecuteStep(const GdbResponse &response);
337 void handleExecuteNext(const GdbResponse &response);
338 void handleExecuteReturn(const GdbResponse &response);
339 void handleExecuteJumpToLine(const GdbResponse &response);
340 void handleExecuteRunToLine(const GdbResponse &response);
342 void maybeHandleInferiorPidChanged(const QString &pid);
343 void handleInfoProc(const GdbResponse &response);
345 QByteArray m_entryPoint;
347 private: ////////// View & Data Stuff //////////
349 void selectThread(int index);
350 void activateFrame(int index);
353 // Breakpoint specific stuff
355 void handleBreakList(const GdbResponse &response);
356 void handleBreakList(const GdbMi &table);
357 void handleBreakIgnore(const GdbResponse &response);
358 void handleBreakDisable(const GdbResponse &response);
359 void handleBreakEnable(const GdbResponse &response);
360 void handleBreakInsert1(const GdbResponse &response);
361 void handleBreakInsert2(const GdbResponse &response);
362 void handleTraceInsert2(const GdbResponse &response);
363 void handleBreakCondition(const GdbResponse &response);
364 void handleBreakInfo(const GdbResponse &response);
365 void handleBreakThreadSpec(const GdbResponse &response);
366 void handleWatchInsert(const GdbResponse &response);
367 void handleInfoLine(const GdbResponse &response);
368 void extractDataFromInfoBreak(const QString &output, BreakpointId);
369 void updateBreakpointDataFromOutput(BreakpointId id, const GdbMi &bkpt);
370 QByteArray breakpointLocation(BreakpointId id);
371 QString breakLocation(const QString &file) const;
372 void reloadBreakListInternal();
373 void attemptAdjustBreakpointLocation(BreakpointId id);
376 // Modules specific stuff
378 void loadSymbols(const QString &moduleName);
379 void loadAllSymbols();
380 void loadSymbolsForStack();
381 void requestModuleSymbols(const QString &moduleName);
382 void reloadModules();
383 void examineModules();
384 void reloadModulesInternal();
385 void handleModulesList(const GdbResponse &response);
386 void handleShowModuleSymbols(const GdbResponse &response);
388 bool m_modulesListOutdated;
391 // Snapshot specific stuff
393 virtual void createSnapshot();
394 void handleMakeSnapshot(const GdbResponse &response);
397 // Register specific stuff
399 Q_SLOT void reloadRegisters();
400 void setRegisterValue(int nr, const QString &value);
401 void handleRegisterListNames(const GdbResponse &response);
402 void handleRegisterListValues(const GdbResponse &response);
405 // Disassembler specific stuff
407 void fetchDisassembler(DisassemblerAgent *agent);
408 void fetchDisassemblerByAddress(const DisassemblerAgentCookie &ac,
410 void fetchDisassemblerByCli(const DisassemblerAgentCookie &ac,
412 void fetchDisassemblerByAddressCli(const DisassemblerAgentCookie &ac);
413 void handleFetchDisassemblerByCli(const GdbResponse &response);
414 void handleFetchDisassemblerByLine(const GdbResponse &response);
415 void handleFetchDisassemblerByAddress1(const GdbResponse &response);
416 void handleFetchDisassemblerByAddress0(const GdbResponse &response);
417 DisassemblerLines parseDisassembler(const GdbMi &lines);
420 // Source file specific stuff
422 void reloadSourceFiles();
423 void reloadSourceFilesInternal();
424 void handleQuerySources(const GdbResponse &response);
426 QString fullName(const QString &fileName);
427 QString cleanupFullName(const QString &fileName);
429 // awful hack to keep track of used files
430 QMap<QString, QString> m_shortToFullName;
431 QMap<QString, QString> m_fullToShortName;
433 void invalidateSourcesList();
434 bool m_sourcesListOutdated;
435 bool m_sourcesListUpdating;
436 bool m_breakListOutdated;
439 // Stack specific stuff
442 void updateAllClassic();
443 void updateAllPython();
444 void handleStackListFrames(const GdbResponse &response);
445 void handleStackSelectThread(const GdbResponse &response);
446 void handleStackSelectFrame(const GdbResponse &response);
447 void handleThreadListIds(const GdbResponse &response);
448 void handleThreadInfo(const GdbResponse &response);
449 void handleThreadNames(const GdbResponse &response);
450 Q_SLOT void reloadStack(bool forceGotoLocation);
451 Q_SLOT virtual void reloadFullStack();
452 int currentFrame() const;
454 QList<GdbMi> m_currentFunctionArgs;
457 // Watch specific stuff
459 virtual void setToolTipExpression(const QPoint &mousePos,
460 TextEditor::ITextEditor *editor, int cursorPos);
462 virtual void assignValueInDebugger(const WatchData *data,
463 const QString &expr, const QVariant &value);
465 virtual void fetchMemory(MemoryAgent *agent, QObject *token,
466 quint64 addr, quint64 length);
467 void handleFetchMemory(const GdbResponse &response);
469 virtual void watchPoint(const QPoint &);
470 void handleWatchPoint(const GdbResponse &response);
472 // FIXME: BaseClass. called to improve situation for a watch item
473 void updateSubItemClassic(const WatchData &data);
475 void virtual updateWatchData(const WatchData &data, const WatchUpdateFlags &flags);
476 Q_SLOT void updateWatchDataHelper(const WatchData &data);
477 void rebuildWatchModel();
480 void insertData(const WatchData &data);
481 void sendWatchParameters(const QByteArray ¶ms0);
482 void createGdbVariableClassic(const WatchData &data);
484 void runDebuggingHelperClassic(const WatchData &data, bool dumpChildren);
485 void runDirectDebuggingHelperClassic(const WatchData &data, bool dumpChildren);
486 bool hasDebuggingHelperForType(const QByteArray &type) const;
488 void handleVarListChildrenClassic(const GdbResponse &response);
489 void handleVarListChildrenHelperClassic(const GdbMi &child,
490 const WatchData &parent);
491 void handleVarCreate(const GdbResponse &response);
492 void handleVarAssign(const GdbResponse &response);
493 void handleEvaluateExpressionClassic(const GdbResponse &response);
494 void handleQueryDebuggingHelperClassic(const GdbResponse &response);
495 void handleDebuggingHelperValue2Classic(const GdbResponse &response);
496 void handleDebuggingHelperValue3Classic(const GdbResponse &response);
497 void handleDebuggingHelperEditValue(const GdbResponse &response);
498 void handleDebuggingHelperSetup(const GdbResponse &response);
499 void handleDebuggingHelperVersionCheckClassic(const GdbResponse &response);
500 void handleDetach(const GdbResponse &response);
502 Q_SLOT void createFullBacktrace();
503 void handleCreateFullBacktrace(const GdbResponse &response);
505 void updateLocals(const QVariant &cookie = QVariant());
506 void updateLocalsClassic(const QVariant &cookie);
507 void updateLocalsPython(bool tryPartial, const QByteArray &varList);
508 void handleStackFramePython(const GdbResponse &response);
510 void handleStackListLocalsClassic(const GdbResponse &response);
511 void handleStackListLocalsPython(const GdbResponse &response);
513 WatchData localVariable(const GdbMi &item,
514 const QStringList &uninitializedVariables,
515 QMap<QByteArray, int> *seen);
516 void setLocals(const QList<GdbMi> &locals);
517 void handleStackListArgumentsClassic(const GdbResponse &response);
519 QSet<QByteArray> m_processedNames;
524 bool checkDebuggingHelpersClassic();
525 void setDebuggingHelperStateClassic(DebuggingHelperState);
526 void tryLoadDebuggingHelpersClassic();
527 void tryQueryDebuggingHelpersClassic();
528 Q_SLOT void setUseDebuggingHelpers(const QVariant &on);
530 DebuggingHelperState m_debuggingHelperState;
531 QtDumperHelper m_dumperHelper;
535 // Convenience Functions
537 QString errorMessage(QProcess::ProcessError error);
538 AbstractGdbProcess *gdbProc() const;
539 void showExecutionError(const QString &message);
541 void removeTooltip();
542 static QByteArray tooltipIName(const QString &exp);
543 QString m_toolTipExpression;
546 // For short-circuiting stack and thread list evaluation.
548 int m_currentThreadId;
551 StackFrame m_targetFrame;
552 QByteArray m_currentThread;
555 } // namespace Internal
556 } // namespace Debugger
558 Q_DECLARE_OPERATORS_FOR_FLAGS(Debugger::Internal::GdbEngine::GdbCommandFlags)
560 #endif // DEBUGGER_GDBENGINE_H