From a5b0dd3ed204cbb24fa1b6b95e030fa89aa0fe53 Mon Sep 17 00:00:00 2001 From: billow Date: Thu, 11 Aug 2022 18:05:14 +0800 Subject: [PATCH] Convert commands(`agJ`, `anj`, `pi`) to rizin APIs (#3005) --- src/common/Configuration.cpp | 1 - src/common/TempConfig.h | 1 - src/core/Cutter.cpp | 66 +++++------- src/core/Cutter.h | 11 +- src/menus/DisassemblyContextMenu.cpp | 74 ++++++------- src/widgets/DisassemblerGraphView.cpp | 143 ++++++++++++++------------ 6 files changed, 140 insertions(+), 156 deletions(-) diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index 25d5907a..7fc76715 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -201,7 +201,6 @@ void Configuration::resetAll() { // Don't reset all rizin vars, that currently breaks a bunch of stuff. // settingsFile.remove()+loadInitials() should reset all settings configurable using Cutter GUI. - // Core()->cmdRaw("e-"); Core()->setSettings(); // Delete the file so no extra configuration is in it. diff --git a/src/common/TempConfig.h b/src/common/TempConfig.h index ba9b6f1e..a3c2239d 100644 --- a/src/common/TempConfig.h +++ b/src/common/TempConfig.h @@ -19,7 +19,6 @@ * { * TempConfig tempConfig; * tempConfig.set("asm.arch", "x86").set("asm.comments", false); - * return Core()->cmdRaw("pd"); * // config automatically restored at the end of scope * } * \endcode diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 78e82ec4..5e25c9dc 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -777,34 +777,32 @@ void CutterCore::delFlag(const QString &name) 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 vec { + returnAtSeek( + [&]() { 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(rz_pvector_pop_front(vec.get())) + : nullptr; + return { ab, rz_analysis_bytes_free }; +} + QString CutterCore::getInstructionBytes(RVA addr) { - auto ret = (char *)Core()->returnAtSeek( - [&]() { - CORE_LOCK(); - RzPVector *vec = rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1); - auto *ab = static_cast(rz_pvector_head(vec)); - char *str = strdup(ab->bytes); - rz_pvector_free(vec); - return str; - }, - addr); - return fromOwnedCharPtr(ret); + auto ab = getRzAnalysisBytesSingle(addr); + return ab ? ab->bytes : ""; } QString CutterCore::getInstructionOpcode(RVA addr) { - auto ret = (char *)Core()->returnAtSeek( - [&]() { - CORE_LOCK(); - RzPVector *vec = rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1); - auto *ab = static_cast(rz_pvector_head(vec)); - char *str = strdup(ab->opcode); - rz_pvector_free(vec); - return str; - }, - addr); - return fromOwnedCharPtr(ret); + auto ab = getRzAnalysisBytesSingle(addr); + return ab ? ab->opcode : ""; } 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.encoding = encoding; opt.escape_nl = escape_nl; - char *s = (char *)returnAtSeek([&]() { return rz_str_stringify_raw_buffer(&opt, NULL); }, addr); + char *s = returnAtSeek([&]() { return rz_str_stringify_raw_buffer(&opt, NULL); }, addr); return fromOwnedCharPtr(s); } @@ -1086,11 +1084,11 @@ RVA CutterCore::prevOpAddr(RVA startAddr, int count) RVA CutterCore::nextOpAddr(RVA startAddr, int count) { CORE_LOCK(); - auto vec = reinterpret_cast(returnAtSeek( + auto vec = returnAtSeek( [&]() { return rz_core_analysis_bytes(core, core->block, (int)core->blocksize, count + 1); }, - startAddr)); + startAddr); RVA addr = startAddr + 1; if (!vec) { return addr; @@ -1326,7 +1324,8 @@ QString CutterCore::disassemble(const QByteArray &data) 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) @@ -1430,19 +1429,8 @@ void CutterCore::createFunctionAt(RVA addr, QString name) RVA CutterCore::getOffsetJump(RVA addr) { - auto rva = (RVA *)Core()->returnAtSeek( - [&]() { - CORE_LOCK(); - RzPVector *vec = rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1); - auto *ab = static_cast(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; + auto ab = getRzAnalysisBytesSingle(addr); + return ab && ab->op ? ab->op->jump : RVA_INVALID; } QList CutterCore::getDecompilers() diff --git a/src/core/Cutter.h b/src/core/Cutter.h index dd042109..b92167e3 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -32,6 +32,7 @@ class RizinTaskDialog; #include "common/Helpers.h" #include +#include #define Core() (CutterCore::instance()) @@ -60,6 +61,8 @@ struct CUTTER_EXPORT RegisterRef QString name; }; +using PRzAnalysisBytes = std::unique_ptr; + class CUTTER_EXPORT CutterCore : public QObject { Q_OBJECT @@ -153,7 +156,7 @@ public: return cmdRawAt(str.toUtf8().constData(), address); } - void applyAtSeek(std::function fn, RVA address) + void applyAtSeek(const std::function &fn, RVA address) { RVA oldOffset = getOffset(); seekSilent(address); @@ -161,11 +164,12 @@ public: seekSilent(oldOffset); } - void *returnAtSeek(std::function fn, RVA address) + template + T returnAtSeek(const std::function &fn, RVA address) { RVA oldOffset = getOffset(); seekSilent(address); - void *ret = fn(); + T ret = fn(); seekSilent(oldOffset); return ret; } @@ -273,6 +277,7 @@ public: void triggerFlagsChanged(); /* Edition functions */ + PRzAnalysisBytes getRzAnalysisBytesSingle(RVA addr); QString getInstructionBytes(RVA addr); QString getInstructionOpcode(RVA addr); void editInstruction(RVA addr, const QString &inst, bool fillWithNops = false); diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index f08b8c5e..ddbfea65 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -313,34 +313,34 @@ void DisassemblyContextMenu::addDebugMenu() QVector DisassemblyContextMenu::getThingUsedHere(RVA offset) { - QVector result; - const CutterJson array = Core()->cmdj("anj @ " + QString::number(offset)); - result.reserve(array.size()); - for (const auto &thing : array) { - auto obj = thing; - RVA offset = obj["offset"].toRVA(); - 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 }); + RzCoreLocked core(Core()); + auto p = std::unique_ptr { + rz_core_analysis_name(core, offset), rz_core_analysis_name_free + }; + if (!p) { + return {}; } + + QVector 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; } @@ -482,13 +482,7 @@ void DisassemblyContextMenu::setupRenaming() void DisassemblyContextMenu::aboutToShowSlot() { // check if set immediate base menu makes sense - RzPVector *vec = (RzPVector *)Core()->returnAtSeek( - [&]() { - RzCoreLocked core(Core()); - return rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1); - }, - offset); - auto *ab = static_cast(rz_pvector_head(vec)); + auto ab = Core()->getRzAnalysisBytesSingle(offset); bool immBase = ab && ab->op && (ab->op->val || ab->op->ptr); setBaseMenu->menuAction()->setVisible(immBase); @@ -514,7 +508,6 @@ void DisassemblyContextMenu::aboutToShowSlot() } } } - rz_pvector_free(vec); if (memBaseReg.isEmpty()) { // hide structure offset menu @@ -727,22 +720,13 @@ void DisassemblyContextMenu::on_actionNopInstruction_triggered() void DisassemblyContextMenu::showReverseJmpQuery() { actionJmpReverse.setVisible(false); - RzCoreLocked core(Core()); - auto vec = reinterpret_cast(Core()->returnAtSeek( - [&]() { return rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1); }, - offset)); - if (!vec) { - return; - } - auto ab = reinterpret_cast(rz_pvector_head(vec)); + auto ab = Core()->getRzAnalysisBytesSingle(offset); if (!(ab && ab->op)) { - rz_pvector_free(vec); return; } if (ab->op->type == RZ_ANALYSIS_OP_TYPE_CJMP) { actionJmpReverse.setVisible(true); } - rz_pvector_free(vec); } void DisassemblyContextMenu::on_actionJmpReverse_triggered() diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index 09dacdd2..63bf6832 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -109,14 +109,14 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable *se if (c.isValid()) { bbh->highlight(currBlockEntry, c); } - Config()->colorsUpdated(); + emit Config()->colorsUpdated(); }); actionUnhighlight.setText(tr("Unhighlight block")); connect(&actionUnhighlight, &QAction::triggered, this, [this]() { auto bbh = Core()->getBBHighlighter(); bbh->clear(blockForAddress(this->seekable->getOffset())->entry); - Config()->colorsUpdated(); + emit Config()->colorsUpdated(); }); QAction *highlightBI = new QAction(this); @@ -162,9 +162,8 @@ void DisassemblerGraphView::connectSeekChanged(bool disconn) DisassemblerGraphView::~DisassemblerGraphView() { - for (QShortcut *shortcut : shortcuts) { - delete shortcut; - } + qDeleteAll(shortcuts); + shortcuts.clear(); } void DisassemblerGraphView::refreshView() @@ -182,13 +181,6 @@ void DisassemblerGraphView::loadCurrentGraph() .set("asm.lines", 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(); blocks.clear(); @@ -197,7 +189,20 @@ void DisassemblerGraphView::loadCurrentGraph() 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 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 there's no function to print, just add a message if (!emptyText) { @@ -213,31 +218,20 @@ void DisassemblerGraphView::loadCurrentGraph() } // Refresh global "empty graph" variable so other widget know there is nothing to show here Core()->setGraphEmpty(emptyGraph); + setEntry(fcn ? fcn->addr : RVA_INVALID); - CutterJson func = functions.first(); - - windowTitle = tr("Graph"); - QString funcName = func["name"].toString().trimmed(); - if (emptyGraph) { - windowTitle += " (Empty)"; - } else if (!funcName.isEmpty()) { - windowTitle += " (" + funcName + ")"; + if (!fcn) { + return; } - emit nameChanged(windowTitle); - RVA entry = func["offset"].toRVA(); - - setEntry(entry); - 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(); + for (const auto &bbi : CutterRzList(fcn->bbs)) { + RVA bbiFail = bbi->fail; + RVA bbiJump = bbi->jump; DisassemblyBlock db; GraphBlock gb; - gb.entry = block_entry; - db.entry = block_entry; + gb.entry = bbi->addr; + db.entry = bbi->addr; if (Config()->getGraphBlockEntryOffset()) { // QColor(0,0,0,0) is transparent db.header_text = Text("[" + RzAddressString(db.entry) + "]", ConfigColor("offset"), @@ -245,50 +239,69 @@ void DisassemblerGraphView::loadCurrentGraph() } db.true_path = RVA_INVALID; db.false_path = RVA_INVALID; - if (block_fail) { - db.false_path = block_fail; - gb.edges.emplace_back(block_fail); + if (bbiFail) { + db.false_path = bbiFail; + gb.edges.emplace_back(bbiFail); } - if (block_jump) { - if (block_fail) { - db.true_path = block_jump; + if (bbiJump) { + if (bbiFail) { + db.true_path = bbiJump; } - gb.edges.emplace_back(block_jump); + gb.edges.emplace_back(bbiJump); } - CutterJson switchOp = block["switchop"]; - if (switchOp.size()) { - for (CutterJson caseOp : switchOp["cases"]) { - RVA caseJump = caseOp["jump"].toRVA(); - if (caseJump == RVA_INVALID) { + RzAnalysisSwitchOp *switchOp = bbi->switch_op; + if (switchOp) { + for (const auto &caseOp : CutterRzList(switchOp->cases)) { + if (caseOp->jump == RVA_INVALID) { continue; } - gb.edges.emplace_back(caseJump); + gb.edges.emplace_back(caseOp->jump); } } - CutterJson opArray = block["ops"]; - CutterJson::iterator iterator = opArray.begin(); - while (iterator != opArray.end()) { - CutterJson op = *iterator; - Instr i; - i.addr = op["offset"].toUt64(); + RzCoreLocked core(Core()); + std::unique_ptr buf { new ut8[bbi->size] }; + if (!buf) { + break; + } + rz_io_read_at(core->io, bbi->addr, buf.get(), (int)bbi->size); - ++iterator; + std::unique_ptr vec { + rz_pvector_new(reinterpret_cast(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(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 ... - RVA nextOffset = (*iterator)["offset"].toRVA(); - i.size = nextOffset - i.addr; + RVA nextOffset = (*iter)->offset; + instr.size = nextOffset - instr.addr; } else { // 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; - 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); // Colors::colorizeAssembly(richText, textDoc.toPlainText(), 0); @@ -296,23 +309,19 @@ void DisassemblerGraphView::loadCurrentGraph() bool cropped; int blockLength = Config()->getGraphBlockMaxChars() + 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) - i.fullText = richText; + instr.fullText = richText; else - i.fullText = Text(); - db.instrs.push_back(i); + instr.fullText = Text(); + db.instrs.push_back(instr); } disassembly_blocks[db.entry] = db; prepareGraphNode(gb); - addBlock(gb); } cleanupEdges(blocks); - - if (func["blocks"].size()) { - computeGraphPlacement(); - } + computeGraphPlacement(); } DisassemblerGraphView::EdgeConfigurationMapping DisassemblerGraphView::getEdgeConfigurations()