#ifndef DEBUGGER_H #define DEBUGGER_H #include #include #include #include #include #include #include #include #include #include #include #include enum class DebugCommandSource { Console, Other }; struct DebugCommand{ QString command; QString params; bool updateWatch; bool showInConsole; DebugCommandSource source; }; using PDebugCommand = std::shared_ptr; struct WatchVar; using PWatchVar = std::shared_ptr; struct WatchVar { QString name; QString value; QString fullName; int gdbIndex; QList children; WatchVar * parent; //use raw point to prevent circular-reference }; struct Breakpoint { int number; // breakpoint number QString type; // type of the breakpoint QString catch_type; int line; QString filename; QString condition; bool enabled; }; using PBreakpoint = std::shared_ptr; struct Trace { QString funcname; QString filename; int line; }; using PTrace = std::shared_ptr; struct Register { QString name; QString hexValue; QString decValue; }; using PRegister = std::shared_ptr; class RegisterModel: public QAbstractTableModel { Q_OBJECT public: explicit RegisterModel(QObject* parent = nullptr); int rowCount(const QModelIndex &parent) const override; int columnCount(const QModelIndex &parent) const override; QVariant data(const QModelIndex &index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; void update(const QList& regs); void clear(); private: QList mRegisters; }; class BreakpointModel: public QAbstractTableModel { Q_OBJECT // QAbstractItemModel interface public: explicit BreakpointModel(QObject *parent = nullptr); int rowCount(const QModelIndex &parent) const override; int columnCount(const QModelIndex &parent) const override; QVariant data(const QModelIndex &index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; void addBreakpoint(PBreakpoint p); void clear(); void removeBreakpoint(int index); PBreakpoint setBreakPointCondition(int index, const QString& condition); const QList& breakpoints() const; PBreakpoint breakpoint(int index) const; void save(const QString& filename); void load(const QString& filename); public slots: void onFileDeleteLines(const QString& filename, int startLine, int count); void onFileInsertLines(const QString& filename, int startLine, int count); private: QList mList; }; class BacktraceModel : public QAbstractTableModel { Q_OBJECT // QAbstractItemModel interface public: explicit BacktraceModel(QObject *parent = nullptr); int rowCount(const QModelIndex &parent) const override; int columnCount(const QModelIndex &parent) const override; QVariant data(const QModelIndex &index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; void addTrace(PTrace p); void clear(); void removeTrace(int index); const QList& backtraces() const; PTrace backtrace(int index) const; private: QList mList; }; class WatchModel: public QAbstractItemModel { Q_OBJECT public: explicit WatchModel(QObject *parent = nullptr); QVariant data(const QModelIndex &index, int role) const override; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &index) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; void addWatchVar(PWatchVar watchVar); void removeWatchVar(const QString& name); void removeWatchVar(int gdbIndex); void removeWatchVar(const QModelIndex& index); void clear(); const QList& watchVars(); PWatchVar findWatchVar(const QString& name); PWatchVar findWatchVar(int gdbIndex); void beginUpdate(); void endUpdate(); void notifyUpdated(PWatchVar var); void save(const QString& filename); void load(const QString& filename); private: QList mWatchVars; int mUpdateCount; // QAbstractItemModel interface public: QVariant headerData(int section, Qt::Orientation orientation, int role) const override; }; class DebugReader; class Editor; using PDebugReader = std::shared_ptr; class Debugger : public QObject { Q_OBJECT public: explicit Debugger(QObject *parent = nullptr); // Play/pause bool start(); void sendCommand(const QString& command, const QString& params, bool updateWatch = true, bool showInConsole = false, DebugCommandSource source = DebugCommandSource::Other); bool commandRunning(); //breakpoints void addBreakpoint(int line, const Editor* editor); void addBreakpoint(int line, const QString& filename); void deleteBreakpoints(const QString& filename); void deleteBreakpoints(const Editor* editor); void deleteBreakpoints(); void removeBreakpoint(int line, const Editor* editor); void removeBreakpoint(int line, const QString& filename); void removeBreakpoint(int index); PBreakpoint breakpointAt(int line, const QString& filename, int &index); PBreakpoint breakpointAt(int line, const Editor* editor, int &index); void setBreakPointCondition(int index, const QString& condition); void sendAllBreakpointsToDebugger(); //watch vars void addWatchVar(const QString& namein); // void removeWatchVar(nodein: TTreeNode); overload; void renameWatchVar(const QString& oldname, const QString& newname); void refreshWatchVars(); void removeWatchVars(bool deleteparent); void removeWatchVar(const QModelIndex& index); void invalidateAllVars(); void sendAllWatchvarsToDebugger(); void invalidateWatchVar(const QString& name); void invalidateWatchVar(PWatchVar var); PWatchVar findWatchVar(const QString& name); // void notifyWatchVarUpdated(PWatchVar var); void notifyBeforeProcessWatchVar(); void notifyAfterProcessWatchVar(); void updateDebugInfo(); bool useUTF8() const; void setUseUTF8(bool useUTF8); BacktraceModel* backtraceModel(); BreakpointModel* breakpointModel(); bool executing() const; int leftPageIndexBackup() const; void setLeftPageIndexBackup(int leftPageIndexBackup); WatchModel *watchModel() const; RegisterModel *registerModel() const; signals: void evalValueReady(const QString& s); void memoryExamineReady(const QStringList& s); void localsReady(const QStringList& s); public slots: void stop(); private: void sendWatchCommand(PWatchVar var); void sendRemoveWatchCommand(PWatchVar var); void sendBreakpointCommand(PBreakpoint breakpoint); void sendClearBreakpointCommand(int index); void sendClearBreakpointCommand(PBreakpoint breakpoint); private slots: void syncFinishedParsing(); void onChangeDebugConsoleLastline(const QString& text); void clearUpReader(); private: bool mExecuting; bool mCommandChanged; BreakpointModel *mBreakpointModel; bool mUseUTF8; BacktraceModel *mBacktraceModel; WatchModel *mWatchModel; RegisterModel *mRegisterModel; DebugReader *mReader; int mLeftPageIndexBackup; }; class DebugReader : public QThread { Q_OBJECT public: explicit DebugReader(Debugger* debugger, QObject *parent = nullptr); void postCommand(const QString &Command, const QString &Params, bool UpdateWatch, bool ShowInConsole, DebugCommandSource Source); QString debuggerPath() const; void setDebuggerPath(const QString &debuggerPath); void stopDebug(); bool commandRunning(); bool waitStart(); bool invalidateAllVars() const; void setInvalidateAllVars(bool invalidateAllVars); bool inferiorPaused() const; bool processExited() const; signals: void parseStarted(); void invalidateAllVars(); void parseFinished(); void writeToDebugFailed(); void pauseWatchUpdate(); void updateWatch(); void processError(QProcess::ProcessError error); void changeDebugConsoleLastLine(const QString& text); void cmdStarted(); void cmdFinished(); private: void clearCmdQueue(); bool outputTerminated(QByteArray& text); void handleDisassembly(); void handleDisplay(); void handleError(); void handleExit(); void handleFrames(); void handleLocalOutput(); void handleLocals(); void handleMemory(); void handleParams(); void handleRegisters(); void handleSignal(); void handleSource(); void handleValueHistoryValue(); QString processEvalOutput(); void processWatchOutput(PWatchVar WatchVar); void runNextCmd(); QStringList tokenize(const QString& s); void handleBreakpoint(const QByteArray& breakpointRecord); void processConsoleOutput(const QByteArray& line); void processResult(const QByteArray& result); void processExecAsyncRecord(const QByteArray& line); void processError(const QByteArray& errorLine); void processResultRecord(const QByteArray& line); void processDebugOutput(const QByteArray& debugOutput); QByteArray removeToken(const QByteArray& line); private: Debugger *mDebugger; QString mDebuggerPath; QRecursiveMutex mCmdQueueMutex; QSemaphore mStartSemaphore; QQueue mCmdQueue; int mUpdateCount; bool mInvalidateAllVars; //fOnInvalidateAllVars: TInvalidateAllVarsEvent; bool mCmdRunning; PDebugCommand mCurrentCmd; QList mRegisters; QStringList mDisassembly; QProcess* mProcess; //fWatchView: TTreeView; int mIndex; int mBreakPointLine; QString mBreakPointFile; QString mEvalValue; QStringList mMemoryValue; QStringList mLocalsValue; QString mSignal; bool mUseUTF8; // attempt to cut down on Synchronize calls bool dobacktraceready; bool dodisassemblerready; bool doregistersready; bool doevalready; bool doupdatecpuwindow; bool doupdateexecution; bool doreceivedsignal; bool doreceivedsfwarning; bool doupdatememoryview; bool doupdatelocal; bool mInferiorPaused; bool mProcessExited; QStringList mConsoleOutput; bool mStop; // QThread interface protected: void run() override; }; #endif // DEBUGGER_H