WingHexExplorer2/src/class/asdebugger.h

176 lines
5.4 KiB
C++

/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** This program is free software: you can redistribute it and/or modify it under
** the terms of the GNU Affero General Public License as published by the Free
** Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
** details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program. If not, see <https://www.gnu.org/licenses/>.
** =============================================================================
*/
#ifndef ASDEBUGGER_H
#define ASDEBUGGER_H
#include "angelscript.h"
#include <QList>
#include <QMap>
#include <QObject>
#include <atomic>
// from AngelScript CDebugger, I modify it for Qt intergration and
// and add some TODO features that easy to implement
class asDebugger : public QObject {
Q_OBJECT
public:
struct BreakPoint {
BreakPoint(QString f, int n, bool _func)
: name(f), lineNbr(n), func(_func), needsAdjusting(true) {}
QString name;
int lineNbr;
bool func;
bool needsAdjusting;
};
struct VariablesInfo {
QString name;
QString value;
};
struct StackTraceInfo {
QString file;
int lineNr;
QString fndecl;
};
struct GCStatistic {
asUINT currentSize = 0;
asUINT totalDestroyed = 0;
asUINT totalDetected = 0;
asUINT newObjects = 0;
asUINT totalNewDestroyed = 0;
};
struct CallStackItem {
QString file;
int lineNbr;
QString decl;
};
enum class WatchExpError {
NoError,
Error,
NotEndAfterSymbol,
NoMatchingSymbol,
ExpectedIdentifier
};
enum DebugAction {
ABORT, // try to abort the script
PAUSE, // try to pause
CONTINUE, // continue until next break point
STEP_INTO, // stop at next instruction
STEP_OVER, // stop at next instruction, skipping called functions
STEP_OUT // run until returning from current function
};
public:
explicit asDebugger(QObject *parent = nullptr);
virtual ~asDebugger();
// Register callbacks to handle to-string conversions of application types
// The expandMembersLevel is a counter for how many recursive levels the
// members should be expanded. If the object that is being converted to a
// string has members of its own the callback should call the debugger's
// ToString passing in expandMembersLevel - 1.
typedef QString (*ToStringCallback)(void *obj, int expandMembersLevel,
asDebugger *dbg);
void registerToStringCallback(const asITypeInfo *ti,
ToStringCallback callback);
// Commands
void addFileBreakPoint(const QString &file, int lineNbr);
void removeFileBreakPoint(const QString &file, int lineNbr);
void addFuncBreakPoint(const QString &func);
void removeFuncBreakPoint(const QString &func);
void clearBreakPoint();
const QVector<BreakPoint> &breakPoints();
// Optionally set the engine pointer in the debugger so it can be retrieved
// by callbacks that need it. This will hold a reference to the engine.
void setEngine(asIScriptEngine *engine);
asIScriptEngine *getEngine();
int expandMembers() const;
void setExpandMembers(int newExpandMembers);
// Line callback invoked by context
void lineCallback(asIScriptContext *ctx);
QString toString(void *value, asUINT typeId, int expandMembersLevel,
asIScriptEngine *engine = nullptr);
GCStatistic gcStatistics();
void runDebugAction(DebugAction action);
DebugAction currentState() const;
private:
QVector<VariablesInfo> globalVariables(asIScriptContext *ctx);
QVector<VariablesInfo> localVariables(asIScriptContext *ctx);
QList<CallStackItem> retriveCallstack(asIScriptContext *ctx);
QString printValue(const QString &expr, asIScriptContext *ctx,
WatchExpError &error);
void takeCommands(asIScriptContext *ctx);
bool checkBreakPoint(asIScriptContext *ctx);
void listMemberProperties(asIScriptContext *ctx);
// Helpers
bool interpretCommand(const QString &cmd, asIScriptContext *ctx);
signals:
void onAdjustBreakPointLine(const BreakPoint &old, int newLineNr);
void onPullVariables(const QVector<VariablesInfo> &globalvars,
const QVector<VariablesInfo> &localvars);
void onPullCallStack(const QList<CallStackItem> &callstacks);
void onRunCurrentLine(const QString &file, int lineNr);
private:
struct ContextDbgInfo {
QString file;
int line = -1;
int col = -1;
int stackCount = -1;
};
private:
std::atomic<DebugAction> m_action;
asUINT m_lastCommandAtStackLevel;
asIScriptFunction *m_lastFunction;
QVector<BreakPoint> m_breakPoints;
asIScriptEngine *m_engine = nullptr;
// Registered callbacks for converting types to strings
QMap<const asITypeInfo *, ToStringCallback> m_toStringCallbacks;
QStringList m_watchVars;
int _expandMembers = 3;
};
#endif // ASDEBUGGER_H