mirror of
https://github.com/rizinorg/cutter.git
synced 2025-01-18 18:38:51 +00:00
Convert commands(agJ
, anj
, pi
) to rizin APIs (#3005)
This commit is contained in:
parent
c263d4bd1b
commit
a5b0dd3ed2
@ -201,7 +201,6 @@ void Configuration::resetAll()
|
|||||||
{
|
{
|
||||||
// Don't reset all rizin vars, that currently breaks a bunch of stuff.
|
// Don't reset all rizin vars, that currently breaks a bunch of stuff.
|
||||||
// settingsFile.remove()+loadInitials() should reset all settings configurable using Cutter GUI.
|
// settingsFile.remove()+loadInitials() should reset all settings configurable using Cutter GUI.
|
||||||
// Core()->cmdRaw("e-");
|
|
||||||
|
|
||||||
Core()->setSettings();
|
Core()->setSettings();
|
||||||
// Delete the file so no extra configuration is in it.
|
// Delete the file so no extra configuration is in it.
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
* {
|
* {
|
||||||
* TempConfig tempConfig;
|
* TempConfig tempConfig;
|
||||||
* tempConfig.set("asm.arch", "x86").set("asm.comments", false);
|
* tempConfig.set("asm.arch", "x86").set("asm.comments", false);
|
||||||
* return Core()->cmdRaw("pd");
|
|
||||||
* // config automatically restored at the end of scope
|
* // config automatically restored at the end of scope
|
||||||
* }
|
* }
|
||||||
* \endcode
|
* \endcode
|
||||||
|
@ -777,34 +777,32 @@ void CutterCore::delFlag(const QString &name)
|
|||||||
emit flagsChanged();
|
emit flagsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRzAnalysisBytes CutterCore::getRzAnalysisBytesSingle(RVA addr)
|
||||||
|
{
|
||||||
|
CORE_LOCK();
|
||||||
|
ut8 buf[128];
|
||||||
|
rz_io_read_at(core->io, addr, buf, sizeof(buf));
|
||||||
|
std::unique_ptr<RzPVector, decltype(rz_pvector_free) *> vec {
|
||||||
|
returnAtSeek<RzPVector *>(
|
||||||
|
[&]() { return rz_core_analysis_bytes(core, buf, sizeof(buf), 1); }, addr),
|
||||||
|
rz_pvector_free
|
||||||
|
};
|
||||||
|
auto ab = vec && rz_pvector_len(vec.get()) > 0
|
||||||
|
? reinterpret_cast<RzAnalysisBytes *>(rz_pvector_pop_front(vec.get()))
|
||||||
|
: nullptr;
|
||||||
|
return { ab, rz_analysis_bytes_free };
|
||||||
|
}
|
||||||
|
|
||||||
QString CutterCore::getInstructionBytes(RVA addr)
|
QString CutterCore::getInstructionBytes(RVA addr)
|
||||||
{
|
{
|
||||||
auto ret = (char *)Core()->returnAtSeek(
|
auto ab = getRzAnalysisBytesSingle(addr);
|
||||||
[&]() {
|
return ab ? ab->bytes : "";
|
||||||
CORE_LOCK();
|
|
||||||
RzPVector *vec = rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1);
|
|
||||||
auto *ab = static_cast<RzAnalysisBytes *>(rz_pvector_head(vec));
|
|
||||||
char *str = strdup(ab->bytes);
|
|
||||||
rz_pvector_free(vec);
|
|
||||||
return str;
|
|
||||||
},
|
|
||||||
addr);
|
|
||||||
return fromOwnedCharPtr(ret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CutterCore::getInstructionOpcode(RVA addr)
|
QString CutterCore::getInstructionOpcode(RVA addr)
|
||||||
{
|
{
|
||||||
auto ret = (char *)Core()->returnAtSeek(
|
auto ab = getRzAnalysisBytesSingle(addr);
|
||||||
[&]() {
|
return ab ? ab->opcode : "";
|
||||||
CORE_LOCK();
|
|
||||||
RzPVector *vec = rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1);
|
|
||||||
auto *ab = static_cast<RzAnalysisBytes *>(rz_pvector_head(vec));
|
|
||||||
char *str = strdup(ab->opcode);
|
|
||||||
rz_pvector_free(vec);
|
|
||||||
return str;
|
|
||||||
},
|
|
||||||
addr);
|
|
||||||
return fromOwnedCharPtr(ret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::editInstruction(RVA addr, const QString &inst, bool fillWithNops)
|
void CutterCore::editInstruction(RVA addr, const QString &inst, bool fillWithNops)
|
||||||
@ -910,7 +908,7 @@ QString CutterCore::getString(RVA addr, uint64_t len, RzStrEnc encoding, bool es
|
|||||||
opt.length = len;
|
opt.length = len;
|
||||||
opt.encoding = encoding;
|
opt.encoding = encoding;
|
||||||
opt.escape_nl = escape_nl;
|
opt.escape_nl = escape_nl;
|
||||||
char *s = (char *)returnAtSeek([&]() { return rz_str_stringify_raw_buffer(&opt, NULL); }, addr);
|
char *s = returnAtSeek<char *>([&]() { return rz_str_stringify_raw_buffer(&opt, NULL); }, addr);
|
||||||
return fromOwnedCharPtr(s);
|
return fromOwnedCharPtr(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1086,11 +1084,11 @@ RVA CutterCore::prevOpAddr(RVA startAddr, int count)
|
|||||||
RVA CutterCore::nextOpAddr(RVA startAddr, int count)
|
RVA CutterCore::nextOpAddr(RVA startAddr, int count)
|
||||||
{
|
{
|
||||||
CORE_LOCK();
|
CORE_LOCK();
|
||||||
auto vec = reinterpret_cast<RzPVector *>(returnAtSeek(
|
auto vec = returnAtSeek<RzPVector *>(
|
||||||
[&]() {
|
[&]() {
|
||||||
return rz_core_analysis_bytes(core, core->block, (int)core->blocksize, count + 1);
|
return rz_core_analysis_bytes(core, core->block, (int)core->blocksize, count + 1);
|
||||||
},
|
},
|
||||||
startAddr));
|
startAddr);
|
||||||
RVA addr = startAddr + 1;
|
RVA addr = startAddr + 1;
|
||||||
if (!vec) {
|
if (!vec) {
|
||||||
return addr;
|
return addr;
|
||||||
@ -1326,7 +1324,8 @@ QString CutterCore::disassemble(const QByteArray &data)
|
|||||||
|
|
||||||
QString CutterCore::disassembleSingleInstruction(RVA addr)
|
QString CutterCore::disassembleSingleInstruction(RVA addr)
|
||||||
{
|
{
|
||||||
return cmdRawAt("pi 1", addr).simplified();
|
auto ab = getRzAnalysisBytesSingle(addr);
|
||||||
|
return QString(ab->disasm).simplified();
|
||||||
}
|
}
|
||||||
|
|
||||||
RzAnalysisFunction *CutterCore::functionIn(ut64 addr)
|
RzAnalysisFunction *CutterCore::functionIn(ut64 addr)
|
||||||
@ -1430,19 +1429,8 @@ void CutterCore::createFunctionAt(RVA addr, QString name)
|
|||||||
|
|
||||||
RVA CutterCore::getOffsetJump(RVA addr)
|
RVA CutterCore::getOffsetJump(RVA addr)
|
||||||
{
|
{
|
||||||
auto rva = (RVA *)Core()->returnAtSeek(
|
auto ab = getRzAnalysisBytesSingle(addr);
|
||||||
[&]() {
|
return ab && ab->op ? ab->op->jump : RVA_INVALID;
|
||||||
CORE_LOCK();
|
|
||||||
RzPVector *vec = rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1);
|
|
||||||
auto *ab = static_cast<RzAnalysisBytes *>(rz_pvector_head(vec));
|
|
||||||
RVA *rva = new RVA(ab->op->jump);
|
|
||||||
rz_pvector_free(vec);
|
|
||||||
return rva;
|
|
||||||
},
|
|
||||||
addr);
|
|
||||||
RVA ret = *rva;
|
|
||||||
delete rva;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Decompiler *> CutterCore::getDecompilers()
|
QList<Decompiler *> CutterCore::getDecompilers()
|
||||||
|
@ -32,6 +32,7 @@ class RizinTaskDialog;
|
|||||||
#include "common/Helpers.h"
|
#include "common/Helpers.h"
|
||||||
|
|
||||||
#include <rz_project.h>
|
#include <rz_project.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#define Core() (CutterCore::instance())
|
#define Core() (CutterCore::instance())
|
||||||
|
|
||||||
@ -60,6 +61,8 @@ struct CUTTER_EXPORT RegisterRef
|
|||||||
QString name;
|
QString name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using PRzAnalysisBytes = std::unique_ptr<RzAnalysisBytes, decltype(rz_analysis_bytes_free) *>;
|
||||||
|
|
||||||
class CUTTER_EXPORT CutterCore : public QObject
|
class CUTTER_EXPORT CutterCore : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -153,7 +156,7 @@ public:
|
|||||||
return cmdRawAt(str.toUtf8().constData(), address);
|
return cmdRawAt(str.toUtf8().constData(), address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void applyAtSeek(std::function<void()> fn, RVA address)
|
void applyAtSeek(const std::function<void()> &fn, RVA address)
|
||||||
{
|
{
|
||||||
RVA oldOffset = getOffset();
|
RVA oldOffset = getOffset();
|
||||||
seekSilent(address);
|
seekSilent(address);
|
||||||
@ -161,11 +164,12 @@ public:
|
|||||||
seekSilent(oldOffset);
|
seekSilent(oldOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *returnAtSeek(std::function<void *()> fn, RVA address)
|
template<typename T>
|
||||||
|
T returnAtSeek(const std::function<T()> &fn, RVA address)
|
||||||
{
|
{
|
||||||
RVA oldOffset = getOffset();
|
RVA oldOffset = getOffset();
|
||||||
seekSilent(address);
|
seekSilent(address);
|
||||||
void *ret = fn();
|
T ret = fn();
|
||||||
seekSilent(oldOffset);
|
seekSilent(oldOffset);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -273,6 +277,7 @@ public:
|
|||||||
void triggerFlagsChanged();
|
void triggerFlagsChanged();
|
||||||
|
|
||||||
/* Edition functions */
|
/* Edition functions */
|
||||||
|
PRzAnalysisBytes getRzAnalysisBytesSingle(RVA addr);
|
||||||
QString getInstructionBytes(RVA addr);
|
QString getInstructionBytes(RVA addr);
|
||||||
QString getInstructionOpcode(RVA addr);
|
QString getInstructionOpcode(RVA addr);
|
||||||
void editInstruction(RVA addr, const QString &inst, bool fillWithNops = false);
|
void editInstruction(RVA addr, const QString &inst, bool fillWithNops = false);
|
||||||
|
@ -313,34 +313,34 @@ void DisassemblyContextMenu::addDebugMenu()
|
|||||||
|
|
||||||
QVector<DisassemblyContextMenu::ThingUsedHere> DisassemblyContextMenu::getThingUsedHere(RVA offset)
|
QVector<DisassemblyContextMenu::ThingUsedHere> DisassemblyContextMenu::getThingUsedHere(RVA offset)
|
||||||
{
|
{
|
||||||
QVector<ThingUsedHere> result;
|
RzCoreLocked core(Core());
|
||||||
const CutterJson array = Core()->cmdj("anj @ " + QString::number(offset));
|
auto p = std::unique_ptr<RzCoreAnalysisName, decltype(rz_core_analysis_name_free) *> {
|
||||||
result.reserve(array.size());
|
rz_core_analysis_name(core, offset), rz_core_analysis_name_free
|
||||||
for (const auto &thing : array) {
|
};
|
||||||
auto obj = thing;
|
if (!p) {
|
||||||
RVA offset = obj["offset"].toRVA();
|
return {};
|
||||||
QString name;
|
|
||||||
|
|
||||||
// If real names display is enabled, show flag's real name instead of full flag name
|
|
||||||
if (Config()->getConfigBool("asm.flags.real") && obj["realname"].valid()) {
|
|
||||||
name = obj["realname"].toString();
|
|
||||||
} else {
|
|
||||||
name = obj["name"].toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString typeString = obj["type"].toString();
|
|
||||||
ThingUsedHere::Type type = ThingUsedHere::Type::Address;
|
|
||||||
if (typeString == "var") {
|
|
||||||
type = ThingUsedHere::Type::Var;
|
|
||||||
} else if (typeString == "flag") {
|
|
||||||
type = ThingUsedHere::Type::Flag;
|
|
||||||
} else if (typeString == "function") {
|
|
||||||
type = ThingUsedHere::Type::Function;
|
|
||||||
} else if (typeString == "address") {
|
|
||||||
type = ThingUsedHere::Type::Address;
|
|
||||||
}
|
|
||||||
result.push_back(ThingUsedHere { name, offset, type });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVector<ThingUsedHere> result;
|
||||||
|
ThingUsedHere th;
|
||||||
|
th.offset = p->offset;
|
||||||
|
th.name = Config()->getConfigBool("asm.flags.real") && p->realname ? p->realname : p->name;
|
||||||
|
switch (p->type) {
|
||||||
|
case RZ_CORE_ANALYSIS_NAME_TYPE_FLAG:
|
||||||
|
th.type = ThingUsedHere::Type::Flag;
|
||||||
|
break;
|
||||||
|
case RZ_CORE_ANALYSIS_NAME_TYPE_FUNCTION:
|
||||||
|
th.type = ThingUsedHere::Type::Function;
|
||||||
|
break;
|
||||||
|
case RZ_CORE_ANALYSIS_NAME_TYPE_VAR:
|
||||||
|
th.type = ThingUsedHere::Type::Var;
|
||||||
|
break;
|
||||||
|
case RZ_CORE_ANALYSIS_NAME_TYPE_ADDRESS:
|
||||||
|
default:
|
||||||
|
th.type = ThingUsedHere::Type::Address;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
result.push_back(th);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -482,13 +482,7 @@ void DisassemblyContextMenu::setupRenaming()
|
|||||||
void DisassemblyContextMenu::aboutToShowSlot()
|
void DisassemblyContextMenu::aboutToShowSlot()
|
||||||
{
|
{
|
||||||
// check if set immediate base menu makes sense
|
// check if set immediate base menu makes sense
|
||||||
RzPVector *vec = (RzPVector *)Core()->returnAtSeek(
|
auto ab = Core()->getRzAnalysisBytesSingle(offset);
|
||||||
[&]() {
|
|
||||||
RzCoreLocked core(Core());
|
|
||||||
return rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1);
|
|
||||||
},
|
|
||||||
offset);
|
|
||||||
auto *ab = static_cast<RzAnalysisBytes *>(rz_pvector_head(vec));
|
|
||||||
|
|
||||||
bool immBase = ab && ab->op && (ab->op->val || ab->op->ptr);
|
bool immBase = ab && ab->op && (ab->op->val || ab->op->ptr);
|
||||||
setBaseMenu->menuAction()->setVisible(immBase);
|
setBaseMenu->menuAction()->setVisible(immBase);
|
||||||
@ -514,7 +508,6 @@ void DisassemblyContextMenu::aboutToShowSlot()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rz_pvector_free(vec);
|
|
||||||
|
|
||||||
if (memBaseReg.isEmpty()) {
|
if (memBaseReg.isEmpty()) {
|
||||||
// hide structure offset menu
|
// hide structure offset menu
|
||||||
@ -727,22 +720,13 @@ void DisassemblyContextMenu::on_actionNopInstruction_triggered()
|
|||||||
void DisassemblyContextMenu::showReverseJmpQuery()
|
void DisassemblyContextMenu::showReverseJmpQuery()
|
||||||
{
|
{
|
||||||
actionJmpReverse.setVisible(false);
|
actionJmpReverse.setVisible(false);
|
||||||
RzCoreLocked core(Core());
|
auto ab = Core()->getRzAnalysisBytesSingle(offset);
|
||||||
auto vec = reinterpret_cast<RzPVector *>(Core()->returnAtSeek(
|
|
||||||
[&]() { return rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1); },
|
|
||||||
offset));
|
|
||||||
if (!vec) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto ab = reinterpret_cast<RzAnalysisBytes *>(rz_pvector_head(vec));
|
|
||||||
if (!(ab && ab->op)) {
|
if (!(ab && ab->op)) {
|
||||||
rz_pvector_free(vec);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ab->op->type == RZ_ANALYSIS_OP_TYPE_CJMP) {
|
if (ab->op->type == RZ_ANALYSIS_OP_TYPE_CJMP) {
|
||||||
actionJmpReverse.setVisible(true);
|
actionJmpReverse.setVisible(true);
|
||||||
}
|
}
|
||||||
rz_pvector_free(vec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisassemblyContextMenu::on_actionJmpReverse_triggered()
|
void DisassemblyContextMenu::on_actionJmpReverse_triggered()
|
||||||
|
@ -109,14 +109,14 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable *se
|
|||||||
if (c.isValid()) {
|
if (c.isValid()) {
|
||||||
bbh->highlight(currBlockEntry, c);
|
bbh->highlight(currBlockEntry, c);
|
||||||
}
|
}
|
||||||
Config()->colorsUpdated();
|
emit Config()->colorsUpdated();
|
||||||
});
|
});
|
||||||
|
|
||||||
actionUnhighlight.setText(tr("Unhighlight block"));
|
actionUnhighlight.setText(tr("Unhighlight block"));
|
||||||
connect(&actionUnhighlight, &QAction::triggered, this, [this]() {
|
connect(&actionUnhighlight, &QAction::triggered, this, [this]() {
|
||||||
auto bbh = Core()->getBBHighlighter();
|
auto bbh = Core()->getBBHighlighter();
|
||||||
bbh->clear(blockForAddress(this->seekable->getOffset())->entry);
|
bbh->clear(blockForAddress(this->seekable->getOffset())->entry);
|
||||||
Config()->colorsUpdated();
|
emit Config()->colorsUpdated();
|
||||||
});
|
});
|
||||||
|
|
||||||
QAction *highlightBI = new QAction(this);
|
QAction *highlightBI = new QAction(this);
|
||||||
@ -162,9 +162,8 @@ void DisassemblerGraphView::connectSeekChanged(bool disconn)
|
|||||||
|
|
||||||
DisassemblerGraphView::~DisassemblerGraphView()
|
DisassemblerGraphView::~DisassemblerGraphView()
|
||||||
{
|
{
|
||||||
for (QShortcut *shortcut : shortcuts) {
|
qDeleteAll(shortcuts);
|
||||||
delete shortcut;
|
shortcuts.clear();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisassemblerGraphView::refreshView()
|
void DisassemblerGraphView::refreshView()
|
||||||
@ -182,13 +181,6 @@ void DisassemblerGraphView::loadCurrentGraph()
|
|||||||
.set("asm.lines", false)
|
.set("asm.lines", false)
|
||||||
.set("asm.lines.fcn", false);
|
.set("asm.lines.fcn", false);
|
||||||
|
|
||||||
CutterJson functions;
|
|
||||||
RzAnalysisFunction *fcn = Core()->functionIn(seekable->getOffset());
|
|
||||||
if (fcn) {
|
|
||||||
currentFcnAddr = fcn->addr;
|
|
||||||
functions = Core()->cmdj("agJ " + RzAddressString(fcn->addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
disassembly_blocks.clear();
|
disassembly_blocks.clear();
|
||||||
blocks.clear();
|
blocks.clear();
|
||||||
|
|
||||||
@ -197,7 +189,20 @@ void DisassemblerGraphView::loadCurrentGraph()
|
|||||||
highlight_token = nullptr;
|
highlight_token = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
emptyGraph = !functions.size();
|
RzAnalysisFunction *fcn = Core()->functionIn(seekable->getOffset());
|
||||||
|
|
||||||
|
windowTitle = tr("Graph");
|
||||||
|
if (fcn && RZ_STR_ISNOTEMPTY(fcn->name)) {
|
||||||
|
std::unique_ptr<char, decltype(std::free) *> fcnName {
|
||||||
|
rz_str_escape_utf8_for_json(fcn->name, -1), std::free
|
||||||
|
};
|
||||||
|
windowTitle += QString("(%0)").arg(fcnName.get());
|
||||||
|
} else {
|
||||||
|
windowTitle += "(Empty)";
|
||||||
|
}
|
||||||
|
emit nameChanged(windowTitle);
|
||||||
|
|
||||||
|
emptyGraph = !fcn;
|
||||||
if (emptyGraph) {
|
if (emptyGraph) {
|
||||||
// If there's no function to print, just add a message
|
// If there's no function to print, just add a message
|
||||||
if (!emptyText) {
|
if (!emptyText) {
|
||||||
@ -213,31 +218,20 @@ void DisassemblerGraphView::loadCurrentGraph()
|
|||||||
}
|
}
|
||||||
// Refresh global "empty graph" variable so other widget know there is nothing to show here
|
// Refresh global "empty graph" variable so other widget know there is nothing to show here
|
||||||
Core()->setGraphEmpty(emptyGraph);
|
Core()->setGraphEmpty(emptyGraph);
|
||||||
|
setEntry(fcn ? fcn->addr : RVA_INVALID);
|
||||||
|
|
||||||
CutterJson func = functions.first();
|
if (!fcn) {
|
||||||
|
return;
|
||||||
windowTitle = tr("Graph");
|
|
||||||
QString funcName = func["name"].toString().trimmed();
|
|
||||||
if (emptyGraph) {
|
|
||||||
windowTitle += " (Empty)";
|
|
||||||
} else if (!funcName.isEmpty()) {
|
|
||||||
windowTitle += " (" + funcName + ")";
|
|
||||||
}
|
}
|
||||||
emit nameChanged(windowTitle);
|
|
||||||
|
|
||||||
RVA entry = func["offset"].toRVA();
|
for (const auto &bbi : CutterRzList<RzAnalysisBlock>(fcn->bbs)) {
|
||||||
|
RVA bbiFail = bbi->fail;
|
||||||
setEntry(entry);
|
RVA bbiJump = bbi->jump;
|
||||||
for (CutterJson block : func["blocks"]) {
|
|
||||||
RVA block_entry = block["offset"].toRVA();
|
|
||||||
RVA block_size = block["size"].toRVA();
|
|
||||||
RVA block_fail = block["fail"].toRVA();
|
|
||||||
RVA block_jump = block["jump"].toRVA();
|
|
||||||
|
|
||||||
DisassemblyBlock db;
|
DisassemblyBlock db;
|
||||||
GraphBlock gb;
|
GraphBlock gb;
|
||||||
gb.entry = block_entry;
|
gb.entry = bbi->addr;
|
||||||
db.entry = block_entry;
|
db.entry = bbi->addr;
|
||||||
if (Config()->getGraphBlockEntryOffset()) {
|
if (Config()->getGraphBlockEntryOffset()) {
|
||||||
// QColor(0,0,0,0) is transparent
|
// QColor(0,0,0,0) is transparent
|
||||||
db.header_text = Text("[" + RzAddressString(db.entry) + "]", ConfigColor("offset"),
|
db.header_text = Text("[" + RzAddressString(db.entry) + "]", ConfigColor("offset"),
|
||||||
@ -245,50 +239,69 @@ void DisassemblerGraphView::loadCurrentGraph()
|
|||||||
}
|
}
|
||||||
db.true_path = RVA_INVALID;
|
db.true_path = RVA_INVALID;
|
||||||
db.false_path = RVA_INVALID;
|
db.false_path = RVA_INVALID;
|
||||||
if (block_fail) {
|
if (bbiFail) {
|
||||||
db.false_path = block_fail;
|
db.false_path = bbiFail;
|
||||||
gb.edges.emplace_back(block_fail);
|
gb.edges.emplace_back(bbiFail);
|
||||||
}
|
}
|
||||||
if (block_jump) {
|
if (bbiJump) {
|
||||||
if (block_fail) {
|
if (bbiFail) {
|
||||||
db.true_path = block_jump;
|
db.true_path = bbiJump;
|
||||||
}
|
}
|
||||||
gb.edges.emplace_back(block_jump);
|
gb.edges.emplace_back(bbiJump);
|
||||||
}
|
}
|
||||||
|
|
||||||
CutterJson switchOp = block["switchop"];
|
RzAnalysisSwitchOp *switchOp = bbi->switch_op;
|
||||||
if (switchOp.size()) {
|
if (switchOp) {
|
||||||
for (CutterJson caseOp : switchOp["cases"]) {
|
for (const auto &caseOp : CutterRzList<RzAnalysisCaseOp>(switchOp->cases)) {
|
||||||
RVA caseJump = caseOp["jump"].toRVA();
|
if (caseOp->jump == RVA_INVALID) {
|
||||||
if (caseJump == RVA_INVALID) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
gb.edges.emplace_back(caseJump);
|
gb.edges.emplace_back(caseOp->jump);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CutterJson opArray = block["ops"];
|
RzCoreLocked core(Core());
|
||||||
CutterJson::iterator iterator = opArray.begin();
|
std::unique_ptr<ut8[]> buf { new ut8[bbi->size] };
|
||||||
while (iterator != opArray.end()) {
|
if (!buf) {
|
||||||
CutterJson op = *iterator;
|
break;
|
||||||
Instr i;
|
}
|
||||||
i.addr = op["offset"].toUt64();
|
rz_io_read_at(core->io, bbi->addr, buf.get(), (int)bbi->size);
|
||||||
|
|
||||||
++iterator;
|
std::unique_ptr<RzPVector, decltype(rz_pvector_free) *> vec {
|
||||||
|
rz_pvector_new(reinterpret_cast<RzPVectorFree>(rz_analysis_disasm_text_free)),
|
||||||
|
rz_pvector_free
|
||||||
|
};
|
||||||
|
if (!vec) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (iterator != opArray.end()) {
|
RzCoreDisasmOptions options = {};
|
||||||
|
options.vec = vec.get();
|
||||||
|
options.cbytes = 1;
|
||||||
|
rz_core_print_disasm(core, bbi->addr, buf.get(), (int)bbi->size, (int)bbi->size, NULL,
|
||||||
|
&options);
|
||||||
|
|
||||||
|
auto vecVisitor = CutterPVector<RzAnalysisDisasmText>(vec.get());
|
||||||
|
auto iter = vecVisitor.begin();
|
||||||
|
while (iter != vecVisitor.end()) {
|
||||||
|
RzAnalysisDisasmText *op = *iter;
|
||||||
|
Instr instr;
|
||||||
|
instr.addr = op->offset;
|
||||||
|
|
||||||
|
++iter;
|
||||||
|
if (iter != vecVisitor.end()) {
|
||||||
// get instruction size from distance to next instruction ...
|
// get instruction size from distance to next instruction ...
|
||||||
RVA nextOffset = (*iterator)["offset"].toRVA();
|
RVA nextOffset = (*iter)->offset;
|
||||||
i.size = nextOffset - i.addr;
|
instr.size = nextOffset - instr.addr;
|
||||||
} else {
|
} else {
|
||||||
// or to the end of the block.
|
// or to the end of the block.
|
||||||
i.size = (block_entry + block_size) - i.addr;
|
instr.size = (bbi->addr + bbi->size) - instr.addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
QTextDocument textDoc;
|
QTextDocument textDoc;
|
||||||
textDoc.setHtml(CutterCore::ansiEscapeToHtml(op["text"].toString()));
|
textDoc.setHtml(CutterCore::ansiEscapeToHtml(op->text));
|
||||||
|
|
||||||
i.plainText = textDoc.toPlainText();
|
instr.plainText = textDoc.toPlainText();
|
||||||
|
|
||||||
RichTextPainter::List richText = RichTextPainter::fromTextDocument(textDoc);
|
RichTextPainter::List richText = RichTextPainter::fromTextDocument(textDoc);
|
||||||
// Colors::colorizeAssembly(richText, textDoc.toPlainText(), 0);
|
// Colors::colorizeAssembly(richText, textDoc.toPlainText(), 0);
|
||||||
@ -296,23 +309,19 @@ void DisassemblerGraphView::loadCurrentGraph()
|
|||||||
bool cropped;
|
bool cropped;
|
||||||
int blockLength = Config()->getGraphBlockMaxChars()
|
int blockLength = Config()->getGraphBlockMaxChars()
|
||||||
+ Core()->getConfigb("asm.bytes") * 24 + Core()->getConfigb("asm.emu") * 10;
|
+ Core()->getConfigb("asm.bytes") * 24 + Core()->getConfigb("asm.emu") * 10;
|
||||||
i.text = Text(RichTextPainter::cropped(richText, blockLength, "...", &cropped));
|
instr.text = Text(RichTextPainter::cropped(richText, blockLength, "...", &cropped));
|
||||||
if (cropped)
|
if (cropped)
|
||||||
i.fullText = richText;
|
instr.fullText = richText;
|
||||||
else
|
else
|
||||||
i.fullText = Text();
|
instr.fullText = Text();
|
||||||
db.instrs.push_back(i);
|
db.instrs.push_back(instr);
|
||||||
}
|
}
|
||||||
disassembly_blocks[db.entry] = db;
|
disassembly_blocks[db.entry] = db;
|
||||||
prepareGraphNode(gb);
|
prepareGraphNode(gb);
|
||||||
|
|
||||||
addBlock(gb);
|
addBlock(gb);
|
||||||
}
|
}
|
||||||
cleanupEdges(blocks);
|
cleanupEdges(blocks);
|
||||||
|
computeGraphPlacement();
|
||||||
if (func["blocks"].size()) {
|
|
||||||
computeGraphPlacement();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DisassemblerGraphView::EdgeConfigurationMapping DisassemblerGraphView::getEdgeConfigurations()
|
DisassemblerGraphView::EdgeConfigurationMapping DisassemblerGraphView::getEdgeConfigurations()
|
||||||
|
Loading…
Reference in New Issue
Block a user