Convert commands(agJ, anj, pi) to rizin APIs (#3005)

This commit is contained in:
billow 2022-08-11 18:05:14 +08:00 committed by GitHub
parent c263d4bd1b
commit a5b0dd3ed2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 140 additions and 156 deletions

View File

@ -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.

View File

@ -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

View File

@ -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()

View File

@ -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);

View File

@ -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()

View File

@ -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()