Initial working diff with resizable columns

This commit is contained in:
wargio 2024-01-02 21:43:49 +08:00
parent d974c24daa
commit 0a5a1dfbcf
16 changed files with 258 additions and 70 deletions

View File

@ -22,6 +22,11 @@ BinDiff::~BinDiff()
rz_analysis_match_result_free(result);
}
bool BinDiff::hasData()
{
return result != nullptr;
}
void BinDiff::setFile(QString filePath)
{
mutex.lock();
@ -36,6 +41,13 @@ void BinDiff::setAnalysisLevel(int aLevel)
mutex.unlock();
}
void BinDiff::setCompareLogic(int cLogic)
{
mutex.lock();
compareLogic = cLogic;
mutex.unlock();
}
void BinDiff::run()
{
qRegisterMetaType<BinDiffStatusDescription>();
@ -47,7 +59,7 @@ void BinDiff::run()
maxTotal = 1; // maxTotal must be at least 1.
mutex.unlock();
result = Core()->diffNewFile(file, level, threadCallback, this);
result = Core()->diffNewFile(file, level, compareLogic, threadCallback, this);
mutex.lock();
bool canComplete = continueRun;

View File

@ -20,6 +20,8 @@ public:
void setFile(QString filePth);
void setAnalysisLevel(int aLevel);
void setCompareLogic(int cLogic);
bool hasData();
QList<BinDiffMatchDescription> matches();
QList<FunctionDescription> mismatch(bool originalFile);
@ -42,6 +44,7 @@ private:
#endif
QString file;
int level;
int compareLogic;
bool updateProgress(const size_t nLeft, const size_t nMatch);
static bool threadCallback(const size_t nLeft, const size_t nMatch, void *user);

View File

@ -4564,8 +4564,13 @@ bool CutterCore::isWriteModeEnabled()
return false;
}
RzList *get_functions(RzAnalysis *analysis)
#define IS_IMPORT(name) \
(name.startsWith("sym.imp.") || name.startsWith("loc.imp.") || name.startsWith("imp."))
#define IS_SYMBOL(name, pfx) (IS_IMPORT(name) || name.startsWith(pfx))
RzList *get_functions(RzAnalysis *analysis, int compareLogic)
{
RzList *functions = rz_analysis_get_fcns(analysis);
if (!functions) {
return nullptr;
@ -4576,12 +4581,21 @@ RzList *get_functions(RzAnalysis *analysis)
return list;
}
QString pfx = Config()->getConfigString("analysis.fcnprefix");
if (pfx.isEmpty()) {
pfx = "fcn.";
} else {
pfx += ".";
}
RzAnalysisFunction *func = nullptr;
RzListIter *it = nullptr;
CutterRzListForeach (functions, it, RzAnalysisFunction, func) {
QString name = func->name;
if (name.startsWith("sym.imp.") || name.startsWith("loc.imp.") || name.startsWith("imp.")) {
if (compareLogic == CutterCore::CompareLogicDefault && IS_IMPORT(name)) {
continue;
} else if (compareLogic == CutterCore::CompareLogicSymbols && IS_SYMBOL(name, pfx)) {
continue;
}
rz_list_add_sorted(list, func, analysis->columnSort);
@ -4590,7 +4604,7 @@ RzList *get_functions(RzAnalysis *analysis)
return list;
}
RzAnalysisMatchResult *CutterCore::diffNewFile(const QString &filePath, int level,
RzAnalysisMatchResult *CutterCore::diffNewFile(const QString &filePath, int level, int compareLogic,
RzAnalysisMatchThreadInfoCb callback, void *user)
{
CORE_LOCK();
@ -4613,17 +4627,17 @@ RzAnalysisMatchResult *CutterCore::diffNewFile(const QString &filePath, int leve
}
if (!rz_core_file_open(core_b, filePath.toUtf8().constData(), RZ_PERM_RX, 0)) {
qWarning() << "cannot open file " << filePath;
qWarning() << tr("cannot open file %1").arg(filePath);
goto fail;
}
if (!rz_core_bin_load(core_b, nullptr, UT64_MAX)) {
qWarning() << "cannot load bin " << filePath;
qWarning() << tr("cannot load bin %1").arg(filePath);
goto fail;
}
if (!rz_core_bin_update_arch_bits(core_b)) {
qWarning() << "cannot set architecture with bits";
qWarning() << tr("cannot set architecture with bits");
goto fail;
}
@ -4637,25 +4651,25 @@ RzAnalysisMatchResult *CutterCore::diffNewFile(const QString &filePath, int leve
}
if (!rz_core_analysis_all(core_b)) {
qWarning() << "cannot perform basic analysis of the binary " << filePath;
qWarning() << tr("cannot perform basic analysis of the binary %1").arg(filePath);
goto fail;
}
if (level != AnalysisLevelSymbols
&& !rz_core_analysis_everything(core_b, level == AnalysisLevelExperimental, nullptr)) {
qWarning() << "cannot perform complete analysis of the binary " << filePath;
qWarning() << tr("cannot perform complete analysis of the binary %1").arg(filePath);
goto fail;
}
fcns_a = get_functions(core_a->analysis);
fcns_a = get_functions(core_a->analysis, compareLogic);
if (rz_list_empty(fcns_a)) {
qWarning() << "no functions found in the current opened file";
qWarning() << tr("no functions found in the current opened file");
goto fail;
}
fcns_b = get_functions(core_b->analysis);
fcns_b = get_functions(core_b->analysis, compareLogic);
if (rz_list_empty(fcns_b)) {
qWarning() << "no functions found in " << filePath;
qWarning() << tr("no functions found in the just opene file %1").arg(filePath);
goto fail;
}
@ -4667,7 +4681,7 @@ RzAnalysisMatchResult *CutterCore::diffNewFile(const QString &filePath, int leve
// calculate all the matches between the functions of the 2 different core files.
result = rz_analysis_match_functions(fcns_a, fcns_b, &opts);
if (!result) {
qWarning() << "failed to perform the function matching operation or job was cancelled.";
qWarning() << tr("failed to perform the function matching operation or job was cancelled.");
goto fail;
}

View File

@ -762,7 +762,13 @@ public:
AnalysisLevelExperimental,
};
RzAnalysisMatchResult *diffNewFile(const QString &filePath, int level,
enum {
CompareLogicDefault = 0, ///< Only symbols and functions (no imports)
CompareLogicComplete, ///< All functions (imports included)
CompareLogicSymbols, ///< Only symbols
};
RzAnalysisMatchResult *diffNewFile(const QString &filePath, int level, int compareLogic,
RzAnalysisMatchThreadInfoCb callback, void *user);
signals:

View File

@ -1638,8 +1638,9 @@ void MainWindow::startDiffing()
}
auto level = diffLoadDialog->getLevel();
auto compare = diffLoadDialog->getCompare();
auto diffWait = new DiffWaitDialog(this);
diffWait->show(filename, modified, level);
diffWait->show(filename, modified, level, compare);
}
void MainWindow::on_actionForward_triggered()

View File

@ -10,6 +10,7 @@ BaseFindDialog::BaseFindDialog(QWidget *parent) : QDialog(parent), ui(new Ui::Ba
{
ui->setupUi(this);
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
setModal(true);
// Fill in N-thread Combo
size_t n_cores = rz_th_physical_core_number();

View File

@ -72,6 +72,7 @@ BaseFindResultsDialog::BaseFindResultsDialog(QList<BasefindResultDescription> re
{
ui->setupUi(this);
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
setModal(true);
model = new BaseFindResultsModel(&list, this);
ui->tableView->setModel(model);

View File

@ -14,6 +14,7 @@ BaseFindSearchDialog::BaseFindSearchDialog(QWidget *parent)
{
ui->setupUi(this);
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
setModal(true);
}
BaseFindSearchDialog::~BaseFindSearchDialog() {}

View File

@ -13,6 +13,7 @@ DiffLoadDialog::DiffLoadDialog(QWidget *parent) : QDialog(parent), ui(new Ui::Di
{
ui->setupUi(this);
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
setModal(true);
ui->lineEditFileName->setReadOnly(true);
ui->lineEditFileName->setText("");
@ -24,6 +25,10 @@ DiffLoadDialog::DiffLoadDialog(QWidget *parent) : QDialog(parent), ui(new Ui::Di
ui->comboBoxAnalysis->addItem(tr("Auto"));
ui->comboBoxAnalysis->addItem(tr("Experimental"));
ui->comboBoxCompare->addItem(tr("Default"));
ui->comboBoxCompare->addItem(tr("All functions"));
ui->comboBoxCompare->addItem(tr("Only Symbols"));
auto index = ui->comboBoxAnalysis->findData(tr("Auto"), Qt::DisplayRole);
ui->comboBoxAnalysis->setCurrentIndex(index);
}
@ -45,6 +50,11 @@ int DiffLoadDialog::getLevel() const
return ui->comboBoxAnalysis->currentIndex();
}
int DiffLoadDialog::getCompare() const
{
return ui->comboBoxCompare->currentIndex();
}
void DiffLoadDialog::on_buttonDiffOpen_clicked()
{
QFileDialog dialog(this);

View File

@ -22,6 +22,7 @@ public:
QString getFileToOpen() const;
QString getPreviousDiffFile() const;
int getLevel() const;
int getCompare() const;
signals:
void startDiffing();

View File

@ -10,7 +10,7 @@
<x>0</x>
<y>0</y>
<width>636</width>
<height>184</height>
<height>226</height>
</rect>
</property>
<property name="sizePolicy">
@ -20,7 +20,7 @@
</sizepolicy>
</property>
<property name="windowTitle">
<string notr="false">Select which file to compare.</string>
<string>Select which file to compare.</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="sizeConstraint">
@ -34,22 +34,6 @@
<item row="1" column="1">
<widget class="QLineEdit" name="lineEditDiffFile"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="fileToCompareLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;File to compare to.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>File to compare (required)</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="buttonFileOpen">
<property name="text">
@ -57,6 +41,19 @@
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="buttonDiffOpen">
<property name="text">
<string>Select</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboBoxAnalysis"/>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEditFileName"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="previousDiffLabel">
<property name="sizePolicy">
@ -73,16 +70,6 @@
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEditFileName"/>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="buttonDiffOpen">
<property name="text">
<string>Select</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelAnalysisLevel">
<property name="text">
@ -90,8 +77,31 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboBoxAnalysis"/>
<item row="0" column="0">
<widget class="QLabel" name="fileToCompareLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;File to compare to.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>File to compare (required)</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelCompareLogic">
<property name="text">
<string>Compare Logic</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="comboBoxCompare"/>
</item>
</layout>
</item>

View File

@ -13,11 +13,10 @@ DiffWaitDialog::DiffWaitDialog(QWidget *parent)
{
ui->setupUi(this);
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
setModal(true);
ui->lineEditNFuncs->setReadOnly(true);
ui->lineEditMatches->setReadOnly(true);
ui->lineEditEstimatedTime->setReadOnly(true);
ui->lineEditElapsedTime->setReadOnly(true);
ui->lineEditOriginal->setReadOnly(true);
ui->lineEditModified->setReadOnly(true);
ui->progressBar->setValue(0);
@ -34,11 +33,11 @@ DiffWaitDialog::~DiffWaitDialog()
if (bDiff && bDiff->isRunning()) {
bDiff->cancel();
bDiff->wait();
delete bDiff;
}
delete bDiff;
}
void DiffWaitDialog::show(QString original, QString modified, int level)
void DiffWaitDialog::show(QString original, QString modified, int level, int compare)
{
connect(this, &DiffWaitDialog::cancelJob, bDiff, &BinDiff::cancel);
connect(bDiff, &BinDiff::progress, this, &DiffWaitDialog::onProgress);
@ -49,6 +48,7 @@ void DiffWaitDialog::show(QString original, QString modified, int level)
ui->lineEditModified->setText(modified);
bDiff->setAnalysisLevel(level);
bDiff->setCompareLogic(compare);
bDiff->setFile(modified);
eTimer.restart();
timer.setSingleShot(false);
@ -80,10 +80,12 @@ void DiffWaitDialog::onCompletion()
{
timer.stop();
auto results = new DiffWindow(bDiff, parentWidget());
bDiff = nullptr;
if (bDiff->hasData()) {
auto results = new DiffWindow(bDiff, parentWidget());
bDiff = nullptr;
results->showMaximized();
}
results->showMaximized();
close();
}
@ -102,4 +104,5 @@ void DiffWaitDialog::on_buttonBox_rejected()
{
timer.stop();
emit cancelJob();
close();
}

View File

@ -22,7 +22,7 @@ public:
explicit DiffWaitDialog(QWidget *parent = nullptr);
~DiffWaitDialog();
void show(QString original, QString modified, int level);
void show(QString original, QString modified, int level, int compare);
public slots:
void onProgress(BinDiffStatusDescription status);

View File

@ -41,7 +41,7 @@
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="1">
<widget class="QLineEdit" name="lineEditElapsedTime"/>
<widget class="QLabel" name="lineEditElapsedTime"/>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEditModified"/>
@ -98,7 +98,7 @@
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineEditEstimatedTime"/>
<widget class="QLabel" name="lineEditEstimatedTime"/>
</item>
</layout>
</item>

View File

@ -56,7 +56,26 @@ QVariant DiffMatchModel::data(const QModelIndex &index, int role) const
}
case Qt::ToolTipRole: {
return entry.simtype;
switch (index.column()) {
case NameOrig:
return entry.original.name;
case SizeOrig:
return QString::asprintf("%llu (%#llx)", entry.original.linearSize,
entry.original.linearSize);
case AddressOrig:
return RzAddressString(entry.original.offset);
case Similarity:
return entry.simtype;
case AddressMod:
return RzAddressString(entry.modified.offset);
case SizeMod:
return QString::asprintf("%llu (%#llx)", entry.modified.linearSize,
entry.modified.linearSize);
case NameMod:
return entry.modified.name;
default:
return QVariant();
}
}
case Qt::BackgroundRole: {
@ -126,6 +145,8 @@ QVariant DiffMismatchModel::data(const QModelIndex &index, int role) const
const FunctionDescription &entry = list->at(index.row());
switch (role) {
case Qt::ToolTipRole:
/* fall-thru */
case Qt::DisplayRole:
switch (index.column()) {
case FuncName:
@ -150,10 +171,6 @@ QVariant DiffMismatchModel::data(const QModelIndex &index, int role) const
return QVariant();
}
case Qt::ToolTipRole: {
return entry.name;
}
default:
return QVariant();
}
@ -194,6 +211,7 @@ DiffWindow::DiffWindow(BinDiff *bd, QWidget *parent)
: QDialog(parent), ui(new Ui::DiffWindow), bDiff(bd)
{
ui->setupUi(this);
setModal(true);
ui->comboBoxShowInfo->addItem(tr("Summary"));
ui->comboBoxShowInfo->addItem(tr("AAAA"));
@ -213,22 +231,16 @@ DiffWindow::DiffWindow(BinDiff *bd, QWidget *parent)
// Matches Table
ui->tableViewMatch->setModel(modelMatch);
ui->tableViewMatch->sortByColumn(DiffMatchModel::Similarity, Qt::AscendingOrder);
ui->tableViewMatch->verticalHeader()->hide();
ui->tableViewMatch->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
ui->tableViewMatch->setContextMenuPolicy(Qt::CustomContextMenu);
// Deletion Table
ui->tableViewRem->setModel(modelDel);
ui->tableViewRem->sortByColumn(DiffMismatchModel::FuncName, Qt::AscendingOrder);
ui->tableViewRem->verticalHeader()->hide();
ui->tableViewRem->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
ui->tableViewRem->setContextMenuPolicy(Qt::CustomContextMenu);
// Addition Table
ui->tableViewAdd->setModel(modelAdd);
ui->tableViewAdd->sortByColumn(DiffMismatchModel::FuncName, Qt::AscendingOrder);
ui->tableViewAdd->verticalHeader()->hide();
ui->tableViewAdd->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
ui->tableViewAdd->setContextMenuPolicy(Qt::CustomContextMenu);
}

View File

@ -64,7 +64,42 @@
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QTableView" name="tableViewMatch"/>
<widget class="CutterTreeView" name="tableViewMatch">
<attribute name="title">
<string>Matches</string>
</attribute>
<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="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="autoScroll">
<bool>true</bool>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="indentation">
<number>8</number>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
@ -74,7 +109,42 @@
</attribute>
<layout class="QVBoxLayout" name="verticalLayoutMismatchRem">
<item>
<widget class="QTableView" name="tableViewRem"/>
<widget class="CutterTreeView" name="tableViewRem">
<attribute name="title">
<string>Matches</string>
</attribute>
<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="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="autoScroll">
<bool>true</bool>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="indentation">
<number>8</number>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
@ -84,7 +154,42 @@
</attribute>
<layout class="QVBoxLayout" name="verticalLayoutMismatchAdd">
<item>
<widget class="QTableView" name="tableViewAdd"/>
<widget class="CutterTreeView" name="tableViewAdd">
<attribute name="title">
<string>Matches</string>
</attribute>
<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="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="autoScroll">
<bool>true</bool>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="indentation">
<number>8</number>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
@ -151,6 +256,14 @@
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>CutterTreeView</class>
<extends>QTreeView</extends>
<header>widgets/CutterTreeView.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>