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

View File

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

View File

@ -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<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)
{
auto ret = (char *)Core()->returnAtSeek(
[&]() {
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);
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<RzAnalysisBytes *>(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<char *>([&]() { 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<RzPVector *>(returnAtSeek(
auto vec = returnAtSeek<RzPVector *>(
[&]() {
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<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;
auto ab = getRzAnalysisBytesSingle(addr);
return ab && ab->op ? ab->op->jump : RVA_INVALID;
}
QList<Decompiler *> CutterCore::getDecompilers()

View File

@ -32,6 +32,7 @@ class RizinTaskDialog;
#include "common/Helpers.h"
#include <rz_project.h>
#include <memory>
#define Core() (CutterCore::instance())
@ -60,6 +61,8 @@ struct CUTTER_EXPORT RegisterRef
QString name;
};
using PRzAnalysisBytes = std::unique_ptr<RzAnalysisBytes, decltype(rz_analysis_bytes_free) *>;
class CUTTER_EXPORT CutterCore : public QObject
{
Q_OBJECT
@ -153,7 +156,7 @@ public:
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();
seekSilent(address);
@ -161,11 +164,12 @@ public:
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();
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);

View File

@ -313,34 +313,34 @@ void DisassemblyContextMenu::addDebugMenu()
QVector<DisassemblyContextMenu::ThingUsedHere> DisassemblyContextMenu::getThingUsedHere(RVA offset)
{
QVector<ThingUsedHere> 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<RzCoreAnalysisName, decltype(rz_core_analysis_name_free) *> {
rz_core_analysis_name(core, offset), rz_core_analysis_name_free
};
if (!p) {
return {};
}
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;
}
@ -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<RzAnalysisBytes *>(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<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));
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()

View File

@ -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<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 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<RzAnalysisBlock>(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<RzAnalysisCaseOp>(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<ut8[]> 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<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 ...
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()