gdbengine.h 15.6 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
3 4
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://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
12 13 14
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
15
**
16 17 18 19 20 21 22
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
con's avatar
con committed
23
**
hjk's avatar
hjk committed
24
****************************************************************************/
hjk's avatar
hjk committed
25

hjk's avatar
hjk committed
26
#pragma once
con's avatar
con committed
27

28
#include <debugger/debuggerengine.h>
29

30
#include <debugger/breakhandler.h>
31
#include <debugger/registerhandler.h>
32 33
#include <debugger/watchhandler.h>
#include <debugger/watchutils.h>
34
#include <debugger/debuggeritem.h>
35
#include <debugger/debuggertooltipmanager.h>
36
#include <debugger/outputcollector.h>
37

hjk's avatar
hjk committed
38 39
#include <coreplugin/id.h>

40
#include <utils/qtcprocess.h>
41

42 43 44
#include <QProcess>
#include <QTextCodec>
#include <QTimer>
con's avatar
con committed
45 46 47 48

namespace Debugger {
namespace Internal {

49 50
class BreakpointParameters;
class BreakpointResponse;
51 52
class DebugInfoTask;
class DebugInfoTaskHandler;
53
class DebuggerResponse;
54
class DisassemblerAgentCookie;
con's avatar
con committed
55
class GdbMi;
56
class MemoryAgentCookie;
con's avatar
con committed
57

58 59 60 61 62 63 64 65 66
struct CoreInfo
{
    QString rawStringFromCore;
    QString foundExecutableName; // empty if no corresponding exec could be found
    bool isCore = false;

    static CoreInfo readExecutableNameFromCore(const ProjectExplorer::StandardRunnable &debugger,
                                               const QString &coreFile);
};
con's avatar
con committed
67

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

public:
73
    GdbEngine();
74
    ~GdbEngine() final;
hjk's avatar
hjk committed
75

76
private: ////////// General Interface //////////
77
    DebuggerEngine *cppEngine() final { return this; }
con's avatar
con committed
78

79 80
    void handleGdbStartFailed();
    void prepareForRestart() final;
hjk's avatar
hjk committed
81

82 83 84
    bool hasCapability(unsigned) const final;
    void detachDebugger() final;
    void shutdownInferior() final;
hjk's avatar
hjk committed
85
    void abortDebuggerProcess() final;
86
    void resetInferior() final;
con's avatar
con committed
87

88 89
    bool acceptsDebuggerCommands() const final;
    void executeDebuggerCommand(const QString &command, DebuggerLanguages languages) final;
con's avatar
con committed
90

91
    ////////// General State //////////
con's avatar
con committed
92

93
    bool m_registerNamesListed = false;
94

95
    ////////// Gdb Process Management //////////
96

97 98
    void handleInferiorShutdown(const DebuggerResponse &response);
    void handleGdbExit(const DebuggerResponse &response);
99
    void setLinuxOsAbi();
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
100

101
    void loadInitScript();
102
    void setEnvironmentVariables();
hjk's avatar
hjk committed
103

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

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

115
    void handleDebugInfoLocation(const DebuggerResponse &response);
116

117 118
    // The engine is still running just fine, but it failed to acquire a debuggee.
    void notifyInferiorSetupFailedHelper(const QString &msg);
hjk's avatar
hjk committed
119

120
    void handleGdbFinished(int exitCode, QProcess::ExitStatus exitStatus);
121 122 123
    void handleGdbError(QProcess::ProcessError error);
    void readGdbStandardOutput();
    void readGdbStandardError();
hjk's avatar
hjk committed
124
    void readDebuggeeOutput(const QByteArray &ba);
125

126 127 128 129
    QTextCodec *m_gdbOutputCodec;
    QTextCodec::ConverterState m_gdbOutputCodecState;
    QTextCodec *m_inferiorOutputCodec;
    QTextCodec::ConverterState m_inferiorOutputCodecState;
130 131

    QByteArray m_inbuffer;
132
    bool m_busy = false;
con's avatar
con committed
133

134 135
    // Name of the convenience variable containing the last
    // known function return value.
hjk's avatar
hjk committed
136
    QString m_resultVarName;
137

138
    ////////// Gdb Command Management //////////
139

140
    void runCommand(const DebuggerCommand &command) final;
141

hjk's avatar
hjk committed
142
    void commandTimeout();
con's avatar
con committed
143 144
    void setTokenBarrier();

145
    // Sets up an "unexpected result" for the following commeand.
hjk's avatar
hjk committed
146
    void scheduleTestResponse(int testCase, const QString &response);
147

148
    QHash<int, DebuggerCommand> m_commandForToken;
149
    QHash<int, int> m_flagsForToken;
150
    int commandTimeoutTime() const;
151
    QTimer m_commandTimer;
con's avatar
con committed
152

hjk's avatar
hjk committed
153 154
    QString m_pendingConsoleStreamOutput;
    QString m_pendingLogStreamOutput;
155

156
    // This contains the first token number for the current round
157 158
    // of evaluation. Responses with older tokens are considers
    // out of date and discarded.
159 160
    int m_oldestAcceptableToken = -1;
    int m_nonDiscardableCount = 0;
con's avatar
con committed
161

162
    int m_pendingBreakpointRequests = 0; // Watch updating commands in flight
hjk's avatar
hjk committed
163

164
    typedef void (GdbEngine::*CommandsDoneCallback)();
165
    // This function is called after all previous responses have been received.
166 167 168
    CommandsDoneCallback m_commandsDoneCallback = nullptr;

    bool m_rerunPending = false;
hjk's avatar
hjk committed
169

170
    ////////// Gdb Output, State & Capability Handling //////////
171

172
    Q_INVOKABLE void handleResponse(const QString &buff);
hjk's avatar
hjk committed
173
    void handleAsyncOutput(const QString &asyncClass, const GdbMi &result);
174
    void handleStopResponse(const GdbMi &data);
175
    void handleResultRecord(DebuggerResponse *response);
176
    void handleStop1(const GdbMi &data);
177
    void handleStop2(const GdbMi &data);
hjk's avatar
hjk committed
178
    void handleStop3();
179
    void resetCommandQueue();
180

181
    bool isSynchronous() const final { return true; }
182 183

    // Gdb initialization sequence
184 185 186
    void handleShowVersion(const DebuggerResponse &response);
    void handleListFeatures(const DebuggerResponse &response);
    void handlePythonSetup(const DebuggerResponse &response);
con's avatar
con committed
187

188 189 190
    int m_gdbVersion = 100;    // 7.6.1 is 70601
    int m_pythonVersion = 0; // 2.7.2 is 20702
    bool m_isQnxGdb = false;
hjk's avatar
hjk committed
191

192
    ////////// Inferior Management //////////
193

194
    // This should be always the last call in a function.
195 196 197 198 199 200 201 202 203 204 205 206
    bool stateAcceptsBreakpointChanges() const final;
    bool acceptsBreakpoint(Breakpoint bp) const final;
    void insertBreakpoint(Breakpoint bp) final;
    void removeBreakpoint(Breakpoint bp) final;
    void changeBreakpoint(Breakpoint bp) final;

    void executeStep() final;
    void executeStepOut() final;
    void executeNext() final;
    void executeStepI() final;
    void executeNextI() final;

207
    void continueInferiorInternal();
208 209
    void continueInferior() final;
    void interruptInferior() final;
con's avatar
con committed
210

211 212 213 214
    void executeRunToLine(const ContextData &data) final;
    void executeRunToFunction(const QString &functionName) final;
    void executeJumpToLine(const ContextData &data) final;
    void executeReturn() final;
con's avatar
con committed
215

216 217 218 219 220 221
    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
222

223
    QString msgPtraceError(DebuggerStartMode sm);
224

225
    ////////// View & Data Stuff //////////
226

227 228
    void selectThread(ThreadId threadId) final;
    void activateFrame(int index) final;
hjk's avatar
hjk committed
229
    void handleAutoContinueInferior();
230

con's avatar
con committed
231 232 233
    //
    // Breakpoint specific stuff
    //
234
    void handleBreakModifications(const GdbMi &bkpts);
235 236 237 238 239 240 241 242
    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);
243 244
    void handleInsertInterpreterBreakpoint(const DebuggerResponse &response, Breakpoint bp);
    void handleInterpreterBreakpointModified(const GdbMi &data);
245 246
    void handleWatchInsert(const DebuggerResponse &response, Breakpoint bp);
    void handleCatchInsert(const DebuggerResponse &response, Breakpoint bp);
247
    void handleBkpt(const GdbMi &bkpt, Breakpoint bp);
hjk's avatar
hjk committed
248
    void updateResponse(BreakpointResponse &response, const GdbMi &bkpt);
hjk's avatar
hjk committed
249 250
    QString breakpointLocation(const BreakpointParameters &data); // For gdb/MI.
    QString breakpointLocation2(const BreakpointParameters &data); // For gdb/CLI fallback.
251
    QString breakLocation(const QString &file) const;
con's avatar
con committed
252 253 254 255

    //
    // Modules specific stuff
    //
256 257 258 259 260 261 262
    void loadSymbols(const QString &moduleName) final;
    void loadAllSymbols() final;
    void loadSymbolsForStack() final;
    void requestModuleSymbols(const QString &moduleName) final;
    void requestModuleSections(const QString &moduleName) final;
    void reloadModules() final;
    void examineModules() final;
263

264
    void reloadModulesInternal();
265
    void handleModulesList(const DebuggerResponse &response);
266
    void handleShowModuleSections(const DebuggerResponse &response, const QString &moduleName);
con's avatar
con committed
267

268 269 270
    //
    // Snapshot specific stuff
    //
271
    void createSnapshot() final;
272
    void handleMakeSnapshot(const DebuggerResponse &response, const QString &coreFile);
273

con's avatar
con committed
274 275
    //
    // Register specific stuff
hjk's avatar
hjk committed
276
    //
277 278
    void reloadRegisters() final;
    void setRegisterValue(const QString &name, const QString &value) final;
279
    void handleRegisterListNames(const DebuggerResponse &response);
280
    void handleRegisterListing(const DebuggerResponse &response);
281 282
    void handleRegisterListValues(const DebuggerResponse &response);
    void handleMaintPrintRegisters(const DebuggerResponse &response);
283
    QHash<int, Register> m_registers; // Map GDB register numbers to indices
con's avatar
con committed
284

285 286 287
    //
    // Disassembler specific stuff
    //
288
    // Chain of fallbacks: PointMixed -> PointPlain -> RangeMixed -> RangePlain.
289
    void fetchDisassembler(DisassemblerAgent *agent) final;
290 291 292
    void fetchDisassemblerByCliPointMixed(const DisassemblerAgentCookie &ac);
    void fetchDisassemblerByCliRangeMixed(const DisassemblerAgentCookie &ac);
    void fetchDisassemblerByCliRangePlain(const DisassemblerAgentCookie &ac);
hjk's avatar
hjk committed
293
    bool handleCliDisassemblerResult(const QString &response, DisassemblerAgent *agent);
294

295 296
    //
    // Source file specific stuff
hjk's avatar
hjk committed
297
    //
298
    void reloadSourceFiles() final;
299
    void reloadSourceFilesInternal();
300
    void handleQuerySources(const DebuggerResponse &response);
301 302

    QString fullName(const QString &fileName);
303
    QString cleanupFullName(const QString &fileName);
304 305 306 307

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

310
    bool m_sourcesListUpdating = false;
311

con's avatar
con committed
312 313
    //
    // Stack specific stuff
hjk's avatar
hjk committed
314
    //
315
    void updateAll() final;
316
    void handleStackListFrames(const DebuggerResponse &response, bool isFull);
317 318 319 320
    void handleStackSelectThread(const DebuggerResponse &response);
    void handleThreadListIds(const DebuggerResponse &response);
    void handleThreadInfo(const DebuggerResponse &response);
    void handleThreadNames(const DebuggerResponse &response);
321
    DebuggerCommand stackCommand(int depth);
hjk's avatar
hjk committed
322
    void reloadStack();
323 324
    void reloadFullStack() final;
    void loadAdditionalQmlStack() final;
325
    int currentFrame() const;
con's avatar
con committed
326 327

    //
328
    // Watch specific stuff
hjk's avatar
hjk committed
329
    //
330 331 332
    void reloadLocals();
    void assignValueInDebugger(WatchItem *item,
        const QString &expr, const QVariant &value) final;
333

334
    void fetchMemory(MemoryAgent *agent, quint64 addr, quint64 length) final;
335
    void fetchMemoryHelper(const MemoryAgentCookie &cookie);
336
    void handleChangeMemory(const DebuggerResponse &response);
337
    void changeMemory(MemoryAgent *agent, quint64 addr, const QByteArray &data) final;
338
    void handleFetchMemory(const DebuggerResponse &response, MemoryAgentCookie ac);
339

hjk's avatar
hjk committed
340
    void showToolTip();
con's avatar
con committed
341

342
    void handleVarAssign(const DebuggerResponse &response);
343 344 345
    void handleThreadGroupCreated(const GdbMi &result);
    void handleThreadGroupExited(const GdbMi &result);

hjk's avatar
hjk committed
346
    void createFullBacktrace();
347

348
    void doUpdateLocals(const UpdateParameters &parameters) final;
349
    void handleFetchVariables(const DebuggerResponse &response);
350

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

353 354 355
    //
    // Dumper Management
    //
356
    void reloadDebuggingHelpers() final;
357

358
    //
359 360
    // Convenience Functions
    //
hjk's avatar
hjk committed
361
    void showExecutionError(const QString &message);
362
    QString failedToStartMessage();
363

364
    // For short-circuiting stack and thread list evaluation.
365
    bool m_stackNeeded = false;
366

367 368
    // For suppressing processing *stopped and *running responses
    // while updating locals.
369
    bool m_inUpdateLocals = false;
370

371
    // HACK:
hjk's avatar
hjk committed
372
    QString m_currentThread;
373
    QString m_lastWinException;
374
    QString m_lastMissingDebugInfo;
375
    bool m_expectTerminalTrap = false;
376
    bool usesExecInterrupt() const;
377
    bool usesTargetAsync() const;
378

hjk's avatar
hjk committed
379 380
    DebuggerCommandSequence m_onStop;

hjk's avatar
hjk committed
381
    QHash<int, QString> m_scheduledTestResponses;
382
    QSet<int> m_testCases;
383 384 385 386 387

    // Debug information
    friend class DebugInfoTaskHandler;
    void requestDebugInformation(const DebugInfoTask &task);
    DebugInfoTaskHandler *m_debugInfoTaskHandler;
388

389
    bool m_systemDumpersLoaded = false;
hjk's avatar
hjk committed
390

391 392 393 394 395 396 397
    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);

398
    void debugLastCommand() final;
399
    DebuggerCommand m_lastDebuggableCommand;
hjk's avatar
hjk committed
400

401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
    bool isPlainEngine() const;
    bool isCoreEngine() const;
    bool isRemoteEngine() const;
    bool isAttachEngine() const;
    bool isTermEngine() const;

    void setupEngine() final;
    void setupInferior() final;
    void runEngine() final;
    void shutdownEngine() final;

    void interruptInferior2();

    // Plain
    void handleExecRun(const DebuggerResponse &response);
    void handleFileExecAndSymbols(const DebuggerResponse &response);

    // Attach
    void handleAttach(const DebuggerResponse &response);

    // Remote
    void callTargetRemote();
    void handleSetTargetAsync(const DebuggerResponse &response);
    void handleTargetRemote(const DebuggerResponse &response);
    void handleTargetExtendedRemote(const DebuggerResponse &response);
    void handleTargetExtendedAttach(const DebuggerResponse &response);
    void handleTargetQnx(const DebuggerResponse &response);
    void handleSetNtoExecutable(const DebuggerResponse &response);
    void handleInterruptInferior(const DebuggerResponse &response);
430
    void interruptLocalInferior(qint64 pid);
431

432
    // Terminal
433
    void handleStubAttached(const DebuggerResponse &response, qint64 mainThreadId);
434 435 436 437 438 439

    // Core
    void handleTargetCore(const DebuggerResponse &response);
    void handleCoreRoundTrip(const DebuggerResponse &response);
    QString coreFileName() const;

440
    QString mainFunction() const;
441

442
    Utils::QtcProcess m_gdbProc;
443
    OutputCollector m_outputCollector;
444
    QString m_errorString;
con's avatar
con committed
445 446 447 448
};

} // namespace Internal
} // namespace Debugger