gdbengine.h 16.8 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2 3 4
**
** This file is part of Qt Creator
**
5
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
6
**
7
** Contact: Nokia Corporation (qt-info@nokia.com)
con's avatar
con committed
8
**
9
** Commercial Usage
10
**
11 12 13 14
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
15
**
16
** GNU Lesser General Public License Usage
17
**
18 19 20 21 22 23
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24
**
25
** If you are unsure which license is appropriate for your use, please
hjk's avatar
hjk committed
26
** contact the sales department at http://qt.nokia.com/contact.
con's avatar
con committed
27
**
28
**************************************************************************/
hjk's avatar
hjk committed
29

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

33 34
#include "idebuggerengine.h"
#include "gdbmi.h"
35
#include "outputcollector.h"
36
#include "watchutils.h"
37

38 39
#include <consoleprocess.h>

con's avatar
con committed
40 41 42 43 44 45
#include <QtCore/QByteArray>
#include <QtCore/QHash>
#include <QtCore/QMap>
#include <QtCore/QObject>
#include <QtCore/QProcess>
#include <QtCore/QPoint>
46
#include <QtCore/QTextCodec>
47
#include <QtCore/QTime>
con's avatar
con committed
48 49 50 51 52 53 54 55 56 57 58
#include <QtCore/QVariant>

QT_BEGIN_NAMESPACE
class QAction;
class QAbstractItemModel;
class QWidget;
QT_END_NAMESPACE

namespace Debugger {
namespace Internal {

59

con's avatar
con committed
60 61 62 63 64 65 66 67
class DebuggerManager;
class IDebuggerManagerAccessForEngines;
class GdbResultRecord;
class GdbMi;

class WatchData;
class BreakpointData;

68
enum DebuggingHelperState
con's avatar
con committed
69
{
70 71 72 73
    DebuggingHelperUninitialized,
    DebuggingHelperLoadTried,
    DebuggingHelperAvailable,
    DebuggingHelperUnavailable,
con's avatar
con committed
74 75
};

76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
// GdbProcessBase is inherited by GdbProcess and the gdb/trk Adapter.
// In the GdbProcess case it's just a wrapper around a QProcess running
// gdb, in the Adapter case it's the interface to the gdb process in
// the whole rfomm/gdb/gdbserver combo.
class GdbProcessBase : public QObject
{
    Q_OBJECT

public:
    GdbProcessBase(QObject *parent) : QObject(parent) {}

    virtual void start(const QString &program, const QStringList &args,
        QIODevice::OpenMode mode = QIODevice::ReadWrite) = 0;
    virtual void kill() = 0;
    virtual void terminate() = 0;
    virtual bool waitForStarted(int msecs = 30000) = 0;
    virtual bool waitForFinished(int msecs = 30000) = 0;
    virtual QProcess::ProcessState state() const = 0;
    virtual QString errorString() const = 0;
    virtual QByteArray readAllStandardError() = 0;
    virtual QByteArray readAllStandardOutput() = 0;
    virtual qint64 write(const char *data) = 0;
    virtual void setWorkingDirectory(const QString &dir) = 0;
    virtual void setEnvironment(const QStringList &env) = 0;

signals:
    void error(QProcess::ProcessError);
    void readyReadStandardOutput();
    void readyReadStandardError();
    void finished(int, QProcess::ExitStatus);
};

class GdbProcess : public GdbProcessBase
{
public:
    GdbProcess(QObject *parent = 0)
        : GdbProcessBase(parent)
    {
        connect(&m_proc, SIGNAL(error(QProcess::ProcessError)),
            this, SIGNAL(error(QProcess::ProcessError)));
        connect(&m_proc, SIGNAL(readyReadStandardOutput()),
            this, SIGNAL(readyReadStandardOutput()));
        connect(&m_proc, SIGNAL(readyReadStandardError()),
            this, SIGNAL(readyReadStandardError()));
        connect(&m_proc, SIGNAL(finished(int, QProcess::ExitStatus)),
            this, SIGNAL(finished(int, QProcess::ExitStatus)));
    }

    void start(const QString &program, const QStringList &args,
        QIODevice::OpenMode mode) { m_proc.start(program, args, mode); }
    void kill() { m_proc.kill(); }
    void terminate() { m_proc.terminate(); }
    bool waitForStarted(int msecs) { return m_proc.waitForStarted(msecs); }
    bool waitForFinished(int msecs) { return m_proc.waitForFinished(msecs); }
    QProcess::ProcessState state() const { return m_proc.state(); }
    QString errorString() const { return m_proc.errorString(); }
    QByteArray readAllStandardError() { return m_proc.readAllStandardError(); }
    QByteArray readAllStandardOutput() { return m_proc.readAllStandardOutput(); }
    qint64 write(const char *data) { return m_proc.write(data); }
    void setWorkingDirectory(const QString &dir) { m_proc.setWorkingDirectory(dir); }
    void setEnvironment(const QStringList &env) { m_proc.setEnvironment(env); }

private:
    QProcess m_proc;
};
hjk's avatar
hjk committed
141

con's avatar
con committed
142 143 144 145 146
class GdbEngine : public IDebuggerEngine
{
    Q_OBJECT

public:
147
    GdbEngine(DebuggerManager *parent, GdbProcessBase *gdbProc);
con's avatar
con committed
148 149 150
    ~GdbEngine();

signals:
151 152
    void gdbInputAvailable(int channel, const QString &msg);
    void gdbOutputAvailable(int channel, const QString &msg);
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
153
    void applicationOutputAvailable(const QString &output);
con's avatar
con committed
154 155 156 157 158 159 160 161 162 163 164 165

private:
    //
    // IDebuggerEngine implementation
    //
    void stepExec();
    void stepOutExec();
    void nextExec();
    void stepIExec();
    void nextIExec();

    void shutdown();
166
    void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos);
167
    bool startDebugger(const QSharedPointer<DebuggerStartParameters> &sp);
con's avatar
con committed
168
    void exitDebugger();
169
    void detachDebugger();
con's avatar
con committed
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184

    void continueInferior();
    void interruptInferior();

    void runToLineExec(const QString &fileName, int lineNumber);
    void runToFunctionExec(const QString &functionName);
    void jumpToLineExec(const QString &fileName, int lineNumber);

    void activateFrame(int index);
    void selectThread(int index);

    Q_SLOT void attemptBreakpointSynchronization();

    void assignValueInDebugger(const QString &expr, const QString &value);
    void executeDebuggerCommand(const QString & command);
185
    void watchPoint(const QPoint &);
con's avatar
con committed
186 187 188

    void loadSymbols(const QString &moduleName);
    void loadAllSymbols();
189
    virtual QList<Symbol> moduleSymbols(const QString &moduleName);
con's avatar
con committed
190

191 192 193
    void fetchMemory(MemoryViewAgent *agent, quint64 addr, quint64 length);
    void handleFetchMemory(const GdbResultRecord &record, const QVariant &cookie);

194 195 196 197 198 199 200 201 202 203 204
    void fetchDisassembler(DisassemblerViewAgent *agent,
        const StackFrame &frame);
    void fetchDisassemblerByAddress(DisassemblerViewAgent *agent,
        bool useMixedMode);
    void handleFetchDisassemblerByLine(const GdbResultRecord &record,
        const QVariant &cookie);
    void handleFetchDisassemblerByAddress1(const GdbResultRecord &record,
        const QVariant &cookie);
    void handleFetchDisassemblerByAddress0(const GdbResultRecord &record,
        const QVariant &cookie);

205 206
    Q_SLOT void setDebugDebuggingHelpers(const QVariant &on);
    Q_SLOT void setUseDebuggingHelpers(const QVariant &on);
207

con's avatar
con committed
208 209 210
    //
    // Own stuff
    //
211

con's avatar
con committed
212 213 214 215
    int currentFrame() const;

    bool supportsThreads() const;

216 217
    void initializeConnections();
    void initializeVariables();
con's avatar
con committed
218 219 220 221 222 223
    QString fullName(const QString &fileName);
    // get one usable name out of these, try full names first
    QString fullName(const QStringList &candidates);

    void handleResult(const GdbResultRecord &, int type, const QVariant &);

224 225 226 227 228 229
public: // otherwise the Qt flag macros are unhappy
    enum GdbCommandFlag {
        NoFlags = 0,
        NeedsStop = 1,
        Discardable = 2,
        RebuildModel = 4,
230
        WatchUpdate = Discardable | RebuildModel,
231
        EmbedToken = 8
232 233 234
    };
    Q_DECLARE_FLAGS(GdbCommandFlags, GdbCommandFlag)

235
private:
236 237 238 239 240 241 242 243 244 245 246
    typedef void (GdbEngine::*GdbCommandCallback)(const GdbResultRecord &record, const QVariant &cookie);

    struct GdbCommand
    {
        GdbCommand() : flags(0), callback(0), callbackName(0) {}

        int flags;
        GdbCommandCallback callback;
        const char *callbackName;
        QString command;
        QVariant cookie;
247
        QTime postTime;
248 249
    };

con's avatar
con committed
250 251 252 253
    // type and cookie are sender-internal data, opaque for the "event
    // queue". resultNeeded == true increments m_pendingResults on
    // send and decrements on receipt, effectively preventing 
    // watch model updates before everything is finished.
254
    void flushCommand(GdbCommand &cmd);
255
    void postCommand(const QString &command,
256 257 258 259
                     GdbCommandFlags flags,
                     GdbCommandCallback callback = 0,
                     const char *callbackName = 0,
                     const QVariant &cookie = QVariant());
260
    void postCommand(const QString &command,
261 262 263
                     GdbCommandCallback callback = 0,
                     const char *callbackName = 0,
                     const QVariant &cookie = QVariant());
con's avatar
con committed
264 265 266 267 268 269 270 271 272

    void setTokenBarrier();

    void updateLocals();

private slots:
    void gdbProcError(QProcess::ProcessError error);
    void readGdbStandardOutput();
    void readGdbStandardError();
273 274
    void readUploadStandardOutput();
    void readUploadStandardError();
275
    void readDebugeeOutput(const QByteArray &data);
276 277
    void stubStarted();
    void stubError(const QString &msg);
278
    void uploadProcError(QProcess::ProcessError error);
con's avatar
con committed
279 280 281

private:
    int terminationIndex(const QByteArray &buffer, int &length);
282
    void handleResponse(const QByteArray &buff);
283 284 285
    void handleStart(const GdbResultRecord &response, const QVariant &);
    void handleAttach(const GdbResultRecord &, const QVariant &);
    void handleStubAttached(const GdbResultRecord &, const QVariant &);
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
286
    void handleAqcuiredInferior();
287
    void handleAsyncOutput2(const GdbResultRecord &, const QVariant &cookie);
con's avatar
con committed
288 289 290
    void handleAsyncOutput2(const GdbMi &data);
    void handleAsyncOutput(const GdbMi &data);
    void handleResultRecord(const GdbResultRecord &response);
291
    void handleFileExecAndSymbols(const GdbResultRecord &response, const QVariant &);
hjk's avatar
hjk committed
292
    void handleExecContinue(const GdbResultRecord &response, const QVariant &);
293 294 295 296 297 298 299 300 301 302 303
    void handleExecRun(const GdbResultRecord &response, const QVariant &);
    void handleExecJumpToLine(const GdbResultRecord &response, const QVariant &);
    void handleExecRunToFunction(const GdbResultRecord &response, const QVariant &);
    void handleInfoShared(const GdbResultRecord &response, const QVariant &);
    void handleInfoProc(const GdbResultRecord &response, const QVariant &);
    void handleInfoThreads(const GdbResultRecord &response, const QVariant &);
    void handleShowVersion(const GdbResultRecord &response, const QVariant &);
    void handleQueryPwd(const GdbResultRecord &response, const QVariant &);
    void handleQuerySources(const GdbResultRecord &response, const QVariant &);
    void handleTargetCore(const GdbResultRecord &, const QVariant &);
    void handleExit(const GdbResultRecord &, const QVariant &);
304 305
    void handleSetTargetAsync(const GdbResultRecord &, const QVariant &);
    void handleTargetRemote(const GdbResultRecord &, const QVariant &);
306
    void handleWatchPoint(const GdbResultRecord &, const QVariant &);
hjk's avatar
hjk committed
307
    void debugMessage(const QString &msg);
308
    bool showToolTip();
con's avatar
con committed
309

310 311
    void handleChildren(const WatchData &parent, const GdbMi &child,
        QList<WatchData> *insertions);
312 313
    const bool m_dumperInjectionLoad;

314 315 316 317
    OutputCollector m_outputCollector;
    QTextCodec *m_outputCodec;
    QTextCodec::ConverterState m_outputCodecState;

con's avatar
con committed
318 319
    QByteArray m_inbuffer;

320
    GdbProcessBase *m_gdbProc;
321
    QProcess m_uploadProc;
con's avatar
con committed
322

323 324
    Core::Utils::ConsoleProcess m_stubProc;

325
    QHash<int, GdbCommand> m_cookieForToken;
con's avatar
con committed
326 327 328 329 330 331 332 333 334 335 336 337
    QHash<int, QByteArray> m_customOutputForToken;

    QByteArray m_pendingConsoleStreamOutput;
    QByteArray m_pendingTargetStreamOutput;
    QByteArray m_pendingLogStreamOutput;

    // contains the first token number for the current round
    // of evaluation. Responses with older tokens are considers
    // out of date and discarded.
    int m_oldestAcceptableToken;

    int m_gdbVersion; // 6.8.0 is 680
hjk's avatar
hjk committed
338
    int m_gdbBuildVersion; // MAC only? 
con's avatar
con committed
339 340

    // awful hack to keep track of used files
341 342
    QMap<QString, QString> m_shortToFullName;
    QMap<QString, QString> m_fullToShortName;
con's avatar
con committed
343 344 345 346

    //
    // Breakpoint specific stuff
    //
347
    void handleBreakList(const GdbResultRecord &record, const QVariant &);
con's avatar
con committed
348
    void handleBreakList(const GdbMi &table);
349 350 351 352 353
    void handleBreakIgnore(const GdbResultRecord &record, const QVariant &cookie);
    void handleBreakInsert(const GdbResultRecord &record, const QVariant &cookie);
    void handleBreakInsert1(const GdbResultRecord &record, const QVariant &cookie);
    void handleBreakCondition(const GdbResultRecord &record, const QVariant &cookie);
    void handleBreakInfo(const GdbResultRecord &record, const QVariant &cookie);
con's avatar
con committed
354 355 356 357 358 359 360 361
    void extractDataFromInfoBreak(const QString &output, BreakpointData *data);
    void breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt);
    void sendInsertBreakpoint(int index);

    //
    // Modules specific stuff
    //
    void reloadModules();
362
    void handleModulesList(const GdbResultRecord &record, const QVariant &);
con's avatar
con committed
363 364 365 366 367


    //
    // Register specific stuff
    // 
368
    Q_SLOT void reloadRegisters();
369
    void setRegisterValue(int nr, const QString &value);
370 371
    void handleRegisterListNames(const GdbResultRecord &record, const QVariant &);
    void handleRegisterListValues(const GdbResultRecord &record, const QVariant &);
con's avatar
con committed
372

373 374 375 376
    //
    // Source file specific stuff
    // 
    void reloadSourceFiles();
con's avatar
con committed
377 378 379 380

    //
    // Stack specific stuff
    // 
381 382 383
    void handleStackListFrames(const GdbResultRecord &record, const QVariant &cookie);
    void handleStackSelectThread(const GdbResultRecord &, const QVariant &);
    void handleStackListThreads(const GdbResultRecord &record, const QVariant &cookie);
384 385
    Q_SLOT void reloadStack();
    Q_SLOT void reloadFullStack();
con's avatar
con committed
386 387 388 389 390 391 392 393 394 395 396 397 398 399


    //
    // Tooltip specific stuff
    // 
    void sendToolTipCommand(const QString &command, const QString &cookie);


    //
    // Watch specific stuff
    //
    // FIXME: BaseClass. called to improve situation for a watch item
    void updateSubItem(const WatchData &data);

400
    void updateWatchData(const WatchData &data);
401
    Q_SLOT void updateWatchDataHelper(const WatchData &data);
hjk's avatar
hjk committed
402
    void rebuildModel();
con's avatar
con committed
403 404 405 406 407 408 409

    void insertData(const WatchData &data);
    void sendWatchParameters(const QByteArray &params0);
    void createGdbVariable(const WatchData &data);

    void maybeHandleInferiorPidChanged(const QString &pid);

410
    void tryLoadDebuggingHelpers();
411
    void tryQueryDebuggingHelpers();
412 413 414 415
    Q_SLOT void recheckDebuggingHelperAvailability();
    void runDebuggingHelper(const WatchData &data, bool dumpChildren);
    void runDirectDebuggingHelper(const WatchData &data, bool dumpChildren);
    bool hasDebuggingHelperForType(const QString &type) const;
con's avatar
con committed
416 417

    void handleVarListChildren(const GdbResultRecord &record,
418
        const QVariant &cookie);
con's avatar
con committed
419
    void handleVarCreate(const GdbResultRecord &record,
420 421
        const QVariant &cookie);
    void handleVarAssign(const GdbResultRecord &, const QVariant &);
con's avatar
con committed
422
    void handleEvaluateExpression(const GdbResultRecord &record,
423
        const QVariant &cookie);
424 425
    //void handleToolTip(const GdbResultRecord &record,
    //    const QVariant &cookie);
426
    void handleQueryDebuggingHelper(const GdbResultRecord &record, const QVariant &);
427
    void handleDebuggingHelperValue1(const GdbResultRecord &record,
428
        const QVariant &cookie);
429
    void handleDebuggingHelperValue2(const GdbResultRecord &record,
430
        const QVariant &cookie);
431
    void handleDebuggingHelperValue3(const GdbResultRecord &record,
432
        const QVariant &cookie);
433
    void handleDebuggingHelperEditValue(const GdbResultRecord &record);
434 435 436
    void handleDebuggingHelperSetup(const GdbResultRecord &record, const QVariant &);
    void handleStackListLocals(const GdbResultRecord &record, const QVariant &);
    void handleStackListArguments(const GdbResultRecord &record, const QVariant &);
con's avatar
con committed
437 438 439
    void handleVarListChildrenHelper(const GdbMi &child,
        const WatchData &parent);
    void setWatchDataType(WatchData &data, const GdbMi &mi);
440
    void setWatchDataDisplayedType(WatchData &data, const GdbMi &mi);
hjk's avatar
hjk committed
441
    void setLocals(const QList<GdbMi> &locals);
442 443
   
    bool startModeAllowsDumpers() const;
444
    QString parseDisassembler(const GdbMi &lines);
con's avatar
con committed
445 446

    int m_pendingRequests;
447
    QSet<QString> m_processedNames; 
con's avatar
con committed
448

449
    QtDumperHelper m_dumperHelper;
con's avatar
con committed
450
    
451
    DebuggingHelperState m_debuggingHelperState;
con's avatar
con committed
452 453 454 455
    QList<GdbMi> m_currentFunctionArgs;
    QString m_currentFrame;
    QMap<QString, QString> m_varToType;

456
    bool m_autoContinue;
457
    bool m_waitingForFirstBreakpointToBeHit;
458
    bool m_modulesListOutdated;
459

460
    QList<GdbCommand> m_commandsToRunOnTemporaryBreak;
hjk's avatar
hjk committed
461

462 463 464
    DebuggerManager * const q;
    IDebuggerManagerAccessForEngines * const qq;
    // make sure to re-initialize new members in initializeVariables();
con's avatar
con committed
465 466 467 468 469
};

} // namespace Internal
} // namespace Debugger

470 471
Q_DECLARE_OPERATORS_FOR_FLAGS(Debugger::Internal::GdbEngine::GdbCommandFlags)

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