gdbengine.h 17.9 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
Eike Ziller's avatar
Eike Ziller committed
3
4
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
con's avatar
con committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
con's avatar
con committed
7
**
hjk's avatar
hjk committed
8
9
10
11
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
Eike Ziller's avatar
Eike Ziller committed
12
13
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
Eike Ziller's avatar
Eike Ziller committed
14
** use the contact form at http://www.qt.io/contact-us.
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18
19
20
21
22
23
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
hjk's avatar
hjk committed
24
**
Eike Ziller's avatar
Eike Ziller committed
25
26
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
con's avatar
con committed
27
28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
29
****************************************************************************/
hjk's avatar
hjk committed
30

con's avatar
con committed
31
32
33
#ifndef DEBUGGER_GDBENGINE_H
#define DEBUGGER_GDBENGINE_H

34
#include <debugger/debuggerengine.h>
35

36
#include <debugger/breakhandler.h>
37
38
#include <debugger/watchhandler.h>
#include <debugger/watchutils.h>
39
#include <debugger/debuggertooltipmanager.h>
40

hjk's avatar
hjk committed
41
42
#include <coreplugin/id.h>

43
44
#include <projectexplorer/devicesupport/idevice.h>

45
46
47
48
#include <QProcess>
#include <QTextCodec>
#include <QTime>
#include <QTimer>
con's avatar
con committed
49
50
51
52

namespace Debugger {
namespace Internal {

53
class GdbProcess;
54
55
class DebugInfoTask;
class DebugInfoTaskHandler;
56
class DebuggerResponse;
con's avatar
con committed
57
class GdbMi;
58
class MemoryAgentCookie;
59
60
class BreakpointParameters;
class BreakpointResponse;
con's avatar
con committed
61

62
class WatchData;
63
class DisassemblerAgentCookie;
64
class DisassemblerLines;
con's avatar
con committed
65

hjk's avatar
hjk committed
66
class GdbEngine : public DebuggerEngine
con's avatar
con committed
67
68
69
70
{
    Q_OBJECT

public:
71
    explicit GdbEngine(const DebuggerStartParameters &startParameters);
con's avatar
con committed
72
    ~GdbEngine();
hjk's avatar
hjk committed
73

74
private: ////////// General Interface //////////
con's avatar
con committed
75

76
77
78
79
    virtual void setupEngine() = 0;
    virtual void handleGdbStartFailed();
    virtual void setupInferior() = 0;
    virtual void notifyInferiorSetupFailed();
hjk's avatar
hjk committed
80

81
    virtual bool hasCapability(unsigned) const;
82
    virtual void detachDebugger();
hjk's avatar
hjk committed
83
    virtual void shutdownInferior();
84
    virtual void shutdownEngine() = 0;
85
    virtual void abortDebugger();
86
    virtual void resetInferior();
con's avatar
con committed
87

88
    virtual bool acceptsDebuggerCommands() const;
89
    virtual void executeDebuggerCommand(const QString &command, DebuggerLanguages languages);
90
91
    virtual QByteArray qtNamespace() const { return m_qtNamespace; }
    virtual void setQtNamespace(const QByteArray &ns) { m_qtNamespace = ns; }
con's avatar
con committed
92

93
private: ////////// General State //////////
con's avatar
con committed
94

95
    DebuggerStartMode startMode() const;
96
    Q_SLOT void reloadLocals();
97

98
    bool m_registerNamesListed;
99

100
protected: ////////// Gdb Process Management //////////
101

hjk's avatar
hjk committed
102
    void startGdb(const QStringList &args = QStringList());
103
104
    void handleInferiorShutdown(const DebuggerResponse &response);
    void handleGdbExit(const DebuggerResponse &response);
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
105

106
    void loadInitScript();
hjk's avatar
hjk committed
107

108
109
    // Something went wrong with the adapter *before* adapterStarted() was emitted.
    // Make sure to clean up everything before emitting this signal.
110
    void handleAdapterStartFailed(const QString &msg,
hjk's avatar
hjk committed
111
        Core::Id settingsIdHint = Core::Id());
con's avatar
con committed
112

113
    // This triggers the initial breakpoint synchronization and causes
hjk's avatar
hjk committed
114
    // finishInferiorSetup() being called once done.
115
    void handleInferiorPrepared();
hjk's avatar
hjk committed
116
117
    // This notifies the base of a successful inferior setup.
    void finishInferiorSetup();
118

119
    void handleDebugInfoLocation(const DebuggerResponse &response);
120

121
    // The adapter is still running just fine, but it failed to acquire a debuggee.
hjk's avatar
hjk committed
122
123
124
125
    void notifyInferiorSetupFailed(const QString &msg);

    void notifyAdapterShutdownOk();
    void notifyAdapterShutdownFailed();
126

127
128
    // Something went wrong with the adapter *after* adapterStarted() was emitted.
    // Make sure to clean up everything before emitting this signal.
129
    void handleAdapterCrashed(const QString &msg);
con's avatar
con committed
130

131
private slots:
hjk's avatar
hjk committed
132
    friend class GdbPlainEngine;
133
    void handleInterruptDeviceInferior(const QString &error);
134
135
    void handleGdbFinished(int, QProcess::ExitStatus status);
    void handleGdbError(QProcess::ProcessError error);
hjk's avatar
hjk committed
136
    void readDebugeeOutput(const QByteArray &data);
137
138
139
    void readGdbStandardOutput();
    void readGdbStandardError();

140
141
142
143
144
private:
    QTextCodec *m_outputCodec;
    QTextCodec::ConverterState m_outputCodecState;

    QByteArray m_inbuffer;
145
    bool m_busy;
con's avatar
con committed
146

147
148
149
150
    // Name of the convenience variable containing the last
    // known function return value.
    QByteArray m_resultVarName;

151
152
private: ////////// Gdb Command Management //////////

153
    public: // Otherwise the Qt flag macros are unhappy.
154
155
    enum GdbCommandFlag {
        NoFlags = 0,
156
        // The command needs a stopped inferior.
157
        NeedsStop = 1,
158
159
        // No need to wait for the reply before continuing inferior.
        Discardable = 2,
hjk's avatar
hjk committed
160
        // We can live without receiving an answer.
161
        NonCriticalResponse = 8,
162
        // Callback expects ResultRunning instead of ResultDone.
163
        RunRequest = 16,
164
        // Callback expects ResultExit instead of ResultDone.
165
166
167
168
169
        ExitRequest = 32,
        // Auto-set inferior shutdown related states.
        LosesChild = 64,
        // Trigger breakpoint model rebuild when no such commands are pending anymore.
        RebuildBreakpointModel = 128,
170
171
        // This command needs to be send immediately.
        Immediate = 256,
172
        // This is a command that needs to be wrapped into -interpreter-exec console
173
        ConsoleCommand = 512
174
175
176
    };
    Q_DECLARE_FLAGS(GdbCommandFlags, GdbCommandFlag)

177
    // Type and cookie are sender-internal data, opaque for the "event
con's avatar
con committed
178
    // queue". resultNeeded == true increments m_pendingResults on
hjk's avatar
hjk committed
179
    // send and decrements on receipt, effectively preventing
con's avatar
con committed
180
    // watch model updates before everything is finished.
181
    void flushCommand(const DebuggerCommand &cmd);
182
protected:
183
    void runCommand(const DebuggerCommand &command);
184
    void postCommand(const QByteArray &command,
185
186
                     int flags = NoFlags,
                     DebuggerCommand::Callback callback = DebuggerCommand::Callback());
187
private:
188
    void flushQueuedCommands();
189
    Q_SLOT void commandTimeout();
con's avatar
con committed
190
191
    void setTokenBarrier();

192
193
194
    // Sets up an "unexpected result" for the following commeand.
    void scheduleTestResponse(int testCase, const QByteArray &response);

195
    QHash<int, DebuggerCommand> m_commandForToken;
196
    int commandTimeoutTime() const;
197
    QTimer m_commandTimer;
con's avatar
con committed
198

199
200
    QByteArray m_pendingConsoleStreamOutput;
    QByteArray m_pendingLogStreamOutput;
201

202
    // This contains the first token number for the current round
203
204
205
    // of evaluation. Responses with older tokens are considers
    // out of date and discarded.
    int m_oldestAcceptableToken;
206
    int m_nonDiscardableCount;
con's avatar
con committed
207

208
    int m_pendingBreakpointRequests; // Watch updating commands in flight
hjk's avatar
hjk committed
209

210
    typedef void (GdbEngine::*CommandsDoneCallback)();
211
    // This function is called after all previous responses have been received.
212
    CommandsDoneCallback m_commandsDoneCallback;
hjk's avatar
hjk committed
213

214
    QList<DebuggerCommand> m_commandsToRunOnTemporaryBreak;
215
216

private: ////////// Gdb Output, State & Capability Handling //////////
217
protected:
218
    Q_SLOT void handleResponse(const QByteArray &buff);
219
    void handleStopResponse(const GdbMi &data);
220
    void handleResultRecord(DebuggerResponse *response);
221
    void handleStop1(const GdbMi &data);
222
    void handleStop2(const GdbMi &data);
223
    Q_SLOT void handleStop2();
224
    StackFrame parseStackFrame(const GdbMi &mi, int level);
225
    void resetCommandQueue();
226

227
    bool isSynchronous() const { return true; }
228
229

    // Gdb initialization sequence
230
231
232
    void handleShowVersion(const DebuggerResponse &response);
    void handleListFeatures(const DebuggerResponse &response);
    void handlePythonSetup(const DebuggerResponse &response);
con's avatar
con committed
233

234
    int m_gdbVersion; // 7.6.1 is 70601
235
    bool m_isQnxGdb;
hjk's avatar
hjk committed
236

237
private: ////////// Inferior Management //////////
238

239
    // This should be always the last call in a function.
hjk's avatar
hjk committed
240
    bool stateAcceptsBreakpointChanges() const;
241
242
243
244
    bool acceptsBreakpoint(Breakpoint bp) const;
    void insertBreakpoint(Breakpoint bp);
    void removeBreakpoint(Breakpoint bp);
    void changeBreakpoint(Breakpoint bp);
hjk's avatar
hjk committed
245
246
247
248
249
250

    void executeStep();
    void executeStepOut();
    void executeNext();
    void executeStepI();
    void executeNextI();
con's avatar
con committed
251

252
    protected:
253
254
    void continueInferiorInternal();
    void autoContinueInferior();
hjk's avatar
hjk committed
255
256
    void continueInferior();
    void interruptInferior();
257
    virtual void interruptInferior2() {}
258
    void interruptInferiorTemporarily();
con's avatar
con committed
259

260
    void executeRunToLine(const ContextData &data);
hjk's avatar
hjk committed
261
    void executeRunToFunction(const QString &functionName);
262
    void executeJumpToLine(const ContextData &data);
hjk's avatar
hjk committed
263
    void executeReturn();
con's avatar
con committed
264

265
266
267
268
269
270
    void handleExecuteContinue(const DebuggerResponse &response);
    void handleExecuteStep(const DebuggerResponse &response);
    void handleExecuteNext(const DebuggerResponse &response);
    void handleExecuteReturn(const DebuggerResponse &response);
    void handleExecuteJumpToLine(const DebuggerResponse &response);
    void handleExecuteRunToLine(const DebuggerResponse &response);
con's avatar
con committed
271

272
    void maybeHandleInferiorPidChanged(const QString &pid);
273
    void handleInfoProc(const DebuggerResponse &response);
274
    QString msgPtraceError(DebuggerStartMode sm);
275

276
277
private: ////////// View & Data Stuff //////////

hjk's avatar
hjk committed
278
    void selectThread(ThreadId threadId);
hjk's avatar
hjk committed
279
    void activateFrame(int index);
280

con's avatar
con committed
281
282
283
    //
    // Breakpoint specific stuff
    //
284
    void handleBreakModifications(const GdbMi &bkpts);
285
286
287
288
289
290
291
292
293
294
    void handleBreakIgnore(const DebuggerResponse &response, Breakpoint bp);
    void handleBreakDisable(const DebuggerResponse &response, Breakpoint bp);
    void handleBreakEnable(const DebuggerResponse &response, Breakpoint bp);
    void handleBreakInsert1(const DebuggerResponse &response, Breakpoint bp);
    void handleBreakInsert2(const DebuggerResponse &response, Breakpoint bp);
    void handleBreakCondition(const DebuggerResponse &response, Breakpoint bp);
    void handleBreakThreadSpec(const DebuggerResponse &response, Breakpoint bp);
    void handleBreakLineNumber(const DebuggerResponse &response, Breakpoint bp);
    void handleWatchInsert(const DebuggerResponse &response, Breakpoint bp);
    void handleCatchInsert(const DebuggerResponse &response, Breakpoint bp);
295
    void handleBkpt(const GdbMi &bkpt, Breakpoint bp);
hjk's avatar
hjk committed
296
    void updateResponse(BreakpointResponse &response, const GdbMi &bkpt);
297
298
    QByteArray breakpointLocation(const BreakpointParameters &data); // For gdb/MI.
    QByteArray breakpointLocation2(const BreakpointParameters &data); // For gdb/CLI fallback.
299
    QString breakLocation(const QString &file) const;
con's avatar
con committed
300
301
302
303

    //
    // Modules specific stuff
    //
304
    protected:
hjk's avatar
hjk committed
305
    void loadSymbols(const QString &moduleName);
306
    Q_SLOT void loadAllSymbols();
307
    void loadSymbolsForStack();
hjk's avatar
hjk committed
308
    void requestModuleSymbols(const QString &moduleName);
309
    void requestModuleSections(const QString &moduleName);
hjk's avatar
hjk committed
310
311
    void reloadModules();
    void examineModules();
312

313
    void reloadModulesInternal();
314
    void handleModulesList(const DebuggerResponse &response);
315
    void handleShowModuleSections(const DebuggerResponse &response, const QString &moduleName);
con's avatar
con committed
316

317
318
319
    //
    // Snapshot specific stuff
    //
320
    virtual void createSnapshot();
321
    void handleMakeSnapshot(const DebuggerResponse &response, const QString &coreFile);
322

con's avatar
con committed
323
324
    //
    // Register specific stuff
hjk's avatar
hjk committed
325
    //
hjk's avatar
hjk committed
326
    Q_SLOT void reloadRegisters();
hjk's avatar
hjk committed
327
    void setRegisterValue(const QByteArray &name, const QString &value);
328
329
330
    void handleRegisterListNames(const DebuggerResponse &response);
    void handleRegisterListValues(const DebuggerResponse &response);
    void handleMaintPrintRegisters(const DebuggerResponse &response);
hjk's avatar
hjk committed
331
    QHash<int, QByteArray> m_registerNames; // Map GDB register numbers to indices
con's avatar
con committed
332

333
334
335
    //
    // Disassembler specific stuff
    //
336
    // Chain of fallbacks: PointMixed -> PointPlain -> RangeMixed -> RangePlain.
337
    void fetchDisassembler(DisassemblerAgent *agent);
338
339
340
    void fetchDisassemblerByCliPointMixed(const DisassemblerAgentCookie &ac);
    void fetchDisassemblerByCliRangeMixed(const DisassemblerAgentCookie &ac);
    void fetchDisassemblerByCliRangePlain(const DisassemblerAgentCookie &ac);
hjk's avatar
hjk committed
341
    bool handleCliDisassemblerResult(const QByteArray &response, DisassemblerAgent *agent);
342

343
    void handleBreakOnQFatal(const DebuggerResponse &response, bool continueSetup);
hjk's avatar
hjk committed
344

345
346
    //
    // Source file specific stuff
hjk's avatar
hjk committed
347
    //
hjk's avatar
hjk committed
348
    void reloadSourceFiles();
349
    void reloadSourceFilesInternal();
350
    void handleQuerySources(const DebuggerResponse &response);
351
352

    QString fullName(const QString &fileName);
353
    QString cleanupFullName(const QString &fileName);
354
355
356
357

    // awful hack to keep track of used files
    QMap<QString, QString> m_shortToFullName;
    QMap<QString, QString> m_fullToShortName;
358
    QMultiMap<QString, QString> m_baseNameToFullName;
con's avatar
con committed
359

360
361
    bool m_sourcesListUpdating;

con's avatar
con committed
362
363
    //
    // Stack specific stuff
hjk's avatar
hjk committed
364
    //
365
protected:
366
    void updateAll();
367
    void handleStackListFrames(const DebuggerResponse &response, bool isFull);
368
369
370
371
    void handleStackSelectThread(const DebuggerResponse &response);
    void handleThreadListIds(const DebuggerResponse &response);
    void handleThreadInfo(const DebuggerResponse &response);
    void handleThreadNames(const DebuggerResponse &response);
372
    DebuggerCommand stackCommand(int depth);
373
    Q_SLOT void reloadStack();
374
    Q_SLOT virtual void reloadFullStack();
375
    virtual void loadAdditionalQmlStack();
376
377
    void handleQmlStackFrameArguments(const DebuggerResponse &response);
    void handleQmlStackTrace(const DebuggerResponse &response);
378
    int currentFrame() const;
con's avatar
con committed
379

380
    QList<GdbMi> m_currentFunctionArgs;
con's avatar
con committed
381
382

    //
383
    // Watch specific stuff
hjk's avatar
hjk committed
384
    //
385
    virtual bool setToolTipExpression(TextEditor::TextEditorWidget *editor,
hjk's avatar
hjk committed
386
        const DebuggerToolTipContext &);
387
388
    virtual void assignValueInDebugger(const WatchData *data,
        const QString &expr, const QVariant &value);
389

390
    virtual void fetchMemory(MemoryAgent *agent, QObject *token,
391
        quint64 addr, quint64 length);
392
    void fetchMemoryHelper(const MemoryAgentCookie &cookie);
393
    void handleChangeMemory(const DebuggerResponse &response);
hjk's avatar
hjk committed
394
395
    virtual void changeMemory(MemoryAgent *agent, QObject *token,
        quint64 addr, const QByteArray &data);
396
    void handleFetchMemory(const DebuggerResponse &response, MemoryAgentCookie ac);
397
398

    virtual void watchPoint(const QPoint &);
399
    void handleWatchPoint(const DebuggerResponse &response);
con's avatar
con committed
400

hjk's avatar
hjk committed
401
    void updateWatchData(const WatchData &data, const WatchUpdateFlags &flags);
402
    void rebuildWatchModel();
hjk's avatar
hjk committed
403
    void showToolTip();
con's avatar
con committed
404
405
406

    void insertData(const WatchData &data);

407
408
    void handleVarAssign(const DebuggerResponse &response);
    void handleDetach(const DebuggerResponse &response);
409
410
411
    void handleThreadGroupCreated(const GdbMi &result);
    void handleThreadGroupExited(const GdbMi &result);

412
    Q_SLOT void createFullBacktrace();
413
    void handleCreateFullBacktrace(const DebuggerResponse &response);
414

415
    void updateLocals();
416
        void updateLocalsPython(const UpdateParameters &parameters);
417
        void handleStackFramePython(const DebuggerResponse &response, bool partial);
418

419
    void setLocals(const QList<GdbMi> &locals);
con's avatar
con committed
420

421
    QSet<QByteArray> m_processedNames;
422
423
424
425
426
427
428
429
    struct TypeInfo
    {
        TypeInfo(uint s = 0) : size(s) {}

        uint size;
    };

    QHash<QByteArray, TypeInfo> m_typeInfoCache;
con's avatar
con committed
430

431
432
433
    //
    // Dumper Management
    //
434
    void reloadDebuggingHelpers();
435

436
    QByteArray m_qtNamespace;
437
    QString m_gdb;
438

439
    //
440
441
    // Convenience Functions
    //
442
    QString errorMessage(QProcess::ProcessError error);
hjk's avatar
hjk committed
443
    void showExecutionError(const QString &message);
444

445
    static QByteArray tooltipIName(const QString &exp);
446

447
448
449
    // For short-circuiting stack and thread list evaluation.
    bool m_stackNeeded;

450
451
    bool isQFatalBreakpoint(const BreakpointResponseId &id) const;
    bool isHiddenBreakpoint(const BreakpointResponseId &id) const;
452

453
    // HACK:
454
    QByteArray m_currentThread;
455
    QString m_lastWinException;
456
    QString m_lastMissingDebugInfo;
457
    BreakpointResponseId m_qFatalBreakpointResponseId;
458
    bool m_terminalTrap;
459

460
461
    bool usesExecInterrupt() const;

462
463
    QHash<int, QByteArray> m_scheduledTestResponses;
    QSet<int> m_testCases;
464
465
466
467
468

    // Debug information
    friend class DebugInfoTaskHandler;
    void requestDebugInformation(const DebugInfoTask &task);
    DebugInfoTaskHandler *m_debugInfoTaskHandler;
469
470
471
472
473

    // Indicates whether we had at least one full attempt to load
    // debug information.
    bool attemptQuickStart() const;
    bool m_fullStartDone;
474
    bool m_systemDumpersLoaded;
hjk's avatar
hjk committed
475
476
477
478

    // Test
    QList<WatchData> m_completed;
    QSet<QByteArray> m_uncompleted;
479
480
481
482
483
484
485

    static QString msgGdbStopFailed(const QString &why);
    static QString msgInferiorStopFailed(const QString &why);
    static QString msgAttachedToStoppedInferior();
    static QString msgInferiorSetupOk();
    static QString msgInferiorRunOk();
    static QString msgConnectRemoteServerFailed(const QString &why);
486
    static QByteArray dotEscape(QByteArray str);
487

hjk's avatar
hjk committed
488
    void debugLastCommand();
489
    DebuggerCommand m_lastDebuggableCommand;
hjk's avatar
hjk committed
490

491
492
493
494
495
496
protected:
    virtual void write(const QByteArray &data);

protected:
    bool prepareCommand();
    void interruptLocalInferior(qint64 pid);
497
498

    GdbProcess *m_gdbProc;
499
    ProjectExplorer::DeviceProcessSignalOperation::Ptr m_signalOperation;
con's avatar
con committed
500
501
502
503
504
};

} // namespace Internal
} // namespace Debugger

505
506
Q_DECLARE_OPERATORS_FOR_FLAGS(Debugger::Internal::GdbEngine::GdbCommandFlags)

con's avatar
con committed
507
#endif // DEBUGGER_GDBENGINE_H