Added widget to view register values (#509)

* Added backtrace info
* Make stack printing arch agnostic
* Split into registers/stack/backtrace widgets
* hide table idxs in stacktable
* backtrace table header has register name instead of generic PC/SP
* imports cleanup
* add sorting to stack table
* add Qheaderview import
* Added button to set registers
* added color to recently changed register
* reorganized Windows tab and added stacking to debug widgets
This commit is contained in:
fcasal 2018-06-06 12:05:20 +01:00 committed by xarkes
parent 14cfe74324
commit e8b024042b
15 changed files with 543 additions and 19 deletions

View File

@ -689,6 +689,31 @@ QJsonDocument CutterCore::getSignatureInfo()
return cmdj("iCj");
}
QJsonDocument CutterCore::getStack(int size)
{
return cmdj("pxrj " + QString::number(size) + " @ r:SP");
}
QJsonDocument CutterCore::getRegisterValues()
{
return cmdj("drj");
}
QString CutterCore::getRegisterName(QString registerRole)
{
return cmd("drn " + registerRole).trimmed();
}
void CutterCore::setRegister(QString regName, QString regValue)
{
cmd("dr " + regName + "=" + regValue);
}
QJsonDocument CutterCore::getBacktrace()
{
return cmdj("dbtj");
}
QStringList CutterCore::getStats()
{
QStringList stats;

View File

@ -414,6 +414,11 @@ public:
QList<QList<QString>> get_exec_sections();
QString getOffsetInfo(QString addr);
QJsonDocument getRegistersInfo();
QJsonDocument getRegisterValues();
QString getRegisterName(QString registerRole);
void setRegister(QString regName, QString regValue);
QJsonDocument getStack(int size = 0x40);
QJsonDocument getBacktrace();
RVA getOffsetJump(RVA addr);
QString getDecompiledCode(RVA addr);
QString getDecompiledCode(QString addr);

View File

@ -162,7 +162,10 @@ SOURCES += \
dialogs/VersionInfoDialog.cpp \
widgets/ZignaturesWidget.cpp \
utils/AsyncTask.cpp \
dialogs/AsyncTaskDialog.cpp
dialogs/AsyncTaskDialog.cpp \
widgets/StackWidget.cpp \
widgets/RegistersWidget.cpp \
widgets/BacktraceWidget.cpp
HEADERS += \
Cutter.h \
@ -239,7 +242,10 @@ HEADERS += \
dialogs/VersionInfoDialog.h \
widgets/ZignaturesWidget.h \
utils/AsyncTask.h \
dialogs/AsyncTaskDialog.h
dialogs/AsyncTaskDialog.h \
widgets/StackWidget.h \
widgets/RegistersWidget.h \
widgets/BacktraceWidget.h
FORMS += \
dialogs/AboutDialog.ui \
@ -283,7 +289,10 @@ FORMS += \
dialogs/R2PluginsDialog.ui \
dialogs/VersionInfoDialog.ui \
widgets/ZignaturesWidget.ui \
dialogs/AsyncTaskDialog.ui
dialogs/AsyncTaskDialog.ui \
widgets/StackWidget.ui \
widgets/RegistersWidget.ui \
widgets/BacktraceWidget.ui
RESOURCES += \
resources.qrc \

View File

@ -178,6 +178,9 @@ void MainWindow::initUI()
commentsDock = new CommentsWidget(this, ui->actionComments);
stringsDock = new StringsWidget(this, ui->actionStrings);
flagsDock = new FlagsWidget(this, ui->actionFlags);
stackDock = new StackWidget(this, ui->actionStack);
backtraceDock = new BacktraceWidget(this, ui->actionBacktrace);
registersDock = new RegistersWidget(this, ui->actionRegisters);
#ifdef CUTTER_ENABLE_JUPYTER
jupyterDock = new JupyterWidget(this, ui->actionJupyter);
#else
@ -497,6 +500,11 @@ void MainWindow::restoreDocks()
tabifyDockWidget(dashboardDock, classesDock);
tabifyDockWidget(dashboardDock, resourcesDock);
tabifyDockWidget(dashboardDock, vTablesDock);
// Add Stack, Registers and Backtrace vertically stacked
addExtraWidget(stackDock);
splitDockWidget(stackDock, registersDock, Qt::Vertical);
splitDockWidget(stackDock, backtraceDock, Qt::Vertical);
#ifdef CUTTER_ENABLE_JUPYTER
tabifyDockWidget(dashboardDock, jupyterDock);
#endif

View File

@ -6,6 +6,9 @@
#include "Cutter.h" // only needed for ut64
#include "widgets/DisassemblyWidget.h"
#include "widgets/SidebarWidget.h"
#include "widgets/StackWidget.h"
#include "widgets/RegistersWidget.h"
#include "widgets/BacktraceWidget.h"
#include "widgets/HexdumpWidget.h"
#include "widgets/PseudocodeWidget.h"
#include "dialogs/NewFileDialog.h"
@ -211,6 +214,9 @@ private:
DisassemblerGraphView *graphView = nullptr;
QDockWidget *asmDock = nullptr;
QDockWidget *calcDock = nullptr;
QDockWidget *stackDock = nullptr;
QDockWidget *registersDock = nullptr;
QDockWidget *backtraceDock = nullptr;
NewFileDialog *newFileDialog = nullptr;
#ifdef CUTTER_ENABLE_JUPYTER
JupyterWidget *jupyterDock = nullptr;

View File

@ -223,6 +223,33 @@ border-top: 0px;
<addaction name="actionUndoSeek"/>
<addaction name="actionRedoSeek"/>
</widget>
<widget class="QMenu" name="addDebugWidgets">
<property name="title">
<string>Debug...</string>
</property>
<addaction name="actionStack"/>
<addaction name="actionRegisters"/>
<addaction name="actionBacktrace"/>
</widget>
<widget class="QMenu" name="addInfoWidgets">
<property name="title">
<string>Info...</string>
</property>
<addaction name="actionEntrypoints"/>
<addaction name="actionClasses"/>
<addaction name="actionImports"/>
<addaction name="actionExports"/>
<addaction name="actionSymbols"/>
<addaction name="actionSDBBrowser"/>
<addaction name="actionResources"/>
<addaction name="actionVTables"/>
<addaction name="actionTypes"/>
<addaction name="actionFlags"/>
<addaction name="actionSections"/>
<addaction name="actionHeaders"/>
<addaction name="actionZignatures"/>
<addaction name="actionRelocs"/>
</widget>
<widget class="QMenu" name="menuWindows">
<property name="title">
<string>Windows</string>
@ -233,26 +260,14 @@ border-top: 0px;
<addaction name="actionGraph"/>
<addaction name="actionHexdump"/>
<addaction name="actionPseudocode"/>
<addaction name="actionFunctions"/>
<addaction name="actionSidebar"/>
<addaction name="separator"/>
<addaction name="actionEntrypoints"/>
<addaction name="actionFunctions"/>
<addaction name="actionClasses"/>
<addaction name="actionImports"/>
<addaction name="actionExports"/>
<addaction name="actionSymbols"/>
<addaction name="actionSDBBrowser"/>
<addaction name="actionResources"/>
<addaction name="actionVTables"/>
<addaction name="actionTypes"/>
<addaction name="actionStrings"/>
<addaction name="actionSearch"/>
<addaction name="separator"/>
<addaction name="actionRelocs"/>
<addaction name="actionStrings"/>
<addaction name="actionFlags"/>
<addaction name="actionSections"/>
<addaction name="actionHeaders"/>
<addaction name="actionZignatures"/>
<addaction name="addInfoWidgets"/>
<addaction name="addDebugWidgets"/>
<addaction name="separator"/>
<addaction name="actionComments"/>
<addaction name="actionConsole"/>
@ -1015,6 +1030,30 @@ background-color: palette(dark);
<string>Console</string>
</property>
</action>
<action name="actionStack">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Stack</string>
</property>
</action>
<action name="actionRegisters">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Registers</string>
</property>
</action>
<action name="actionBacktrace">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Backtrace</string>
</property>
</action>
<action name="actionClasses">
<property name="checkable">
<bool>true</bool>

View File

@ -0,0 +1,63 @@
#include "BacktraceWidget.h"
#include "ui_BacktraceWidget.h"
#include "utils/JsonModel.h"
#include "MainWindow.h"
BacktraceWidget::BacktraceWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
ui(new Ui::BacktraceWidget)
{
ui->setupUi(this);
// setup backtrace model
QString PC = Core()->getRegisterName("PC");
QString SP = Core()->getRegisterName("SP");
modelBacktrace->setHorizontalHeaderItem(0, new QStandardItem(PC));
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")));
viewBacktrace->setStyleSheet("QTableView {font-family: mono}");
viewBacktrace->setModel(modelBacktrace);
ui->verticalLayout->addWidget(viewBacktrace);
connect(Core(), &CutterCore::refreshAll, this, &BacktraceWidget::updateContents);
connect(Core(), &CutterCore::seekChanged, this, &BacktraceWidget::updateContents);
}
BacktraceWidget::~BacktraceWidget() {}
void BacktraceWidget::updateContents()
{
setBacktraceGrid();
}
void BacktraceWidget::setBacktraceGrid()
{
QJsonArray backtraceValues = Core()->getBacktrace().array();
int i = 0;
for (QJsonValueRef value : backtraceValues) {
QJsonObject backtraceItem = value.toObject();
QString progCounter = RAddressString(backtraceItem["pc"].toVariant().toULongLong());
QString stackPointer = RAddressString(backtraceItem["sp"].toVariant().toULongLong());
int frameSize = backtraceItem["frame_size"].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 *rowFuncName = new QStandardItem(funcName);
QStandardItem *rowDesc = new QStandardItem(desc);
modelBacktrace->setItem(i, 0, rowPC);
modelBacktrace->setItem(i, 1, rowSP);
modelBacktrace->setItem(i, 2, rowFrameSize);
modelBacktrace->setItem(i, 3, rowFuncName);
modelBacktrace->setItem(i, 4, rowDesc);
i++;
}
viewBacktrace->setModel(modelBacktrace);
viewBacktrace->resizeColumnsToContents();;
}

View File

@ -0,0 +1,33 @@
#pragma once
#include <QJsonObject>
#include <memory>
#include <QStandardItem>
#include <QTableView>
#include "Cutter.h"
#include "CutterDockWidget.h"
class MainWindow;
namespace Ui {
class BacktraceWidget;
}
class BacktraceWidget : public CutterDockWidget
{
Q_OBJECT
public:
explicit BacktraceWidget(MainWindow *main, QAction *action = nullptr);
~BacktraceWidget();
private slots:
void updateContents();
void setBacktraceGrid();
private:
std::unique_ptr<Ui::BacktraceWidget> ui;
QStandardItemModel *modelBacktrace = new QStandardItemModel(1, 5, this);
QTableView *viewBacktrace = new QTableView;
};

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BacktraceWidget</class>
<widget class="QDockWidget" name="BacktraceWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>463</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Backtrace</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>10</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,103 @@
#include "RegistersWidget.h"
#include "ui_RegistersWidget.h"
#include "utils/JsonModel.h"
#include "MainWindow.h"
#include "QPushButton"
RegistersWidget::RegistersWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
ui(new Ui::RegistersWidget)
{
ui->setupUi(this);
// setup register layout
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::seekChanged, this, &RegistersWidget::updateContents);
}
RegistersWidget::~RegistersWidget() {}
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;
int col = 0;
QString regValue;
QLabel *registerLabel;
QLineEdit *registerEditValue;
QJsonObject registerValues = Core()->getRegisterValues().object();
QStringList registerNames = registerValues.keys();
registerLen = registerNames.size();
for (const QString &key : registerNames) {
regValue = RAddressString(registerValues[key].toVariant().toULongLong());
// check if we already filled this grid space with label/value
if (!registerLayout->itemAtPosition(i, col)) {
registerLabel = new QLabel;
registerLabel->setStyleSheet("font-weight: bold; font-family: mono");
registerEditValue = new QLineEdit;
QFont font = registerEditValue->font();
font.setWeight(QFont::Monospace);
registerEditValue->setFont(font);
// add label and register value to grid
registerLayout->addWidget(registerLabel, i, col);
registerLayout->addWidget(registerEditValue, i, col + 1);
}
else {
QWidget *regNameWidget = registerLayout->itemAtPosition(i, col)->widget();
QWidget *regValueWidget = registerLayout->itemAtPosition(i, col + 1)->widget();
registerLabel = qobject_cast<QLabel *>(regNameWidget);
registerEditValue = qobject_cast<QLineEdit *>(regValueWidget);
}
// decide to highlight QLine Box in case of change of register value
if (regValue != registerEditValue->text() && registerEditValue->text() != 0) {
registerEditValue->setStyleSheet("QLineEdit {border: 1px solid green;} QLineEdit:hover { border: 1px solid #3daee9; color: #eff0f1;}");
}
else {
// reset stylesheet
registerEditValue->setStyleSheet("");
}
// define register label and value
registerLabel->setText(key);
registerEditValue->setPlaceholderText(regValue);
registerEditValue->setText(regValue);
i++;
// decide if we should change column
if (i >= registerLen/numCols + 1) {
i = 0;
col += 2;
}
}
}

View File

@ -0,0 +1,37 @@
#pragma once
#include <QTextEdit>
#include <QPlainTextEdit>
#include <QGridLayout>
#include <QJsonObject>
#include <memory>
#include "Cutter.h"
#include "CutterDockWidget.h"
class MainWindow;
namespace Ui {
class RegistersWidget;
}
class RegistersWidget : public CutterDockWidget
{
Q_OBJECT
public:
explicit RegistersWidget(MainWindow *main, QAction *action = nullptr);
~RegistersWidget();
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;
};

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RegistersWidget</class>
<widget class="QDockWidget" name="RegistersWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>463</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Registers</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>10</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,58 @@
#include "StackWidget.h"
#include "ui_StackWidget.h"
#include "utils/JsonModel.h"
#include "utils/Helpers.h"
#include "MainWindow.h"
#include "QHeaderView"
StackWidget::StackWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
ui(new Ui::StackWidget)
{
ui->setupUi(this);
// setup stack model
modelStack->setHorizontalHeaderItem(0, new QStandardItem(tr("Offset")));
modelStack->setHorizontalHeaderItem(1, new QStandardItem(tr("Value")));
modelStack->setHorizontalHeaderItem(2, new QStandardItem(tr("Reference")));
viewStack->setStyleSheet("QTableView {font-family: mono}");
viewStack->setModel(modelStack);
viewStack->verticalHeader()->hide();
viewStack->setSortingEnabled(true);
ui->verticalLayout->addWidget(viewStack);
connect(Core(), &CutterCore::refreshAll, this, &StackWidget::updateContents);
connect(Core(), &CutterCore::seekChanged, this, &StackWidget::updateContents);
}
StackWidget::~StackWidget() {}
void StackWidget::updateContents()
{
setStackGrid();
}
void StackWidget::setStackGrid()
{
QJsonArray stackValues = Core()->getStack().array();
int i = 0;
for (QJsonValueRef value : stackValues) {
QJsonObject stackItem = value.toObject();
QString addr = RAddressString(stackItem["addr"].toVariant().toULongLong());
QString valueStack = RAddressString(stackItem["value"].toVariant().toULongLong());
QStandardItem *rowOffset = new QStandardItem(addr);
QStandardItem *rowValue = new QStandardItem(valueStack);
modelStack->setItem(i, 0, rowOffset);
modelStack->setItem(i, 1, rowValue);
QJsonValue refObject = stackItem["ref"];
if (!refObject.isUndefined()) { // check that the key exists
QString ref = refObject.toString();
QStandardItem *rowRef = new QStandardItem(ref);
modelStack->setItem(i, 2, rowRef);
}
i++;
}
viewStack->setModel(modelStack);
viewStack->resizeColumnsToContents();;
}

33
src/widgets/StackWidget.h Normal file
View File

@ -0,0 +1,33 @@
#pragma once
#include <QJsonObject>
#include <memory>
#include <QStandardItem>
#include <QTableView>
#include "Cutter.h"
#include "CutterDockWidget.h"
class MainWindow;
namespace Ui {
class StackWidget;
}
class StackWidget : public CutterDockWidget
{
Q_OBJECT
public:
explicit StackWidget(MainWindow *main, QAction *action = nullptr);
~StackWidget();
private slots:
void updateContents();
void setStackGrid();
private:
std::unique_ptr<Ui::StackWidget> ui;
QTableView *viewStack = new QTableView;
QStandardItemModel *modelStack = new QStandardItemModel(1, 3, this);
};

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>StackWidget</class>
<widget class="QDockWidget" name="StackWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>463</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Stack</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>10</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>