mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-24 13:55:26 +00:00
Detach Cutter interface from debug command execution (#1857)
This commit is contained in:
parent
a3e140bf4d
commit
c85e1db3b3
@ -298,12 +298,6 @@ QString CutterCore::sanitizeStringForCommand(QString s)
|
|||||||
return s.replace(regexp, QStringLiteral("_"));
|
return s.replace(regexp, QStringLiteral("_"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief CutterCore::cmd send a command to radare2
|
|
||||||
* @param str the command you want to execute
|
|
||||||
* Note that if you want to seek to an address, you should use CutterCore::seek
|
|
||||||
* @return command output
|
|
||||||
*/
|
|
||||||
QString CutterCore::cmd(const char *str)
|
QString CutterCore::cmd(const char *str)
|
||||||
{
|
{
|
||||||
CORE_LOCK();
|
CORE_LOCK();
|
||||||
@ -319,6 +313,54 @@ QString CutterCore::cmd(const char *str)
|
|||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CutterCore::isDebugTaskInProgress()
|
||||||
|
{
|
||||||
|
if (!debugTask.isNull()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CutterCore::asyncCmdEsil(const char *command, QSharedPointer<R2Task> &task)
|
||||||
|
{
|
||||||
|
asyncCmd(command, task);
|
||||||
|
|
||||||
|
if (task.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(task.data(), &R2Task::finished, this, [this, task] () {
|
||||||
|
QString res = task.data()->getResult();
|
||||||
|
|
||||||
|
if (res.contains(QStringLiteral("[ESIL] Stopped execution in an invalid instruction"))) {
|
||||||
|
msgBox.showMessage("Stopped when attempted to run an invalid instruction. You can disable this in Preferences");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void CutterCore::asyncCmd(const char *str, QSharedPointer<R2Task> &task)
|
||||||
|
{
|
||||||
|
if (!task.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CORE_LOCK();
|
||||||
|
|
||||||
|
RVA offset = core->offset;
|
||||||
|
|
||||||
|
task = QSharedPointer<R2Task>(new R2Task(str, true));
|
||||||
|
connect(task.data(), &R2Task::finished, this, [this, offset, task] () {
|
||||||
|
CORE_LOCK();
|
||||||
|
|
||||||
|
if (offset != core->offset) {
|
||||||
|
updateSeek();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
task->startTask();
|
||||||
|
}
|
||||||
|
|
||||||
QString CutterCore::cmdRaw(const QString &str)
|
QString CutterCore::cmdRaw(const QString &str)
|
||||||
{
|
{
|
||||||
QString cmdStr = str;
|
QString cmdStr = str;
|
||||||
@ -1130,11 +1172,18 @@ void CutterCore::setRegister(QString regName, QString regValue)
|
|||||||
|
|
||||||
void CutterCore::setCurrentDebugThread(int tid)
|
void CutterCore::setCurrentDebugThread(int tid)
|
||||||
{
|
{
|
||||||
cmd("dpt=" + QString::number(tid));
|
asyncCmd("dpt=" + QString::number(tid), debugTask);
|
||||||
|
if (!debugTask.isNull()) {
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
||||||
|
debugTask.clear();
|
||||||
emit registersChanged();
|
emit registersChanged();
|
||||||
emit refreshCodeViews();
|
emit refreshCodeViews();
|
||||||
emit stackChanged();
|
emit stackChanged();
|
||||||
syncAndSeekProgramCounter();
|
syncAndSeekProgramCounter();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::startDebug()
|
void CutterCore::startDebug()
|
||||||
@ -1153,6 +1202,7 @@ void CutterCore::startDebug()
|
|||||||
emit refreshCodeViews();
|
emit refreshCodeViews();
|
||||||
}
|
}
|
||||||
emit stackChanged();
|
emit stackChanged();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::startEmulation()
|
void CutterCore::startEmulation()
|
||||||
@ -1175,6 +1225,7 @@ void CutterCore::startEmulation()
|
|||||||
emit registersChanged();
|
emit registersChanged();
|
||||||
emit stackChanged();
|
emit stackChanged();
|
||||||
emit refreshCodeViews();
|
emit refreshCodeViews();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::attachDebug(int pid)
|
void CutterCore::attachDebug(int pid)
|
||||||
@ -1182,6 +1233,7 @@ void CutterCore::attachDebug(int pid)
|
|||||||
if (!currentlyDebugging) {
|
if (!currentlyDebugging) {
|
||||||
offsetPriorDebugging = getOffset();
|
offsetPriorDebugging = getOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// attach to process with dbg plugin
|
// attach to process with dbg plugin
|
||||||
cmd("o-*; e cfg.debug = true; o+ dbg://" + QString::number(pid));
|
cmd("o-*; e cfg.debug = true; o+ dbg://" + QString::number(pid));
|
||||||
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
|
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
|
||||||
@ -1196,11 +1248,20 @@ void CutterCore::attachDebug(int pid)
|
|||||||
emit flagsChanged();
|
emit flagsChanged();
|
||||||
emit changeDebugView();
|
emit changeDebugView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CutterCore::suspendDebug()
|
||||||
|
{
|
||||||
|
debugTask->breakTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::stopDebug()
|
void CutterCore::stopDebug()
|
||||||
{
|
{
|
||||||
if (currentlyDebugging) {
|
if (currentlyDebugging) {
|
||||||
|
currentlyDebugging = false;
|
||||||
|
emit debugTaskStateChanged();
|
||||||
if (currentlyEmulating) {
|
if (currentlyEmulating) {
|
||||||
cmd("aeim-; aei-; wcr; .ar-");
|
cmd("aeim-; aei-; wcr; .ar-");
|
||||||
currentlyEmulating = false;
|
currentlyEmulating = false;
|
||||||
@ -1222,7 +1283,6 @@ void CutterCore::stopDebug()
|
|||||||
seekAndShow(offsetPriorDebugging);
|
seekAndShow(offsetPriorDebugging);
|
||||||
setConfig("asm.flags", true);
|
setConfig("asm.flags", true);
|
||||||
setConfig("io.cache", false);
|
setConfig("io.cache", false);
|
||||||
currentlyDebugging = false;
|
|
||||||
emit flagsChanged();
|
emit flagsChanged();
|
||||||
emit changeDefinedView();
|
emit changeDefinedView();
|
||||||
}
|
}
|
||||||
@ -1239,26 +1299,43 @@ void CutterCore::continueDebug()
|
|||||||
{
|
{
|
||||||
if (currentlyDebugging) {
|
if (currentlyDebugging) {
|
||||||
if (currentlyEmulating) {
|
if (currentlyEmulating) {
|
||||||
cmdEsil("aec");
|
asyncCmdEsil("aec", debugTask);
|
||||||
} else {
|
} else {
|
||||||
cmd("dc");
|
asyncCmd("dc", debugTask);
|
||||||
}
|
}
|
||||||
|
if (!debugTask.isNull()) {
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
||||||
|
debugTask.clear();
|
||||||
|
syncAndSeekProgramCounter();
|
||||||
emit registersChanged();
|
emit registersChanged();
|
||||||
emit refreshCodeViews();
|
emit refreshCodeViews();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::continueUntilDebug(QString offset)
|
void CutterCore::continueUntilDebug(QString offset)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (currentlyDebugging) {
|
if (currentlyDebugging) {
|
||||||
if (currentlyEmulating) {
|
if (currentlyEmulating) {
|
||||||
cmdEsil("aecu " + offset);
|
asyncCmdEsil("aecu " + offset, debugTask);
|
||||||
} else {
|
} else {
|
||||||
cmd("dcu " + offset);
|
asyncCmd("dcu " + offset, debugTask);
|
||||||
}
|
}
|
||||||
|
if (!debugTask.isNull()) {
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
||||||
|
debugTask.clear();
|
||||||
|
syncAndSeekProgramCounter();
|
||||||
emit registersChanged();
|
emit registersChanged();
|
||||||
emit stackChanged();
|
emit stackChanged();
|
||||||
emit refreshCodeViews();
|
emit refreshCodeViews();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1266,11 +1343,18 @@ void CutterCore::continueUntilCall()
|
|||||||
{
|
{
|
||||||
if (currentlyDebugging) {
|
if (currentlyDebugging) {
|
||||||
if (currentlyEmulating) {
|
if (currentlyEmulating) {
|
||||||
cmdEsil("aecc");
|
asyncCmdEsil("aecc", debugTask);
|
||||||
} else {
|
} else {
|
||||||
cmd("dcc");
|
asyncCmd("dcc", debugTask);
|
||||||
}
|
}
|
||||||
|
if (!debugTask.isNull()) {
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
||||||
|
debugTask.clear();
|
||||||
syncAndSeekProgramCounter();
|
syncAndSeekProgramCounter();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1278,11 +1362,18 @@ void CutterCore::continueUntilSyscall()
|
|||||||
{
|
{
|
||||||
if (currentlyDebugging) {
|
if (currentlyDebugging) {
|
||||||
if (currentlyEmulating) {
|
if (currentlyEmulating) {
|
||||||
cmdEsil("aecs");
|
asyncCmdEsil("aecs", debugTask);
|
||||||
} else {
|
} else {
|
||||||
cmd("dcs");
|
asyncCmd("dcs", debugTask);
|
||||||
}
|
}
|
||||||
|
if (!debugTask.isNull()) {
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
||||||
|
debugTask.clear();
|
||||||
syncAndSeekProgramCounter();
|
syncAndSeekProgramCounter();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1290,11 +1381,18 @@ void CutterCore::stepDebug()
|
|||||||
{
|
{
|
||||||
if (currentlyDebugging) {
|
if (currentlyDebugging) {
|
||||||
if (currentlyEmulating) {
|
if (currentlyEmulating) {
|
||||||
cmdEsil("aes");
|
asyncCmdEsil("aes", debugTask);
|
||||||
} else {
|
} else {
|
||||||
cmd("ds");
|
asyncCmd("ds", debugTask);
|
||||||
}
|
}
|
||||||
|
if (!debugTask.isNull()) {
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
||||||
|
debugTask.clear();
|
||||||
syncAndSeekProgramCounter();
|
syncAndSeekProgramCounter();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1302,19 +1400,33 @@ void CutterCore::stepOverDebug()
|
|||||||
{
|
{
|
||||||
if (currentlyDebugging) {
|
if (currentlyDebugging) {
|
||||||
if (currentlyEmulating) {
|
if (currentlyEmulating) {
|
||||||
cmdEsil("aeso");
|
asyncCmdEsil("aeso", debugTask);
|
||||||
} else {
|
} else {
|
||||||
cmd("dso");
|
asyncCmd("dso", debugTask);
|
||||||
}
|
}
|
||||||
|
if (!debugTask.isNull()) {
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
||||||
|
debugTask.clear();
|
||||||
syncAndSeekProgramCounter();
|
syncAndSeekProgramCounter();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::stepOutDebug()
|
void CutterCore::stepOutDebug()
|
||||||
{
|
{
|
||||||
if (currentlyDebugging) {
|
if (currentlyDebugging) {
|
||||||
cmd("dsf");
|
emit debugTaskStateChanged();
|
||||||
|
asyncCmd("dsf", debugTask);
|
||||||
|
if (!debugTask.isNull()) {
|
||||||
|
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
||||||
|
debugTask.clear();
|
||||||
syncAndSeekProgramCounter();
|
syncAndSeekProgramCounter();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,9 +18,11 @@ class AsyncTaskManager;
|
|||||||
class BasicInstructionHighlighter;
|
class BasicInstructionHighlighter;
|
||||||
class CutterCore;
|
class CutterCore;
|
||||||
class Decompiler;
|
class Decompiler;
|
||||||
|
class R2Task;
|
||||||
|
|
||||||
#include "plugins/CutterPlugin.h"
|
#include "plugins/CutterPlugin.h"
|
||||||
#include "common/BasicBlockHighlighter.h"
|
#include "common/BasicBlockHighlighter.h"
|
||||||
|
#include "common/R2Task.h"
|
||||||
|
|
||||||
#define Core() (CutterCore::instance())
|
#define Core() (CutterCore::instance())
|
||||||
|
|
||||||
@ -47,8 +49,25 @@ public:
|
|||||||
|
|
||||||
/* Core functions (commands) */
|
/* Core functions (commands) */
|
||||||
static QString sanitizeStringForCommand(QString s);
|
static QString sanitizeStringForCommand(QString s);
|
||||||
|
/**
|
||||||
|
* @brief send a command to radare2
|
||||||
|
* @param str the command you want to execute
|
||||||
|
* @return command output
|
||||||
|
* @note if you want to seek to an address, you should use CutterCore::seek.
|
||||||
|
*/
|
||||||
QString cmd(const char *str);
|
QString cmd(const char *str);
|
||||||
QString cmd(const QString &str) { return cmd(str.toUtf8().constData()); }
|
QString cmd(const QString &str) { return cmd(str.toUtf8().constData()); }
|
||||||
|
/**
|
||||||
|
* @brief send a command to radare2 asynchronously
|
||||||
|
* @param str the command you want to execute
|
||||||
|
* @param task a shared pointer that will be returned with the R2 command task
|
||||||
|
* @note connect to the &R2Task::finished signal to add your own logic once
|
||||||
|
* the command is finished. Use task->getResult()/getResultJson() for the
|
||||||
|
* return value.
|
||||||
|
* If you want to seek to an address, you should use CutterCore::seek.
|
||||||
|
*/
|
||||||
|
void asyncCmd(const char *str, QSharedPointer<R2Task> &task);
|
||||||
|
void asyncCmd(const QString &str, QSharedPointer<R2Task> &task) { return asyncCmd(str.toUtf8().constData(), task); }
|
||||||
QString cmdRaw(const QString &str);
|
QString cmdRaw(const QString &str);
|
||||||
QJsonDocument cmdj(const char *str);
|
QJsonDocument cmdj(const char *str);
|
||||||
QJsonDocument cmdj(const QString &str) { return cmdj(str.toUtf8().constData()); }
|
QJsonDocument cmdj(const QString &str) { return cmdj(str.toUtf8().constData()); }
|
||||||
@ -56,8 +75,24 @@ public:
|
|||||||
QStringList cmdList(const QString &str) { return cmdList(str.toUtf8().constData()); }
|
QStringList cmdList(const QString &str) { return cmdList(str.toUtf8().constData()); }
|
||||||
QString cmdTask(const QString &str);
|
QString cmdTask(const QString &str);
|
||||||
QJsonDocument cmdjTask(const QString &str);
|
QJsonDocument cmdjTask(const QString &str);
|
||||||
|
/**
|
||||||
|
* @brief send a command to radare2 and check for ESIL errors
|
||||||
|
* @param command the command you want to execute
|
||||||
|
* @note If you want to seek to an address, you should use CutterCore::seek.
|
||||||
|
*/
|
||||||
void cmdEsil(const char *command);
|
void cmdEsil(const char *command);
|
||||||
void cmdEsil(const QString &command) { cmdEsil(command.toUtf8().constData()); }
|
void cmdEsil(const QString &command) { cmdEsil(command.toUtf8().constData()); }
|
||||||
|
/**
|
||||||
|
* @brief send a command to radare2 and check for ESIL errors
|
||||||
|
* @param command the command you want to execute
|
||||||
|
* @param task a shared pointer that will be returned with the R2 command task
|
||||||
|
* @note connect to the &R2Task::finished signal to add your own logic once
|
||||||
|
* the command is finished. Use task->getResult()/getResultJson() for the
|
||||||
|
* return value.
|
||||||
|
* If you want to seek to an address, you should use CutterCore::seek.
|
||||||
|
*/
|
||||||
|
void asyncCmdEsil(const char *command, QSharedPointer<R2Task> &task);
|
||||||
|
void asyncCmdEsil(const QString &command, QSharedPointer<R2Task> &task) { return asyncCmdEsil(command.toUtf8().constData(), task); }
|
||||||
QString getVersionInformation();
|
QString getVersionInformation();
|
||||||
|
|
||||||
QJsonDocument parseJson(const char *res, const char *cmd = nullptr);
|
QJsonDocument parseJson(const char *res, const char *cmd = nullptr);
|
||||||
@ -234,6 +269,7 @@ public:
|
|||||||
void startEmulation();
|
void startEmulation();
|
||||||
void attachDebug(int pid);
|
void attachDebug(int pid);
|
||||||
void stopDebug();
|
void stopDebug();
|
||||||
|
void suspendDebug();
|
||||||
void syncAndSeekProgramCounter();
|
void syncAndSeekProgramCounter();
|
||||||
void continueDebug();
|
void continueDebug();
|
||||||
void continueUntilCall();
|
void continueUntilCall();
|
||||||
@ -253,6 +289,7 @@ public:
|
|||||||
QString getActiveDebugPlugin();
|
QString getActiveDebugPlugin();
|
||||||
QStringList getDebugPlugins();
|
QStringList getDebugPlugins();
|
||||||
void setDebugPlugin(QString plugin);
|
void setDebugPlugin(QString plugin);
|
||||||
|
bool isDebugTaskInProgress();
|
||||||
bool currentlyDebugging = false;
|
bool currentlyDebugging = false;
|
||||||
bool currentlyEmulating = false;
|
bool currentlyEmulating = false;
|
||||||
int currentlyAttachedToPID = -1;
|
int currentlyAttachedToPID = -1;
|
||||||
@ -438,6 +475,11 @@ signals:
|
|||||||
|
|
||||||
void projectSaved(bool successfully, const QString &name);
|
void projectSaved(bool successfully, const QString &name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* emitted when debugTask started or finished running
|
||||||
|
*/
|
||||||
|
void debugTaskStateChanged();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* emitted when config regarding disassembly display changes
|
* emitted when config regarding disassembly display changes
|
||||||
*/
|
*/
|
||||||
@ -483,6 +525,8 @@ private:
|
|||||||
bool emptyGraph = false;
|
bool emptyGraph = false;
|
||||||
BasicBlockHighlighter *bbHighlighter;
|
BasicBlockHighlighter *bbHighlighter;
|
||||||
BasicInstructionHighlighter biHighlighter;
|
BasicInstructionHighlighter biHighlighter;
|
||||||
|
|
||||||
|
QSharedPointer<R2Task> debugTask;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RCoreLocked
|
class RCoreLocked
|
||||||
|
6
src/img/icons/media-suspend_light.svg
Normal file
6
src/img/icons/media-suspend_light.svg
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8">
|
||||||
|
<g>
|
||||||
|
<rect id="svg_3" height="5.953009" width="1.970973" y="1.138955" x="5.520464" stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null" stroke-width="null" fill="#b15858"/>
|
||||||
|
<rect id="svg_6" height="5.966372" width="1.970973" y="1.122789" x="0.516538" stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null" stroke-width="null" fill="#b15858"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 470 B |
@ -25,6 +25,7 @@
|
|||||||
<file>img/icons/play_light_emul.svg</file>
|
<file>img/icons/play_light_emul.svg</file>
|
||||||
<file>img/icons/play_light_attach.svg</file>
|
<file>img/icons/play_light_attach.svg</file>
|
||||||
<file>img/icons/media-stop_light.svg</file>
|
<file>img/icons/media-stop_light.svg</file>
|
||||||
|
<file>img/icons/media-suspend_light.svg</file>
|
||||||
<file>img/icons/media-skip-forward_light.svg</file>
|
<file>img/icons/media-skip-forward_light.svg</file>
|
||||||
<file>img/icons/continue_until_main.svg</file>
|
<file>img/icons/continue_until_main.svg</file>
|
||||||
<file>img/icons/continue_until_call.svg</file>
|
<file>img/icons/continue_until_call.svg</file>
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include "core/MainWindow.h"
|
#include "core/MainWindow.h"
|
||||||
#include "dialogs/AttachProcDialog.h"
|
#include "dialogs/AttachProcDialog.h"
|
||||||
|
|
||||||
#include <QAction>
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
@ -22,7 +21,6 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) :
|
|||||||
QIcon startEmulIcon = QIcon(":/img/icons/play_light_emul.svg");
|
QIcon startEmulIcon = QIcon(":/img/icons/play_light_emul.svg");
|
||||||
QIcon startAttachIcon = QIcon(":/img/icons/play_light_attach.svg");
|
QIcon startAttachIcon = QIcon(":/img/icons/play_light_attach.svg");
|
||||||
QIcon stopIcon = QIcon(":/img/icons/media-stop_light.svg");
|
QIcon stopIcon = QIcon(":/img/icons/media-stop_light.svg");
|
||||||
QIcon continueIcon = QIcon(":/img/icons/media-skip-forward_light.svg");
|
|
||||||
QIcon continueUntilMainIcon = QIcon(":/img/icons/continue_until_main.svg");
|
QIcon continueUntilMainIcon = QIcon(":/img/icons/continue_until_main.svg");
|
||||||
QIcon continueUntilCallIcon = QIcon(":/img/icons/continue_until_call.svg");
|
QIcon continueUntilCallIcon = QIcon(":/img/icons/continue_until_call.svg");
|
||||||
QIcon continueUntilSyscallIcon = QIcon(":/img/icons/continue_until_syscall.svg");
|
QIcon continueUntilSyscallIcon = QIcon(":/img/icons/continue_until_syscall.svg");
|
||||||
@ -30,6 +28,8 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) :
|
|||||||
QIcon stepOverIcon = QIcon(":/img/icons/step_over_light.svg");
|
QIcon stepOverIcon = QIcon(":/img/icons/step_over_light.svg");
|
||||||
QIcon stepOutIcon = QIcon(":/img/icons/step_out_light.svg");
|
QIcon stepOutIcon = QIcon(":/img/icons/step_out_light.svg");
|
||||||
QIcon restartIcon = QIcon(":/img/icons/spin_light.svg");
|
QIcon restartIcon = QIcon(":/img/icons/spin_light.svg");
|
||||||
|
continueIcon = QIcon(":/img/icons/media-skip-forward_light.svg");
|
||||||
|
suspendIcon = QIcon(":/img/icons/media-suspend_light.svg");
|
||||||
|
|
||||||
// define action labels
|
// define action labels
|
||||||
QString startDebugLabel = tr("Start debug");
|
QString startDebugLabel = tr("Start debug");
|
||||||
@ -39,13 +39,14 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) :
|
|||||||
QString stopEmulLabel = tr("Stop emulation");
|
QString stopEmulLabel = tr("Stop emulation");
|
||||||
QString restartDebugLabel = tr("Restart program");
|
QString restartDebugLabel = tr("Restart program");
|
||||||
QString restartEmulLabel = tr("Restart emulation");
|
QString restartEmulLabel = tr("Restart emulation");
|
||||||
QString continueLabel = tr("Continue");
|
|
||||||
QString continueUMLabel = tr("Continue until main");
|
QString continueUMLabel = tr("Continue until main");
|
||||||
QString continueUCLabel = tr("Continue until call");
|
QString continueUCLabel = tr("Continue until call");
|
||||||
QString continueUSLabel = tr("Continue until syscall");
|
QString continueUSLabel = tr("Continue until syscall");
|
||||||
QString stepLabel = tr("Step");
|
QString stepLabel = tr("Step");
|
||||||
QString stepOverLabel = tr("Step over");
|
QString stepOverLabel = tr("Step over");
|
||||||
QString stepOutLabel = tr("Step out");
|
QString stepOutLabel = tr("Step out");
|
||||||
|
suspendLabel = tr("Suspend the process");
|
||||||
|
continueLabel = tr("Continue");
|
||||||
|
|
||||||
// define actions
|
// define actions
|
||||||
actionStart = new QAction(startDebugIcon, startDebugLabel, this);
|
actionStart = new QAction(startDebugIcon, startDebugLabel, this);
|
||||||
@ -102,6 +103,26 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) :
|
|||||||
// hide allactions
|
// hide allactions
|
||||||
setAllActionsVisible(false);
|
setAllActionsVisible(false);
|
||||||
|
|
||||||
|
// Toggle all buttons except restart, suspend(=continue) and stop since those are
|
||||||
|
// necessary to avoid staying stuck
|
||||||
|
toggleActions = { actionStep, actionStepOver, actionStepOut, actionContinueUntilMain,
|
||||||
|
actionContinueUntilCall, actionContinueUntilSyscall};
|
||||||
|
|
||||||
|
connect(Core(), &CutterCore::debugTaskStateChanged, this, [ = ]() {
|
||||||
|
bool disableToolbar = Core()->isDebugTaskInProgress() || !Core()->currentlyDebugging;
|
||||||
|
for (QAction *a : toggleActions) {
|
||||||
|
a->setDisabled(disableToolbar);
|
||||||
|
}
|
||||||
|
// Suspend should only be available when other icons are disabled
|
||||||
|
if (disableToolbar) {
|
||||||
|
actionContinue->setText(suspendLabel);
|
||||||
|
actionContinue->setIcon(suspendIcon);
|
||||||
|
} else {
|
||||||
|
actionContinue->setText(continueLabel);
|
||||||
|
actionContinue->setIcon(continueIcon);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
connect(actionStop, &QAction::triggered, Core(), &CutterCore::stopDebug);
|
connect(actionStop, &QAction::triggered, Core(), &CutterCore::stopDebug);
|
||||||
connect(actionStop, &QAction::triggered, [ = ]() {
|
connect(actionStop, &QAction::triggered, [ = ]() {
|
||||||
actionStart->setVisible(true);
|
actionStart->setVisible(true);
|
||||||
@ -150,10 +171,17 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) :
|
|||||||
});
|
});
|
||||||
connect(actionStepOver, &QAction::triggered, Core(), &CutterCore::stepOverDebug);
|
connect(actionStepOver, &QAction::triggered, Core(), &CutterCore::stepOverDebug);
|
||||||
connect(actionStepOut, &QAction::triggered, Core(), &CutterCore::stepOutDebug);
|
connect(actionStepOut, &QAction::triggered, Core(), &CutterCore::stepOutDebug);
|
||||||
connect(actionContinue, &QAction::triggered, Core(), &CutterCore::continueDebug);
|
|
||||||
connect(actionContinueUntilMain, &QAction::triggered, this, &DebugActions::continueUntilMain);
|
connect(actionContinueUntilMain, &QAction::triggered, this, &DebugActions::continueUntilMain);
|
||||||
connect(actionContinueUntilCall, &QAction::triggered, Core(), &CutterCore::continueUntilCall);
|
connect(actionContinueUntilCall, &QAction::triggered, Core(), &CutterCore::continueUntilCall);
|
||||||
connect(actionContinueUntilSyscall, &QAction::triggered, Core(), &CutterCore::continueUntilSyscall);
|
connect(actionContinueUntilSyscall, &QAction::triggered, Core(), &CutterCore::continueUntilSyscall);
|
||||||
|
connect(actionContinue, &QAction::triggered, Core(), [=]() {
|
||||||
|
// Switch between continue and suspend depending on the debugger's state
|
||||||
|
if (Core()->isDebugTaskInProgress()) {
|
||||||
|
Core()->suspendDebug();
|
||||||
|
} else {
|
||||||
|
Core()->continueDebug();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugActions::setButtonVisibleIfMainExists()
|
void DebugActions::setButtonVisibleIfMainExists()
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "core/Cutter.h"
|
#include "core/Cutter.h"
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
class QToolBar;
|
class QToolBar;
|
||||||
class QToolButton;
|
class QToolButton;
|
||||||
@ -28,7 +30,17 @@ public:
|
|||||||
QAction *actionStop;
|
QAction *actionStop;
|
||||||
QAction *actionAllContinues;
|
QAction *actionAllContinues;
|
||||||
|
|
||||||
|
// Continue and suspend interchange during runtime
|
||||||
|
QIcon continueIcon;
|
||||||
|
QIcon suspendIcon;
|
||||||
|
QString suspendLabel;
|
||||||
|
QString continueLabel;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* @brief buttons that will be disabled/enabled on (disable/enable)DebugToolbar
|
||||||
|
*/
|
||||||
|
QList<QAction *> toggleActions;
|
||||||
MainWindow *main;
|
MainWindow *main;
|
||||||
QList<QAction *> allActions;
|
QList<QAction *> allActions;
|
||||||
QToolButton *continueUntilButton;
|
QToolButton *continueUntilButton;
|
||||||
|
@ -67,7 +67,12 @@ void ThreadsWidget::updateContents()
|
|||||||
if (!refreshDeferrer->attemptRefresh(nullptr)) {
|
if (!refreshDeferrer->attemptRefresh(nullptr)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setThreadsGrid();
|
setThreadsGrid();
|
||||||
|
|
||||||
|
if (Core()->isDebugTaskInProgress() || !Core()->currentlyDebugging) {
|
||||||
|
ui->viewThreads->setSelectionMode(QAbstractItemView::NoSelection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ThreadsWidget::translateStatus(QString status)
|
QString ThreadsWidget::translateStatus(QString status)
|
||||||
|
Loading…
Reference in New Issue
Block a user