mirror of
https://github.com/rizinorg/cutter.git
synced 2025-01-31 08:37:26 +00:00
Moving to proper bindiff
This commit is contained in:
parent
39532d312c
commit
439b268927
@ -7,6 +7,7 @@ set(SOURCES
|
||||
core/CutterJson.cpp
|
||||
core/RizinCpp.cpp
|
||||
core/Basefind.cpp
|
||||
core/BinDiff.cpp
|
||||
dialogs/EditStringDialog.cpp
|
||||
dialogs/WriteCommandsDialogs.cpp
|
||||
widgets/DisassemblerGraphView.cpp
|
||||
@ -58,7 +59,6 @@ set(SOURCES
|
||||
widgets/DecompilerWidget.cpp
|
||||
widgets/VisualNavbar.cpp
|
||||
widgets/GraphView.cpp
|
||||
dialogs/bindiff/BinDiffDialog.cpp
|
||||
dialogs/preferences/PreferencesDialog.cpp
|
||||
dialogs/preferences/AppearanceOptionsWidget.cpp
|
||||
dialogs/preferences/GraphOptionsWidget.cpp
|
||||
@ -156,6 +156,7 @@ set(SOURCES
|
||||
tools/basefind/BaseFindDialog.cpp
|
||||
tools/basefind/BaseFindSearchDialog.cpp
|
||||
tools/basefind/BaseFindResultsDialog.cpp
|
||||
tools/bindiff/DiffLoadDialog.cpp
|
||||
)
|
||||
set(HEADER_FILES
|
||||
core/Cutter.h
|
||||
@ -164,6 +165,7 @@ set(HEADER_FILES
|
||||
core/CutterJson.h
|
||||
core/RizinCpp.h
|
||||
core/Basefind.h
|
||||
core/BinDiff.h
|
||||
dialogs/EditStringDialog.h
|
||||
dialogs/WriteCommandsDialogs.h
|
||||
widgets/DisassemblerGraphView.h
|
||||
@ -214,7 +216,6 @@ set(HEADER_FILES
|
||||
widgets/DecompilerWidget.h
|
||||
widgets/VisualNavbar.h
|
||||
widgets/GraphView.h
|
||||
dialogs/bindiff/BinDiffDialog.h
|
||||
dialogs/preferences/PreferencesDialog.h
|
||||
dialogs/preferences/AppearanceOptionsWidget.h
|
||||
dialogs/preferences/PreferenceCategory.h
|
||||
@ -321,6 +322,7 @@ set(HEADER_FILES
|
||||
tools/basefind/BaseFindDialog.h
|
||||
tools/basefind/BaseFindSearchDialog.h
|
||||
tools/basefind/BaseFindResultsDialog.h
|
||||
tools/bindiff/DiffLoadDialog.h
|
||||
)
|
||||
set(UI_FILES
|
||||
dialogs/AboutDialog.ui
|
||||
@ -347,7 +349,6 @@ set(UI_FILES
|
||||
widgets/GlobalsWidget.ui
|
||||
widgets/StringsWidget.ui
|
||||
widgets/HexdumpWidget.ui
|
||||
dialogs/bindiff/BinDiffDialog.ui
|
||||
dialogs/preferences/PreferencesDialog.ui
|
||||
dialogs/preferences/AppearanceOptionsWidget.ui
|
||||
dialogs/preferences/GraphOptionsWidget.ui
|
||||
@ -396,6 +397,7 @@ set(UI_FILES
|
||||
tools/basefind/BaseFindDialog.ui
|
||||
tools/basefind/BaseFindSearchDialog.ui
|
||||
tools/basefind/BaseFindResultsDialog.ui
|
||||
tools/bindiff/DiffLoadDialog.ui
|
||||
)
|
||||
set(QRC_FILES
|
||||
resources.qrc
|
||||
|
120
src/core/BinDiff.cpp
Normal file
120
src/core/BinDiff.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
#include "BinDiff.h"
|
||||
|
||||
bool BinDiff::threadCallback(const size_t nLeft, const size_t nMatch, void *user)
|
||||
{
|
||||
auto bdiff = reinterpret_cast<BinDiff *>(user);
|
||||
return bdiff->updateProgress(nLeft, nMatch);
|
||||
}
|
||||
|
||||
BinDiff::BinDiff(CutterCore *core)
|
||||
: core(core),
|
||||
result(nullptr),
|
||||
continue_run(true),
|
||||
maxTotal(1)
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||
,
|
||||
mutex(QMutex::Recursive)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
BinDiff::~BinDiff()
|
||||
{
|
||||
cancel();
|
||||
wait();
|
||||
rz_analysis_match_result_free(result);
|
||||
}
|
||||
|
||||
void BinDiff::run(QString fileName)
|
||||
{
|
||||
mutex.lock();
|
||||
rz_analysis_match_result_free(result);
|
||||
result = nullptr;
|
||||
continue_run = true;
|
||||
maxTotal = 1; // maxTotal must be at least 1.
|
||||
mutex.unlock();
|
||||
|
||||
core->coreMutex.lock();
|
||||
result = core->diffNewFile(fileName, threadCallback, this);
|
||||
core->coreMutex.unlock();
|
||||
|
||||
emit complete();
|
||||
}
|
||||
|
||||
void BinDiff::cancel()
|
||||
{
|
||||
mutex.lock();
|
||||
continue_run = false;
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
static void setFunctionDescription(FunctionDescription *desc, const RzAnalysisFunction *func)
|
||||
{
|
||||
desc->offset = func->addr;
|
||||
desc->linearSize = rz_analysis_function_linear_size((RzAnalysisFunction *)func);
|
||||
desc->nargs = rz_analysis_arg_count((RzAnalysisFunction *)func);
|
||||
desc->nlocals = rz_analysis_var_local_count((RzAnalysisFunction *)func);
|
||||
desc->nbbs = rz_list_length(func->bbs);
|
||||
desc->calltype = func->cc ? QString::fromUtf8(func->cc) : QString();
|
||||
desc->name = func->name ? QString::fromUtf8(func->name) : QString();
|
||||
desc->edges = rz_analysis_function_count_edges(func, nullptr);
|
||||
desc->stackframe = func->maxstack;
|
||||
}
|
||||
|
||||
QList<BinDiffMatchDescription> BinDiff::matches()
|
||||
{
|
||||
QList<BinDiffMatchDescription> pairs;
|
||||
RzAnalysisMatchPair *pair = nullptr;
|
||||
RzListIter *it = nullptr;
|
||||
const RzAnalysisFunction *fcn_a = nullptr;
|
||||
const RzAnalysisFunction *fcn_b = nullptr;
|
||||
|
||||
CutterRzListForeach (result->matches, it, RzAnalysisMatchPair, pair) {
|
||||
BinDiffMatchDescription desc;
|
||||
fcn_a = static_cast<const RzAnalysisFunction *>(pair->pair_a);
|
||||
fcn_b = static_cast<const RzAnalysisFunction *>(pair->pair_b);
|
||||
|
||||
setFunctionDescription(&desc.original, fcn_a);
|
||||
setFunctionDescription(&desc.modified, fcn_b);
|
||||
|
||||
desc.simtype = RZ_ANALYSIS_SIMILARITY_TYPE_STR(pair->similarity);
|
||||
desc.similarity = pair->similarity;
|
||||
|
||||
pairs << desc;
|
||||
}
|
||||
|
||||
return pairs;
|
||||
}
|
||||
|
||||
QList<FunctionDescription> BinDiff::mismatch(bool fileA)
|
||||
{
|
||||
QList<FunctionDescription> list;
|
||||
RzAnalysisFunction *func = nullptr;
|
||||
RzList *unmatch = fileA ? result->unmatch_a : result->unmatch_b;
|
||||
RzListIter *it = nullptr;
|
||||
|
||||
CutterRzListForeach (unmatch, it, RzAnalysisFunction, func) {
|
||||
FunctionDescription desc;
|
||||
setFunctionDescription(&desc, func);
|
||||
list << desc;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
bool BinDiff::updateProgress(const size_t nLeft, const size_t nMatch)
|
||||
{
|
||||
mutex.lock();
|
||||
|
||||
if (maxTotal < nMatch) {
|
||||
maxTotal = nMatch;
|
||||
}
|
||||
if (maxTotal < nLeft) {
|
||||
maxTotal = nLeft;
|
||||
}
|
||||
|
||||
emit progress(maxTotal, nLeft, nMatch);
|
||||
bool ret = continue_run;
|
||||
mutex.unlock();
|
||||
return ret;
|
||||
}
|
47
src/core/BinDiff.h
Normal file
47
src/core/BinDiff.h
Normal file
@ -0,0 +1,47 @@
|
||||
#ifndef CUTTER_BINDIFF_CORE_H
|
||||
#define CUTTER_BINDIFF_CORE_H
|
||||
|
||||
#include <QThread>
|
||||
#include <QMutex>
|
||||
|
||||
#include "Cutter.h"
|
||||
#include "CutterDescriptions.h"
|
||||
#include <rz_analysis.h>
|
||||
|
||||
class CutterCore;
|
||||
|
||||
class BinDiff : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BinDiff(CutterCore *core);
|
||||
virtual ~BinDiff();
|
||||
|
||||
void run(QString fileName);
|
||||
QList<BinDiffMatchDescription> matches();
|
||||
QList<FunctionDescription> mismatch(bool fileA);
|
||||
|
||||
public slots:
|
||||
void cancel();
|
||||
|
||||
signals:
|
||||
void progress(const size_t total, const size_t nLeft, const size_t nMatch);
|
||||
void complete();
|
||||
|
||||
private:
|
||||
CutterCore *const core;
|
||||
RzAnalysisMatchResult *result;
|
||||
bool continue_run;
|
||||
size_t maxTotal;
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||
QMutex mutex;
|
||||
#else
|
||||
QRecursiveMutex mutex;
|
||||
#endif
|
||||
|
||||
bool updateProgress(const size_t nLeft, const size_t nMatch);
|
||||
static bool threadCallback(const size_t nLeft, const size_t nMatch, void *user);
|
||||
};
|
||||
|
||||
#endif // CUTTER_BINDIFF_CORE_H
|
@ -396,7 +396,7 @@ QString CutterCore::getFunctionExecOut(const std::function<bool(RzCore *)> &fcn,
|
||||
o = rz_cons_get_buffer();
|
||||
|
||||
rz_cons_pop();
|
||||
rz_cons_echo(NULL);
|
||||
rz_cons_echo(nullptr);
|
||||
|
||||
clean_return:
|
||||
if (offset != core->offset) {
|
||||
@ -487,7 +487,7 @@ QString CutterCore::cmdRaw(const char *cmd)
|
||||
|
||||
// cleaning up
|
||||
rz_cons_pop();
|
||||
rz_cons_echo(NULL);
|
||||
rz_cons_echo(nullptr);
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -603,14 +603,14 @@ bool CutterCore::loadFile(QString path, ut64 baddr, ut64 mapaddr, int perms, int
|
||||
// load RzBin information
|
||||
// XXX only for sub-bins
|
||||
rz_core_bin_load(core, path.toUtf8(), baddr);
|
||||
rz_bin_select_idx(core->bin, NULL, idx);
|
||||
rz_bin_select_idx(core->bin, nullptr, idx);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// Not loading RzBin info coz va = false
|
||||
}
|
||||
|
||||
auto iod = core->io ? core->io->desc : NULL;
|
||||
auto iod = core->io ? core->io->desc : nullptr;
|
||||
auto debug =
|
||||
core->file && iod && (core->file->fd == iod->fd) && iod->plugin && iod->plugin->isdbg;
|
||||
|
||||
@ -856,7 +856,7 @@ QString CutterCore::getString(RVA addr, uint64_t len, RzStrEnc encoding, bool es
|
||||
opt.encoding = encoding;
|
||||
opt.escape_nl = escape_nl;
|
||||
auto seek = seekTemp(addr);
|
||||
return fromOwnedCharPtr(rz_str_stringify_raw_buffer(&opt, NULL));
|
||||
return fromOwnedCharPtr(rz_str_stringify_raw_buffer(&opt, nullptr));
|
||||
}
|
||||
|
||||
QString CutterCore::getMetaString(RVA addr)
|
||||
@ -1093,13 +1093,13 @@ void CutterCore::createSignature(const QString &filepath)
|
||||
ut64 CutterCore::math(const QString &expr)
|
||||
{
|
||||
CORE_LOCK();
|
||||
return rz_num_math(core ? core->num : NULL, expr.toUtf8().constData());
|
||||
return rz_num_math(core ? core->num : nullptr, expr.toUtf8().constData());
|
||||
}
|
||||
|
||||
ut64 CutterCore::num(const QString &expr)
|
||||
{
|
||||
CORE_LOCK();
|
||||
return rz_num_get(core ? core->num : NULL, expr.toUtf8().constData());
|
||||
return rz_num_get(core ? core->num : nullptr, expr.toUtf8().constData());
|
||||
}
|
||||
|
||||
QString CutterCore::itoa(ut64 num, int rdx)
|
||||
@ -1902,7 +1902,7 @@ void CutterCore::setCurrentDebugThread(int tid)
|
||||
if (!asyncTask(
|
||||
[=](RzCore *core) {
|
||||
rz_debug_select(core->dbg, core->dbg->pid, tid);
|
||||
return (void *)NULL;
|
||||
return (void *)nullptr;
|
||||
},
|
||||
debugTask)) {
|
||||
return;
|
||||
@ -1929,7 +1929,7 @@ void CutterCore::setCurrentDebugProcess(int pid)
|
||||
[=](RzCore *core) {
|
||||
rz_debug_select(core->dbg, pid, core->dbg->tid);
|
||||
core->dbg->main_pid = pid;
|
||||
return (void *)NULL;
|
||||
return (void *)nullptr;
|
||||
},
|
||||
debugTask)) {
|
||||
return;
|
||||
@ -2004,7 +2004,7 @@ void CutterCore::startEmulation()
|
||||
asyncTask(
|
||||
[&](RzCore *core) {
|
||||
rz_core_analysis_esil_reinit(core);
|
||||
rz_core_analysis_esil_init_mem(core, NULL, UT64_MAX, UT32_MAX);
|
||||
rz_core_analysis_esil_init_mem(core, nullptr, UT64_MAX, UT32_MAX);
|
||||
rz_core_analysis_esil_init_regs(core);
|
||||
return nullptr;
|
||||
},
|
||||
@ -2180,7 +2180,7 @@ void CutterCore::stopDebug()
|
||||
|
||||
CORE_LOCK();
|
||||
if (currentlyEmulating) {
|
||||
rz_core_analysis_esil_init_mem_del(core, NULL, UT64_MAX, UT32_MAX);
|
||||
rz_core_analysis_esil_init_mem_del(core, nullptr, UT64_MAX, UT32_MAX);
|
||||
rz_core_analysis_esil_deinit(core);
|
||||
resetWriteCache();
|
||||
rz_core_debug_clear_register_flags(core);
|
||||
@ -2218,7 +2218,7 @@ void CutterCore::continueDebug()
|
||||
if (currentlyEmulating) {
|
||||
if (!asyncTask(
|
||||
[](RzCore *core) {
|
||||
rz_core_esil_step(core, UT64_MAX, "0", NULL, false);
|
||||
rz_core_esil_step(core, UT64_MAX, "0", nullptr, false);
|
||||
rz_core_reg_update_flags(core);
|
||||
return nullptr;
|
||||
},
|
||||
@ -2294,7 +2294,7 @@ void CutterCore::continueUntilDebug(ut64 offset)
|
||||
if (currentlyEmulating) {
|
||||
if (!asyncTask(
|
||||
[=](RzCore *core) {
|
||||
rz_core_esil_step(core, offset, NULL, NULL, false);
|
||||
rz_core_esil_step(core, offset, nullptr, nullptr, false);
|
||||
rz_core_reg_update_flags(core);
|
||||
return nullptr;
|
||||
},
|
||||
@ -2380,7 +2380,7 @@ void CutterCore::continueUntilSyscall()
|
||||
[](void *x) { rz_debug_stop(reinterpret_cast<RzDebug *>(x)); },
|
||||
core->dbg);
|
||||
rz_reg_arena_swap(core->dbg->reg, true);
|
||||
rz_debug_continue_syscalls(core->dbg, NULL, 0);
|
||||
rz_debug_continue_syscalls(core->dbg, nullptr, 0);
|
||||
rz_cons_break_pop();
|
||||
rz_core_dbg_follow_seek_register(core);
|
||||
return nullptr;
|
||||
@ -2410,7 +2410,7 @@ void CutterCore::stepDebug()
|
||||
if (currentlyEmulating) {
|
||||
if (!asyncTask(
|
||||
[](RzCore *core) {
|
||||
rz_core_esil_step(core, UT64_MAX, NULL, NULL, false);
|
||||
rz_core_esil_step(core, UT64_MAX, nullptr, nullptr, false);
|
||||
rz_core_reg_update_flags(core);
|
||||
return nullptr;
|
||||
},
|
||||
@ -2635,7 +2635,7 @@ void CutterCore::stopTraceSession()
|
||||
if (!asyncTask(
|
||||
[](RzCore *core) {
|
||||
rz_debug_session_free(core->dbg->session);
|
||||
core->dbg->session = NULL;
|
||||
core->dbg->session = nullptr;
|
||||
return nullptr;
|
||||
},
|
||||
debugTask)) {
|
||||
@ -3255,8 +3255,8 @@ QList<FlirtDescription> CutterCore::getSignaturesDB()
|
||||
{
|
||||
CORE_LOCK();
|
||||
|
||||
void *ptr = NULL;
|
||||
RzListIter *iter = NULL;
|
||||
void *ptr = nullptr;
|
||||
RzListIter *iter = nullptr;
|
||||
QList<FlirtDescription> sigdb;
|
||||
|
||||
RzList *list = rz_core_analysis_sigdb_list(core, true);
|
||||
@ -3451,7 +3451,7 @@ QList<SectionDescription> CutterCore::getAllSections()
|
||||
if (!digests) {
|
||||
continue;
|
||||
}
|
||||
const char *entropy = (const char *)ht_pp_find(digests, "entropy", NULL);
|
||||
const char *entropy = (const char *)ht_pp_find(digests, "entropy", nullptr);
|
||||
section.entropy = rz_str_get(entropy);
|
||||
ht_pp_free(digests);
|
||||
}
|
||||
@ -4055,7 +4055,7 @@ void CutterCore::addGlobalVariable(RVA offset, QString name, QString typ)
|
||||
{
|
||||
name = sanitizeStringForCommand(name);
|
||||
CORE_LOCK();
|
||||
char *errmsg = NULL;
|
||||
char *errmsg = nullptr;
|
||||
RzType *globType = rz_type_parse_string_single(core->analysis->typedb->parser,
|
||||
typ.toStdString().c_str(), &errmsg);
|
||||
if (errmsg) {
|
||||
@ -4084,7 +4084,7 @@ void CutterCore::modifyGlobalVariable(RVA offset, QString name, QString typ)
|
||||
if (name.compare(glob->name)) {
|
||||
rz_analysis_var_global_rename(core->analysis, glob->name, name.toStdString().c_str());
|
||||
}
|
||||
char *errmsg = NULL;
|
||||
char *errmsg = nullptr;
|
||||
RzType *globType = rz_type_parse_string_single(core->analysis->typedb->parser,
|
||||
typ.toStdString().c_str(), &errmsg);
|
||||
if (errmsg) {
|
||||
@ -4260,7 +4260,7 @@ QList<DisassemblyLine> CutterCore::disassembleLines(RVA offset, int lines)
|
||||
rz_cons_singleton()->is_html = false;
|
||||
rz_cons_singleton()->was_html = true;
|
||||
}
|
||||
rz_core_print_disasm(core, offset, core->block, core->blocksize, lines, NULL, &options);
|
||||
rz_core_print_disasm(core, offset, core->block, core->blocksize, lines, nullptr, &options);
|
||||
}
|
||||
|
||||
QList<DisassemblyLine> r;
|
||||
@ -4387,7 +4387,7 @@ QString CutterCore::getVersionInformation()
|
||||
{ "rz_syscall", &rz_syscall_version },
|
||||
{ "rz_util", &rz_util_version },
|
||||
/* ... */
|
||||
{ NULL, NULL }
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
versionInfo.append(getRizinVersionReadable());
|
||||
versionInfo.append("\n");
|
||||
@ -4564,9 +4564,12 @@ bool CutterCore::isWriteModeEnabled()
|
||||
return false;
|
||||
}
|
||||
|
||||
RzAnalysisMatchResult *CutterCore::matchFunctionsFromNewFile(const QString &filePath) {
|
||||
RzList *fcns_a = NULL, *fcns_b = NULL;
|
||||
RzAnalysisMatchResult *result = NULL;
|
||||
RzAnalysisMatchResult *CutterCore::diffNewFile(const QString &filePath,
|
||||
RzAnalysisMatchThreadInfoCb callback, void *user)
|
||||
{
|
||||
RzList *fcns_a = nullptr, *fcns_b = nullptr;
|
||||
RzAnalysisMatchResult *result = nullptr;
|
||||
RzAnalysisMatchOpt opts;
|
||||
RzListIter *iter;
|
||||
RzConfigNode *node;
|
||||
void *ptr;
|
||||
@ -4590,7 +4593,7 @@ RzAnalysisMatchResult *CutterCore::matchFunctionsFromNewFile(const QString &file
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!rz_core_bin_load(core_b, NULL, UT64_MAX)) {
|
||||
if (!rz_core_bin_load(core_b, nullptr, UT64_MAX)) {
|
||||
qWarning() << "cannot load bin " << filePath;
|
||||
goto fail;
|
||||
}
|
||||
@ -4600,18 +4603,18 @@ RzAnalysisMatchResult *CutterCore::matchFunctionsFromNewFile(const QString &file
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rz_list_foreach (core_a->config->nodes, iter, ptr) {
|
||||
rz_list_foreach(core_a->config->nodes, iter, ptr)
|
||||
{
|
||||
node = reinterpret_cast<RzConfigNode *>(ptr);
|
||||
if (!strcmp(node->name, "scr.color") ||
|
||||
!strcmp(node->name, "scr.interactive") ||
|
||||
!strcmp(node->name, "cfg.debug")) {
|
||||
if (!strcmp(node->name, "scr.color") || !strcmp(node->name, "scr.interactive")
|
||||
|| !strcmp(node->name, "cfg.debug")) {
|
||||
rz_config_set(core_b->config, node->name, "0");
|
||||
continue;
|
||||
}
|
||||
rz_config_set(core_b->config, node->name, node->value);
|
||||
}
|
||||
|
||||
if (!rz_core_analysis_everything(core_b, false, NULL)) {
|
||||
if (!rz_core_analysis_everything(core_b, false, nullptr)) {
|
||||
qWarning() << "cannot analyze binary " << filePath;
|
||||
goto fail;
|
||||
}
|
||||
@ -4631,10 +4634,15 @@ RzAnalysisMatchResult *CutterCore::matchFunctionsFromNewFile(const QString &file
|
||||
rz_list_sort(fcns_a, core_a->analysis->columnSort);
|
||||
rz_list_sort(fcns_b, core_b->analysis->columnSort);
|
||||
|
||||
opts.analysis_a = core_a->analysis;
|
||||
opts.analysis_b = core_b->analysis;
|
||||
opts.callback = callback;
|
||||
opts.user = user;
|
||||
|
||||
// calculate all the matches between the functions of the 2 different core files.
|
||||
result = rz_analysis_match_functions_2(core_a->analysis, fcns_a, core_b->analysis, fcns_b);
|
||||
result = rz_analysis_match_functions(fcns_a, fcns_b, &opts);
|
||||
if (!result) {
|
||||
qWarning() << "failed to perform the function matching operation";
|
||||
qWarning() << "failed to perform the function matching operation or job was cancelled.";
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -4647,10 +4655,9 @@ fail:
|
||||
rz_list_free(fcns_b);
|
||||
rz_core_free(this->core_b);
|
||||
this->core_b = nullptr;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief get a compact disassembly preview for tooltips
|
||||
* @param address - the address from which to print the disassembly
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "core/CutterDescriptions.h"
|
||||
#include "core/CutterJson.h"
|
||||
#include "core/Basefind.h"
|
||||
#include "core/BinDiff.h"
|
||||
#include "common/BasicInstructionHighlighter.h"
|
||||
|
||||
#include <QMap>
|
||||
@ -71,6 +72,7 @@ class CUTTER_EXPORT CutterCore : public QObject
|
||||
friend class RzCoreLocked;
|
||||
friend class RizinTask;
|
||||
friend class Basefind;
|
||||
friend class BinDiff;
|
||||
|
||||
public:
|
||||
explicit CutterCore(QObject *parent = nullptr);
|
||||
@ -755,7 +757,8 @@ public:
|
||||
void writeGraphvizGraphToFile(QString path, QString format, RzCoreGraphType type, RVA address);
|
||||
|
||||
/* Diffing/Matching */
|
||||
RzAnalysisMatchResult *matchFunctionsFromNewFile(const QString &filePath);
|
||||
RzAnalysisMatchResult *diffNewFile(const QString &filePath,
|
||||
RzAnalysisMatchThreadInfoCb callback, void *user);
|
||||
|
||||
signals:
|
||||
void refreshAll();
|
||||
|
@ -405,6 +405,14 @@ struct BasefindResultDescription
|
||||
ut32 score;
|
||||
};
|
||||
|
||||
struct BinDiffMatchDescription
|
||||
{
|
||||
FunctionDescription original;
|
||||
FunctionDescription modified;
|
||||
QString simtype;
|
||||
double similarity;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(FunctionDescription)
|
||||
Q_DECLARE_METATYPE(ImportDescription)
|
||||
Q_DECLARE_METATYPE(ExportDescription)
|
||||
@ -446,5 +454,6 @@ Q_DECLARE_METATYPE(RefDescription)
|
||||
Q_DECLARE_METATYPE(VariableDescription)
|
||||
Q_DECLARE_METATYPE(BasefindCoreStatusDescription)
|
||||
Q_DECLARE_METATYPE(BasefindResultDescription)
|
||||
Q_DECLARE_METATYPE(BinDiffMatchDescription)
|
||||
|
||||
#endif // DESCRIPTIONS_H
|
||||
|
@ -119,6 +119,7 @@
|
||||
|
||||
// Tools
|
||||
#include "tools/basefind/BaseFindDialog.h"
|
||||
#include "tools/bindiff/DiffLoadDialog.h"
|
||||
|
||||
#define PROJECT_FILE_FILTER tr("Rizin Project (*.rzdb)")
|
||||
|
||||
@ -1616,60 +1617,14 @@ void MainWindow::on_actionBackward_triggered()
|
||||
|
||||
void MainWindow::on_actionDiff_triggered()
|
||||
{
|
||||
QFileDialog dialog(this);
|
||||
dialog.setWindowTitle(tr("Select a file to use for diffing"));
|
||||
dialog.setNameFilters({ tr("All files (*)") });
|
||||
|
||||
if (!dialog.exec()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QString &fileName = QDir::toNativeSeparators(dialog.selectedFiles().first());
|
||||
|
||||
if (fileName.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto compareTask = new RizinFunctionTask([=](RzCore *) {
|
||||
return Core()->matchFunctionsFromNewFile(fileName);
|
||||
}, false);
|
||||
|
||||
task = QSharedPointer<RizinTask>(compareTask);
|
||||
taskDialog = new RizinTaskDialog(task);
|
||||
taskDialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
taskDialog->setDesc(tr("Performing function comparison..."));
|
||||
taskDialog->show();
|
||||
|
||||
connect(task.data(), &RizinTask::finished, this, [this, compareTask]() {
|
||||
RzAnalysisMatchResult *result = static_cast<RzAnalysisMatchResult *>(compareTask->getResult());
|
||||
openBinDiffDialog(result);
|
||||
delete taskDialog;
|
||||
taskDialog = nullptr;
|
||||
});
|
||||
|
||||
compareTask->startTask();
|
||||
auto dialog = new DiffLoadDialog(this);
|
||||
dialog->show();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionForward_triggered()
|
||||
{
|
||||
core->seekNext();
|
||||
}
|
||||
|
||||
void MainWindow::openBinDiffDialog(RzAnalysisMatchResult *result)
|
||||
{
|
||||
if (!result) {
|
||||
messageBoxWarning(tr("Error"), tr("Failed to perform the function matching."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (binDiffDialog) {
|
||||
delete binDiffDialog;
|
||||
}
|
||||
|
||||
binDiffDialog = new BinDiffDialog(result, this);
|
||||
binDiffDialog->show();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionDisasAdd_comment_triggered()
|
||||
{
|
||||
CommentsDialog c(this);
|
||||
|
@ -152,10 +152,10 @@ public slots:
|
||||
|
||||
void openNewFileFailed();
|
||||
|
||||
void openBinDiffDialog(RzAnalysisMatchResult *result);
|
||||
|
||||
void toggleOverview(bool visibility, GraphWidget *targetGraph);
|
||||
|
||||
private slots:
|
||||
void on_actionDiff_triggered();
|
||||
void on_actionBaseFind_triggered();
|
||||
void on_actionAbout_triggered();
|
||||
void on_actionIssue_triggered();
|
||||
@ -179,8 +179,6 @@ private slots:
|
||||
void on_actionBackward_triggered();
|
||||
void on_actionForward_triggered();
|
||||
|
||||
void on_actionDiff_triggered();
|
||||
|
||||
void on_actionMap_triggered();
|
||||
|
||||
void on_actionTabs_on_Top_triggered();
|
||||
|
94
src/tools/bindiff/DiffLoadDialog.cpp
Normal file
94
src/tools/bindiff/DiffLoadDialog.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
#include "DiffLoadDialog.h"
|
||||
#include "ui_DiffLoadDialog.h"
|
||||
|
||||
#include <core/Cutter.h>
|
||||
#include <rz_th.h>
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
DiffLoadDialog::DiffLoadDialog(QWidget *parent) : QDialog(parent), ui(new Ui::DiffLoadDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
|
||||
ui->lineEditFileName->setReadOnly(true);
|
||||
ui->lineEditFileName->setText("");
|
||||
|
||||
ui->lineEditDiffFile->setReadOnly(true);
|
||||
ui->lineEditDiffFile->setText("");
|
||||
}
|
||||
|
||||
DiffLoadDialog::~DiffLoadDialog() {}
|
||||
|
||||
QString DiffLoadDialog::getFileToOpen() const
|
||||
{
|
||||
return ui->lineEditFileName->text();
|
||||
}
|
||||
|
||||
QString DiffLoadDialog::getPreviousDiffFile() const
|
||||
{
|
||||
return ui->lineEditDiffFile->text();
|
||||
}
|
||||
|
||||
void DiffLoadDialog::on_buttonDiffOpen_clicked()
|
||||
{
|
||||
QFileDialog dialog(this);
|
||||
dialog.setWindowTitle(tr("Select the previous diff to load"));
|
||||
dialog.setNameFilters({ tr("JSON array (*.json)") });
|
||||
|
||||
if (!dialog.exec()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QString &fileName = QDir::toNativeSeparators(dialog.selectedFiles().first());
|
||||
|
||||
if (fileName.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ui->lineEditDiffFile->setText(fileName);
|
||||
}
|
||||
|
||||
void DiffLoadDialog::on_buttonFileOpen_clicked()
|
||||
{
|
||||
QFileDialog dialog(this);
|
||||
dialog.setWindowTitle(tr("Select a file to use for diffing"));
|
||||
dialog.setNameFilters({ tr("All files (*)") });
|
||||
|
||||
if (!dialog.exec()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QString &fileName = QDir::toNativeSeparators(dialog.selectedFiles().first());
|
||||
|
||||
if (fileName.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ui->lineEditFileName->setText(fileName);
|
||||
}
|
||||
|
||||
void DiffLoadDialog::openErrorBox(QString errorMessage)
|
||||
{
|
||||
QMessageBox mb(this);
|
||||
mb.setIcon(QMessageBox::Warning);
|
||||
mb.setStandardButtons(QMessageBox::Ok);
|
||||
mb.setWindowTitle(tr("Error"));
|
||||
mb.setText(errorMessage);
|
||||
mb.exec();
|
||||
}
|
||||
|
||||
void DiffLoadDialog::on_buttonBox_accepted()
|
||||
{
|
||||
QString fileName = getFileToOpen();
|
||||
if (fileName.isEmpty()) {
|
||||
openErrorBox(tr("The compare file was not selected."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void DiffLoadDialog::on_buttonBox_rejected()
|
||||
{
|
||||
// cancel
|
||||
}
|
37
src/tools/bindiff/DiffLoadDialog.h
Normal file
37
src/tools/bindiff/DiffLoadDialog.h
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef DIFF_LOAD_DIALOG_H
|
||||
#define DIFF_LOAD_DIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QListWidgetItem>
|
||||
#include <memory>
|
||||
|
||||
#include <core/Cutter.h>
|
||||
|
||||
namespace Ui {
|
||||
class DiffLoadDialog;
|
||||
}
|
||||
|
||||
class DiffLoadDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DiffLoadDialog(QWidget *parent = nullptr);
|
||||
~DiffLoadDialog();
|
||||
|
||||
QString getFileToOpen() const;
|
||||
QString getPreviousDiffFile() const;
|
||||
|
||||
private slots:
|
||||
void on_buttonDiffOpen_clicked();
|
||||
void on_buttonFileOpen_clicked();
|
||||
void on_buttonBox_accepted();
|
||||
void on_buttonBox_rejected();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::DiffLoadDialog> ui;
|
||||
|
||||
void openErrorBox(QString errorMessage);
|
||||
};
|
||||
|
||||
#endif // DIFF_LOAD_DIALOG_H
|
142
src/tools/bindiff/DiffLoadDialog.ui
Normal file
142
src/tools/bindiff/DiffLoadDialog.ui
Normal file
@ -0,0 +1,142 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DiffLoadDialog</class>
|
||||
<widget class="QDialog" name="DiffLoadDialog">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::NonModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>636</width>
|
||||
<height>142</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Select which file to compare.</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinimumSize</enum>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinimumSize</enum>
|
||||
</property>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="lineEditDiffFile"/>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="lineEditFileName"/>
|
||||
</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><html><head/><body><p>File to compare to.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>File to compare (required)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="buttonDiffOpen">
|
||||
<property name="text">
|
||||
<string>Select</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="buttonFileOpen">
|
||||
<property name="text">
|
||||
<string>Select</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="previousDiffLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>You can load a previous saved diff instead of performing a new diff scan.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Previous diff file (optional)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinimumSize</enum>
|
||||
</property>
|
||||
<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>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>DiffLoadDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>234</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>DiffLoadDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>240</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
Loading…
Reference in New Issue
Block a user