From cb173aa61639b78379e5c0eec52e2e415348fe6f Mon Sep 17 00:00:00 2001 From: fcasal Date: Tue, 31 Jul 2018 18:16:05 +0100 Subject: [PATCH] Attach update (#603) * Handle process detaching * List procs wth current filename in separate table; * Refresh proc list every second * Fixed restarting debug executable check * Update r2 * Added option to break esil execution on invalid instructions (#597) * Added continue until call in esil * Remove set registers button * Reordered backtrace widget columns --- src/Cutter.cpp | 13 +- src/Cutter.h | 2 + src/dialogs/AttachProcDialog.cpp | 254 ++++++++++++++++++++++++------- src/dialogs/AttachProcDialog.h | 40 ++++- src/dialogs/AttachProcDialog.ui | 123 ++++++++++++--- src/widgets/BacktraceWidget.cpp | 20 +-- src/widgets/DebugToolbar.cpp | 45 ++++-- src/widgets/DebugToolbar.h | 1 + src/widgets/RegistersWidget.cpp | 28 +--- src/widgets/RegistersWidget.h | 2 - 10 files changed, 385 insertions(+), 143 deletions(-) diff --git a/src/Cutter.cpp b/src/Cutter.cpp index b9c20490..cdd5d901 100644 --- a/src/Cutter.cpp +++ b/src/Cutter.cpp @@ -884,9 +884,8 @@ void CutterCore::startDebug() if (!currentlyDebugging) { offsetPriorDebugging = getOffset(); } - // FIXME: we do a 'ds' here since otherwise the continue until commands - // sometimes do not work in r2. - cmd("ood; ds"); + // FIXME: we do a 'dr' here since otherwise the process continues + cmd("ood; dr"); emit registersChanged(); if (!currentlyDebugging) { setConfig("asm.flags", false); @@ -934,6 +933,8 @@ void CutterCore::attachDebug(int pid) // prevent register flags from appearing during debug/emul setConfig("asm.flags", false); currentlyDebugging = true; + currentlyOpenFile = getConfig("file.path"); + currentlyAttachedToPID = pid; emit flagsChanged(); emit changeDebugView(); } @@ -945,9 +946,11 @@ void CutterCore::stopDebug() if (currentlyEmulating) { cmd("aeim-; aei-; wcr; .ar-"); currentlyEmulating = false; + } else if (currentlyAttachedToPID != -1) { + cmd(QString("dp- %1; o %2; .ar-").arg(QString::number(currentlyAttachedToPID), currentlyOpenFile)); + currentlyAttachedToPID = -1; } else { - // we do a ds since otherwise the process does not die. - cmd("dk 9; ds; oo; .ar-"); + cmd("dk 9; oo; .ar-"); } seek(offsetPriorDebugging); setConfig("asm.flags", true); diff --git a/src/Cutter.h b/src/Cutter.h index 1c90c953..79c1e880 100644 --- a/src/Cutter.h +++ b/src/Cutter.h @@ -528,6 +528,8 @@ public: void setDebugPlugin(QString plugin); bool currentlyDebugging = false; bool currentlyEmulating = false; + int currentlyAttachedToPID = -1; + QString currentlyOpenFile; QString getDecompiledCodePDC(RVA addr); bool getR2DecAvailable(); diff --git a/src/dialogs/AttachProcDialog.cpp b/src/dialogs/AttachProcDialog.cpp index d8437cf8..3c2c91a9 100644 --- a/src/dialogs/AttachProcDialog.cpp +++ b/src/dialogs/AttachProcDialog.cpp @@ -5,15 +5,29 @@ #include "utils/Helpers.h" -ProcessModel::ProcessModel(QList *processes, QObject *parent) - : QAbstractListModel(parent), - processes(processes) +#include + +// ------------ +// ProcessModel +// ------------ +ProcessModel::ProcessModel(QObject *parent) + : QAbstractListModel(parent) { + updateData(); +} + +void ProcessModel::updateData() +{ + beginResetModel(); + + processes = Core()->getAllProcesses(); + + endResetModel(); } int ProcessModel::rowCount(const QModelIndex &) const { - return processes->count(); + return processes.count(); } int ProcessModel::columnCount(const QModelIndex &) const @@ -23,10 +37,10 @@ int ProcessModel::columnCount(const QModelIndex &) const QVariant ProcessModel::data(const QModelIndex &index, int role) const { - if (index.row() >= processes->count()) + if (index.row() >= processes.count()) return QVariant(); - const ProcessDescription &proc = processes->at(index.row()); + const ProcessDescription &proc = processes.at(index.row()); switch (role) { case Qt::DisplayRole: @@ -70,16 +84,67 @@ QVariant ProcessModel::headerData(int section, Qt::Orientation, int role) const } } -void ProcessModel::beginReloadProcess() +bool ProcessModel::lessThan(const ProcessDescription &leftProc, const ProcessDescription &rightProc, + int column) { - beginResetModel(); + switch (column) { + case ProcessModel::PidColumn: + return leftProc.pid < rightProc.pid; + case ProcessModel::UidColumn: + return leftProc.uid < rightProc.uid; + case ProcessModel::StatusColumn: + return leftProc.status < rightProc.status; + case ProcessModel::PathColumn: + return leftProc.path < rightProc.path; + default: + break; + } + + return leftProc.pid < rightProc.pid; } -void ProcessModel::endReloadProcess() +// ------------------------------ +// ProcessBeingAnalysedProxyModel +// ------------------------------ +ProcessBeingAnalysedProxyModel::ProcessBeingAnalysedProxyModel(ProcessModel *sourceModel, + QObject *parent) + : QSortFilterProxyModel(parent) { - endResetModel(); + setSourceModel(sourceModel); + + // @SEE: Should there be a getFilename() in Core()? Not the first time I use this + processBeingAnalysedFilename = processPathToFilename(Core()->getConfig("file.path")); } +QString ProcessBeingAnalysedProxyModel::processPathToFilename(const QString &path) const +{ + // removes the arguments and gets filename from the process path + return path.split(" ").first().split("/").last(); +} + +bool ProcessBeingAnalysedProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const +{ + QModelIndex index = sourceModel()->index(row, 0, parent); + ProcessDescription item = index.data(ProcessModel::ProcDescriptionRole).value(); + + QString procFilename = processPathToFilename(item.path); + return procFilename == processBeingAnalysedFilename; +} + +bool ProcessBeingAnalysedProxyModel::lessThan(const QModelIndex &left, + const QModelIndex &right) const +{ + ProcessDescription leftProc = left.data( + ProcessModel::ProcDescriptionRole).value(); + ProcessDescription rightProc = right.data( + ProcessModel::ProcDescriptionRole).value(); + + return ProcessModel::lessThan(leftProc, rightProc, left.column()); +} + +// ----------------- +// ProcessProxyModel +// ----------------- ProcessProxyModel::ProcessProxyModel(ProcessModel *sourceModel, QObject *parent) : QSortFilterProxyModel(parent) { @@ -100,22 +165,12 @@ bool ProcessProxyModel::lessThan(const QModelIndex &left, const QModelIndex &rig ProcessDescription rightProc = right.data( ProcessModel::ProcDescriptionRole).value(); - switch (left.column()) { - case ProcessModel::PidColumn: - return leftProc.pid < rightProc.pid; - case ProcessModel::UidColumn: - return leftProc.uid < rightProc.uid; - case ProcessModel::StatusColumn: - return leftProc.status < rightProc.status; - case ProcessModel::PathColumn: - return leftProc.path < rightProc.path; - default: - break; - } - - return leftProc.pid < rightProc.pid; + return ProcessModel::lessThan(leftProc, rightProc, left.column()); } +// ---------------- +// AttachProcDialog +// ---------------- AttachProcDialog::AttachProcDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AttachProcDialog) @@ -123,22 +178,97 @@ AttachProcDialog::AttachProcDialog(QWidget *parent) : ui->setupUi(this); setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint)); - processes = Core()->getAllProcesses(); - processModel = new ProcessModel(&processes, this); + processModel = new ProcessModel(this); processProxyModel = new ProcessProxyModel(processModel, this); - ui->procTreeView->setModel(processProxyModel); - ui->procTreeView->sortByColumn(ProcessModel::PidColumn, Qt::AscendingOrder); - connect(ui->filterLineEdit, SIGNAL(textChanged(const QString &)), processProxyModel, - SLOT(setFilterWildcard(const QString &))); - qhelpers::setVerticalScrollMode(ui->procTreeView); + processBeingAnalyzedProxyModel = new ProcessBeingAnalysedProxyModel(processModel, this); + + // View of all processes + auto allView = ui->allProcView; + allView->setModel(processProxyModel); + allView->sortByColumn(ProcessModel::PidColumn, Qt::DescendingOrder); + + // View of the processes with the same name as the one being analyzed + auto smallView = ui->procBeingAnalyzedView; + smallView->setModel(processBeingAnalyzedProxyModel); + smallView->setCurrentIndex(smallView->model()->index(0, 0)); + + // To get the 'FocusIn' events + allView->installEventFilter(this); + smallView->installEventFilter(this); // focus on filter line ui->filterLineEdit->setFocus(); - // Event filter for capturing Ctrl/Cmd+Return - ui->filterLineEdit->installEventFilter(this); + connect(ui->filterLineEdit, SIGNAL(textChanged(const QString &)), processProxyModel, + SLOT(setFilterWildcard(const QString &))); + + // Update the processes every 'updateIntervalMs' seconds + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(updateModelData())); + timer->start(updateIntervalMs); } -AttachProcDialog::~AttachProcDialog() {} +AttachProcDialog::~AttachProcDialog() +{ + timer->stop(); + delete timer; + delete processBeingAnalyzedProxyModel; + delete processProxyModel; + delete processModel; +} + +void AttachProcDialog::updateModelData() +{ + auto allView = ui->allProcView; + auto smallView = ui->procBeingAnalyzedView; + + // Save the old selection and scroll position so that we can update and + // model and then restore it. + bool allViewHadSelection = allView->selectionModel()->hasSelection(); + bool smallViewHadSelection = smallView->selectionModel()->hasSelection(); + int allViewPrevScrollPos = 0; + int smallViewPrevScrollPos = 0; + int allViewPrevPID = 0; + int smallViewPrevPID = 0; + + if (allViewHadSelection) { + allViewPrevScrollPos = allView->verticalScrollBar()->value(); + allViewPrevPID = allView->selectionModel()->currentIndex().data( + ProcessModel::ProcDescriptionRole).value().pid; + } + if (smallViewHadSelection) { + smallViewPrevScrollPos = smallView->verticalScrollBar()->value(); + smallViewPrevPID = smallView->selectionModel()->currentIndex().data( + ProcessModel::ProcDescriptionRole).value().pid; + } + + // Let the model update + processModel->updateData(); + + // Restore the selection and scroll position + if (allViewHadSelection) { + QModelIndexList idx = allView->model()->match( + allView->model()->index(0, 0), Qt::DisplayRole, QVariant::fromValue(allViewPrevPID)); + if (!idx.isEmpty()) { + allView->setCurrentIndex(idx.first()); + allView->verticalScrollBar()->setValue(allViewPrevScrollPos); + } + } + if (smallViewHadSelection) { + QModelIndexList idx = smallView->model()->match( + smallView->model()->index(0, 0), Qt::DisplayRole, QVariant::fromValue(smallViewPrevPID)); + + if (!idx.isEmpty()) { + smallView->setCurrentIndex(idx.first()); + smallView->verticalScrollBar()->setValue(smallViewPrevScrollPos); + } + } + + // Init selection if nothing was ever selected yet, and a new process with the same name + // as the one being analysed was launched. + if (!allView->selectionModel()->hasSelection() && !smallView->selectionModel()->hasSelection()) { + smallView->setCurrentIndex(smallView->model()->index(0, 0)); + } +} void AttachProcDialog::on_buttonBox_accepted() { @@ -149,23 +279,16 @@ void AttachProcDialog::on_buttonBox_rejected() close(); } -int AttachProcDialog::getPID() -{ - ProcessDescription proc = ui->procTreeView->selectionModel()->currentIndex().data( - ProcessModel::ProcDescriptionRole).value(); - return proc.pid; -} - bool AttachProcDialog::eventFilter(QObject *obj, QEvent *event) { - Q_UNUSED(obj); - if (event -> type() == QEvent::KeyPress) { - QKeyEvent *keyEvent = static_cast (event); - - // Confirm comment by pressing Ctrl/Cmd+Return - if ((keyEvent -> modifiers() & Qt::ControlModifier) && - ((keyEvent -> key() == Qt::Key_Enter) || (keyEvent -> key() == Qt::Key_Return))) { - this->accept(); + if (event->type() == QEvent::FocusIn) { + if (obj == ui->allProcView) { + ui->procBeingAnalyzedView->selectionModel()->clearSelection(); + wasAllProcViewLastPressed = true; + return true; + } else if (obj == ui->procBeingAnalyzedView) { + ui->allProcView->selectionModel()->clearSelection(); + wasAllProcViewLastPressed = false; return true; } } @@ -173,8 +296,37 @@ bool AttachProcDialog::eventFilter(QObject *obj, QEvent *event) return false; } -void AttachProcDialog::on_procTreeView_doubleClicked(const QModelIndex &index) +int AttachProcDialog::getPID() { - ProcessDescription proc = index.data(ProcessModel::ProcDescriptionRole).value(); + int pid; + + // Here we need to know which table was selected last to get the proper PID + if (wasAllProcViewLastPressed && ui->allProcView->selectionModel()->hasSelection()) { + pid = ui->allProcView->selectionModel()->currentIndex(). + data(ProcessModel::ProcDescriptionRole).value().pid; + } else if (!wasAllProcViewLastPressed + && ui->procBeingAnalyzedView->selectionModel()->hasSelection()) { + pid = ui->procBeingAnalyzedView->selectionModel()->currentIndex(). + data(ProcessModel::ProcDescriptionRole).value().pid; + } else { + // Error attaching. No process selected! Happens when you press ENTER but + // there was no process with the same name as the one being analyzed. + pid = -1; + } + + return pid; +} + +void AttachProcDialog::on_allProcView_doubleClicked(const QModelIndex &index) +{ + Q_UNUSED(index); + + accept(); +} + +void AttachProcDialog::on_procBeingAnalyzedView_doubleClicked(const QModelIndex &index) +{ + Q_UNUSED(index); + accept(); } \ No newline at end of file diff --git a/src/dialogs/AttachProcDialog.h b/src/dialogs/AttachProcDialog.h index 28123a99..2010e498 100644 --- a/src/dialogs/AttachProcDialog.h +++ b/src/dialogs/AttachProcDialog.h @@ -5,6 +5,7 @@ #include #include #include +#include namespace Ui { class AttachProcDialog; @@ -20,22 +21,23 @@ class ProcessModel: public QAbstractListModel Q_OBJECT private: - QList *processes; + QList processes; public: enum Column { PidColumn = 0, UidColumn, StatusColumn, PathColumn, ColumnCount }; enum Role { ProcDescriptionRole = Qt::UserRole }; - ProcessModel(QList *processes, QObject *parent = 0); + ProcessModel(QObject *parent = 0); int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + static bool lessThan(const ProcessDescription &left, const ProcessDescription &right, int column); - void beginReloadProcess(); - void endReloadProcess(); +public slots: + void updateData(); }; @@ -53,6 +55,23 @@ protected: }; +class ProcessBeingAnalysedProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + ProcessBeingAnalysedProxyModel(ProcessModel *sourceModel, QObject *parent = nullptr); + +protected: + bool filterAcceptsRow(int row, const QModelIndex &parent) const override; + bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; + +private: + QString processBeingAnalysedFilename; + QString processPathToFilename(const QString &path) const; +}; + + class AttachProcDialog : public QDialog { @@ -67,16 +86,21 @@ public: private slots: void on_buttonBox_accepted(); void on_buttonBox_rejected(); - void on_procTreeView_doubleClicked(const QModelIndex &index); + void on_allProcView_doubleClicked(const QModelIndex &index); + void on_procBeingAnalyzedView_doubleClicked(const QModelIndex &index); + void updateModelData(); -signals: - void attachProcess(int pid); private: std::unique_ptr ui; bool eventFilter(QObject *obj, QEvent *event); ProcessModel *processModel; ProcessProxyModel *processProxyModel; - QList processes; + ProcessBeingAnalysedProxyModel *processBeingAnalyzedProxyModel; + // whether the 'small table' or 'table with all procs' was last focused + bool wasAllProcViewLastPressed = false; + + QTimer *timer; + const int updateIntervalMs = 1000; }; diff --git a/src/dialogs/AttachProcDialog.ui b/src/dialogs/AttachProcDialog.ui index be5980af..e49e57cb 100644 --- a/src/dialogs/AttachProcDialog.ui +++ b/src/dialogs/AttachProcDialog.ui @@ -30,42 +30,115 @@ 2 - + 0 - - - QTreeView::item + + + + 16777215 + 150 + + + + Processes with same name as currently open file: + + + + + 0 + 30 + 794 + 111 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + QTreeView::item { padding-top: 1px; padding-bottom: 1px; } - - - QFrame::NoFrame - - - 0 - - - 8 - - - true - - + + + QFrame::NoFrame + + + 0 + + + 8 + + + true + + + + + + + + All processes: + + + + + 0 + 50 + 794 + 331 + + + + + 16777215 + 16777215 + + + + QTreeView::item +{ + padding-top: 1px; + padding-bottom: 1px; +} + + + QFrame::NoFrame + + + 0 + + + 8 + + + true + + + - - - - Quick Filter - - - + + + + Quick Filter + + + diff --git a/src/widgets/BacktraceWidget.cpp b/src/widgets/BacktraceWidget.cpp index a8f1648a..ecc1039f 100644 --- a/src/widgets/BacktraceWidget.cpp +++ b/src/widgets/BacktraceWidget.cpp @@ -13,11 +13,11 @@ BacktraceWidget::BacktraceWidget(MainWindow *main, QAction *action) : // setup backtrace model QString PC = Core()->getRegisterName("PC"); QString SP = Core()->getRegisterName("SP"); - modelBacktrace->setHorizontalHeaderItem(0, new QStandardItem(PC)); + modelBacktrace->setHorizontalHeaderItem(0, new QStandardItem(tr("Func Name"))); modelBacktrace->setHorizontalHeaderItem(1, new QStandardItem(SP)); - modelBacktrace->setHorizontalHeaderItem(2, new QStandardItem(tr("Frame Size"))); - modelBacktrace->setHorizontalHeaderItem(3, new QStandardItem(tr("Func Name"))); - modelBacktrace->setHorizontalHeaderItem(4, new QStandardItem(tr("Description"))); + modelBacktrace->setHorizontalHeaderItem(2, new QStandardItem(PC)); + modelBacktrace->setHorizontalHeaderItem(3, new QStandardItem(tr("Description"))); + modelBacktrace->setHorizontalHeaderItem(4, new QStandardItem(tr("Frame Size"))); viewBacktrace->setFont(Config()->getFont()); viewBacktrace->setModel(modelBacktrace); ui->verticalLayout->addWidget(viewBacktrace); @@ -42,21 +42,21 @@ void BacktraceWidget::setBacktraceGrid() QJsonObject backtraceItem = value.toObject(); QString progCounter = RAddressString(backtraceItem["pc"].toVariant().toULongLong()); QString stackPointer = RAddressString(backtraceItem["sp"].toVariant().toULongLong()); - int frameSize = backtraceItem["frame_size"].toInt(); + int frameSize = backtraceItem["frame_size"].toVariant().toInt(); QString funcName = backtraceItem["fname"].toString(); QString desc = backtraceItem["desc"].toString(); QStandardItem *rowPC = new QStandardItem(progCounter); QStandardItem *rowSP = new QStandardItem(stackPointer); - QStandardItem *rowFrameSize = new QStandardItem(frameSize); + QStandardItem *rowFrameSize = new QStandardItem(QString::number(frameSize)); QStandardItem *rowFuncName = new QStandardItem(funcName); QStandardItem *rowDesc = new QStandardItem(desc); - modelBacktrace->setItem(i, 0, rowPC); + modelBacktrace->setItem(i, 0, rowFuncName); modelBacktrace->setItem(i, 1, rowSP); - modelBacktrace->setItem(i, 2, rowFrameSize); - modelBacktrace->setItem(i, 3, rowFuncName); - modelBacktrace->setItem(i, 4, rowDesc); + modelBacktrace->setItem(i, 2, rowPC); + modelBacktrace->setItem(i, 3, rowDesc); + modelBacktrace->setItem(i, 4, rowFrameSize); i++; } viewBacktrace->setModel(modelBacktrace); diff --git a/src/widgets/DebugToolbar.cpp b/src/widgets/DebugToolbar.cpp index e881b16c..32bf3de3 100644 --- a/src/widgets/DebugToolbar.cpp +++ b/src/widgets/DebugToolbar.cpp @@ -29,7 +29,7 @@ DebugToolbar::DebugToolbar(MainWindow *main, QWidget *parent) : actionStart->setShortcut(QKeySequence(Qt::Key_F9)); actionStartEmul = new QAction(startEmulIcon, tr("Start emulation"), parent); actionAttach = new QAction(startAttachIcon, tr("Attach to process"), parent); - QAction *actionStop = new QAction(stopIcon, tr("Stop debug"), parent); + actionStop = new QAction(stopIcon, tr("Stop debug"), parent); actionContinue = new QAction(continueIcon, tr("Continue"), parent); actionContinue->setShortcut(QKeySequence(Qt::Key_F5)); actionContinueUntilMain = new QAction(continueUntilMainIcon, tr("Continue until main"), parent); @@ -82,18 +82,20 @@ DebugToolbar::DebugToolbar(MainWindow *main, QWidget *parent) : actionContinueUntilMain->setVisible(true); actionStepOut->setVisible(true); this->colorToolbar(false); + actionStop->setText("Stop debug"); + colorToolbar(false); }); connect(actionStep, &QAction::triggered, Core(), &CutterCore::stepDebug); - connect(actionStart, &QAction::triggered, [ = ]() { - QString filename = Core()->getConfig("file.lastpath"); + connect(actionStart, &QAction::triggered, [=]() { + QString filename = Core()->getConfig("file.path").split(" ").first(); QFileInfo info(filename); - if (!info.isExecutable()) { + if (!Core()->currentlyDebugging && !info.isExecutable()) { QMessageBox msgBox; msgBox.setText(QString("File '%1' does not have executable permissions.").arg(filename)); msgBox.exec(); return; } - this->colorToolbar(true); + colorToolbar(true); actionAttach->setVisible(false); actionStartEmul->setVisible(false); Core()->startDebug(); @@ -107,7 +109,8 @@ DebugToolbar::DebugToolbar(MainWindow *main, QWidget *parent) : actionContinueUntilMain->setVisible(false); actionStepOut->setVisible(false); continueUntilButton->setDefaultAction(actionContinueUntilSyscall); - this->colorToolbar(true); + actionStop->setText("Stop emulation"); + colorToolbar(true); }); connect(actionStepOver, &QAction::triggered, Core(), &CutterCore::stepOverDebug); connect(actionStepOut, &QAction::triggered, Core(), &CutterCore::stepOutDebug); @@ -125,28 +128,40 @@ void DebugToolbar::continueUntilMain() void DebugToolbar::colorToolbar(bool p) { if (p) { - this->setStyleSheet("QToolBar {background: green;}"); + setStyleSheet("QToolBar {background: green;}"); } else { - this->setStyleSheet(""); + setStyleSheet(""); } } void DebugToolbar::attachProcessDialog() { AttachProcDialog *dialog = new AttachProcDialog(this); - - if (dialog->exec()) { - int pid = dialog->getPID(); - attachProcess(pid); + bool success = false; + while (!success) { + success = true; + if (dialog->exec()) { + int pid = dialog->getPID(); + if (pid >= 0) { + attachProcess(pid); + } else { + success = false; + QMessageBox msgBox; + msgBox.setText("Error attaching. No process selected!"); + msgBox.exec(); + } + } } + delete dialog; } void DebugToolbar::attachProcess(int pid) { // hide unwanted buttons - this->colorToolbar(true); - this->actionStart->setVisible(false); - this->actionStartEmul->setVisible(false); + colorToolbar(true); + actionStart->setVisible(false); + actionStartEmul->setVisible(false); + actionStop->setText("Detach from process"); // attach Core()->attachDebug(pid); } \ No newline at end of file diff --git a/src/widgets/DebugToolbar.h b/src/widgets/DebugToolbar.h index 46c5f7ea..4fea4604 100644 --- a/src/widgets/DebugToolbar.h +++ b/src/widgets/DebugToolbar.h @@ -21,6 +21,7 @@ public: QAction *actionStep; QAction *actionStepOver; QAction *actionStepOut; + QAction *actionStop; private: MainWindow *main; diff --git a/src/widgets/RegistersWidget.cpp b/src/widgets/RegistersWidget.cpp index 3d0e79f2..94070252 100644 --- a/src/widgets/RegistersWidget.cpp +++ b/src/widgets/RegistersWidget.cpp @@ -3,7 +3,6 @@ #include "utils/JsonModel.h" #include "MainWindow.h" -#include "QPushButton" RegistersWidget::RegistersWidget(MainWindow *main, QAction *action) : CutterDockWidget(main, action), @@ -12,12 +11,9 @@ RegistersWidget::RegistersWidget(MainWindow *main, QAction *action) : ui->setupUi(this); // setup register layout + registerLayout->setVerticalSpacing(0); ui->verticalLayout->addLayout(registerLayout); - buttonSetRegisters = new QPushButton("Set registers", this); - connect(buttonSetRegisters, &QPushButton::clicked, this, &RegistersWidget::handleButton); - - ui->verticalLayout->addWidget(buttonSetRegisters); connect(Core(), &CutterCore::refreshAll, this, &RegistersWidget::updateContents); connect(Core(), &CutterCore::registersChanged, this, &RegistersWidget::updateContents); } @@ -29,28 +25,6 @@ void RegistersWidget::updateContents() setRegisterGrid(); } -void RegistersWidget::handleButton() -{ - int j = 0; - int i = 0; - int col = 0; - for (j = 0; j < registerLen; j++) { - QWidget *regName = registerLayout->itemAtPosition(i, col)->widget(); - QWidget *regValue = registerLayout->itemAtPosition(i, col + 1)->widget(); - QLabel *regLabel = qobject_cast(regName); - QLineEdit *regLine = qobject_cast(regValue); - QString regNameString = regLabel->text(); - QString regValueString = regLine->text(); - Core()->setRegister(regNameString, regValueString); - i++; - if (i >= registerLen / numCols + 1) { - i = 0; - col += 2; - } - } - setRegisterGrid(); -} - void RegistersWidget::setRegisterGrid() { int i = 0; diff --git a/src/widgets/RegistersWidget.h b/src/widgets/RegistersWidget.h index d6970d74..360c600a 100644 --- a/src/widgets/RegistersWidget.h +++ b/src/widgets/RegistersWidget.h @@ -26,12 +26,10 @@ public: private slots: void updateContents(); void setRegisterGrid(); - void handleButton(); private: std::unique_ptr ui; QGridLayout *registerLayout = new QGridLayout; int numCols = 2; int registerLen = 0; - QPushButton *buttonSetRegisters; }; \ No newline at end of file