mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-21 12:26:11 +00:00
Add Global Vars widget, dialog, context menus (#3203)
* Add global variables support - Add Globals widget - Add global variable add/modify dialog - Add "Add at" context submenu in Disassembly widget Co-authored-by: Giovanni <561184+wargio@users.noreply.github.com> --------- Co-authored-by: Giovanni <561184+wargio@users.noreply.github.com>
This commit is contained in:
parent
041118dbd7
commit
3d30892a30
@ -18,6 +18,7 @@ set(SOURCES
|
|||||||
dialogs/CommentsDialog.cpp
|
dialogs/CommentsDialog.cpp
|
||||||
dialogs/EditInstructionDialog.cpp
|
dialogs/EditInstructionDialog.cpp
|
||||||
dialogs/FlagDialog.cpp
|
dialogs/FlagDialog.cpp
|
||||||
|
dialogs/GlobalVariableDialog.cpp
|
||||||
dialogs/RemoteDebugDialog.cpp
|
dialogs/RemoteDebugDialog.cpp
|
||||||
dialogs/NativeDebugDialog.cpp
|
dialogs/NativeDebugDialog.cpp
|
||||||
dialogs/XrefsDialog.cpp
|
dialogs/XrefsDialog.cpp
|
||||||
@ -36,6 +37,7 @@ set(SOURCES
|
|||||||
widgets/ExportsWidget.cpp
|
widgets/ExportsWidget.cpp
|
||||||
widgets/FlagsWidget.cpp
|
widgets/FlagsWidget.cpp
|
||||||
widgets/FunctionsWidget.cpp
|
widgets/FunctionsWidget.cpp
|
||||||
|
widgets/GlobalsWidget.cpp
|
||||||
widgets/ImportsWidget.cpp
|
widgets/ImportsWidget.cpp
|
||||||
widgets/Omnibar.cpp
|
widgets/Omnibar.cpp
|
||||||
widgets/RelocsWidget.cpp
|
widgets/RelocsWidget.cpp
|
||||||
@ -172,6 +174,7 @@ set(HEADER_FILES
|
|||||||
dialogs/CommentsDialog.h
|
dialogs/CommentsDialog.h
|
||||||
dialogs/EditInstructionDialog.h
|
dialogs/EditInstructionDialog.h
|
||||||
dialogs/FlagDialog.h
|
dialogs/FlagDialog.h
|
||||||
|
dialogs/GlobalVariableDialog.h
|
||||||
dialogs/RemoteDebugDialog.h
|
dialogs/RemoteDebugDialog.h
|
||||||
dialogs/NativeDebugDialog.h
|
dialogs/NativeDebugDialog.h
|
||||||
dialogs/XrefsDialog.h
|
dialogs/XrefsDialog.h
|
||||||
@ -327,6 +330,7 @@ set(UI_FILES
|
|||||||
dialogs/CommentsDialog.ui
|
dialogs/CommentsDialog.ui
|
||||||
dialogs/EditInstructionDialog.ui
|
dialogs/EditInstructionDialog.ui
|
||||||
dialogs/FlagDialog.ui
|
dialogs/FlagDialog.ui
|
||||||
|
dialogs/GlobalVariableDialog.ui
|
||||||
dialogs/RemoteDebugDialog.ui
|
dialogs/RemoteDebugDialog.ui
|
||||||
dialogs/NativeDebugDialog.ui
|
dialogs/NativeDebugDialog.ui
|
||||||
dialogs/XrefsDialog.ui
|
dialogs/XrefsDialog.ui
|
||||||
@ -338,6 +342,7 @@ set(UI_FILES
|
|||||||
widgets/Dashboard.ui
|
widgets/Dashboard.ui
|
||||||
widgets/EntrypointWidget.ui
|
widgets/EntrypointWidget.ui
|
||||||
widgets/FlagsWidget.ui
|
widgets/FlagsWidget.ui
|
||||||
|
widgets/GlobalsWidget.ui
|
||||||
widgets/StringsWidget.ui
|
widgets/StringsWidget.ui
|
||||||
widgets/HexdumpWidget.ui
|
widgets/HexdumpWidget.ui
|
||||||
dialogs/preferences/PreferencesDialog.ui
|
dialogs/preferences/PreferencesDialog.ui
|
||||||
|
@ -1815,6 +1815,32 @@ QList<VariableDescription> CutterCore::getVariables(RVA at)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<GlobalDescription> CutterCore::getAllGlobals()
|
||||||
|
{
|
||||||
|
CORE_LOCK();
|
||||||
|
RzListIter *it;
|
||||||
|
|
||||||
|
QList<GlobalDescription> ret;
|
||||||
|
|
||||||
|
RzAnalysisVarGlobal *glob;
|
||||||
|
if (core && core->analysis && core->analysis->typedb) {
|
||||||
|
const RzList *globals = rz_analysis_var_global_get_all(core->analysis);
|
||||||
|
CutterRzListForeach (globals, it, RzAnalysisVarGlobal, glob) {
|
||||||
|
const char *gtype = rz_type_as_string(core->analysis->typedb, glob->type);
|
||||||
|
if (!gtype) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
GlobalDescription global;
|
||||||
|
global.addr = glob->addr;
|
||||||
|
global.name = QString(glob->name);
|
||||||
|
global.type = QString(gtype);
|
||||||
|
ret << global;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
QVector<RegisterRefValueDescription> CutterCore::getRegisterRefValues()
|
QVector<RegisterRefValueDescription> CutterCore::getRegisterRefValues()
|
||||||
{
|
{
|
||||||
QVector<RegisterRefValueDescription> result;
|
QVector<RegisterRefValueDescription> result;
|
||||||
@ -4022,6 +4048,99 @@ QList<XrefDescription> CutterCore::getXRefs(RVA addr, bool to, bool whole_functi
|
|||||||
return xrefList;
|
return xrefList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CutterCore::addGlobalVariable(RVA offset, QString name, QString typ)
|
||||||
|
{
|
||||||
|
name = sanitizeStringForCommand(name);
|
||||||
|
CORE_LOCK();
|
||||||
|
char *errmsg = NULL;
|
||||||
|
RzType *globType = rz_type_parse_string_single(core->analysis->typedb->parser,
|
||||||
|
typ.toStdString().c_str(), &errmsg);
|
||||||
|
if (errmsg) {
|
||||||
|
qWarning() << tr("Error parsing type: \"%1\" message: ").arg(typ) << errmsg;
|
||||||
|
free(errmsg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!rz_analysis_var_global_create(core->analysis, name.toStdString().c_str(), globType,
|
||||||
|
offset)) {
|
||||||
|
qWarning() << tr("Error creating global variable: \"%1\"").arg(name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit globalVarsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CutterCore::modifyGlobalVariable(RVA offset, QString name, QString typ)
|
||||||
|
{
|
||||||
|
name = sanitizeStringForCommand(name);
|
||||||
|
CORE_LOCK();
|
||||||
|
RzAnalysisVarGlobal *glob = rz_analysis_var_global_get_byaddr_at(core->analysis, offset);
|
||||||
|
if (!glob) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Compare if the name is not the same - also rename it
|
||||||
|
if (name.compare(glob->name)) {
|
||||||
|
rz_analysis_var_global_rename(core->analysis, glob->name, name.toStdString().c_str());
|
||||||
|
}
|
||||||
|
char *errmsg = NULL;
|
||||||
|
RzType *globType = rz_type_parse_string_single(core->analysis->typedb->parser,
|
||||||
|
typ.toStdString().c_str(), &errmsg);
|
||||||
|
if (errmsg) {
|
||||||
|
qWarning() << tr("Error parsing type: \"%1\" message: ").arg(typ) << errmsg;
|
||||||
|
free(errmsg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rz_analysis_var_global_set_type(glob, globType);
|
||||||
|
|
||||||
|
emit globalVarsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CutterCore::delGlobalVariable(QString name)
|
||||||
|
{
|
||||||
|
name = sanitizeStringForCommand(name);
|
||||||
|
CORE_LOCK();
|
||||||
|
rz_analysis_var_global_delete_byname(core->analysis, name.toStdString().c_str());
|
||||||
|
|
||||||
|
emit globalVarsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CutterCore::delGlobalVariable(RVA offset)
|
||||||
|
{
|
||||||
|
CORE_LOCK();
|
||||||
|
rz_analysis_var_global_delete_byaddr_at(core->analysis, offset);
|
||||||
|
|
||||||
|
emit globalVarsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CutterCore::getGlobalVariableType(QString name)
|
||||||
|
{
|
||||||
|
name = sanitizeStringForCommand(name);
|
||||||
|
CORE_LOCK();
|
||||||
|
RzAnalysisVarGlobal *glob =
|
||||||
|
rz_analysis_var_global_get_byname(core->analysis, name.toStdString().c_str());
|
||||||
|
if (!glob) {
|
||||||
|
return QString("");
|
||||||
|
}
|
||||||
|
const char *gtype = rz_type_as_string(core->analysis->typedb, glob->type);
|
||||||
|
if (!gtype) {
|
||||||
|
return QString("");
|
||||||
|
}
|
||||||
|
return QString(gtype);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CutterCore::getGlobalVariableType(RVA offset)
|
||||||
|
{
|
||||||
|
CORE_LOCK();
|
||||||
|
RzAnalysisVarGlobal *glob = rz_analysis_var_global_get_byaddr_at(core->analysis, offset);
|
||||||
|
if (!glob) {
|
||||||
|
return QString("");
|
||||||
|
}
|
||||||
|
const char *gtype = rz_type_as_string(core->analysis->typedb, glob->type);
|
||||||
|
if (!gtype) {
|
||||||
|
return QString("");
|
||||||
|
}
|
||||||
|
return QString(gtype);
|
||||||
|
}
|
||||||
|
|
||||||
void CutterCore::addFlag(RVA offset, QString name, RVA size)
|
void CutterCore::addFlag(RVA offset, QString name, RVA size)
|
||||||
{
|
{
|
||||||
name = sanitizeStringForCommand(name);
|
name = sanitizeStringForCommand(name);
|
||||||
@ -4536,9 +4655,9 @@ char *CutterCore::getTextualGraphAt(RzCoreGraphType type, RzCoreGraphFormat form
|
|||||||
RzGraph *graph = rz_core_graph(core, type, address);
|
RzGraph *graph = rz_core_graph(core, type, address);
|
||||||
if (!graph) {
|
if (!graph) {
|
||||||
if (address == RVA_INVALID) {
|
if (address == RVA_INVALID) {
|
||||||
qWarning() << "Cannot get global graph";
|
qWarning() << tr("Cannot get global graph");
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Cannot get graph at " << RzAddressString(address);
|
qWarning() << tr("Cannot get graph at ") << RzAddressString(address);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -239,6 +239,14 @@ public:
|
|||||||
QString nearestFlag(RVA offset, RVA *flagOffsetOut);
|
QString nearestFlag(RVA offset, RVA *flagOffsetOut);
|
||||||
void triggerFlagsChanged();
|
void triggerFlagsChanged();
|
||||||
|
|
||||||
|
/* Global Variables */
|
||||||
|
void addGlobalVariable(RVA offset, QString name, QString typ);
|
||||||
|
void delGlobalVariable(QString name);
|
||||||
|
void delGlobalVariable(RVA offset);
|
||||||
|
void modifyGlobalVariable(RVA offset, QString name, QString typ);
|
||||||
|
QString getGlobalVariableType(QString name);
|
||||||
|
QString getGlobalVariableType(RVA offset);
|
||||||
|
|
||||||
/* Edition functions */
|
/* Edition functions */
|
||||||
PRzAnalysisBytes getRzAnalysisBytesSingle(RVA addr);
|
PRzAnalysisBytes getRzAnalysisBytesSingle(RVA addr);
|
||||||
QString getInstructionBytes(RVA addr);
|
QString getInstructionBytes(RVA addr);
|
||||||
@ -584,6 +592,7 @@ public:
|
|||||||
QList<ExportDescription> getAllExports();
|
QList<ExportDescription> getAllExports();
|
||||||
QList<SymbolDescription> getAllSymbols();
|
QList<SymbolDescription> getAllSymbols();
|
||||||
QList<HeaderDescription> getAllHeaders();
|
QList<HeaderDescription> getAllHeaders();
|
||||||
|
QList<GlobalDescription> getAllGlobals();
|
||||||
QList<FlirtDescription> getSignaturesDB();
|
QList<FlirtDescription> getSignaturesDB();
|
||||||
QList<CommentDescription> getAllComments(const QString &filterType);
|
QList<CommentDescription> getAllComments(const QString &filterType);
|
||||||
QList<RelocDescription> getAllRelocs();
|
QList<RelocDescription> getAllRelocs();
|
||||||
@ -750,6 +759,7 @@ signals:
|
|||||||
|
|
||||||
void functionRenamed(const RVA offset, const QString &new_name);
|
void functionRenamed(const RVA offset, const QString &new_name);
|
||||||
void varsChanged();
|
void varsChanged();
|
||||||
|
void globalVarsChanged();
|
||||||
void functionsChanged();
|
void functionsChanged();
|
||||||
void flagsChanged();
|
void flagsChanged();
|
||||||
void commentsChanged(RVA addr);
|
void commentsChanged(RVA addr);
|
||||||
|
@ -360,6 +360,13 @@ struct VariableDescription
|
|||||||
QString value;
|
QString value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GlobalDescription
|
||||||
|
{
|
||||||
|
RVA addr;
|
||||||
|
QString type;
|
||||||
|
QString name;
|
||||||
|
};
|
||||||
|
|
||||||
struct RegisterRefValueDescription
|
struct RegisterRefValueDescription
|
||||||
{
|
{
|
||||||
QString name;
|
QString name;
|
||||||
@ -407,6 +414,7 @@ Q_DECLARE_METATYPE(RelocDescription)
|
|||||||
Q_DECLARE_METATYPE(StringDescription)
|
Q_DECLARE_METATYPE(StringDescription)
|
||||||
Q_DECLARE_METATYPE(FlagspaceDescription)
|
Q_DECLARE_METATYPE(FlagspaceDescription)
|
||||||
Q_DECLARE_METATYPE(FlagDescription)
|
Q_DECLARE_METATYPE(FlagDescription)
|
||||||
|
Q_DECLARE_METATYPE(GlobalDescription)
|
||||||
Q_DECLARE_METATYPE(XrefDescription)
|
Q_DECLARE_METATYPE(XrefDescription)
|
||||||
Q_DECLARE_METATYPE(EntrypointDescription)
|
Q_DECLARE_METATYPE(EntrypointDescription)
|
||||||
Q_DECLARE_METATYPE(RzBinPluginDescription)
|
Q_DECLARE_METATYPE(RzBinPluginDescription)
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "widgets/DisassemblerGraphView.h"
|
#include "widgets/DisassemblerGraphView.h"
|
||||||
#include "widgets/GraphView.h"
|
#include "widgets/GraphView.h"
|
||||||
#include "widgets/GraphWidget.h"
|
#include "widgets/GraphWidget.h"
|
||||||
|
#include "widgets/GlobalsWidget.h"
|
||||||
#include "widgets/OverviewWidget.h"
|
#include "widgets/OverviewWidget.h"
|
||||||
#include "widgets/OverviewView.h"
|
#include "widgets/OverviewView.h"
|
||||||
#include "widgets/FunctionsWidget.h"
|
#include "widgets/FunctionsWidget.h"
|
||||||
@ -401,6 +402,7 @@ void MainWindow::initDocks()
|
|||||||
sectionsDock = new SectionsWidget(this),
|
sectionsDock = new SectionsWidget(this),
|
||||||
segmentsDock = new SegmentsWidget(this),
|
segmentsDock = new SegmentsWidget(this),
|
||||||
symbolsDock = new SymbolsWidget(this),
|
symbolsDock = new SymbolsWidget(this),
|
||||||
|
globalsDock = new GlobalsWidget(this),
|
||||||
vTablesDock = new VTablesWidget(this),
|
vTablesDock = new VTablesWidget(this),
|
||||||
flirtDock = new FlirtWidget(this),
|
flirtDock = new FlirtWidget(this),
|
||||||
rzGraphDock = new RizinGraphWidget(this),
|
rzGraphDock = new RizinGraphWidget(this),
|
||||||
@ -905,6 +907,7 @@ void MainWindow::restoreDocks()
|
|||||||
tabifyDockWidget(dashboardDock, headersDock);
|
tabifyDockWidget(dashboardDock, headersDock);
|
||||||
tabifyDockWidget(dashboardDock, flirtDock);
|
tabifyDockWidget(dashboardDock, flirtDock);
|
||||||
tabifyDockWidget(dashboardDock, symbolsDock);
|
tabifyDockWidget(dashboardDock, symbolsDock);
|
||||||
|
tabifyDockWidget(dashboardDock, globalsDock);
|
||||||
tabifyDockWidget(dashboardDock, classesDock);
|
tabifyDockWidget(dashboardDock, classesDock);
|
||||||
tabifyDockWidget(dashboardDock, resourcesDock);
|
tabifyDockWidget(dashboardDock, resourcesDock);
|
||||||
tabifyDockWidget(dashboardDock, vTablesDock);
|
tabifyDockWidget(dashboardDock, vTablesDock);
|
||||||
|
@ -26,6 +26,7 @@ class FunctionsWidget;
|
|||||||
class ImportsWidget;
|
class ImportsWidget;
|
||||||
class ExportsWidget;
|
class ExportsWidget;
|
||||||
class SymbolsWidget;
|
class SymbolsWidget;
|
||||||
|
class GlobalsWidget;
|
||||||
class RelocsWidget;
|
class RelocsWidget;
|
||||||
class CommentsWidget;
|
class CommentsWidget;
|
||||||
class StringsWidget;
|
class StringsWidget;
|
||||||
@ -240,6 +241,7 @@ private:
|
|||||||
TypesWidget *typesDock = nullptr;
|
TypesWidget *typesDock = nullptr;
|
||||||
SearchWidget *searchDock = nullptr;
|
SearchWidget *searchDock = nullptr;
|
||||||
SymbolsWidget *symbolsDock = nullptr;
|
SymbolsWidget *symbolsDock = nullptr;
|
||||||
|
GlobalsWidget *globalsDock = nullptr;
|
||||||
RelocsWidget *relocsDock = nullptr;
|
RelocsWidget *relocsDock = nullptr;
|
||||||
CommentsWidget *commentsDock = nullptr;
|
CommentsWidget *commentsDock = nullptr;
|
||||||
StringsWidget *stringsDock = nullptr;
|
StringsWidget *stringsDock = nullptr;
|
||||||
|
71
src/dialogs/GlobalVariableDialog.cpp
Normal file
71
src/dialogs/GlobalVariableDialog.cpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#include "GlobalVariableDialog.h"
|
||||||
|
#include "ui_GlobalVariableDialog.h"
|
||||||
|
|
||||||
|
#include <QIntValidator>
|
||||||
|
#include "core/Cutter.h"
|
||||||
|
|
||||||
|
GlobalVariableDialog::GlobalVariableDialog(RVA offset, QWidget *parent)
|
||||||
|
: QDialog(parent),
|
||||||
|
ui(new Ui::GlobalVariableDialog),
|
||||||
|
offset(offset),
|
||||||
|
globalVariableName(""),
|
||||||
|
globalVariableOffset(RVA_INVALID)
|
||||||
|
{
|
||||||
|
// Setup UI
|
||||||
|
ui->setupUi(this);
|
||||||
|
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||||
|
RzAnalysisVarGlobal *globalVariable =
|
||||||
|
rz_analysis_var_global_get_byaddr_at(Core()->core()->analysis, offset);
|
||||||
|
if (globalVariable) {
|
||||||
|
globalVariableName = QString(globalVariable->name);
|
||||||
|
globalVariableOffset = globalVariable->addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (globalVariable) {
|
||||||
|
ui->nameEdit->setText(globalVariable->name);
|
||||||
|
QString globalVarType = Core()->getGlobalVariableType(globalVariable->name);
|
||||||
|
ui->typeEdit->setText(globalVarType);
|
||||||
|
ui->labelAction->setText(tr("Edit global variable at %1").arg(RzAddressString(offset)));
|
||||||
|
} else {
|
||||||
|
ui->labelAction->setText(tr("Add global variable at %1").arg(RzAddressString(offset)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect slots
|
||||||
|
connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
|
||||||
|
&GlobalVariableDialog::buttonBoxAccepted);
|
||||||
|
connect(ui->buttonBox, &QDialogButtonBox::rejected, this,
|
||||||
|
&GlobalVariableDialog::buttonBoxRejected);
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalVariableDialog::~GlobalVariableDialog() {}
|
||||||
|
|
||||||
|
void GlobalVariableDialog::buttonBoxAccepted()
|
||||||
|
{
|
||||||
|
QString name = ui->nameEdit->text();
|
||||||
|
QString typ = ui->typeEdit->text();
|
||||||
|
|
||||||
|
if (name.isEmpty()) {
|
||||||
|
if (globalVariableOffset != RVA_INVALID) {
|
||||||
|
// Empty name and global variable exists -> delete the global variable
|
||||||
|
Core()->delGlobalVariable(globalVariableOffset);
|
||||||
|
} else {
|
||||||
|
// GlobalVariable was not existing and we gave an empty name, do nothing
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (globalVariableOffset != RVA_INVALID) {
|
||||||
|
// Name provided and global variable exists -> rename the global variable
|
||||||
|
Core()->modifyGlobalVariable(globalVariableOffset, name, typ);
|
||||||
|
} else {
|
||||||
|
// Name provided and global variable does not exist -> create the global variable
|
||||||
|
Core()->addGlobalVariable(offset, name, typ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close();
|
||||||
|
this->setResult(QDialog::Accepted);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalVariableDialog::buttonBoxRejected()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
this->setResult(QDialog::Rejected);
|
||||||
|
}
|
32
src/dialogs/GlobalVariableDialog.h
Normal file
32
src/dialogs/GlobalVariableDialog.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef GLOBALVARIABLEDIALOG_H
|
||||||
|
#define GLOBALVARIABLEDIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <memory>
|
||||||
|
#include "core/CutterCommon.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class GlobalVariableDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class GlobalVariableDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit GlobalVariableDialog(RVA offset, QWidget *parent = nullptr);
|
||||||
|
~GlobalVariableDialog();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void buttonBoxAccepted();
|
||||||
|
void buttonBoxRejected();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<Ui::GlobalVariableDialog> ui;
|
||||||
|
RVA offset;
|
||||||
|
QString globalVariableName;
|
||||||
|
RVA globalVariableOffset;
|
||||||
|
QString typ;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // GLOBALVARIABLEDIALOG_H
|
100
src/dialogs/GlobalVariableDialog.ui
Normal file
100
src/dialogs/GlobalVariableDialog.ui
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>GlobalVariableDialog</class>
|
||||||
|
<widget class="QDialog" name="GlobalVariableDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>452</width>
|
||||||
|
<height>121</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Add Global Variable</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labelAction">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add global variable at</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<property name="horizontalSpacing">
|
||||||
|
<number>12</number>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="labelName">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Name:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="nameEdit">
|
||||||
|
<property name="frame">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="typeEdit">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>100</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>int</string>
|
||||||
|
</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="labelType">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Type:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
@ -3,6 +3,7 @@
|
|||||||
#include "dialogs/EditInstructionDialog.h"
|
#include "dialogs/EditInstructionDialog.h"
|
||||||
#include "dialogs/CommentsDialog.h"
|
#include "dialogs/CommentsDialog.h"
|
||||||
#include "dialogs/FlagDialog.h"
|
#include "dialogs/FlagDialog.h"
|
||||||
|
#include "dialogs/GlobalVariableDialog.h"
|
||||||
#include "dialogs/XrefsDialog.h"
|
#include "dialogs/XrefsDialog.h"
|
||||||
#include "dialogs/EditVariablesDialog.h"
|
#include "dialogs/EditVariablesDialog.h"
|
||||||
#include "dialogs/SetToDataDialog.h"
|
#include "dialogs/SetToDataDialog.h"
|
||||||
@ -34,6 +35,7 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow *main
|
|||||||
actionAnalyzeFunction(this),
|
actionAnalyzeFunction(this),
|
||||||
actionEditFunction(this),
|
actionEditFunction(this),
|
||||||
actionRename(this),
|
actionRename(this),
|
||||||
|
actionGlobalVar(this),
|
||||||
actionSetFunctionVarTypes(this),
|
actionSetFunctionVarTypes(this),
|
||||||
actionXRefs(this),
|
actionXRefs(this),
|
||||||
actionXRefsForVariables(this),
|
actionXRefsForVariables(this),
|
||||||
@ -83,10 +85,6 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow *main
|
|||||||
getCommentSequence());
|
getCommentSequence());
|
||||||
addAction(&actionAddComment);
|
addAction(&actionAddComment);
|
||||||
|
|
||||||
initAction(&actionRename, tr("Rename or add flag"), SLOT(on_actionRename_triggered()),
|
|
||||||
getRenameSequence());
|
|
||||||
addAction(&actionRename);
|
|
||||||
|
|
||||||
initAction(&actionSetFunctionVarTypes, tr("Re-type Local Variables"),
|
initAction(&actionSetFunctionVarTypes, tr("Re-type Local Variables"),
|
||||||
SLOT(on_actionSetFunctionVarTypes_triggered()), getRetypeSequence());
|
SLOT(on_actionSetFunctionVarTypes_triggered()), getRetypeSequence());
|
||||||
addAction(&actionSetFunctionVarTypes);
|
addAction(&actionSetFunctionVarTypes);
|
||||||
@ -112,6 +110,8 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow *main
|
|||||||
|
|
||||||
addSeparator();
|
addSeparator();
|
||||||
|
|
||||||
|
addAddAtMenu();
|
||||||
|
|
||||||
addSetBaseMenu();
|
addSetBaseMenu();
|
||||||
|
|
||||||
addSetBitsMenu();
|
addSetBitsMenu();
|
||||||
@ -166,6 +166,19 @@ QWidget *DisassemblyContextMenu::parentForDialog()
|
|||||||
return parentWidget();
|
return parentWidget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisassemblyContextMenu::addAddAtMenu()
|
||||||
|
{
|
||||||
|
setAsMenu = addMenu(tr("Add at..."));
|
||||||
|
|
||||||
|
initAction(&actionRename, tr("Rename or add flag"), SLOT(on_actionRename_triggered()),
|
||||||
|
getRenameSequence());
|
||||||
|
setAsMenu->addAction(&actionRename);
|
||||||
|
|
||||||
|
initAction(&actionGlobalVar, tr("Modify or add global variable"),
|
||||||
|
SLOT(on_actionGlobalVar_triggered()), getGlobalVarSequence());
|
||||||
|
setAsMenu->addAction(&actionGlobalVar);
|
||||||
|
}
|
||||||
|
|
||||||
void DisassemblyContextMenu::addSetBaseMenu()
|
void DisassemblyContextMenu::addSetBaseMenu()
|
||||||
{
|
{
|
||||||
setBaseMenu = addMenu(tr("Set base of immediate value to.."));
|
setBaseMenu = addMenu(tr("Set base of immediate value to.."));
|
||||||
@ -479,7 +492,12 @@ void DisassemblyContextMenu::setupRenaming()
|
|||||||
|
|
||||||
// Now, build the renaming menu and show it
|
// Now, build the renaming menu and show it
|
||||||
buildRenameMenu(tuh);
|
buildRenameMenu(tuh);
|
||||||
|
|
||||||
|
auto name = RzAddressString(tuh->offset);
|
||||||
|
actionGlobalVar.setText(tr("Add or change global variable at %1 (used here)").arg(name));
|
||||||
|
|
||||||
actionRename.setVisible(true);
|
actionRename.setVisible(true);
|
||||||
|
actionGlobalVar.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisassemblyContextMenu::aboutToShowSlot()
|
void DisassemblyContextMenu::aboutToShowSlot()
|
||||||
@ -655,6 +673,11 @@ QKeySequence DisassemblyContextMenu::getRenameSequence() const
|
|||||||
return { Qt::Key_N };
|
return { Qt::Key_N };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QKeySequence DisassemblyContextMenu::getGlobalVarSequence() const
|
||||||
|
{
|
||||||
|
return { Qt::Key_G };
|
||||||
|
}
|
||||||
|
|
||||||
QKeySequence DisassemblyContextMenu::getRetypeSequence() const
|
QKeySequence DisassemblyContextMenu::getRetypeSequence() const
|
||||||
{
|
{
|
||||||
return { Qt::Key_Y };
|
return { Qt::Key_Y };
|
||||||
@ -868,6 +891,18 @@ void DisassemblyContextMenu::on_actionRename_triggered()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisassemblyContextMenu::on_actionGlobalVar_triggered()
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
GlobalVariableDialog dialog(doRenameInfo.addr, parentForDialog());
|
||||||
|
ok = dialog.exec();
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
// Rebuild menu in case the user presses the rename shortcut directly before clicking
|
||||||
|
setupRenaming();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DisassemblyContextMenu::on_actionSetFunctionVarTypes_triggered()
|
void DisassemblyContextMenu::on_actionSetFunctionVarTypes_triggered()
|
||||||
{
|
{
|
||||||
RzAnalysisFunction *fcn = Core()->functionIn(offset);
|
RzAnalysisFunction *fcn = Core()->functionIn(offset);
|
||||||
|
@ -45,6 +45,7 @@ private slots:
|
|||||||
void on_actionAddComment_triggered();
|
void on_actionAddComment_triggered();
|
||||||
void on_actionAnalyzeFunction_triggered();
|
void on_actionAnalyzeFunction_triggered();
|
||||||
void on_actionRename_triggered();
|
void on_actionRename_triggered();
|
||||||
|
void on_actionGlobalVar_triggered();
|
||||||
void on_actionSetFunctionVarTypes_triggered();
|
void on_actionSetFunctionVarTypes_triggered();
|
||||||
void on_actionXRefs_triggered();
|
void on_actionXRefs_triggered();
|
||||||
void on_actionXRefsForVariables_triggered();
|
void on_actionXRefsForVariables_triggered();
|
||||||
@ -78,6 +79,7 @@ private:
|
|||||||
QKeySequence getCopySequence() const;
|
QKeySequence getCopySequence() const;
|
||||||
QKeySequence getCommentSequence() const;
|
QKeySequence getCommentSequence() const;
|
||||||
QKeySequence getCopyAddressSequence() const;
|
QKeySequence getCopyAddressSequence() const;
|
||||||
|
QKeySequence getGlobalVarSequence() const;
|
||||||
QKeySequence getSetToCodeSequence() const;
|
QKeySequence getSetToCodeSequence() const;
|
||||||
QKeySequence getSetAsStringSequence() const;
|
QKeySequence getSetAsStringSequence() const;
|
||||||
QKeySequence getSetAsStringAdvanced() const;
|
QKeySequence getSetAsStringAdvanced() const;
|
||||||
@ -118,6 +120,7 @@ private:
|
|||||||
QAction actionXRefs;
|
QAction actionXRefs;
|
||||||
QAction actionXRefsForVariables;
|
QAction actionXRefsForVariables;
|
||||||
QAction actionDisplayOptions;
|
QAction actionDisplayOptions;
|
||||||
|
QAction actionGlobalVar;
|
||||||
|
|
||||||
QAction actionDeleteComment;
|
QAction actionDeleteComment;
|
||||||
QAction actionDeleteFlag;
|
QAction actionDeleteFlag;
|
||||||
@ -190,6 +193,7 @@ private:
|
|||||||
void addSetAsMenu();
|
void addSetAsMenu();
|
||||||
void addSetToDataMenu();
|
void addSetToDataMenu();
|
||||||
void addEditMenu();
|
void addEditMenu();
|
||||||
|
void addAddAtMenu();
|
||||||
void addBreakpointMenu();
|
void addBreakpointMenu();
|
||||||
void addDebugMenu();
|
void addDebugMenu();
|
||||||
|
|
||||||
|
@ -90,6 +90,7 @@ DecompilerWidget::DecompilerWidget(MainWindow *main)
|
|||||||
connect(Core(), &CutterCore::varsChanged, this, &DecompilerWidget::doRefresh);
|
connect(Core(), &CutterCore::varsChanged, this, &DecompilerWidget::doRefresh);
|
||||||
connect(Core(), &CutterCore::functionsChanged, this, &DecompilerWidget::doRefresh);
|
connect(Core(), &CutterCore::functionsChanged, this, &DecompilerWidget::doRefresh);
|
||||||
connect(Core(), &CutterCore::flagsChanged, this, &DecompilerWidget::doRefresh);
|
connect(Core(), &CutterCore::flagsChanged, this, &DecompilerWidget::doRefresh);
|
||||||
|
connect(Core(), &CutterCore::globalVarsChanged, this, &DecompilerWidget::doRefresh);
|
||||||
connect(Core(), &CutterCore::commentsChanged, this, &DecompilerWidget::refreshIfChanged);
|
connect(Core(), &CutterCore::commentsChanged, this, &DecompilerWidget::refreshIfChanged);
|
||||||
connect(Core(), &CutterCore::instructionChanged, this, &DecompilerWidget::refreshIfChanged);
|
connect(Core(), &CutterCore::instructionChanged, this, &DecompilerWidget::refreshIfChanged);
|
||||||
connect(Core(), &CutterCore::refreshCodeViews, this, &DecompilerWidget::doRefresh);
|
connect(Core(), &CutterCore::refreshCodeViews, this, &DecompilerWidget::doRefresh);
|
||||||
|
@ -52,6 +52,7 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable *se
|
|||||||
connect(Core(), &CutterCore::commentsChanged, this, &DisassemblerGraphView::refreshView);
|
connect(Core(), &CutterCore::commentsChanged, this, &DisassemblerGraphView::refreshView);
|
||||||
connect(Core(), &CutterCore::functionRenamed, this, &DisassemblerGraphView::refreshView);
|
connect(Core(), &CutterCore::functionRenamed, this, &DisassemblerGraphView::refreshView);
|
||||||
connect(Core(), &CutterCore::flagsChanged, this, &DisassemblerGraphView::refreshView);
|
connect(Core(), &CutterCore::flagsChanged, this, &DisassemblerGraphView::refreshView);
|
||||||
|
connect(Core(), &CutterCore::globalVarsChanged, this, &DisassemblerGraphView::refreshView);
|
||||||
connect(Core(), &CutterCore::varsChanged, this, &DisassemblerGraphView::refreshView);
|
connect(Core(), &CutterCore::varsChanged, this, &DisassemblerGraphView::refreshView);
|
||||||
connect(Core(), &CutterCore::instructionChanged, this, &DisassemblerGraphView::refreshView);
|
connect(Core(), &CutterCore::instructionChanged, this, &DisassemblerGraphView::refreshView);
|
||||||
connect(Core(), &CutterCore::breakpointsChanged, this, &DisassemblerGraphView::refreshView);
|
connect(Core(), &CutterCore::breakpointsChanged, this, &DisassemblerGraphView::refreshView);
|
||||||
|
@ -128,6 +128,7 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main)
|
|||||||
|
|
||||||
connect(Core(), &CutterCore::commentsChanged, this, [this]() { refreshDisasm(); });
|
connect(Core(), &CutterCore::commentsChanged, this, [this]() { refreshDisasm(); });
|
||||||
connect(Core(), SIGNAL(flagsChanged()), this, SLOT(refreshDisasm()));
|
connect(Core(), SIGNAL(flagsChanged()), this, SLOT(refreshDisasm()));
|
||||||
|
connect(Core(), SIGNAL(globalVarsChanged()), this, SLOT(refreshDisasm()));
|
||||||
connect(Core(), SIGNAL(functionsChanged()), this, SLOT(refreshDisasm()));
|
connect(Core(), SIGNAL(functionsChanged()), this, SLOT(refreshDisasm()));
|
||||||
connect(Core(), &CutterCore::functionRenamed, this, [this]() { refreshDisasm(); });
|
connect(Core(), &CutterCore::functionRenamed, this, [this]() { refreshDisasm(); });
|
||||||
connect(Core(), SIGNAL(varsChanged()), this, SLOT(refreshDisasm()));
|
connect(Core(), SIGNAL(varsChanged()), this, SLOT(refreshDisasm()));
|
||||||
|
228
src/widgets/GlobalsWidget.cpp
Normal file
228
src/widgets/GlobalsWidget.cpp
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
#include "GlobalsWidget.h"
|
||||||
|
#include "ui_GlobalsWidget.h"
|
||||||
|
#include "core/MainWindow.h"
|
||||||
|
#include "common/Helpers.h"
|
||||||
|
#include "dialogs/GlobalVariableDialog.h"
|
||||||
|
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QShortcut>
|
||||||
|
|
||||||
|
GlobalsModel::GlobalsModel(QList<GlobalDescription> *globals, QObject *parent)
|
||||||
|
: AddressableItemModel<QAbstractListModel>(parent), globals(globals)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int GlobalsModel::rowCount(const QModelIndex &) const
|
||||||
|
{
|
||||||
|
return globals->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
int GlobalsModel::columnCount(const QModelIndex &) const
|
||||||
|
{
|
||||||
|
return GlobalsModel::ColumnCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant GlobalsModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (index.row() >= globals->count()) {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
const GlobalDescription &global = globals->at(index.row());
|
||||||
|
|
||||||
|
switch (role) {
|
||||||
|
case Qt::DisplayRole:
|
||||||
|
switch (index.column()) {
|
||||||
|
case GlobalsModel::AddressColumn:
|
||||||
|
return RzAddressString(global.addr);
|
||||||
|
case GlobalsModel::TypeColumn:
|
||||||
|
return QString(global.type).trimmed();
|
||||||
|
case GlobalsModel::NameColumn:
|
||||||
|
return global.name;
|
||||||
|
case GlobalsModel::CommentColumn:
|
||||||
|
return Core()->getCommentAt(global.addr);
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
case GlobalsModel::GlobalDescriptionRole:
|
||||||
|
return QVariant::fromValue(global);
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant GlobalsModel::headerData(int section, Qt::Orientation, int role) const
|
||||||
|
{
|
||||||
|
switch (role) {
|
||||||
|
case Qt::DisplayRole:
|
||||||
|
switch (section) {
|
||||||
|
case GlobalsModel::AddressColumn:
|
||||||
|
return tr("Address");
|
||||||
|
case GlobalsModel::TypeColumn:
|
||||||
|
return tr("Type");
|
||||||
|
case GlobalsModel::NameColumn:
|
||||||
|
return tr("Name");
|
||||||
|
case GlobalsModel::CommentColumn:
|
||||||
|
return tr("Comment");
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RVA GlobalsModel::address(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
const GlobalDescription &global = globals->at(index.row());
|
||||||
|
return global.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString GlobalsModel::name(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
const GlobalDescription &global = globals->at(index.row());
|
||||||
|
return global.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalsProxyModel::GlobalsProxyModel(GlobalsModel *sourceModel, QObject *parent)
|
||||||
|
: AddressableFilterProxyModel(sourceModel, parent)
|
||||||
|
{
|
||||||
|
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||||
|
setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GlobalsProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
QModelIndex index = sourceModel()->index(row, 0, parent);
|
||||||
|
auto global = index.data(GlobalsModel::GlobalDescriptionRole).value<GlobalDescription>();
|
||||||
|
|
||||||
|
return qhelpers::filterStringContains(global.name, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GlobalsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
||||||
|
{
|
||||||
|
auto leftGlobal = left.data(GlobalsModel::GlobalDescriptionRole).value<GlobalDescription>();
|
||||||
|
auto rightGlobal = right.data(GlobalsModel::GlobalDescriptionRole).value<GlobalDescription>();
|
||||||
|
|
||||||
|
switch (left.column()) {
|
||||||
|
case GlobalsModel::AddressColumn:
|
||||||
|
return leftGlobal.addr < rightGlobal.addr;
|
||||||
|
case GlobalsModel::TypeColumn:
|
||||||
|
return leftGlobal.type < rightGlobal.type;
|
||||||
|
case GlobalsModel::NameColumn:
|
||||||
|
return leftGlobal.name < rightGlobal.name;
|
||||||
|
case GlobalsModel::CommentColumn:
|
||||||
|
return Core()->getCommentAt(leftGlobal.addr) < Core()->getCommentAt(rightGlobal.addr);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalsWidget::editGlobal()
|
||||||
|
{
|
||||||
|
QModelIndex index = ui->treeView->currentIndex();
|
||||||
|
|
||||||
|
if (!index.isValid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RVA globalVariableAddress = globalsModel->address(index);
|
||||||
|
|
||||||
|
GlobalVariableDialog dialog(globalVariableAddress, parentWidget());
|
||||||
|
dialog.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalsWidget::deleteGlobal()
|
||||||
|
{
|
||||||
|
QModelIndex index = ui->treeView->currentIndex();
|
||||||
|
|
||||||
|
if (!index.isValid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RVA globalVariableAddress = globalsModel->address(index);
|
||||||
|
Core()->delGlobalVariable(globalVariableAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalsWidget::showGlobalsContextMenu(const QPoint &pt)
|
||||||
|
{
|
||||||
|
QModelIndex index = ui->treeView->indexAt(pt);
|
||||||
|
|
||||||
|
QMenu menu(ui->treeView);
|
||||||
|
|
||||||
|
if (index.isValid()) {
|
||||||
|
menu.addAction(actionEditGlobal);
|
||||||
|
menu.addAction(actionDeleteGlobal);
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.exec(ui->treeView->mapToGlobal(pt));
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalsWidget::GlobalsWidget(MainWindow *main)
|
||||||
|
: CutterDockWidget(main), ui(new Ui::GlobalsWidget), tree(new CutterTreeWidget(this))
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
ui->quickFilterView->setLabelText(tr("Category"));
|
||||||
|
|
||||||
|
setWindowTitle(tr("Globals"));
|
||||||
|
setObjectName("GlobalsWidget");
|
||||||
|
|
||||||
|
// Add status bar which displays the count
|
||||||
|
tree->addStatusBar(ui->verticalLayout);
|
||||||
|
|
||||||
|
// Set single select mode
|
||||||
|
ui->treeView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
|
|
||||||
|
// Setup up the model and the proxy model
|
||||||
|
globalsModel = new GlobalsModel(&globals, this);
|
||||||
|
globalsProxyModel = new GlobalsProxyModel(globalsModel, this);
|
||||||
|
ui->treeView->setModel(globalsProxyModel);
|
||||||
|
ui->treeView->sortByColumn(GlobalsModel::AddressColumn, Qt::AscendingOrder);
|
||||||
|
|
||||||
|
// Setup custom context menu
|
||||||
|
connect(ui->treeView, &QWidget::customContextMenuRequested, this,
|
||||||
|
&GlobalsWidget::showGlobalsContextMenu);
|
||||||
|
|
||||||
|
ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
|
||||||
|
connect(ui->quickFilterView, &ComboQuickFilterView::filterTextChanged, globalsProxyModel,
|
||||||
|
&QSortFilterProxyModel::setFilterWildcard);
|
||||||
|
|
||||||
|
connect(ui->quickFilterView, &ComboQuickFilterView::filterTextChanged, this,
|
||||||
|
[this] { tree->showItemsNumber(globalsProxyModel->rowCount()); });
|
||||||
|
|
||||||
|
QShortcut *searchShortcut = new QShortcut(QKeySequence::Find, this);
|
||||||
|
connect(searchShortcut, &QShortcut::activated, ui->quickFilterView,
|
||||||
|
&ComboQuickFilterView::showFilter);
|
||||||
|
searchShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
||||||
|
|
||||||
|
QShortcut *clearShortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
||||||
|
connect(clearShortcut, &QShortcut::activated, ui->quickFilterView,
|
||||||
|
&ComboQuickFilterView::clearFilter);
|
||||||
|
clearShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
||||||
|
|
||||||
|
actionEditGlobal = new QAction(tr("Edit Global Variable"), this);
|
||||||
|
actionDeleteGlobal = new QAction(tr("Delete Global Variable"), this);
|
||||||
|
|
||||||
|
connect(actionEditGlobal, &QAction::triggered, [this]() { editGlobal(); });
|
||||||
|
connect(actionDeleteGlobal, &QAction::triggered, [this]() { deleteGlobal(); });
|
||||||
|
|
||||||
|
connect(Core(), &CutterCore::globalVarsChanged, this, &GlobalsWidget::refreshGlobals);
|
||||||
|
connect(Core(), &CutterCore::codeRebased, this, &GlobalsWidget::refreshGlobals);
|
||||||
|
connect(Core(), &CutterCore::refreshAll, this, &GlobalsWidget::refreshGlobals);
|
||||||
|
connect(Core(), &CutterCore::commentsChanged, this,
|
||||||
|
[this]() { qhelpers::emitColumnChanged(globalsModel, GlobalsModel::CommentColumn); });
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalsWidget::~GlobalsWidget() {}
|
||||||
|
|
||||||
|
void GlobalsWidget::refreshGlobals()
|
||||||
|
{
|
||||||
|
globalsModel->beginResetModel();
|
||||||
|
globals = Core()->getAllGlobals();
|
||||||
|
globalsModel->endResetModel();
|
||||||
|
|
||||||
|
qhelpers::adjustColumns(ui->treeView, GlobalsModel::ColumnCount, 0);
|
||||||
|
}
|
89
src/widgets/GlobalsWidget.h
Normal file
89
src/widgets/GlobalsWidget.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#ifndef GLOBALSWIDGET_H
|
||||||
|
#define GLOBALSWIDGET_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
|
#include "core/Cutter.h"
|
||||||
|
#include "CutterDockWidget.h"
|
||||||
|
#include "widgets/ListDockWidget.h"
|
||||||
|
|
||||||
|
class MainWindow;
|
||||||
|
class QTreeWidget;
|
||||||
|
class GlobalsWidget;
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class GlobalsWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MainWindow;
|
||||||
|
class QTreeWidgetItem;
|
||||||
|
|
||||||
|
class GlobalsModel : public AddressableItemModel<QAbstractListModel>
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
friend GlobalsWidget;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList<GlobalDescription> *globals;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Column { AddressColumn = 0, TypeColumn, NameColumn, CommentColumn, ColumnCount };
|
||||||
|
enum Role { GlobalDescriptionRole = Qt::UserRole };
|
||||||
|
|
||||||
|
GlobalsModel(QList<GlobalDescription> *exports, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
|
||||||
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation,
|
||||||
|
int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
RVA address(const QModelIndex &index) const override;
|
||||||
|
QString name(const QModelIndex &index) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GlobalsProxyModel : public AddressableFilterProxyModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
GlobalsProxyModel(GlobalsModel *sourceModel, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool filterAcceptsRow(int row, const QModelIndex &parent) const override;
|
||||||
|
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GlobalsWidget : public CutterDockWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit GlobalsWidget(MainWindow *main);
|
||||||
|
~GlobalsWidget();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void refreshGlobals();
|
||||||
|
|
||||||
|
void showGlobalsContextMenu(const QPoint &pt);
|
||||||
|
|
||||||
|
void editGlobal();
|
||||||
|
void deleteGlobal();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<Ui::GlobalsWidget> ui;
|
||||||
|
|
||||||
|
QList<GlobalDescription> globals;
|
||||||
|
GlobalsModel *globalsModel;
|
||||||
|
GlobalsProxyModel *globalsProxyModel;
|
||||||
|
CutterTreeWidget *tree;
|
||||||
|
|
||||||
|
QAction *actionEditGlobal;
|
||||||
|
QAction *actionDeleteGlobal;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // GLOBALSWIDGET_H
|
107
src/widgets/GlobalsWidget.ui
Normal file
107
src/widgets/GlobalsWidget.ui
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>GlobalsWidget</class>
|
||||||
|
<widget class="QDockWidget" name="GlobalsWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>300</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string notr="true">Global Variables</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="dockWidgetContents">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="CutterTreeView" name="treeView">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">CutterTreeView::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>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="ComboQuickFilterView" name="quickFilterView" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<action name="actionEditGlobal">
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit Global Variable</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Edit Global Variable</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDeleteGlobal">
|
||||||
|
<property name="text">
|
||||||
|
<string>Delete Global Variable</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Delete Global Variable</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>CutterTreeView</class>
|
||||||
|
<extends>QTreeView</extends>
|
||||||
|
<header>widgets/CutterTreeView.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>ComboQuickFilterView</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>widgets/ComboQuickFilterView.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
@ -50,6 +50,7 @@ VisualNavbar::VisualNavbar(MainWindow *main, QWidget *parent)
|
|||||||
connect(Core(), &CutterCore::refreshAll, this, &VisualNavbar::fetchAndPaintData);
|
connect(Core(), &CutterCore::refreshAll, this, &VisualNavbar::fetchAndPaintData);
|
||||||
connect(Core(), &CutterCore::functionsChanged, this, &VisualNavbar::fetchAndPaintData);
|
connect(Core(), &CutterCore::functionsChanged, this, &VisualNavbar::fetchAndPaintData);
|
||||||
connect(Core(), &CutterCore::flagsChanged, this, &VisualNavbar::fetchAndPaintData);
|
connect(Core(), &CutterCore::flagsChanged, this, &VisualNavbar::fetchAndPaintData);
|
||||||
|
connect(Core(), &CutterCore::globalVarsChanged, this, &VisualNavbar::fetchAndPaintData);
|
||||||
|
|
||||||
graphicsScene = new QGraphicsScene(this);
|
graphicsScene = new QGraphicsScene(this);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user