mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-18 19:06:10 +00:00
gdbserver and windbg remote debugging support (#1874)
* Added remote debugging
This commit is contained in:
parent
c85e1db3b3
commit
49d58b3624
@ -267,6 +267,7 @@ SOURCES += \
|
||||
dialogs/EditInstructionDialog.cpp \
|
||||
dialogs/FlagDialog.cpp \
|
||||
dialogs/RenameDialog.cpp \
|
||||
dialogs/RemoteDebugDialog.cpp \
|
||||
dialogs/XrefsDialog.cpp \
|
||||
core/MainWindow.cpp \
|
||||
common/Helpers.cpp \
|
||||
@ -335,6 +336,7 @@ SOURCES += \
|
||||
common/CommandTask.cpp \
|
||||
common/ProgressIndicator.cpp \
|
||||
common/R2Task.cpp \
|
||||
dialogs/R2TaskDialog.cpp \
|
||||
widgets/DebugActions.cpp \
|
||||
widgets/MemoryMapWidget.cpp \
|
||||
dialogs/preferences/DebugOptionsWidget.cpp \
|
||||
@ -398,6 +400,7 @@ HEADERS += \
|
||||
dialogs/EditInstructionDialog.h \
|
||||
dialogs/FlagDialog.h \
|
||||
dialogs/RenameDialog.h \
|
||||
dialogs/RemoteDebugDialog.h \
|
||||
dialogs/XrefsDialog.h \
|
||||
common/Helpers.h \
|
||||
common/HexAsciiHighlighter.h \
|
||||
@ -469,6 +472,7 @@ HEADERS += \
|
||||
common/ProgressIndicator.h \
|
||||
plugins/CutterPlugin.h \
|
||||
common/R2Task.h \
|
||||
dialogs/R2TaskDialog.h \
|
||||
widgets/DebugActions.h \
|
||||
widgets/MemoryMapWidget.h \
|
||||
dialogs/preferences/DebugOptionsWidget.h \
|
||||
@ -527,6 +531,7 @@ FORMS += \
|
||||
dialogs/EditInstructionDialog.ui \
|
||||
dialogs/FlagDialog.ui \
|
||||
dialogs/RenameDialog.ui \
|
||||
dialogs/RemoteDebugDialog.ui \
|
||||
dialogs/XrefsDialog.ui \
|
||||
dialogs/NewfileDialog.ui \
|
||||
dialogs/InitialOptionsDialog.ui \
|
||||
@ -552,6 +557,7 @@ FORMS += \
|
||||
dialogs/VersionInfoDialog.ui \
|
||||
widgets/ZignaturesWidget.ui \
|
||||
dialogs/AsyncTaskDialog.ui \
|
||||
dialogs/R2TaskDialog.ui \
|
||||
widgets/StackWidget.ui \
|
||||
widgets/RegistersWidget.ui \
|
||||
widgets/ThreadsWidget.ui \
|
||||
|
@ -15,6 +15,8 @@ private:
|
||||
void taskFinished();
|
||||
|
||||
public:
|
||||
using Ptr = QSharedPointer<R2Task>;
|
||||
|
||||
explicit R2Task(const QString &cmd, bool transient = true);
|
||||
~R2Task();
|
||||
|
||||
@ -30,4 +32,4 @@ signals:
|
||||
void finished();
|
||||
};
|
||||
|
||||
#endif // R2TASK_H
|
||||
#endif // R2TASK_H
|
||||
|
@ -1228,6 +1228,59 @@ void CutterCore::startEmulation()
|
||||
emit debugTaskStateChanged();
|
||||
}
|
||||
|
||||
void CutterCore::attachRemote(const QString &uri)
|
||||
{
|
||||
if (!currentlyDebugging) {
|
||||
offsetPriorDebugging = getOffset();
|
||||
}
|
||||
|
||||
// connect to a debugger with the given plugin
|
||||
asyncCmd("o-*; e cfg.debug = true; o+ " + uri, debugTask);
|
||||
emit debugTaskStateChanged();
|
||||
|
||||
connect(debugTask.data(), &R2Task::finished, this, [this, uri] () {
|
||||
if (debugTaskDialog) {
|
||||
delete debugTaskDialog;
|
||||
}
|
||||
debugTask.clear();
|
||||
// Check if we actually connected
|
||||
bool connected = false;
|
||||
QJsonArray openFilesArray = getOpenedFiles();
|
||||
for (QJsonValue value : openFilesArray) {
|
||||
QJsonObject openFile = value.toObject();
|
||||
QString fileUri= openFile["uri"].toString();
|
||||
if (!fileUri.compare(uri)) {
|
||||
connected = true;
|
||||
}
|
||||
}
|
||||
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
|
||||
seekAndShow(programCounterValue);
|
||||
if (!connected) {
|
||||
emit attachedRemote(false);
|
||||
emit debugTaskStateChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
emit registersChanged();
|
||||
if (!currentlyDebugging || !currentlyEmulating) {
|
||||
// prevent register flags from appearing during debug/emul
|
||||
setConfig("asm.flags", false);
|
||||
currentlyDebugging = true;
|
||||
emit flagsChanged();
|
||||
emit changeDebugView();
|
||||
}
|
||||
|
||||
emit attachedRemote(true);
|
||||
emit debugTaskStateChanged();
|
||||
});
|
||||
|
||||
debugTaskDialog = new R2TaskDialog(debugTask);
|
||||
debugTaskDialog->setBreakOnClose(true);
|
||||
debugTaskDialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
debugTaskDialog->setDesc("Connecting to: " + uri);
|
||||
debugTaskDialog->show();
|
||||
}
|
||||
|
||||
void CutterCore::attachDebug(int pid)
|
||||
{
|
||||
if (!currentlyDebugging) {
|
||||
|
@ -19,10 +19,12 @@ class BasicInstructionHighlighter;
|
||||
class CutterCore;
|
||||
class Decompiler;
|
||||
class R2Task;
|
||||
class R2TaskDialog;
|
||||
|
||||
#include "plugins/CutterPlugin.h"
|
||||
#include "common/BasicBlockHighlighter.h"
|
||||
#include "common/R2Task.h"
|
||||
#include "dialogs/R2TaskDialog.h"
|
||||
|
||||
#define Core() (CutterCore::instance())
|
||||
|
||||
@ -267,6 +269,12 @@ public:
|
||||
QJsonDocument getBacktrace();
|
||||
void startDebug();
|
||||
void startEmulation();
|
||||
/**
|
||||
* @brief attach to a remote debugger
|
||||
* @param uri remote debugger uri
|
||||
* @note attachedRemote(bool) signals the result
|
||||
*/
|
||||
void attachRemote(const QString &uri);
|
||||
void attachDebug(int pid);
|
||||
void stopDebug();
|
||||
void suspendDebug();
|
||||
@ -473,6 +481,8 @@ signals:
|
||||
void classRenamed(const QString &oldName, const QString &newName);
|
||||
void classAttrsChanged(const QString &cls);
|
||||
|
||||
void attachedRemote(bool successfully);
|
||||
|
||||
void projectSaved(bool successfully, const QString &name);
|
||||
|
||||
/**
|
||||
@ -527,6 +537,7 @@ private:
|
||||
BasicInstructionHighlighter biHighlighter;
|
||||
|
||||
QSharedPointer<R2Task> debugTask;
|
||||
R2TaskDialog *debugTaskDialog;
|
||||
};
|
||||
|
||||
class RCoreLocked
|
||||
|
72
src/dialogs/R2TaskDialog.cpp
Normal file
72
src/dialogs/R2TaskDialog.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
#include "R2TaskDialog.h"
|
||||
#include "common/R2Task.h"
|
||||
|
||||
#include <QCloseEvent>
|
||||
|
||||
#include "ui_R2TaskDialog.h"
|
||||
|
||||
R2TaskDialog::R2TaskDialog(R2Task::Ptr task, QWidget *parent)
|
||||
: QDialog(parent),
|
||||
ui(new Ui::R2TaskDialog),
|
||||
task(task)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
connect(task.data(), &R2Task::finished, this, [this]() {
|
||||
close();
|
||||
});
|
||||
|
||||
connect(&timer, SIGNAL(timeout()), this, SLOT(updateProgressTimer()));
|
||||
timer.setInterval(1000);
|
||||
timer.setSingleShot(false);
|
||||
timer.start();
|
||||
|
||||
elapsedTimer.start();
|
||||
updateProgressTimer();
|
||||
}
|
||||
|
||||
R2TaskDialog::~R2TaskDialog()
|
||||
{
|
||||
}
|
||||
|
||||
void R2TaskDialog::updateProgressTimer()
|
||||
{
|
||||
int secondsElapsed = elapsedTimer.elapsed() / 1000;
|
||||
int minutesElapsed = secondsElapsed / 60;
|
||||
int hoursElapsed = minutesElapsed / 60;
|
||||
|
||||
QString label = tr("Running for") + " ";
|
||||
if (hoursElapsed) {
|
||||
label += tr("%n hour", "%n hours", hoursElapsed);
|
||||
label += " ";
|
||||
}
|
||||
if (minutesElapsed) {
|
||||
label += tr("%n minute", "%n minutes", minutesElapsed % 60);
|
||||
label += " ";
|
||||
}
|
||||
label += tr("%n seconds", "%n second", secondsElapsed % 60);
|
||||
ui->timeLabel->setText(label);
|
||||
}
|
||||
|
||||
void R2TaskDialog::setDesc(const QString &label)
|
||||
{
|
||||
ui->descLabel->setText(label);
|
||||
}
|
||||
|
||||
void R2TaskDialog::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
if (breakOnClose) {
|
||||
task->breakTask();
|
||||
setDesc("Attempting to stop the task...");
|
||||
event->ignore();
|
||||
} else {
|
||||
QWidget::closeEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void R2TaskDialog::reject()
|
||||
{
|
||||
task->breakTask();
|
||||
setDesc("Attempting to stop the task...");
|
||||
|
||||
}
|
49
src/dialogs/R2TaskDialog.h
Normal file
49
src/dialogs/R2TaskDialog.h
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef R2TASKDIALOG_H
|
||||
#define R2TASKDIALOG_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QDialog>
|
||||
#include <QTimer>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include "common/R2Task.h"
|
||||
|
||||
class R2Task;
|
||||
namespace Ui {
|
||||
class R2TaskDialog;
|
||||
}
|
||||
|
||||
class R2TaskDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
using Ptr = QSharedPointer<R2Task>;
|
||||
R2TaskDialog(Ptr task, QWidget *parent = nullptr);
|
||||
~R2TaskDialog();
|
||||
|
||||
void setBreakOnClose(bool v) { breakOnClose = v; }
|
||||
bool getBreakOnClose() { return breakOnClose; }
|
||||
void setDesc(const QString &label);
|
||||
|
||||
public slots:
|
||||
void reject() override;
|
||||
|
||||
private slots:
|
||||
void updateProgressTimer();
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::R2TaskDialog> ui;
|
||||
QSharedPointer<R2Task> task;
|
||||
|
||||
QTimer timer;
|
||||
QElapsedTimer elapsedTimer;
|
||||
|
||||
bool breakOnClose = false;
|
||||
};
|
||||
|
||||
#endif //R2TASKDIALOG_H
|
91
src/dialogs/R2TaskDialog.ui
Normal file
91
src/dialogs/R2TaskDialog.ui
Normal file
@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>R2TaskDialog</class>
|
||||
<widget class="QDialog" name="R2TaskDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>87</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>R2 Task</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="descLabel">
|
||||
<property name="text">
|
||||
<string>R2 task in progress..</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="timeLabel">
|
||||
<property name="text">
|
||||
<string>Time</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="maximum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="textVisible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>R2TaskDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>R2TaskDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
188
src/dialogs/RemoteDebugDialog.cpp
Normal file
188
src/dialogs/RemoteDebugDialog.cpp
Normal file
@ -0,0 +1,188 @@
|
||||
#include "RemoteDebugDialog.h"
|
||||
#include "ui_RemoteDebugDialog.h"
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QFileInfo>
|
||||
#include <QMessageBox>
|
||||
|
||||
#define GDBSERVER "GDB"
|
||||
#define WINDBGPIPE "WinDbg - Pipe"
|
||||
#define WINDBG_URI_PREFIX "windbg"
|
||||
#define GDB_URI_PREFIX "gdb"
|
||||
#define DEFAULT_INDEX (GDBSERVER)
|
||||
|
||||
RemoteDebugDialog::RemoteDebugDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::RemoteDebugDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
|
||||
// Set a default selection
|
||||
ui->debuggerCombo->setCurrentIndex(ui->debuggerCombo->findText(DEFAULT_INDEX));
|
||||
onIndexChange();
|
||||
|
||||
connect(ui->debuggerCombo,
|
||||
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
||||
this, &RemoteDebugDialog::onIndexChange);
|
||||
}
|
||||
|
||||
RemoteDebugDialog::~RemoteDebugDialog() {}
|
||||
|
||||
bool RemoteDebugDialog::validate()
|
||||
{
|
||||
QString debugger = getDebugger();
|
||||
|
||||
if (debugger == GDBSERVER) {
|
||||
if (!validateIp()) {
|
||||
return false;
|
||||
}
|
||||
if (!validatePort()) {
|
||||
return false;
|
||||
}
|
||||
} else if (debugger == WINDBGPIPE) {
|
||||
if (!validatePath()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText(tr("Invalid debugger"));
|
||||
msgBox.exec();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RemoteDebugDialog::validateIp()
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
|
||||
QString ip = getIp();
|
||||
if (QHostAddress(ip).isNull()) {
|
||||
msgBox.setText(tr("Invalid IP address"));
|
||||
msgBox.exec();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RemoteDebugDialog::validatePath()
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
|
||||
QString path = getPath();
|
||||
if (!QFileInfo(path).exists()) {
|
||||
msgBox.setText(tr("Path does not exist"));
|
||||
msgBox.exec();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RemoteDebugDialog::validatePort()
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
|
||||
int port = getPort();
|
||||
if (port < 1 || port > 65535) {
|
||||
msgBox.setText(tr("Invalid port"));
|
||||
msgBox.exec();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void RemoteDebugDialog::onIndexChange()
|
||||
{
|
||||
QString debugger = getDebugger();
|
||||
if (debugger == GDBSERVER) {
|
||||
activateGdb();
|
||||
} else if (debugger == WINDBGPIPE) {
|
||||
activateWinDbgPipe();
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteDebugDialog::activateGdb()
|
||||
{
|
||||
ui->ipEdit->setVisible(true);
|
||||
ui->portEdit->setVisible(true);
|
||||
ui->ipText->setVisible(true);
|
||||
ui->portText->setVisible(true);
|
||||
ui->pathEdit->setVisible(false);
|
||||
ui->pathText->setVisible(false);
|
||||
}
|
||||
|
||||
void RemoteDebugDialog::activateWinDbgPipe()
|
||||
{
|
||||
ui->ipEdit->setVisible(false);
|
||||
ui->portEdit->setVisible(false);
|
||||
ui->ipText->setVisible(false);
|
||||
ui->portText->setVisible(false);
|
||||
ui->pathEdit->setVisible(true);
|
||||
ui->pathText->setVisible(true);
|
||||
}
|
||||
|
||||
void RemoteDebugDialog::on_buttonBox_accepted()
|
||||
{
|
||||
}
|
||||
|
||||
void RemoteDebugDialog::on_buttonBox_rejected()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void RemoteDebugDialog::setIp(QString ip)
|
||||
{
|
||||
ui->ipEdit->setText(ip);
|
||||
ui->ipEdit->selectAll();
|
||||
}
|
||||
|
||||
void RemoteDebugDialog::setPath(QString path)
|
||||
{
|
||||
ui->pathEdit->setText(path);
|
||||
ui->pathEdit->selectAll();
|
||||
}
|
||||
|
||||
void RemoteDebugDialog::setPort(QString port)
|
||||
{
|
||||
ui->portEdit->setText(port);
|
||||
ui->portEdit->selectAll();
|
||||
}
|
||||
|
||||
void RemoteDebugDialog::setDebugger(QString debugger)
|
||||
{
|
||||
ui->debuggerCombo->setCurrentIndex(ui->debuggerCombo->findText(debugger));
|
||||
}
|
||||
|
||||
QString RemoteDebugDialog::getUri() const
|
||||
{
|
||||
QString debugger = getDebugger();
|
||||
if (debugger == WINDBGPIPE) {
|
||||
return QString("%1://%2").arg(WINDBG_URI_PREFIX, getPath());
|
||||
} else if (debugger == GDBSERVER) {
|
||||
return QString("%1://%2:%3").arg(GDB_URI_PREFIX, getIp(), QString::number(getPort()));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QString RemoteDebugDialog::getIp() const
|
||||
{
|
||||
return ui->ipEdit->text();
|
||||
}
|
||||
|
||||
QString RemoteDebugDialog::getPath() const
|
||||
{
|
||||
return ui->pathEdit->text();
|
||||
}
|
||||
|
||||
int RemoteDebugDialog::getPort() const
|
||||
{
|
||||
return ui->portEdit->text().toInt();
|
||||
}
|
||||
|
||||
QString RemoteDebugDialog::getDebugger() const
|
||||
{
|
||||
return ui->debuggerCombo->currentText();
|
||||
}
|
48
src/dialogs/RemoteDebugDialog.h
Normal file
48
src/dialogs/RemoteDebugDialog.h
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef REMOTEDEBUGDIALOG_H
|
||||
#define REMOTEDEBUGDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <memory>
|
||||
|
||||
namespace Ui {
|
||||
class RemoteDebugDialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Dialog for connecting to remote debuggers
|
||||
*/
|
||||
class RemoteDebugDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RemoteDebugDialog(QWidget *parent = nullptr);
|
||||
~RemoteDebugDialog();
|
||||
|
||||
void setIp(QString ip);
|
||||
void setPort(QString port);
|
||||
void setPath(QString path);
|
||||
void setDebugger(QString debugger);
|
||||
QString getUri() const;
|
||||
QString getIp() const;
|
||||
int getPort() const;
|
||||
QString getPath() const;
|
||||
QString getDebugger() const;
|
||||
bool validate();
|
||||
|
||||
private slots:
|
||||
void on_buttonBox_accepted();
|
||||
void on_buttonBox_rejected();
|
||||
void onIndexChange();
|
||||
|
||||
private:
|
||||
void activateGdb();
|
||||
void activateWinDbgPipe();
|
||||
bool validateIp();
|
||||
bool validatePort();
|
||||
bool validatePath();
|
||||
|
||||
std::unique_ptr<Ui::RemoteDebugDialog> ui;
|
||||
};
|
||||
|
||||
#endif // REMOTE_DEBUG_DIALOG
|
197
src/dialogs/RemoteDebugDialog.ui
Normal file
197
src/dialogs/RemoteDebugDialog.ui
Normal file
@ -0,0 +1,197 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>RemoteDebugDialog</class>
|
||||
<widget class="QDialog" name="RemoteDebugDialog">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::NonModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>320</width>
|
||||
<height>170</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Remote debugging configuration</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="gridLayoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>300</width>
|
||||
<height>110</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="debugText">
|
||||
<property name="text">
|
||||
<string>Debugger:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="debuggerCombo">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>GDB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>WinDbg - Pipe</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="ipText">
|
||||
<property name="text">
|
||||
<string>IP:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="ipEdit">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>382</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="inputMask">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="frame">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="portText">
|
||||
<property name="text">
|
||||
<string>Port:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="portEdit">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>382</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="inputMask">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="frame">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="pathText">
|
||||
<property name="text">
|
||||
<string>Path:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="pathEdit">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>382</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="inputMask">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="frame">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="verticalLayoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>130</y>
|
||||
<width>301</width>
|
||||
<height>35</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<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>RemoteDebugDialog</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>RemoteDebugDialog</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>
|
5
src/img/icons/play_light_remote.svg
Normal file
5
src/img/icons/play_light_remote.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
|
||||
<svg style="enable-background:new 0 0 24 32" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="32px" width="24px" version="1.1" y="0px" x="0px" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 32">
|
||||
<polygon points="0 0 24 16 0 32" fill="#78de82"/>
|
||||
<text x="15" y="10" font-family="Helvetica, Arial, sans-serif" font-size="13" stroke-width="2" stroke="#aaacaf" fill="#aaacaf" >R</text>
|
||||
</svg>
|
After Width: | Height: | Size: 526 B |
@ -24,6 +24,7 @@
|
||||
<file>img/icons/play_light_debug.svg</file>
|
||||
<file>img/icons/play_light_emul.svg</file>
|
||||
<file>img/icons/play_light_attach.svg</file>
|
||||
<file>img/icons/play_light_remote.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>
|
||||
|
@ -20,6 +20,7 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) :
|
||||
QIcon startDebugIcon = QIcon(":/img/icons/play_light_debug.svg");
|
||||
QIcon startEmulIcon = QIcon(":/img/icons/play_light_emul.svg");
|
||||
QIcon startAttachIcon = QIcon(":/img/icons/play_light_attach.svg");
|
||||
QIcon startRemoteIcon = QIcon(":/img/icons/play_light_remote.svg");
|
||||
QIcon stopIcon = QIcon(":/img/icons/media-stop_light.svg");
|
||||
QIcon continueUntilMainIcon = QIcon(":/img/icons/continue_until_main.svg");
|
||||
QIcon continueUntilCallIcon = QIcon(":/img/icons/continue_until_call.svg");
|
||||
@ -35,6 +36,7 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) :
|
||||
QString startDebugLabel = tr("Start debug");
|
||||
QString startEmulLabel = tr("Start emulation");
|
||||
QString startAttachLabel = tr("Attach to process");
|
||||
QString startRemoteLabel = tr("Connect to a remote debugger");
|
||||
QString stopDebugLabel = tr("Stop debug");
|
||||
QString stopEmulLabel = tr("Stop emulation");
|
||||
QString restartDebugLabel = tr("Restart program");
|
||||
@ -53,6 +55,7 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) :
|
||||
actionStart->setShortcut(QKeySequence(Qt::Key_F9));
|
||||
actionStartEmul = new QAction(startEmulIcon, startEmulLabel, this);
|
||||
actionAttach = new QAction(startAttachIcon, startAttachLabel, this);
|
||||
actionStartRemote = new QAction(startRemoteIcon, startRemoteLabel, this);
|
||||
actionStop = new QAction(stopIcon, stopDebugLabel, this);
|
||||
actionContinue = new QAction(continueIcon, continueLabel, this);
|
||||
actionContinue->setShortcut(QKeySequence(Qt::Key_F5));
|
||||
@ -75,8 +78,8 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) :
|
||||
startMenu->addAction(actionStart);
|
||||
startMenu->addAction(actionStartEmul);
|
||||
startMenu->addAction(actionAttach);
|
||||
startMenu->addAction(actionStartRemote);
|
||||
startButton->setDefaultAction(actionStart);
|
||||
// startButton->setDefaultAction(actionStartEmul);
|
||||
startButton->setMenu(startMenu);
|
||||
|
||||
continueUntilButton = new QToolButton;
|
||||
@ -105,21 +108,28 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) :
|
||||
|
||||
// Toggle all buttons except restart, suspend(=continue) and stop since those are
|
||||
// necessary to avoid staying stuck
|
||||
toggleActions = { actionStep, actionStepOver, actionStepOut, actionContinueUntilMain,
|
||||
toggleActions = {actionStep, actionStepOver, actionStepOut, actionContinueUntilMain,
|
||||
actionContinueUntilCall, actionContinueUntilSyscall};
|
||||
toggleConnectionActions = {actionAttach, actionStart, actionStartRemote, actionStartEmul};
|
||||
|
||||
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);
|
||||
bool disableToolbar = Core()->isDebugTaskInProgress();
|
||||
if (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);
|
||||
}
|
||||
} else {
|
||||
actionContinue->setText(continueLabel);
|
||||
actionContinue->setIcon(continueIcon);
|
||||
for (QAction *a : toggleConnectionActions) {
|
||||
a->setDisabled(disableToolbar);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -128,6 +138,7 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) :
|
||||
actionStart->setVisible(true);
|
||||
actionStartEmul->setVisible(true);
|
||||
actionAttach->setVisible(true);
|
||||
actionStartRemote->setVisible(true);
|
||||
actionStop->setText(stopDebugLabel);
|
||||
actionStart->setText(startDebugLabel);
|
||||
actionStart->setIcon(startDebugIcon);
|
||||
@ -149,6 +160,7 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) :
|
||||
}
|
||||
setAllActionsVisible(true);
|
||||
actionAttach->setVisible(false);
|
||||
actionStartRemote->setVisible(false);
|
||||
actionStartEmul->setVisible(false);
|
||||
actionStart->setText(restartDebugLabel);
|
||||
actionStart->setIcon(restartIcon);
|
||||
@ -157,11 +169,14 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) :
|
||||
});
|
||||
|
||||
connect(actionAttach, &QAction::triggered, this, &DebugActions::attachProcessDialog);
|
||||
connect(actionStartRemote, &QAction::triggered, this, &DebugActions::attachRemoteDialog);
|
||||
connect(Core(), &CutterCore::attachedRemote, this, &DebugActions::onAttachedRemoteDebugger);
|
||||
connect(actionStartEmul, &QAction::triggered, Core(), &CutterCore::startEmulation);
|
||||
connect(actionStartEmul, &QAction::triggered, [ = ]() {
|
||||
setAllActionsVisible(true);
|
||||
actionStart->setVisible(false);
|
||||
actionAttach->setVisible(false);
|
||||
actionStartRemote->setVisible(false);
|
||||
actionContinueUntilMain->setVisible(false);
|
||||
actionStepOut->setVisible(false);
|
||||
continueUntilButton->setDefaultAction(actionContinueUntilSyscall);
|
||||
@ -200,6 +215,49 @@ void DebugActions::continueUntilMain()
|
||||
Core()->continueUntilDebug(mainAddr);
|
||||
}
|
||||
|
||||
void DebugActions::attachRemoteDebugger()
|
||||
{
|
||||
QString stopAttachLabel = tr("Detach from process");
|
||||
// Hide unwanted buttons
|
||||
setAllActionsVisible(true);
|
||||
actionStart->setVisible(false);
|
||||
actionStartRemote->setVisible(false);
|
||||
actionStartEmul->setVisible(false);
|
||||
actionStop->setText(stopAttachLabel);
|
||||
}
|
||||
|
||||
void DebugActions::onAttachedRemoteDebugger(bool successfully) {
|
||||
if (!successfully) {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText(tr("Error connecting."));
|
||||
msgBox.exec();
|
||||
attachRemoteDialog();
|
||||
} else {
|
||||
delete remoteDialog;
|
||||
attachRemoteDebugger();
|
||||
}
|
||||
}
|
||||
|
||||
void DebugActions::attachRemoteDialog()
|
||||
{
|
||||
if (!remoteDialog) {
|
||||
remoteDialog = new RemoteDebugDialog(main);
|
||||
}
|
||||
QMessageBox msgBox;
|
||||
bool success = false;
|
||||
while (!success) {
|
||||
success = true;
|
||||
if (remoteDialog->exec()) {
|
||||
if (!remoteDialog->validate()) {
|
||||
success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
Core()->attachRemote(remoteDialog->getUri());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DebugActions::attachProcessDialog()
|
||||
{
|
||||
AttachProcDialog dialog(main);
|
||||
@ -226,6 +284,7 @@ void DebugActions::attachProcess(int pid)
|
||||
// hide unwanted buttons
|
||||
setAllActionsVisible(true);
|
||||
actionStart->setVisible(false);
|
||||
actionStartRemote->setVisible(false);
|
||||
actionStartEmul->setVisible(false);
|
||||
actionStop->setText(stopAttachLabel);
|
||||
// attach
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "core/Cutter.h"
|
||||
#include "dialogs/RemoteDebugDialog.h"
|
||||
|
||||
#include <QAction>
|
||||
|
||||
@ -18,6 +19,7 @@ public:
|
||||
void addToToolBar(QToolBar *toolBar);
|
||||
|
||||
QAction *actionStart;
|
||||
QAction *actionStartRemote;
|
||||
QAction *actionStartEmul;
|
||||
QAction *actionAttach;
|
||||
QAction *actionContinue;
|
||||
@ -29,7 +31,7 @@ public:
|
||||
QAction *actionStepOut;
|
||||
QAction *actionStop;
|
||||
QAction *actionAllContinues;
|
||||
|
||||
|
||||
// Continue and suspend interchange during runtime
|
||||
QIcon continueIcon;
|
||||
QIcon suspendIcon;
|
||||
@ -41,14 +43,19 @@ private:
|
||||
* @brief buttons that will be disabled/enabled on (disable/enable)DebugToolbar
|
||||
*/
|
||||
QList<QAction *> toggleActions;
|
||||
MainWindow *main;
|
||||
QList<QAction *> toggleConnectionActions;
|
||||
QList<QAction *> allActions;
|
||||
QToolButton *continueUntilButton;
|
||||
RemoteDebugDialog *remoteDialog = nullptr;
|
||||
MainWindow *main;
|
||||
|
||||
private slots:
|
||||
void continueUntilMain();
|
||||
void attachProcessDialog();
|
||||
void attachProcess(int pid);
|
||||
void attachRemoteDialog();
|
||||
void attachRemoteDebugger();
|
||||
void onAttachedRemoteDebugger(bool successfully);
|
||||
void setAllActionsVisible(bool visible);
|
||||
void setButtonVisibleIfMainExists();
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user