mirror of
https://github.com/rizinorg/cutter.git
synced 2025-01-31 08:37:26 +00:00
Add debug dialogs (#1903)
This commit is contained in:
parent
ef97c84351
commit
519cd5dabd
@ -268,6 +268,7 @@ SOURCES += \
|
|||||||
dialogs/FlagDialog.cpp \
|
dialogs/FlagDialog.cpp \
|
||||||
dialogs/RenameDialog.cpp \
|
dialogs/RenameDialog.cpp \
|
||||||
dialogs/RemoteDebugDialog.cpp \
|
dialogs/RemoteDebugDialog.cpp \
|
||||||
|
dialogs/NativeDebugDialog.cpp \
|
||||||
dialogs/XrefsDialog.cpp \
|
dialogs/XrefsDialog.cpp \
|
||||||
core/MainWindow.cpp \
|
core/MainWindow.cpp \
|
||||||
common/Helpers.cpp \
|
common/Helpers.cpp \
|
||||||
@ -403,6 +404,7 @@ HEADERS += \
|
|||||||
dialogs/FlagDialog.h \
|
dialogs/FlagDialog.h \
|
||||||
dialogs/RenameDialog.h \
|
dialogs/RenameDialog.h \
|
||||||
dialogs/RemoteDebugDialog.h \
|
dialogs/RemoteDebugDialog.h \
|
||||||
|
dialogs/NativeDebugDialog.h \
|
||||||
dialogs/XrefsDialog.h \
|
dialogs/XrefsDialog.h \
|
||||||
common/Helpers.h \
|
common/Helpers.h \
|
||||||
common/HexAsciiHighlighter.h \
|
common/HexAsciiHighlighter.h \
|
||||||
@ -536,6 +538,7 @@ FORMS += \
|
|||||||
dialogs/FlagDialog.ui \
|
dialogs/FlagDialog.ui \
|
||||||
dialogs/RenameDialog.ui \
|
dialogs/RenameDialog.ui \
|
||||||
dialogs/RemoteDebugDialog.ui \
|
dialogs/RemoteDebugDialog.ui \
|
||||||
|
dialogs/NativeDebugDialog.ui \
|
||||||
dialogs/XrefsDialog.ui \
|
dialogs/XrefsDialog.ui \
|
||||||
dialogs/NewfileDialog.ui \
|
dialogs/NewfileDialog.ui \
|
||||||
dialogs/InitialOptionsDialog.ui \
|
dialogs/InitialOptionsDialog.ui \
|
||||||
|
@ -340,12 +340,12 @@ bool CutterCore::isDebugTaskInProgress()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::asyncCmdEsil(const char *command, QSharedPointer<R2Task> &task)
|
bool CutterCore::asyncCmdEsil(const char *command, QSharedPointer<R2Task> &task)
|
||||||
{
|
{
|
||||||
asyncCmd(command, task);
|
asyncCmd(command, task);
|
||||||
|
|
||||||
if (task.isNull()) {
|
if (task.isNull()) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(task.data(), &R2Task::finished, this, [this, task] () {
|
connect(task.data(), &R2Task::finished, this, [this, task] () {
|
||||||
@ -355,12 +355,14 @@ void CutterCore::asyncCmdEsil(const char *command, QSharedPointer<R2Task> &task)
|
|||||||
msgBox.showMessage("Stopped when attempted to run an invalid instruction. You can disable this in Preferences");
|
msgBox.showMessage("Stopped when attempted to run an invalid instruction. You can disable this in Preferences");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::asyncCmd(const char *str, QSharedPointer<R2Task> &task)
|
bool CutterCore::asyncCmd(const char *str, QSharedPointer<R2Task> &task)
|
||||||
{
|
{
|
||||||
if (!task.isNull()) {
|
if (!task.isNull()) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CORE_LOCK();
|
CORE_LOCK();
|
||||||
@ -376,7 +378,7 @@ void CutterCore::asyncCmd(const char *str, QSharedPointer<R2Task> &task)
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
task->startTask();
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CutterCore::cmdRaw(const QString &str)
|
QString CutterCore::cmdRaw(const QString &str)
|
||||||
@ -1200,42 +1202,43 @@ void CutterCore::setRegister(QString regName, QString regValue)
|
|||||||
|
|
||||||
void CutterCore::setCurrentDebugThread(int tid)
|
void CutterCore::setCurrentDebugThread(int tid)
|
||||||
{
|
{
|
||||||
asyncCmd("dpt=" + QString::number(tid), debugTask);
|
if (!asyncCmd("dpt=" + QString::number(tid), debugTask)) {
|
||||||
if (!debugTask.isNull()) {
|
|
||||||
emit debugTaskStateChanged();
|
|
||||||
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
|
||||||
debugTask.clear();
|
|
||||||
emit registersChanged();
|
|
||||||
emit refreshCodeViews();
|
|
||||||
emit stackChanged();
|
|
||||||
syncAndSeekProgramCounter();
|
|
||||||
emit switchedThread();
|
|
||||||
emit debugTaskStateChanged();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CutterCore::setCurrentDebugProcess(int pid)
|
|
||||||
{
|
|
||||||
if (!currentlyDebugging) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit debugTaskStateChanged();
|
emit debugTaskStateChanged();
|
||||||
asyncCmd("dp=" + QString::number(pid), debugTask);
|
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
||||||
if (!debugTask.isNull()) {
|
debugTask.clear();
|
||||||
|
emit registersChanged();
|
||||||
|
emit refreshCodeViews();
|
||||||
|
emit stackChanged();
|
||||||
|
syncAndSeekProgramCounter();
|
||||||
|
emit switchedThread();
|
||||||
emit debugTaskStateChanged();
|
emit debugTaskStateChanged();
|
||||||
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
});
|
||||||
debugTask.clear();
|
|
||||||
emit registersChanged();
|
debugTask->startTask();
|
||||||
emit refreshCodeViews();
|
}
|
||||||
emit stackChanged();
|
|
||||||
emit flagsChanged();
|
void CutterCore::setCurrentDebugProcess(int pid)
|
||||||
syncAndSeekProgramCounter();
|
{
|
||||||
emit switchedProcess();
|
if (!currentlyDebugging || !asyncCmd("dp=" + QString::number(pid), debugTask)) {
|
||||||
emit debugTaskStateChanged();
|
return;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
||||||
|
debugTask.clear();
|
||||||
|
emit registersChanged();
|
||||||
|
emit refreshCodeViews();
|
||||||
|
emit stackChanged();
|
||||||
|
emit flagsChanged();
|
||||||
|
syncAndSeekProgramCounter();
|
||||||
|
emit switchedProcess();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
});
|
||||||
|
|
||||||
|
debugTask->startTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::startDebug()
|
void CutterCore::startDebug()
|
||||||
@ -1244,17 +1247,38 @@ void CutterCore::startDebug()
|
|||||||
offsetPriorDebugging = getOffset();
|
offsetPriorDebugging = getOffset();
|
||||||
}
|
}
|
||||||
currentlyOpenFile = getConfig("file.path");
|
currentlyOpenFile = getConfig("file.path");
|
||||||
cmd("ood");
|
|
||||||
emit registersChanged();
|
if (!asyncCmd("ood", debugTask)) {
|
||||||
if (!currentlyDebugging) {
|
return;
|
||||||
setConfig("asm.flags", false);
|
|
||||||
currentlyDebugging = true;
|
|
||||||
emit changeDebugView();
|
|
||||||
emit flagsChanged();
|
|
||||||
emit refreshCodeViews();
|
|
||||||
}
|
}
|
||||||
emit stackChanged();
|
|
||||||
emit debugTaskStateChanged();
|
emit debugTaskStateChanged();
|
||||||
|
|
||||||
|
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
||||||
|
if (debugTaskDialog) {
|
||||||
|
delete debugTaskDialog;
|
||||||
|
}
|
||||||
|
debugTask.clear();
|
||||||
|
|
||||||
|
emit registersChanged();
|
||||||
|
if (!currentlyDebugging) {
|
||||||
|
setConfig("asm.flags", false);
|
||||||
|
currentlyDebugging = true;
|
||||||
|
emit changeDebugView();
|
||||||
|
emit flagsChanged();
|
||||||
|
emit refreshCodeViews();
|
||||||
|
}
|
||||||
|
emit stackChanged();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
});
|
||||||
|
|
||||||
|
debugTaskDialog = new R2TaskDialog(debugTask);
|
||||||
|
debugTaskDialog->setBreakOnClose(true);
|
||||||
|
debugTaskDialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
debugTaskDialog->setDesc(tr("Starting native debug..."));
|
||||||
|
debugTaskDialog->show();
|
||||||
|
|
||||||
|
debugTask->startTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::startEmulation()
|
void CutterCore::startEmulation()
|
||||||
@ -1262,22 +1286,41 @@ void CutterCore::startEmulation()
|
|||||||
if (!currentlyDebugging) {
|
if (!currentlyDebugging) {
|
||||||
offsetPriorDebugging = getOffset();
|
offsetPriorDebugging = getOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear registers, init esil state, stack, progcounter at current seek
|
// clear registers, init esil state, stack, progcounter at current seek
|
||||||
cmd("aei; aeim; aeip");
|
asyncCmd("aei; aeim; aeip", debugTask);
|
||||||
if (!currentlyDebugging || !currentlyEmulating) {
|
|
||||||
// prevent register flags from appearing during debug/emul
|
|
||||||
setConfig("asm.flags", false);
|
|
||||||
// allows to view self-modifying code changes or other binary changes
|
|
||||||
setConfig("io.cache", true);
|
|
||||||
currentlyDebugging = true;
|
|
||||||
currentlyEmulating = true;
|
|
||||||
emit changeDebugView();
|
|
||||||
emit flagsChanged();
|
|
||||||
}
|
|
||||||
emit registersChanged();
|
|
||||||
emit stackChanged();
|
|
||||||
emit refreshCodeViews();
|
|
||||||
emit debugTaskStateChanged();
|
emit debugTaskStateChanged();
|
||||||
|
|
||||||
|
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
||||||
|
if (debugTaskDialog) {
|
||||||
|
delete debugTaskDialog;
|
||||||
|
}
|
||||||
|
debugTask.clear();
|
||||||
|
|
||||||
|
if (!currentlyDebugging || !currentlyEmulating) {
|
||||||
|
// prevent register flags from appearing during debug/emul
|
||||||
|
setConfig("asm.flags", false);
|
||||||
|
// allows to view self-modifying code changes or other binary changes
|
||||||
|
setConfig("io.cache", true);
|
||||||
|
currentlyDebugging = true;
|
||||||
|
currentlyEmulating = true;
|
||||||
|
emit changeDebugView();
|
||||||
|
emit flagsChanged();
|
||||||
|
}
|
||||||
|
emit registersChanged();
|
||||||
|
emit stackChanged();
|
||||||
|
emit refreshCodeViews();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
});
|
||||||
|
|
||||||
|
debugTaskDialog = new R2TaskDialog(debugTask);
|
||||||
|
debugTaskDialog->setBreakOnClose(true);
|
||||||
|
debugTaskDialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
debugTaskDialog->setDesc(tr("Starting emulation..."));
|
||||||
|
debugTaskDialog->show();
|
||||||
|
|
||||||
|
debugTask->startTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::attachRemote(const QString &uri)
|
void CutterCore::attachRemote(const QString &uri)
|
||||||
@ -1329,8 +1372,10 @@ void CutterCore::attachRemote(const QString &uri)
|
|||||||
debugTaskDialog = new R2TaskDialog(debugTask);
|
debugTaskDialog = new R2TaskDialog(debugTask);
|
||||||
debugTaskDialog->setBreakOnClose(true);
|
debugTaskDialog->setBreakOnClose(true);
|
||||||
debugTaskDialog->setAttribute(Qt::WA_DeleteOnClose);
|
debugTaskDialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
debugTaskDialog->setDesc("Connecting to: " + uri);
|
debugTaskDialog->setDesc(tr("Connecting to: ") + uri);
|
||||||
debugTaskDialog->show();
|
debugTaskDialog->show();
|
||||||
|
|
||||||
|
debugTask->startTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::attachDebug(int pid)
|
void CutterCore::attachDebug(int pid)
|
||||||
@ -1340,21 +1385,34 @@ void CutterCore::attachDebug(int pid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// attach to process with dbg plugin
|
// attach to process with dbg plugin
|
||||||
cmd("o-*; e cfg.debug = true; o+ dbg://" + QString::number(pid));
|
asyncCmd("o-*; e cfg.debug = true; o+ dbg://" + QString::number(pid), debugTask);
|
||||||
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
|
|
||||||
seekAndShow(programCounterValue);
|
|
||||||
emit registersChanged();
|
|
||||||
if (!currentlyDebugging || !currentlyEmulating) {
|
|
||||||
// prevent register flags from appearing during debug/emul
|
|
||||||
setConfig("asm.flags", false);
|
|
||||||
currentlyDebugging = true;
|
|
||||||
currentlyOpenFile = getConfig("file.path");
|
|
||||||
currentlyAttachedToPID = pid;
|
|
||||||
emit flagsChanged();
|
|
||||||
emit changeDebugView();
|
|
||||||
}
|
|
||||||
|
|
||||||
emit debugTaskStateChanged();
|
emit debugTaskStateChanged();
|
||||||
|
|
||||||
|
connect(debugTask.data(), &R2Task::finished, this, [this, pid] () {
|
||||||
|
if (debugTaskDialog) {
|
||||||
|
delete debugTaskDialog;
|
||||||
|
}
|
||||||
|
debugTask.clear();
|
||||||
|
|
||||||
|
syncAndSeekProgramCounter();
|
||||||
|
if (!currentlyDebugging || !currentlyEmulating) {
|
||||||
|
// prevent register flags from appearing during debug/emul
|
||||||
|
setConfig("asm.flags", false);
|
||||||
|
currentlyDebugging = true;
|
||||||
|
currentlyOpenFile = getConfig("file.path");
|
||||||
|
currentlyAttachedToPID = pid;
|
||||||
|
emit flagsChanged();
|
||||||
|
emit changeDebugView();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
debugTaskDialog = new R2TaskDialog(debugTask);
|
||||||
|
debugTaskDialog->setBreakOnClose(true);
|
||||||
|
debugTaskDialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
debugTaskDialog->setDesc(tr("Attaching to process (") + QString::number(pid) + ")...");
|
||||||
|
debugTaskDialog->show();
|
||||||
|
|
||||||
|
debugTask->startTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::suspendDebug()
|
void CutterCore::suspendDebug()
|
||||||
@ -1364,33 +1422,45 @@ void CutterCore::suspendDebug()
|
|||||||
|
|
||||||
void CutterCore::stopDebug()
|
void CutterCore::stopDebug()
|
||||||
{
|
{
|
||||||
if (currentlyDebugging) {
|
if (!currentlyDebugging) {
|
||||||
currentlyDebugging = false;
|
return;
|
||||||
emit debugTaskStateChanged();
|
}
|
||||||
if (currentlyEmulating) {
|
|
||||||
cmd("aeim-; aei-; wcr; .ar-");
|
if (!debugTask.isNull()) {
|
||||||
currentlyEmulating = false;
|
suspendDebug();
|
||||||
} else if (currentlyAttachedToPID != -1) {
|
}
|
||||||
cmd(QString("dp- %1; o %2; .ar-").arg(QString::number(currentlyAttachedToPID), currentlyOpenFile));
|
|
||||||
currentlyAttachedToPID = -1;
|
currentlyDebugging = false;
|
||||||
} else {
|
emit debugTaskStateChanged();
|
||||||
cmd("dk 9; oo; .ar-");
|
|
||||||
// close ptrace file descriptors left open
|
if (currentlyEmulating) {
|
||||||
QJsonArray openFilesArray = cmdj("oj").array();;
|
cmdEsil("aeim-; aei-; wcr; .ar-");
|
||||||
for (QJsonValue value : openFilesArray) {
|
currentlyEmulating = false;
|
||||||
QJsonObject openFile = value.toObject();
|
} else if (currentlyAttachedToPID != -1) {
|
||||||
QString URI = openFile["uri"].toString();
|
cmd(QString("dp- %1; o %2; .ar-").arg(
|
||||||
if (URI.contains("ptrace")) {
|
QString::number(currentlyAttachedToPID), currentlyOpenFile));
|
||||||
cmd("o-" + QString::number(openFile["fd"].toInt()));
|
currentlyAttachedToPID = -1;
|
||||||
}
|
} else {
|
||||||
|
QString ptraceFiles = "";
|
||||||
|
// close ptrace file descriptors left open
|
||||||
|
QJsonArray openFilesArray = cmdj("oj").array();;
|
||||||
|
for (QJsonValue value : openFilesArray) {
|
||||||
|
QJsonObject openFile = value.toObject();
|
||||||
|
QString URI = openFile["uri"].toString();
|
||||||
|
if (URI.contains("ptrace")) {
|
||||||
|
ptraceFiles += "o-" + QString::number(openFile["fd"].toInt()) + ";";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
seekAndShow(offsetPriorDebugging);
|
cmd("dk 9; oo; .ar-;" + ptraceFiles);
|
||||||
setConfig("asm.flags", true);
|
|
||||||
setConfig("io.cache", false);
|
|
||||||
emit flagsChanged();
|
|
||||||
emit changeDefinedView();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
syncAndSeekProgramCounter();
|
||||||
|
setConfig("asm.flags", true);
|
||||||
|
setConfig("io.cache", false);
|
||||||
|
emit flagsChanged();
|
||||||
|
emit changeDefinedView();
|
||||||
|
offsetPriorDebugging = getOffset();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::syncAndSeekProgramCounter()
|
void CutterCore::syncAndSeekProgramCounter()
|
||||||
@ -1402,137 +1472,183 @@ void CutterCore::syncAndSeekProgramCounter()
|
|||||||
|
|
||||||
void CutterCore::continueDebug()
|
void CutterCore::continueDebug()
|
||||||
{
|
{
|
||||||
if (currentlyDebugging) {
|
if (!currentlyDebugging) {
|
||||||
if (currentlyEmulating) {
|
return;
|
||||||
asyncCmdEsil("aec", debugTask);
|
}
|
||||||
} else {
|
|
||||||
asyncCmd("dc", debugTask);
|
if (currentlyEmulating) {
|
||||||
|
if (!asyncCmdEsil("aec", debugTask)) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (!debugTask.isNull()) {
|
} else {
|
||||||
emit debugTaskStateChanged();
|
if (!asyncCmd("dc", debugTask)) {
|
||||||
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
return;
|
||||||
debugTask.clear();
|
|
||||||
syncAndSeekProgramCounter();
|
|
||||||
emit registersChanged();
|
|
||||||
emit refreshCodeViews();
|
|
||||||
emit debugTaskStateChanged();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
||||||
|
debugTask.clear();
|
||||||
|
syncAndSeekProgramCounter();
|
||||||
|
emit registersChanged();
|
||||||
|
emit refreshCodeViews();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
});
|
||||||
|
|
||||||
|
debugTask->startTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::continueUntilDebug(QString offset)
|
void CutterCore::continueUntilDebug(QString offset)
|
||||||
{
|
{
|
||||||
|
if (!currentlyDebugging) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (currentlyDebugging) {
|
if (currentlyEmulating) {
|
||||||
if (currentlyEmulating) {
|
if (!asyncCmdEsil("aecu " + offset, debugTask)) {
|
||||||
asyncCmdEsil("aecu " + offset, debugTask);
|
return;
|
||||||
} else {
|
|
||||||
asyncCmd("dcu " + offset, debugTask);
|
|
||||||
}
|
}
|
||||||
if (!debugTask.isNull()) {
|
} else {
|
||||||
emit debugTaskStateChanged();
|
if (!asyncCmd("dcu " + offset, debugTask)) {
|
||||||
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
return;
|
||||||
debugTask.clear();
|
|
||||||
syncAndSeekProgramCounter();
|
|
||||||
emit registersChanged();
|
|
||||||
emit stackChanged();
|
|
||||||
emit refreshCodeViews();
|
|
||||||
emit debugTaskStateChanged();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
||||||
|
debugTask.clear();
|
||||||
|
syncAndSeekProgramCounter();
|
||||||
|
emit registersChanged();
|
||||||
|
emit stackChanged();
|
||||||
|
emit refreshCodeViews();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
});
|
||||||
|
|
||||||
|
debugTask->startTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::continueUntilCall()
|
void CutterCore::continueUntilCall()
|
||||||
{
|
{
|
||||||
if (currentlyDebugging) {
|
if (!currentlyDebugging) {
|
||||||
if (currentlyEmulating) {
|
return;
|
||||||
asyncCmdEsil("aecc", debugTask);
|
}
|
||||||
} else {
|
|
||||||
asyncCmd("dcc", debugTask);
|
if (currentlyEmulating) {
|
||||||
|
if (!asyncCmdEsil("aecc", debugTask)) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (!debugTask.isNull()) {
|
} else {
|
||||||
emit debugTaskStateChanged();
|
if (!asyncCmd("dcc", debugTask)) {
|
||||||
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
return;
|
||||||
debugTask.clear();
|
|
||||||
syncAndSeekProgramCounter();
|
|
||||||
emit debugTaskStateChanged();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
||||||
|
debugTask.clear();
|
||||||
|
syncAndSeekProgramCounter();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
});
|
||||||
|
|
||||||
|
debugTask->startTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::continueUntilSyscall()
|
void CutterCore::continueUntilSyscall()
|
||||||
{
|
{
|
||||||
if (currentlyDebugging) {
|
if (!currentlyDebugging) {
|
||||||
if (currentlyEmulating) {
|
return;
|
||||||
asyncCmdEsil("aecs", debugTask);
|
}
|
||||||
} else {
|
|
||||||
asyncCmd("dcs", debugTask);
|
if (currentlyEmulating) {
|
||||||
|
if (!asyncCmdEsil("aecs", debugTask)) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (!debugTask.isNull()) {
|
} else {
|
||||||
emit debugTaskStateChanged();
|
if (!asyncCmd("dcs", debugTask)) {
|
||||||
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
return;
|
||||||
debugTask.clear();
|
|
||||||
syncAndSeekProgramCounter();
|
|
||||||
emit debugTaskStateChanged();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
||||||
|
debugTask.clear();
|
||||||
|
syncAndSeekProgramCounter();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
});
|
||||||
|
|
||||||
|
debugTask->startTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::stepDebug()
|
void CutterCore::stepDebug()
|
||||||
{
|
{
|
||||||
if (currentlyDebugging) {
|
if (!currentlyDebugging) {
|
||||||
if (currentlyEmulating) {
|
return;
|
||||||
asyncCmdEsil("aes", debugTask);
|
}
|
||||||
} else {
|
|
||||||
asyncCmd("ds", debugTask);
|
if (currentlyEmulating) {
|
||||||
|
if (!asyncCmdEsil("aes", debugTask)) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (!debugTask.isNull()) {
|
} else {
|
||||||
emit debugTaskStateChanged();
|
if (!asyncCmd("ds", debugTask)) {
|
||||||
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
return;
|
||||||
debugTask.clear();
|
|
||||||
syncAndSeekProgramCounter();
|
|
||||||
emit debugTaskStateChanged();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
||||||
|
debugTask.clear();
|
||||||
|
syncAndSeekProgramCounter();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
});
|
||||||
|
|
||||||
|
debugTask->startTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::stepOverDebug()
|
void CutterCore::stepOverDebug()
|
||||||
{
|
{
|
||||||
if (currentlyDebugging) {
|
if (!currentlyDebugging) {
|
||||||
if (currentlyEmulating) {
|
return;
|
||||||
asyncCmdEsil("aeso", debugTask);
|
}
|
||||||
} else {
|
|
||||||
asyncCmd("dso", debugTask);
|
if (currentlyEmulating) {
|
||||||
|
if (!asyncCmdEsil("aeso", debugTask)) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (!debugTask.isNull()) {
|
} else {
|
||||||
emit debugTaskStateChanged();
|
if (!asyncCmd("dso", debugTask)) {
|
||||||
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
return;
|
||||||
debugTask.clear();
|
|
||||||
syncAndSeekProgramCounter();
|
|
||||||
emit debugTaskStateChanged();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
||||||
|
debugTask.clear();
|
||||||
|
syncAndSeekProgramCounter();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
});
|
||||||
|
|
||||||
|
debugTask->startTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::stepOutDebug()
|
void CutterCore::stepOutDebug()
|
||||||
{
|
{
|
||||||
if (currentlyDebugging) {
|
if (!currentlyDebugging) {
|
||||||
emit debugTaskStateChanged();
|
return;
|
||||||
asyncCmd("dsf", debugTask);
|
|
||||||
if (!debugTask.isNull()) {
|
|
||||||
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
|
||||||
debugTask.clear();
|
|
||||||
syncAndSeekProgramCounter();
|
|
||||||
emit debugTaskStateChanged();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
if (!asyncCmd("dsf", debugTask)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(debugTask.data(), &R2Task::finished, this, [this] () {
|
||||||
|
debugTask.clear();
|
||||||
|
syncAndSeekProgramCounter();
|
||||||
|
emit debugTaskStateChanged();
|
||||||
|
});
|
||||||
|
|
||||||
|
debugTask->startTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList CutterCore::getDebugPlugins()
|
QStringList CutterCore::getDebugPlugins()
|
||||||
|
@ -66,10 +66,11 @@ public:
|
|||||||
* @note connect to the &R2Task::finished signal to add your own logic once
|
* @note connect to the &R2Task::finished signal to add your own logic once
|
||||||
* the command is finished. Use task->getResult()/getResultJson() for the
|
* the command is finished. Use task->getResult()/getResultJson() for the
|
||||||
* return value.
|
* return value.
|
||||||
|
* Once you have setup connections you can start the task with task->startTask()
|
||||||
* If you want to seek to an address, you should use CutterCore::seek.
|
* If you want to seek to an address, you should use CutterCore::seek.
|
||||||
*/
|
*/
|
||||||
void asyncCmd(const char *str, QSharedPointer<R2Task> &task);
|
bool asyncCmd(const char *str, QSharedPointer<R2Task> &task);
|
||||||
void asyncCmd(const QString &str, QSharedPointer<R2Task> &task) { return asyncCmd(str.toUtf8().constData(), task); }
|
bool 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()); }
|
||||||
@ -91,10 +92,11 @@ public:
|
|||||||
* @note connect to the &R2Task::finished signal to add your own logic once
|
* @note connect to the &R2Task::finished signal to add your own logic once
|
||||||
* the command is finished. Use task->getResult()/getResultJson() for the
|
* the command is finished. Use task->getResult()/getResultJson() for the
|
||||||
* return value.
|
* return value.
|
||||||
|
* Once you have setup connections you can start the task with task->startTask()
|
||||||
* If you want to seek to an address, you should use CutterCore::seek.
|
* If you want to seek to an address, you should use CutterCore::seek.
|
||||||
*/
|
*/
|
||||||
void asyncCmdEsil(const char *command, QSharedPointer<R2Task> &task);
|
bool asyncCmdEsil(const char *command, QSharedPointer<R2Task> &task);
|
||||||
void asyncCmdEsil(const QString &command, QSharedPointer<R2Task> &task) { return asyncCmdEsil(command.toUtf8().constData(), task); }
|
bool 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);
|
||||||
|
25
src/dialogs/NativeDebugDialog.cpp
Normal file
25
src/dialogs/NativeDebugDialog.cpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include "NativeDebugDialog.h"
|
||||||
|
#include "ui_NativeDebugDialog.h"
|
||||||
|
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
NativeDebugDialog::NativeDebugDialog(QWidget *parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
ui(new Ui::NativeDebugDialog)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeDebugDialog::~NativeDebugDialog() {}
|
||||||
|
|
||||||
|
QString NativeDebugDialog::getArgs() const
|
||||||
|
{
|
||||||
|
return ui->argEdit->toPlainText();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeDebugDialog::setArgs(const QString &args)
|
||||||
|
{
|
||||||
|
ui->argEdit->setText(args);
|
||||||
|
ui->argEdit->selectAll();
|
||||||
|
}
|
29
src/dialogs/NativeDebugDialog.h
Normal file
29
src/dialogs/NativeDebugDialog.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef NATIVEDEBUGDIALOG_H
|
||||||
|
#define NATIVEDEBUGDIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class NativeDebugDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Dialog for connecting to native debug
|
||||||
|
*/
|
||||||
|
class NativeDebugDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit NativeDebugDialog(QWidget *parent = nullptr);
|
||||||
|
~NativeDebugDialog();
|
||||||
|
|
||||||
|
QString getArgs() const;
|
||||||
|
void setArgs(const QString &args);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<Ui::NativeDebugDialog> ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // NATIVE_DEBUG_DIALOG
|
100
src/dialogs/NativeDebugDialog.ui
Normal file
100
src/dialogs/NativeDebugDialog.ui
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>NativeDebugDialog</class>
|
||||||
|
<widget class="QDialog" name="NativeDebugDialog">
|
||||||
|
<property name="windowModality">
|
||||||
|
<enum>Qt::NonModal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>320</width>
|
||||||
|
<height>101</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string notr="true">Native debugging configuration</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="verticalLayoutWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>301</width>
|
||||||
|
<height>81</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="argText">
|
||||||
|
<property name="text">
|
||||||
|
<string>Command line arguments:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="argEdit">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>382</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>NativeDebugDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>234</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>NativeDebugDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>240</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
@ -37,11 +37,6 @@ void DebugOptionsWidget::updateDebugPlugin()
|
|||||||
connect(ui->pluginComboBox, SIGNAL(currentIndexChanged(const QString &)), this,
|
connect(ui->pluginComboBox, SIGNAL(currentIndexChanged(const QString &)), this,
|
||||||
SLOT(on_pluginComboBox_currentIndexChanged(const QString &)));
|
SLOT(on_pluginComboBox_currentIndexChanged(const QString &)));
|
||||||
|
|
||||||
QString debugArgs = Core()->getConfig("dbg.args");
|
|
||||||
ui->debugArgs->setText(debugArgs);
|
|
||||||
ui->debugArgs->setPlaceholderText(debugArgs);
|
|
||||||
connect(ui->debugArgs, &QLineEdit::editingFinished, this, &DebugOptionsWidget::updateDebugArgs);
|
|
||||||
|
|
||||||
QString stackSize = Core()->getConfig("esil.stack.size");
|
QString stackSize = Core()->getConfig("esil.stack.size");
|
||||||
ui->stackSize->setText(stackSize);
|
ui->stackSize->setText(stackSize);
|
||||||
ui->stackSize->setPlaceholderText(stackSize);
|
ui->stackSize->setPlaceholderText(stackSize);
|
||||||
@ -52,13 +47,6 @@ void DebugOptionsWidget::updateDebugPlugin()
|
|||||||
connect(ui->stackSize, &QLineEdit::editingFinished, this, &DebugOptionsWidget::updateStackSize);
|
connect(ui->stackSize, &QLineEdit::editingFinished, this, &DebugOptionsWidget::updateStackSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugOptionsWidget::updateDebugArgs()
|
|
||||||
{
|
|
||||||
QString newArgs = ui->debugArgs->text();
|
|
||||||
Core()->setConfig("dbg.args", newArgs);
|
|
||||||
ui->debugArgs->setPlaceholderText(newArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebugOptionsWidget::on_pluginComboBox_currentIndexChanged(const QString &plugin)
|
void DebugOptionsWidget::on_pluginComboBox_currentIndexChanged(const QString &plugin)
|
||||||
{
|
{
|
||||||
Core()->setDebugPlugin(plugin);
|
Core()->setDebugPlugin(plugin);
|
||||||
|
@ -24,7 +24,6 @@ private:
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void updateDebugPlugin();
|
void updateDebugPlugin();
|
||||||
void updateDebugArgs();
|
|
||||||
void updateStackAddr();
|
void updateStackAddr();
|
||||||
void updateStackSize();
|
void updateStackSize();
|
||||||
void on_pluginComboBox_currentIndexChanged(const QString &index);
|
void on_pluginComboBox_currentIndexChanged(const QString &index);
|
||||||
|
@ -33,30 +33,13 @@
|
|||||||
<widget class="QComboBox" name="pluginComboBox"/>
|
<widget class="QComboBox" name="pluginComboBox"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="argsLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Program Arguments:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QLineEdit" name="debugArgs">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
|
||||||
<widget class="QLabel" name="esilstackAddr">
|
<widget class="QLabel" name="esilstackAddr">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>ESIL stack address:</string>
|
<string>ESIL stack address:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="1" column="1">
|
||||||
<widget class="QLineEdit" name="stackAddr">
|
<widget class="QLineEdit" name="stackAddr">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
@ -66,14 +49,14 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QLabel" name="esilStackSize">
|
<widget class="QLabel" name="esilStackSize">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>ESIL stack size:</string>
|
<string>ESIL stack size:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QLineEdit" name="stackSize">
|
<widget class="QLineEdit" name="stackSize">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "DebugActions.h"
|
#include "DebugActions.h"
|
||||||
#include "core/MainWindow.h"
|
#include "core/MainWindow.h"
|
||||||
#include "dialogs/AttachProcDialog.h"
|
#include "dialogs/AttachProcDialog.h"
|
||||||
|
#include "dialogs/NativeDebugDialog.h"
|
||||||
#include "common/Configuration.h"
|
#include "common/Configuration.h"
|
||||||
#include "common/Helpers.h"
|
#include "common/Helpers.h"
|
||||||
|
|
||||||
@ -19,24 +20,22 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) :
|
|||||||
// setIconSize(QSize(16, 16));
|
// setIconSize(QSize(16, 16));
|
||||||
|
|
||||||
// define icons
|
// define icons
|
||||||
QIcon startDebugIcon = QIcon(":/img/icons/play_light_debug.svg");
|
|
||||||
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 startRemoteIcon = QIcon(":/img/icons/play_light_remote.svg");
|
QIcon startRemoteIcon = QIcon(":/img/icons/play_light_remote.svg");
|
||||||
stopIcon = QIcon(":/img/icons/media-stop_light.svg");
|
stopIcon = QIcon(":/img/icons/media-stop_light.svg");
|
||||||
QIcon restartIcon = QIcon(":/img/icons/spin_light.svg");
|
restartIcon = QIcon(":/img/icons/spin_light.svg");
|
||||||
detachIcon = QIcon(":/img/icons/detach_debugger.svg");
|
detachIcon = QIcon(":/img/icons/detach_debugger.svg");
|
||||||
|
startDebugIcon = QIcon(":/img/icons/play_light_debug.svg");
|
||||||
continueIcon = QIcon(":/img/icons/media-skip-forward_light.svg");
|
continueIcon = QIcon(":/img/icons/media-skip-forward_light.svg");
|
||||||
suspendIcon = QIcon(":/img/icons/media-suspend_light.svg");
|
suspendIcon = QIcon(":/img/icons/media-suspend_light.svg");
|
||||||
|
|
||||||
// define action labels
|
// define action labels
|
||||||
QString startDebugLabel = tr("Start debug");
|
|
||||||
QString startEmulLabel = tr("Start emulation");
|
QString startEmulLabel = tr("Start emulation");
|
||||||
QString startAttachLabel = tr("Attach to process");
|
QString startAttachLabel = tr("Attach to process");
|
||||||
QString startRemoteLabel = tr("Connect to a remote debugger");
|
QString startRemoteLabel = tr("Connect to a remote debugger");
|
||||||
QString stopDebugLabel = tr("Stop debug");
|
QString stopDebugLabel = tr("Stop debug");
|
||||||
QString stopEmulLabel = tr("Stop emulation");
|
QString stopEmulLabel = tr("Stop emulation");
|
||||||
QString restartDebugLabel = tr("Restart program");
|
|
||||||
QString restartEmulLabel = tr("Restart emulation");
|
QString restartEmulLabel = tr("Restart emulation");
|
||||||
QString continueUMLabel = tr("Continue until main");
|
QString continueUMLabel = tr("Continue until main");
|
||||||
QString continueUCLabel = tr("Continue until call");
|
QString continueUCLabel = tr("Continue until call");
|
||||||
@ -44,8 +43,10 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) :
|
|||||||
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 process");
|
suspendLabel = tr("Suspend the process");
|
||||||
continueLabel = tr("Continue");
|
continueLabel = tr("Continue");
|
||||||
|
restartDebugLabel = tr("Restart program");
|
||||||
|
startDebugLabel = tr("Start debug");
|
||||||
|
|
||||||
// define actions
|
// define actions
|
||||||
actionStart = new QAction(startDebugIcon, startDebugLabel, this);
|
actionStart = new QAction(startDebugIcon, startDebugLabel, this);
|
||||||
@ -107,7 +108,7 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) :
|
|||||||
// necessary to avoid staying stuck
|
// necessary to avoid staying stuck
|
||||||
toggleActions = {actionStepOver, actionStep, actionStepOut, actionContinueUntilMain,
|
toggleActions = {actionStepOver, actionStep, actionStepOut, actionContinueUntilMain,
|
||||||
actionContinueUntilCall, actionContinueUntilSyscall};
|
actionContinueUntilCall, actionContinueUntilSyscall};
|
||||||
toggleConnectionActions = {actionAttach, actionStart, actionStartRemote, actionStartEmul};
|
toggleConnectionActions = {actionAttach, actionStartRemote, actionStartEmul};
|
||||||
|
|
||||||
connect(Core(), &CutterCore::debugTaskStateChanged, this, [ = ]() {
|
connect(Core(), &CutterCore::debugTaskStateChanged, this, [ = ]() {
|
||||||
bool disableToolbar = Core()->isDebugTaskInProgress();
|
bool disableToolbar = Core()->isDebugTaskInProgress();
|
||||||
@ -146,25 +147,7 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) :
|
|||||||
setAllActionsVisible(false);
|
setAllActionsVisible(false);
|
||||||
});
|
});
|
||||||
connect(actionStep, &QAction::triggered, Core(), &CutterCore::stepDebug);
|
connect(actionStep, &QAction::triggered, Core(), &CutterCore::stepDebug);
|
||||||
connect(actionStart, &QAction::triggered, [ = ]() {
|
connect(actionStart, &QAction::triggered, this, &DebugActions::startDebug);
|
||||||
// check if file is executable before starting debug
|
|
||||||
QString filename = Core()->getConfig("file.path").section(QLatin1Char(' '), 0, 0);
|
|
||||||
QFileInfo info(filename);
|
|
||||||
if (!Core()->currentlyDebugging && !info.isExecutable()) {
|
|
||||||
QMessageBox msgBox;
|
|
||||||
msgBox.setText(tr("File '%1' does not have executable permissions.").arg(filename));
|
|
||||||
msgBox.exec();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setAllActionsVisible(true);
|
|
||||||
actionAttach->setVisible(false);
|
|
||||||
actionStartRemote->setVisible(false);
|
|
||||||
actionStartEmul->setVisible(false);
|
|
||||||
actionStart->setText(restartDebugLabel);
|
|
||||||
actionStart->setIcon(restartIcon);
|
|
||||||
setButtonVisibleIfMainExists();
|
|
||||||
Core()->startDebug();
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(actionAttach, &QAction::triggered, this, &DebugActions::attachProcessDialog);
|
connect(actionAttach, &QAction::triggered, this, &DebugActions::attachProcessDialog);
|
||||||
connect(actionStartRemote, &QAction::triggered, this, &DebugActions::attachRemoteDialog);
|
connect(actionStartRemote, &QAction::triggered, this, &DebugActions::attachRemoteDialog);
|
||||||
@ -210,6 +193,18 @@ void DebugActions::setButtonVisibleIfMainExists()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DebugActions::showDebugWarning()
|
||||||
|
{
|
||||||
|
if (!acceptedDebugWarning) {
|
||||||
|
acceptedDebugWarning = true;
|
||||||
|
QMessageBox msgBox;
|
||||||
|
msgBox.setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse);
|
||||||
|
msgBox.setText(tr("Debug is currently in beta.\n") +
|
||||||
|
tr("If you encounter any problems or have suggestions, please submit an issue to https://github.com/radareorg/cutter/issues"));
|
||||||
|
msgBox.exec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DebugActions::continueUntilMain()
|
void DebugActions::continueUntilMain()
|
||||||
{
|
{
|
||||||
QString mainAddr = Core()->cmd("?v sym.main");
|
QString mainAddr = Core()->cmd("?v sym.main");
|
||||||
@ -227,7 +222,8 @@ void DebugActions::attachRemoteDebugger()
|
|||||||
actionStop->setText(stopAttachLabel);
|
actionStop->setText(stopAttachLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugActions::onAttachedRemoteDebugger(bool successfully) {
|
void DebugActions::onAttachedRemoteDebugger(bool successfully)
|
||||||
|
{
|
||||||
if (!successfully) {
|
if (!successfully) {
|
||||||
QMessageBox msgBox;
|
QMessageBox msgBox;
|
||||||
msgBox.setText(tr("Error connecting."));
|
msgBox.setText(tr("Error connecting."));
|
||||||
@ -241,6 +237,8 @@ void DebugActions::onAttachedRemoteDebugger(bool successfully) {
|
|||||||
|
|
||||||
void DebugActions::attachRemoteDialog()
|
void DebugActions::attachRemoteDialog()
|
||||||
{
|
{
|
||||||
|
showDebugWarning();
|
||||||
|
|
||||||
if (!remoteDialog) {
|
if (!remoteDialog) {
|
||||||
remoteDialog = new RemoteDebugDialog(main);
|
remoteDialog = new RemoteDebugDialog(main);
|
||||||
}
|
}
|
||||||
@ -261,6 +259,8 @@ void DebugActions::attachRemoteDialog()
|
|||||||
|
|
||||||
void DebugActions::attachProcessDialog()
|
void DebugActions::attachProcessDialog()
|
||||||
{
|
{
|
||||||
|
showDebugWarning();
|
||||||
|
|
||||||
AttachProcDialog dialog(main);
|
AttachProcDialog dialog(main);
|
||||||
bool success = false;
|
bool success = false;
|
||||||
while (!success) {
|
while (!success) {
|
||||||
@ -293,6 +293,44 @@ void DebugActions::attachProcess(int pid)
|
|||||||
Core()->attachDebug(pid);
|
Core()->attachDebug(pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DebugActions::startDebug()
|
||||||
|
{
|
||||||
|
// check if file is executable before starting debug
|
||||||
|
QString filename = Core()->getConfig("file.path").section(QLatin1Char(' '), 0, 0);
|
||||||
|
|
||||||
|
QFileInfo info(filename);
|
||||||
|
if (!Core()->currentlyDebugging && !info.isExecutable()) {
|
||||||
|
QMessageBox msgBox;
|
||||||
|
msgBox.setText(tr("File '%1' does not have executable permissions.").arg(filename));
|
||||||
|
msgBox.exec();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
showDebugWarning();
|
||||||
|
|
||||||
|
NativeDebugDialog dialog(main);
|
||||||
|
dialog.setArgs(Core()->getConfig("dbg.args"));
|
||||||
|
QString args;
|
||||||
|
if (dialog.exec()) {
|
||||||
|
args = dialog.getArgs();
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update dbg.args with the new args
|
||||||
|
Core()->setConfig("dbg.args", args);
|
||||||
|
|
||||||
|
setAllActionsVisible(true);
|
||||||
|
actionAttach->setVisible(false);
|
||||||
|
actionStartRemote->setVisible(false);
|
||||||
|
actionStartEmul->setVisible(false);
|
||||||
|
actionStart->setText(restartDebugLabel);
|
||||||
|
actionStart->setIcon(restartIcon);
|
||||||
|
setButtonVisibleIfMainExists();
|
||||||
|
|
||||||
|
Core()->startDebug();
|
||||||
|
}
|
||||||
|
|
||||||
void DebugActions::setAllActionsVisible(bool visible)
|
void DebugActions::setAllActionsVisible(bool visible)
|
||||||
{
|
{
|
||||||
for (QAction *action : allActions) {
|
for (QAction *action : allActions) {
|
||||||
|
@ -32,11 +32,15 @@ public:
|
|||||||
QAction *actionStop;
|
QAction *actionStop;
|
||||||
QAction *actionAllContinues;
|
QAction *actionAllContinues;
|
||||||
|
|
||||||
// Continue and suspend interchange during runtime
|
// Continue/suspend and start/restart interchange during runtime
|
||||||
QIcon continueIcon;
|
QIcon continueIcon;
|
||||||
QIcon suspendIcon;
|
QIcon suspendIcon;
|
||||||
|
QIcon restartIcon;
|
||||||
|
QIcon startDebugIcon;
|
||||||
QString suspendLabel;
|
QString suspendLabel;
|
||||||
QString continueLabel;
|
QString continueLabel;
|
||||||
|
QString restartDebugLabel;
|
||||||
|
QString startDebugLabel;
|
||||||
|
|
||||||
// Stop and Detach interchange during runtime
|
// Stop and Detach interchange during runtime
|
||||||
QIcon detachIcon;
|
QIcon detachIcon;
|
||||||
@ -52,9 +56,14 @@ private:
|
|||||||
QToolButton *continueUntilButton;
|
QToolButton *continueUntilButton;
|
||||||
RemoteDebugDialog *remoteDialog = nullptr;
|
RemoteDebugDialog *remoteDialog = nullptr;
|
||||||
MainWindow *main;
|
MainWindow *main;
|
||||||
|
bool acceptedDebugWarning = false;
|
||||||
|
|
||||||
|
// TODO: Remove once debug is stable
|
||||||
|
void showDebugWarning();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void continueUntilMain();
|
void continueUntilMain();
|
||||||
|
void startDebug();
|
||||||
void attachProcessDialog();
|
void attachProcessDialog();
|
||||||
void attachProcess(int pid);
|
void attachProcess(int pid);
|
||||||
void attachRemoteDialog();
|
void attachRemoteDialog();
|
||||||
|
Loading…
Reference in New Issue
Block a user