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
This commit is contained in:
fcasal 2018-07-31 18:16:05 +01:00 committed by xarkes
parent 08245a8694
commit cb173aa616
10 changed files with 385 additions and 143 deletions

View File

@ -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);

View File

@ -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();

View File

@ -5,15 +5,29 @@
#include "utils/Helpers.h"
ProcessModel::ProcessModel(QList<ProcessDescription> *processes, QObject *parent)
: QAbstractListModel(parent),
processes(processes)
#include <QScrollBar>
// ------------
// 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<ProcessDescription>();
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>();
ProcessDescription rightProc = right.data(
ProcessModel::ProcDescriptionRole).value<ProcessDescription>();
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<ProcessDescription>();
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<ProcessDescription>().pid;
}
if (smallViewHadSelection) {
smallViewPrevScrollPos = smallView->verticalScrollBar()->value();
smallViewPrevPID = smallView->selectionModel()->currentIndex().data(
ProcessModel::ProcDescriptionRole).value<ProcessDescription>().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<ProcessDescription>();
return proc.pid;
}
bool AttachProcDialog::eventFilter(QObject *obj, QEvent *event)
{
Q_UNUSED(obj);
if (event -> type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast <QKeyEvent *> (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<ProcessDescription>();
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<ProcessDescription>().pid;
} else if (!wasAllProcViewLastPressed
&& ui->procBeingAnalyzedView->selectionModel()->hasSelection()) {
pid = ui->procBeingAnalyzedView->selectionModel()->currentIndex().
data(ProcessModel::ProcDescriptionRole).value<ProcessDescription>().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();
}

View File

@ -5,6 +5,7 @@
#include <memory>
#include <QAbstractListModel>
#include <QSortFilterProxyModel>
#include <QTimer>
namespace Ui {
class AttachProcDialog;
@ -20,22 +21,23 @@ class ProcessModel: public QAbstractListModel
Q_OBJECT
private:
QList<ProcessDescription> *processes;
QList<ProcessDescription> processes;
public:
enum Column { PidColumn = 0, UidColumn, StatusColumn, PathColumn, ColumnCount };
enum Role { ProcDescriptionRole = Qt::UserRole };
ProcessModel(QList<ProcessDescription> *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::AttachProcDialog> ui;
bool eventFilter(QObject *obj, QEvent *event);
ProcessModel *processModel;
ProcessProxyModel *processProxyModel;
QList<ProcessDescription> processes;
ProcessBeingAnalysedProxyModel *processBeingAnalyzedProxyModel;
// whether the 'small table' or 'table with all procs' was last focused
bool wasAllProcViewLastPressed = false;
QTimer *timer;
const int updateIntervalMs = 1000;
};

View File

@ -30,42 +30,115 @@
<number>2</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QTreeView" name="procTreeView">
<property name="styleSheet">
<string notr="true">QTreeView::item
<widget class="QGroupBox" name="groupBox_2">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>150</height>
</size>
</property>
<property name="title">
<string>Processes with same name as currently open file:</string>
</property>
<widget class="QTreeView" name="procBeingAnalyzedView">
<property name="geometry">
<rect>
<x>0</x>
<y>30</y>
<width>794</width>
<height>111</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QTreeView::item
{
padding-top: 1px;
padding-bottom: 1px;
}</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="indentation">
<number>8</number>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="indentation">
<number>8</number>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>All processes:</string>
</property>
<widget class="QTreeView" name="allProcView">
<property name="geometry">
<rect>
<x>0</x>
<y>50</y>
<width>794</width>
<height>331</height>
</rect>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QTreeView::item
{
padding-top: 1px;
padding-bottom: 1px;
}</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="indentation">
<number>8</number>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLineEdit" name="filterLineEdit">
<property name="placeholderText">
<string>Quick Filter</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="filterLineEdit">
<property name="placeholderText">
<string>Quick Filter</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">

View File

@ -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);

View File

@ -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);
}

View File

@ -21,6 +21,7 @@ public:
QAction *actionStep;
QAction *actionStepOver;
QAction *actionStepOut;
QAction *actionStop;
private:
MainWindow *main;

View File

@ -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<QLabel *>(regName);
QLineEdit *regLine = qobject_cast<QLineEdit *>(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;

View File

@ -26,12 +26,10 @@ public:
private slots:
void updateContents();
void setRegisterGrid();
void handleButton();
private:
std::unique_ptr<Ui::RegistersWidget> ui;
QGridLayout *registerLayout = new QGridLayout;
int numCols = 2;
int registerLen = 0;
QPushButton *buttonSetRegisters;
};