From 518014ee195b346481663a77e4069f2dc120395e Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 14 Mar 2022 17:04:49 +0900 Subject: [PATCH] Use rizin instead of Qt to parse JSON (#2902) Qt truncates integers to 52-bit, corrupting e.g. memory addresses. Use rizin's JSON parser, which can parse integers whose size is up to 64 bits. --- .../code/development-guidelines.rst | 2 +- src/CMakeLists.txt | 2 + src/common/BugReporting.cpp | 10 +- src/common/ColorThemeWorker.cpp | 31 +- src/common/ColorThemeWorker.h | 1 + src/common/Decompiler.cpp | 21 +- src/common/IOModesController.cpp | 5 +- src/common/RizinTask.cpp | 8 +- src/common/RizinTask.h | 2 +- src/common/SettingsUpgrade.cpp | 2 +- src/core/Cutter.cpp | 519 +++++++----------- src/core/Cutter.h | 64 ++- src/core/CutterJson.cpp | 28 + src/core/CutterJson.h | 119 ++++ src/dialogs/VersionInfoDialog.cpp | 61 +- src/menus/DisassemblyContextMenu.cpp | 45 +- src/widgets/BacktraceWidget.cpp | 10 +- src/widgets/CallGraph.cpp | 10 +- src/widgets/ColorThemeListView.h | 1 + src/widgets/Dashboard.cpp | 45 +- src/widgets/Dashboard.h | 3 +- src/widgets/DisassemblerGraphView.cpp | 54 +- src/widgets/FunctionsWidget.cpp | 2 +- src/widgets/ProcessesWidget.cpp | 15 +- src/widgets/RegisterRefsWidget.cpp | 9 +- src/widgets/RizinGraphWidget.cpp | 13 +- src/widgets/StackWidget.cpp | 10 +- src/widgets/ThreadsWidget.cpp | 11 +- 28 files changed, 575 insertions(+), 528 deletions(-) create mode 100644 src/core/CutterJson.cpp create mode 100644 src/core/CutterJson.h diff --git a/docs/source/contributing/code/development-guidelines.rst b/docs/source/contributing/code/development-guidelines.rst index 948d134f..25560bfe 100644 --- a/docs/source/contributing/code/development-guidelines.rst +++ b/docs/source/contributing/code/development-guidelines.rst @@ -47,7 +47,7 @@ Example: .. code:: cpp - QJsonArray array = Core()->cmdj("pdj 1 @ main").array(); + CutterJson array = Core()->cmdj("pdj 1 @ main"); Seek the Current File ~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eb556529..4601cb96 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,6 +4,7 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/CutterConfig.h.in" set(SOURCES Main.cpp core/Cutter.cpp + core/CutterJson.cpp dialogs/EditStringDialog.cpp dialogs/WriteCommandsDialogs.cpp widgets/DisassemblerGraphView.cpp @@ -153,6 +154,7 @@ set(HEADER_FILES core/Cutter.h core/CutterCommon.h core/CutterDescriptions.h + core/CutterJson.h dialogs/EditStringDialog.h dialogs/WriteCommandsDialogs.h widgets/DisassemblerGraphView.h diff --git a/src/common/BugReporting.cpp b/src/common/BugReporting.cpp index f2242900..7d5ec919 100644 --- a/src/common/BugReporting.cpp +++ b/src/common/BugReporting.cpp @@ -12,13 +12,13 @@ void openIssue() // Pull in info needed for git issue osInfo = QSysInfo::productType() + " " + (QSysInfo::productVersion() == "unknown" ? "" : QSysInfo::productVersion()); - QJsonDocument docu = Core()->getFileInfo(); - QJsonObject coreObj = docu.object()["core"].toObject(); - QJsonObject binObj = docu.object()["bin"].toObject(); - if (!binObj.QJsonObject::isEmpty()) { + CutterJson docu = Core()->getFileInfo(); + CutterJson coreObj = docu["core"]; + CutterJson binObj = docu["bin"]; + if (binObj.size()) { format = coreObj["format"].toString(); arch = binObj["arch"].toString(); - if (!binObj["type"].isUndefined()) { + if (binObj["type"].valid()) { type = coreObj["type"].toString(); } else { type = "N/A"; diff --git a/src/common/ColorThemeWorker.cpp b/src/common/ColorThemeWorker.cpp index a7ca2bc8..aabc0c1f 100644 --- a/src/common/ColorThemeWorker.cpp +++ b/src/common/ColorThemeWorker.cpp @@ -128,22 +128,34 @@ bool ColorThemeWorker::isThemeExist(const QString &name) const QJsonDocument ColorThemeWorker::getTheme(const QString &themeName) const { int r, g, b, a; + CutterJson rzTheme; QVariantMap theme; QString curr = Config()->getColorTheme(); if (themeName != curr) { RzCoreLocked core(Core()); rz_core_theme_load(core, themeName.toUtf8().constData()); - theme = Core()->cmdj("ecj").object().toVariantMap(); + rzTheme = Core()->cmdj("ecj"); rz_core_theme_load(core, curr.toUtf8().constData()); } else { - theme = Core()->cmdj("ecj").object().toVariantMap(); + rzTheme = Core()->cmdj("ecj"); } - for (auto it = theme.begin(); it != theme.end(); it++) { - auto arr = it.value().toList(); - QColor(arr[0].toInt(), arr[1].toInt(), arr[2].toInt()).getRgb(&r, &g, &b, &a); - theme[it.key()] = QJsonArray({ r, g, b, a }); + for (CutterJson value : rzTheme) { + QJsonArray arr; + int count = 0; + for (CutterJson element : value) { + arr.append(element.toSt64()); + count++; + if (count >= 3) { + break; + } + } + while (count < 3) { + arr.append(0); + } + arr.append(255); + theme[value.key()] = arr; } ColorFlags colorFlags = ColorFlags::DarkFlag; @@ -278,9 +290,8 @@ bool ColorThemeWorker::isFileTheme(const QString &filePath, bool *ok) const } const QString colors = "black|red|white|green|magenta|yellow|cyan|blue|gray|none"; - QString options = (Core()->cmdj("ecj").object().keys() << cutterSpecificOptions) - .join('|') - .replace(".", "\\."); + QString options = + (Core()->cmdj("ecj").keys() << cutterSpecificOptions).join('|').replace(".", "\\."); QString pattern = QString("((ec\\s+(%1)\\s+(((rgb:|#)[0-9a-fA-F]{3,8})|(%2))))\\s*") .arg(options) @@ -315,7 +326,7 @@ QStringList ColorThemeWorker::customThemes() const const QStringList &ColorThemeWorker::getRizinSpecificOptions() { if (rizinSpecificOptions.isEmpty()) { - rizinSpecificOptions = Core()->cmdj("ecj").object().keys(); + rizinSpecificOptions = Core()->cmdj("ecj").keys(); } return rizinSpecificOptions; } diff --git a/src/common/ColorThemeWorker.h b/src/common/ColorThemeWorker.h index 7c228804..3d67826f 100644 --- a/src/common/ColorThemeWorker.h +++ b/src/common/ColorThemeWorker.h @@ -5,6 +5,7 @@ #include #include #include "Cutter.h" +#include #include #define ThemeWorker() (ColorThemeWorker::instance()) diff --git a/src/common/Decompiler.cpp b/src/common/Decompiler.cpp index 569a7d68..94892075 100644 --- a/src/common/Decompiler.cpp +++ b/src/common/Decompiler.cpp @@ -33,40 +33,37 @@ void JSDecDecompiler::decompileAt(RVA addr) } task = new RizinCmdTask("pddj @ " + QString::number(addr)); connect(task, &RizinCmdTask::finished, this, [this]() { - QJsonObject json = task->getResultJson().object(); + CutterJson json = task->getResultJson(); delete task; task = nullptr; - if (json.isEmpty()) { + if (!json.size()) { emit finished(Decompiler::makeWarning(tr("Failed to parse JSON from jsdec"))); return; } RzAnnotatedCode *code = rz_annotated_code_new(nullptr); QString codeString = ""; - for (const auto &line : json["log"].toArray()) { - if (!line.isString()) { + for (auto line : json["log"]) { + if (line.type() != RZ_JSON_STRING) { continue; } codeString.append(line.toString() + "\n"); } - auto linesArray = json["lines"].toArray(); - for (const auto &line : linesArray) { - QJsonObject lineObject = line.toObject(); - if (lineObject.isEmpty()) { + for (auto lineObject : json["lines"]) { + if (!lineObject.size()) { continue; } RzCodeAnnotation annotationi = {}; annotationi.start = codeString.length(); codeString.append(lineObject["str"].toString() + "\n"); annotationi.end = codeString.length(); - bool ok; annotationi.type = RZ_CODE_ANNOTATION_TYPE_OFFSET; - annotationi.offset.offset = lineObject["offset"].toVariant().toULongLong(&ok); + annotationi.offset.offset = lineObject["offset"].toUt64(); rz_annotated_code_add_annotation(code, &annotationi); } - for (const auto &line : json["errors"].toArray()) { - if (!line.isString()) { + for (auto line : json["errors"]) { + if (line.type() != RZ_JSON_STRING) { continue; } codeString.append(line.toString() + "\n"); diff --git a/src/common/IOModesController.cpp b/src/common/IOModesController.cpp index e7a11aaf..4fa29502 100644 --- a/src/common/IOModesController.cpp +++ b/src/common/IOModesController.cpp @@ -78,11 +78,10 @@ bool IOModesController::prepareForWriting() bool IOModesController::allChangesComitted() { // Get a list of available write changes - QJsonArray changes = Core()->cmdj("wcj").array(); + CutterJson changes = Core()->cmdj("wcj"); // Check if there is a change which isn't written to the file - for (const QJsonValue &value : changes) { - QJsonObject changeObject = value.toObject(); + for (CutterJson changeObject : changes) { if (!changeObject["written"].toBool()) { return false; } diff --git a/src/common/RizinTask.cpp b/src/common/RizinTask.cpp index 48cb0901..14433585 100644 --- a/src/common/RizinTask.cpp +++ b/src/common/RizinTask.cpp @@ -54,13 +54,15 @@ QString RizinCmdTask::getResult() return QString::fromUtf8(res); } -QJsonDocument RizinCmdTask::getResultJson() +CutterJson RizinCmdTask::getResultJson() { const char *res = rz_core_cmd_task_get_result(task); if (!res) { - return QJsonDocument(); + return CutterJson(); } - return Core()->parseJson(res, nullptr); + char *copy = static_cast(rz_mem_alloc(strlen(res) + 1)); + strcpy(copy, res); + return Core()->parseJson(copy, nullptr); } const char *RizinCmdTask::getResultRaw() diff --git a/src/common/RizinTask.h b/src/common/RizinTask.h index e07e1fb3..e0972bc4 100644 --- a/src/common/RizinTask.h +++ b/src/common/RizinTask.h @@ -38,7 +38,7 @@ public: explicit RizinCmdTask(const QString &cmd, bool transient = true); QString getResult(); - QJsonDocument getResultJson(); + CutterJson getResultJson(); const char *getResultRaw(); }; diff --git a/src/common/SettingsUpgrade.cpp b/src/common/SettingsUpgrade.cpp index 9ff48999..4ef57e59 100644 --- a/src/common/SettingsUpgrade.cpp +++ b/src/common/SettingsUpgrade.cpp @@ -181,7 +181,7 @@ void Cutter::initializeSettings() static void removeObsoleteOptionsFromCustomThemes() { - const QStringList options = Core()->cmdj("ecj").object().keys() + const QStringList options = Core()->cmdj("ecj").keys() << ColorThemeWorker::cutterSpecificOptions; RzList *themes_list = rz_core_theme_list(Core()->core()); RzListIter *th_iter; diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 21a07c57..bb0b661a 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -481,7 +481,7 @@ QString CutterCore::cmdRaw(const char *cmd) return res; } -QJsonDocument CutterCore::cmdj(const char *str) +CutterJson CutterCore::cmdj(const char *str) { char *res; { @@ -489,15 +489,12 @@ QJsonDocument CutterCore::cmdj(const char *str) res = rz_core_cmd_str(core, str); } - QJsonDocument doc = parseJson(res, str); - rz_mem_free(res); - - return doc; + return parseJson(res, str); } -QJsonDocument CutterCore::cmdjAt(const char *str, RVA address) +CutterJson CutterCore::cmdjAt(const char *str, RVA address) { - QJsonDocument res; + CutterJson res; RVA oldOffset = getOffset(); seekSilent(address); @@ -515,49 +512,42 @@ QString CutterCore::cmdTask(const QString &str) return task.getResult(); } -QJsonDocument CutterCore::cmdjTask(const QString &str) +CutterJson CutterCore::cmdjTask(const QString &str) { RizinCmdTask task(str); task.startTask(); task.joinTask(); - return parseJson(task.getResultRaw(), str); + const char *res = task.getResultRaw(); + char *copy = static_cast(rz_mem_alloc(strlen(res) + 1)); + strcpy(copy, res); + return parseJson(copy, str); } -QJsonDocument CutterCore::parseJson(const char *res, const char *cmd) +CutterJson CutterCore::parseJson(char *res, const char *cmd) { - QByteArray json(res); - - if (json.isEmpty()) { - return QJsonDocument(); + if (!res) { + return CutterJson(); } - QJsonParseError jsonError; - QJsonDocument doc = QJsonDocument::fromJson(json, &jsonError); + RzJson *doc = rz_json_parse(res); - if (jsonError.error != QJsonParseError::NoError) { - // don't call trimmed() before knowing that parsing failed to avoid copying huge jsons all - // the time - if (json.trimmed().isEmpty()) { - return doc; - } + if (!doc) { if (cmd) { - eprintf("Failed to parse JSON for command \"%s\": %s\n", cmd, - jsonError.errorString().toLocal8Bit().constData()); + eprintf("Failed to parse JSON for command \"%s\"\n", cmd); } else { - eprintf("Failed to parse JSON: %s\n", - jsonError.errorString().toLocal8Bit().constData()); + eprintf("Failed to parse JSON\n"); } const int MAX_JSON_DUMP_SIZE = 8 * 1024; - if (json.length() > MAX_JSON_DUMP_SIZE) { - int originalSize = json.length(); - json.resize(MAX_JSON_DUMP_SIZE); - eprintf("%d bytes total: %s ...\n", originalSize, json.constData()); + size_t originalSize = strlen(res); + if (originalSize > MAX_JSON_DUMP_SIZE) { + res[MAX_JSON_DUMP_SIZE] = 0; + eprintf("%zu bytes total: %s ...\n", originalSize, res); } else { - eprintf("%s\n", json.constData()); + eprintf("%s\n", res); } } - return doc; + return CutterJson(doc, QSharedPointer::create(doc, res)); } QStringList CutterCore::autocomplete(const QString &cmd, RzLinePromptType promptType, size_t limit) @@ -675,8 +665,7 @@ bool CutterCore::mapFile(QString path, RVA mapaddr) { CORE_LOCK(); RVA addr = mapaddr != RVA_INVALID ? mapaddr : 0; - ut64 baddr = - Core()->getFileInfo().object()["bin"].toObject()["baddr"].toVariant().toULongLong(); + ut64 baddr = Core()->getFileInfo()["bin"]["baddr"].toUt64(); if (rz_core_file_open(core, path.toUtf8().constData(), RZ_PERM_RX, addr)) { rz_core_bin_load(core, path.toUtf8().constData(), baddr); } else { @@ -737,20 +726,12 @@ void CutterCore::delFlag(const QString &name) QString CutterCore::getInstructionBytes(RVA addr) { - return cmdj("aoj @ " + RzAddressString(addr)) - .array() - .first() - .toObject()[RJsonKey::bytes] - .toString(); + return cmdj("aoj @ " + RzAddressString(addr)).first()[RJsonKey::bytes].toString(); } QString CutterCore::getInstructionOpcode(RVA addr) { - return cmdj("aoj @ " + RzAddressString(addr)) - .array() - .first() - .toObject()[RJsonKey::opcode] - .toString(); + return cmdj("aoj @ " + RzAddressString(addr)).first()[RJsonKey::opcode].toString(); } void CutterCore::editInstruction(RVA addr, const QString &inst) @@ -1010,21 +991,19 @@ RVA CutterCore::nextOpAddr(RVA startAddr, int count) { CORE_LOCK(); - QJsonArray array = - Core()->cmdj("pdj " + QString::number(count + 1) + " @ " + QString::number(startAddr)) - .array(); - if (array.isEmpty()) { + CutterJson array = + Core()->cmdj("pdj " + QString::number(count + 1) + " @ " + QString::number(startAddr)); + if (!array.size()) { return startAddr + 1; } - QJsonValue instValue = array.last(); - if (!instValue.isObject()) { + CutterJson instValue = array.last(); + if (instValue.type() != RZ_JSON_OBJECT) { return startAddr + 1; } - bool ok; - RVA offset = instValue.toObject()[RJsonKey::offset].toVariant().toULongLong(&ok); - if (!ok) { + RVA offset = instValue[RJsonKey::offset].toRVA(); + if (offset == RVA_INVALID) { return startAddr + 1; } @@ -1340,27 +1319,14 @@ void CutterCore::createFunctionAt(RVA addr, QString name) emit functionsChanged(); } -QJsonDocument CutterCore::getRegistersInfo() +CutterJson CutterCore::getRegistersInfo() { return cmdj("aeafj"); } RVA CutterCore::getOffsetJump(RVA addr) { - bool ok; - RVA value = cmdj("aoj @" + QString::number(addr)) - .array() - .first() - .toObject() - .value(RJsonKey::jump) - .toVariant() - .toULongLong(&ok); - - if (!ok) { - return RVA_INVALID; - } - - return value; + return cmdj("aoj @" + QString::number(addr)).first().toRVA(); } QList CutterCore::getDecompilers() @@ -1388,17 +1354,17 @@ bool CutterCore::registerDecompiler(Decompiler *decompiler) return true; } -QJsonDocument CutterCore::getFileInfo() +CutterJson CutterCore::getFileInfo() { return cmdj("ij"); } -QJsonDocument CutterCore::getFileVersionInfo() +CutterJson CutterCore::getFileVersionInfo() { return cmdj("iVj"); } -QJsonDocument CutterCore::getSignatureInfo() +CutterJson CutterCore::getSignatureInfo() { return cmdj("iCj"); } @@ -1413,41 +1379,43 @@ static inline const QString appendVar(QString &dst, const QString val, const QSt return val; } -RefDescription CutterCore::formatRefDesc(QJsonObject refItem) +RefDescription CutterCore::formatRefDesc(const AddrRefs &refItem) { RefDescription desc; - // Ignore empty refs and refs that only contain addr - if (refItem.size() <= 1) { + if (refItem.addr == RVA_INVALID) { return desc; } - QString str = refItem["string"].toVariant().toString(); + QString str = refItem.string; if (!str.isEmpty()) { desc.ref = str; desc.refColor = ConfigColor("comment"); } else { + QSharedPointer cursor(&refItem); QString type, string; - do { + while (true) { desc.ref += " ->"; - appendVar(desc.ref, refItem["reg"].toVariant().toString(), " @", ""); - appendVar(desc.ref, refItem["mapname"].toVariant().toString(), " (", ")"); - appendVar(desc.ref, refItem["section"].toVariant().toString(), " (", ")"); - appendVar(desc.ref, refItem["func"].toVariant().toString(), " ", ""); - type = appendVar(desc.ref, refItem["type"].toVariant().toString(), " ", ""); - appendVar(desc.ref, refItem["perms"].toVariant().toString(), " ", ""); - appendVar(desc.ref, refItem["asm"].toVariant().toString(), " \"", "\""); - string = appendVar(desc.ref, refItem["string"].toVariant().toString(), " ", ""); + appendVar(desc.ref, cursor->reg, " @", ""); + appendVar(desc.ref, cursor->mapname, " (", ")"); + appendVar(desc.ref, cursor->section, " (", ")"); + appendVar(desc.ref, cursor->fcn, " ", ""); + type = appendVar(desc.ref, cursor->type, " ", ""); + appendVar(desc.ref, cursor->perms, " ", ""); + appendVar(desc.ref, cursor->asm_op, " \"", "\""); + string = appendVar(desc.ref, cursor->string, " ", ""); if (!string.isNull()) { // There is no point in adding ascii and addr info after a string break; } - if (!refItem["value"].isNull()) { - appendVar(desc.ref, RzAddressString(refItem["value"].toVariant().toULongLong()), - " ", ""); + if (cursor->has_value) { + appendVar(desc.ref, RzAddressString(cursor->value), " ", ""); } - refItem = refItem["ref"].toObject(); - } while (!refItem.empty()); + if (!cursor->ref) { + break; + } + cursor = cursor->ref; + } // Set the ref's color according to the last item type if (type == "ascii" || !string.isEmpty()) { @@ -1464,29 +1432,28 @@ RefDescription CutterCore::formatRefDesc(QJsonObject refItem) return desc; } -QList CutterCore::getRegisterRefs(int depth) +QList CutterCore::getRegisterRefs(int depth) { - QList ret; + QList ret; if (!currentlyDebugging) { return ret; } - QJsonObject registers = cmdj("drj").object(); - - for (const QString &key : registers.keys()) { - QJsonObject reg; - reg["value"] = registers.value(key); - reg["ref"] = getAddrRefs(registers.value(key).toVariant().toULongLong(), depth); - reg["name"] = key; + CutterJson registers = cmdj("drj"); + for (CutterJson value : registers) { + RegisterRef reg; + reg.value = value.toUt64(); + reg.ref = getAddrRefs(reg.value, depth); + reg.name = value.key(); ret.append(reg); } return ret; } -QList CutterCore::getStack(int size, int depth) +QList CutterCore::getStack(int size, int depth) { - QList stack; + QList stack; if (!currentlyDebugging) { return stack; } @@ -1510,11 +1477,12 @@ QList CutterCore::getStack(int size, int depth) return stack; } -QJsonObject CutterCore::getAddrRefs(RVA addr, int depth) +AddrRefs CutterCore::getAddrRefs(RVA addr, int depth) { - QJsonObject json; + AddrRefs refs; if (depth < 1 || addr == UT64_MAX) { - return json; + refs.addr = RVA_INVALID; + return refs; } CORE_LOCK(); @@ -1522,19 +1490,19 @@ QJsonObject CutterCore::getAddrRefs(RVA addr, int depth) QByteArray buf = QByteArray(); ut64 type = rz_core_analysis_address(core, addr); - json["addr"] = QString::number(addr); + refs.addr = addr; // Search for the section the addr is in, avoid duplication for heap/stack with type if (!(type & RZ_ANALYSIS_ADDR_TYPE_HEAP || type & RZ_ANALYSIS_ADDR_TYPE_STACK)) { // Attempt to find the address within a map RzDebugMap *map = rz_debug_map_get(core->dbg, addr); if (map && map->name && map->name[0]) { - json["mapname"] = map->name; + refs.mapname = map->name; } RzBinSection *sect = rz_bin_get_section_at(rz_bin_cur_object(core->bin), addr, true); if (sect && sect->name[0]) { - json["section"] = sect->name; + refs.section = sect->name; } } @@ -1543,30 +1511,30 @@ QJsonObject CutterCore::getAddrRefs(RVA addr, int depth) if (fi) { RzRegItem *r = rz_reg_get(core->dbg->reg, fi->name, -1); if (r) { - json["reg"] = r->name; + refs.reg = r->name; } } // Attempt to find the address within a function RzAnalysisFunction *fcn = rz_analysis_get_fcn_in(core->analysis, addr, 0); if (fcn) { - json["fcn"] = fcn->name; + refs.fcn = fcn->name; } // Update type and permission information if (type != 0) { if (type & RZ_ANALYSIS_ADDR_TYPE_HEAP) { - json["type"] = "heap"; + refs.type = "heap"; } else if (type & RZ_ANALYSIS_ADDR_TYPE_STACK) { - json["type"] = "stack"; + refs.type = "stack"; } else if (type & RZ_ANALYSIS_ADDR_TYPE_PROGRAM) { - json["type"] = "program"; + refs.type = "program"; } else if (type & RZ_ANALYSIS_ADDR_TYPE_LIBRARY) { - json["type"] = "library"; + refs.type = "library"; } else if (type & RZ_ANALYSIS_ADDR_TYPE_ASCII) { - json["type"] = "ascii"; + refs.type = "ascii"; } else if (type & RZ_ANALYSIS_ADDR_TYPE_SEQUENCE) { - json["type"] = "sequence"; + refs.type = "sequence"; } QString perms = ""; @@ -1584,11 +1552,11 @@ QJsonObject CutterCore::getAddrRefs(RVA addr, int depth) rz_io_read_at(core->io, addr, (unsigned char *)buf.data(), buf.size()); rz_asm_set_pc(core->rasm, addr); rz_asm_disassemble(core->rasm, &op, (unsigned char *)buf.data(), buf.size()); - json["asm"] = rz_asm_op_get_asm(&op); + refs.asm_op = rz_asm_op_get_asm(&op); } if (!perms.isEmpty()) { - json["perms"] = perms; + refs.perms = perms; } } @@ -1601,14 +1569,15 @@ QJsonObject CutterCore::getAddrRefs(RVA addr, int depth) ut64 n = (bits == 64) ? *n64 : *n32; // The value of the next address will serve as an indication that there's more to // telescope if we have reached the depth limit - json["value"] = QString::number(n); + refs.value = n; + refs.has_value = true; if (depth && n != addr && !(type & RZ_ANALYSIS_ADDR_TYPE_EXEC)) { // Make sure we aren't telescoping the same address - QJsonObject ref = getAddrRefs(n, depth - 1); - if (!ref.empty() && !ref["type"].isNull()) { + AddrRefs ref = getAddrRefs(n, depth - 1); + if (!ref.type.isNull()) { // If the dereference of the current pointer is an ascii character we // might have a string in this address - if (ref["type"].toString().contains("ascii")) { + if (ref.type.contains("ascii")) { buf.resize(128); rz_io_read_at(core->io, addr, (unsigned char *)buf.data(), buf.size()); QString strVal = QString(buf); @@ -1616,16 +1585,16 @@ QJsonObject CutterCore::getAddrRefs(RVA addr, int depth) if (strVal.size() == buf.size()) { strVal += "..."; } - json["string"] = strVal; + refs.string = strVal; } - json["ref"] = ref; + refs.ref = QSharedPointer::create(ref); } } } - return json; + return refs; } -QJsonDocument CutterCore::getProcessThreads(int pid) +CutterJson CutterCore::getProcessThreads(int pid) { if (-1 == pid) { // Return threads list of the currently debugged PID @@ -1765,7 +1734,7 @@ bool CutterCore::writeHeapChunk(RzHeapChunkSimple *chunk_simple) return rz_heap_write_chunk(core, chunk_simple); } -QJsonDocument CutterCore::getChildProcesses(int pid) +CutterJson CutterCore::getChildProcesses(int pid) { // Return the currently debugged process and it's children if (-1 == pid) { @@ -1775,7 +1744,7 @@ QJsonDocument CutterCore::getChildProcesses(int pid) return cmdj("dpj " + QString::number(pid)); } -QJsonDocument CutterCore::getRegisterValues() +CutterJson CutterCore::getRegisterValues() { return cmdj("drj"); } @@ -1783,11 +1752,10 @@ QJsonDocument CutterCore::getRegisterValues() QList CutterCore::getVariables(RVA at) { QList ret; - QJsonObject varsObject = cmdj(QString("afvj @ %1").arg(at)).object(); + CutterJson varsObject = cmdj(QString("afvj @ %1").arg(at)); - auto addVars = [&](VariableDescription::RefType refType, const QJsonArray &array) { - for (const QJsonValue &varValue : array) { - QJsonObject varObject = varValue.toObject(); + auto addVars = [&](VariableDescription::RefType refType, const CutterJson &array) { + for (CutterJson varObject : array) { VariableDescription desc; desc.refType = refType; desc.name = varObject["name"].toString(); @@ -1796,21 +1764,19 @@ QList CutterCore::getVariables(RVA at) } }; - addVars(VariableDescription::RefType::SP, varsObject["sp"].toArray()); - addVars(VariableDescription::RefType::BP, varsObject["bp"].toArray()); - addVars(VariableDescription::RefType::Reg, varsObject["reg"].toArray()); + addVars(VariableDescription::RefType::SP, varsObject["sp"]); + addVars(VariableDescription::RefType::BP, varsObject["bp"]); + addVars(VariableDescription::RefType::Reg, varsObject["reg"]); return ret; } QVector CutterCore::getRegisterRefValues() { - QJsonArray registerRefArray = cmdj("drrj").array(); + CutterJson registerRefArray = cmdj("drrj"); QVector result; - for (const QJsonValue value : registerRefArray) { - QJsonObject regRefObject = value.toObject(); - + for (CutterJson regRefObject : registerRefArray) { RegisterRefValueDescription desc; desc.name = regRefObject[RJsonKey::reg].toString(); desc.value = regRefObject[RJsonKey::value].toString(); @@ -2371,11 +2337,8 @@ void CutterCore::stepBackDebug() QStringList CutterCore::getDebugPlugins() { QStringList plugins; - QJsonArray pluginArray = cmdj("dLj").array(); - - for (const QJsonValue &value : pluginArray) { - QJsonObject pluginObject = value.toObject(); + for (CutterJson pluginObject : cmdj("dLj")) { QString plugin = pluginObject[RJsonKey::name].toString(); plugins << plugin; @@ -2647,7 +2610,7 @@ bool CutterCore::isBreakpoint(const QList &breakpoints, RVA addr) return breakpoints.contains(addr); } -QJsonDocument CutterCore::getBacktrace() +CutterJson CutterCore::getBacktrace() { return cmdj("dbtj"); } @@ -2655,15 +2618,12 @@ QJsonDocument CutterCore::getBacktrace() QList CutterCore::getAllProcesses() { QList ret; - QJsonArray processArray = cmdj("dplj").array(); - - for (const QJsonValue &value : processArray) { - QJsonObject procObject = value.toObject(); + for (CutterJson procObject : cmdj("dplj")) { ProcessDescription proc; - proc.pid = procObject[RJsonKey::pid].toInt(); - proc.uid = procObject[RJsonKey::uid].toInt(); + proc.pid = procObject[RJsonKey::pid].toSt64(); + proc.uid = procObject[RJsonKey::uid].toSt64(); proc.status = procObject[RJsonKey::status].toString(); proc.path = procObject[RJsonKey::path].toString(); @@ -2676,17 +2636,14 @@ QList CutterCore::getAllProcesses() QList CutterCore::getMemoryMap() { QList ret; - QJsonArray memoryMapArray = cmdj("dmj").array(); - - for (const QJsonValue &value : memoryMapArray) { - QJsonObject memMapObject = value.toObject(); + for (CutterJson memMapObject : cmdj("dmj")) { MemoryMapDescription memMap; memMap.name = memMapObject[RJsonKey::name].toString(); memMap.fileName = memMapObject[RJsonKey::file].toString(); - memMap.addrStart = memMapObject[RJsonKey::addr].toVariant().toULongLong(); - memMap.addrEnd = memMapObject[RJsonKey::addr_end].toVariant().toULongLong(); + memMap.addrStart = memMapObject[RJsonKey::addr].toRVA(); + memMap.addrEnd = memMapObject[RJsonKey::addr_end].toRVA(); memMap.type = memMapObject[RJsonKey::type].toString(); memMap.permission = memMapObject[RJsonKey::perm].toString(); @@ -2925,15 +2882,11 @@ QList CutterCore::getAllImports() CORE_LOCK(); QList ret; - QJsonArray importsArray = cmdj("iij").array(); - - for (const QJsonValue &value : importsArray) { - QJsonObject importObject = value.toObject(); - + for (CutterJson importObject : cmdj("iij")) { ImportDescription import; - import.plt = importObject[RJsonKey::plt].toVariant().toULongLong(); - import.ordinal = importObject[RJsonKey::ordinal].toInt(); + import.plt = importObject[RJsonKey::plt].toRVA(); + import.ordinal = importObject[RJsonKey::ordinal].toSt64(); import.bind = importObject[RJsonKey::bind].toString(); import.type = importObject[RJsonKey::type].toString(); import.libname = importObject[RJsonKey::libname].toString(); @@ -2950,16 +2903,12 @@ QList CutterCore::getAllExports() CORE_LOCK(); QList ret; - QJsonArray exportsArray = cmdj("iEj").array(); - - for (const QJsonValue &value : exportsArray) { - QJsonObject exportObject = value.toObject(); - + for (CutterJson exportObject : cmdj("iEj")) { ExportDescription exp; - exp.vaddr = exportObject[RJsonKey::vaddr].toVariant().toULongLong(); - exp.paddr = exportObject[RJsonKey::paddr].toVariant().toULongLong(); - exp.size = exportObject[RJsonKey::size].toVariant().toULongLong(); + exp.vaddr = exportObject[RJsonKey::vaddr].toRVA(); + exp.paddr = exportObject[RJsonKey::paddr].toRVA(); + exp.size = exportObject[RJsonKey::size].toRVA(); exp.type = exportObject[RJsonKey::type].toString(); exp.name = exportObject[RJsonKey::name].toString(); exp.flag_name = exportObject[RJsonKey::flagname].toString(); @@ -3010,15 +2959,11 @@ QList CutterCore::getAllHeaders() CORE_LOCK(); QList ret; - QJsonArray headersArray = cmdj("ihj").array(); - - for (const QJsonValue &value : headersArray) { - QJsonObject headerObject = value.toObject(); - + for (CutterJson headerObject : cmdj("ihj")) { HeaderDescription header; - header.vaddr = headerObject[RJsonKey::vaddr].toVariant().toULongLong(); - header.paddr = headerObject[RJsonKey::paddr].toVariant().toULongLong(); + header.vaddr = headerObject[RJsonKey::vaddr].toRVA(); + header.paddr = headerObject[RJsonKey::paddr].toRVA(); header.value = headerObject[RJsonKey::comment].toString(); header.name = headerObject[RJsonKey::name].toString(); @@ -3063,16 +3008,13 @@ QList CutterCore::getAllComments(const QString &filterType) CORE_LOCK(); QList ret; - QJsonArray commentsArray = cmdj("CClj").array(); - for (const QJsonValue &value : commentsArray) { - QJsonObject commentObject = value.toObject(); - + for (CutterJson commentObject : cmdj("CClj")) { QString type = commentObject[RJsonKey::type].toString(); if (type != filterType) continue; CommentDescription comment; - comment.offset = commentObject[RJsonKey::offset].toVariant().toULongLong(); + comment.offset = commentObject[RJsonKey::offset].toRVA(); comment.name = commentObject[RJsonKey::name].toString(); ret << comment; @@ -3114,22 +3056,19 @@ QList CutterCore::getAllStrings() return parseStringsJson(cmdjTask("izzj")); } -QList CutterCore::parseStringsJson(const QJsonDocument &doc) +QList CutterCore::parseStringsJson(const CutterJson &doc) { QList ret; - QJsonArray stringsArray = doc.array(); - for (const QJsonValue &value : stringsArray) { - QJsonObject stringObject = value.toObject(); - + for (CutterJson value : doc) { StringDescription string; - string.string = stringObject[RJsonKey::string].toString(); - string.vaddr = stringObject[RJsonKey::vaddr].toVariant().toULongLong(); - string.type = stringObject[RJsonKey::type].toString(); - string.size = stringObject[RJsonKey::size].toVariant().toUInt(); - string.length = stringObject[RJsonKey::length].toVariant().toUInt(); - string.section = stringObject[RJsonKey::section].toString(); + string.string = value[RJsonKey::string].toString(); + string.vaddr = value[RJsonKey::vaddr].toRVA(); + string.type = value[RJsonKey::type].toString(); + string.size = value[RJsonKey::size].toUt64(); + string.length = value[RJsonKey::length].toUt64(); + string.section = value[RJsonKey::section].toString(); ret << string; } @@ -3249,21 +3188,17 @@ QList CutterCore::getAllSegments() CORE_LOCK(); QList ret; - QJsonArray segments = cmdj("iSSj").array(); - - for (const QJsonValue &value : segments) { - QJsonObject segmentObject = value.toObject(); - + for (CutterJson segmentObject : cmdj("iSSj")) { QString name = segmentObject[RJsonKey::name].toString(); if (name.isEmpty()) continue; SegmentDescription segment; segment.name = name; - segment.vaddr = segmentObject[RJsonKey::vaddr].toVariant().toULongLong(); - segment.paddr = segmentObject[RJsonKey::paddr].toVariant().toULongLong(); - segment.size = segmentObject[RJsonKey::size].toVariant().toULongLong(); - segment.vsize = segmentObject[RJsonKey::vsize].toVariant().toULongLong(); + segment.vaddr = segmentObject[RJsonKey::vaddr].toRVA(); + segment.paddr = segmentObject[RJsonKey::paddr].toRVA(); + segment.size = segmentObject[RJsonKey::size].toRVA(); + segment.vsize = segmentObject[RJsonKey::vsize].toRVA(); segment.perm = segmentObject[RJsonKey::perm].toString(); ret << segment; @@ -3276,17 +3211,14 @@ QList CutterCore::getAllEntrypoint() CORE_LOCK(); QList ret; - QJsonArray entrypointsArray = cmdj("iej").array(); - for (const QJsonValue &value : entrypointsArray) { - QJsonObject entrypointObject = value.toObject(); - + for (CutterJson entrypointObject : cmdj("iej")) { EntrypointDescription entrypoint; - entrypoint.vaddr = entrypointObject[RJsonKey::vaddr].toVariant().toULongLong(); - entrypoint.paddr = entrypointObject[RJsonKey::paddr].toVariant().toULongLong(); - entrypoint.baddr = entrypointObject[RJsonKey::baddr].toVariant().toULongLong(); - entrypoint.laddr = entrypointObject[RJsonKey::laddr].toVariant().toULongLong(); - entrypoint.haddr = entrypointObject[RJsonKey::haddr].toVariant().toULongLong(); + entrypoint.vaddr = entrypointObject[RJsonKey::vaddr].toRVA(); + entrypoint.paddr = entrypointObject[RJsonKey::paddr].toRVA(); + entrypoint.baddr = entrypointObject[RJsonKey::baddr].toRVA(); + entrypoint.laddr = entrypointObject[RJsonKey::laddr].toRVA(); + entrypoint.haddr = entrypointObject[RJsonKey::haddr].toRVA(); entrypoint.type = entrypointObject[RJsonKey::type].toString(); ret << entrypoint; @@ -3299,34 +3231,27 @@ QList CutterCore::getAllClassesFromBin() CORE_LOCK(); QList ret; - QJsonArray classesArray = cmdj("icj").array(); - for (const QJsonValue &value : classesArray) { - QJsonObject classObject = value.toObject(); - + for (CutterJson classObject : cmdj("icj")) { BinClassDescription cls; cls.name = classObject[RJsonKey::classname].toString(); - cls.addr = classObject[RJsonKey::addr].toVariant().toULongLong(); - cls.index = classObject[RJsonKey::index].toVariant().toULongLong(); - - for (const QJsonValue &value2 : classObject[RJsonKey::methods].toArray()) { - QJsonObject methObject = value2.toObject(); + cls.addr = classObject[RJsonKey::addr].toRVA(); + cls.index = classObject[RJsonKey::index].toUt64(); + for (CutterJson methObject : classObject[RJsonKey::methods]) { BinClassMethodDescription meth; meth.name = methObject[RJsonKey::name].toString(); - meth.addr = methObject[RJsonKey::addr].toVariant().toULongLong(); + meth.addr = methObject[RJsonKey::addr].toRVA(); cls.methods << meth; } - for (const QJsonValue &value2 : classObject[RJsonKey::fields].toArray()) { - QJsonObject fieldObject = value2.toObject(); - + for (CutterJson fieldObject : classObject[RJsonKey::fields]) { BinClassFieldDescription field; field.name = fieldObject[RJsonKey::name].toString(); - field.addr = fieldObject[RJsonKey::addr].toVariant().toULongLong(); + field.addr = fieldObject[RJsonKey::addr].toRVA(); cls.fields << field; } @@ -3345,10 +3270,7 @@ QList CutterCore::getAllClassesFromFlags() QList ret; QMap classesCache; - QJsonArray flagsArray = cmdj("fj@F:classes").array(); - for (const QJsonValue &value : flagsArray) { - QJsonObject flagObject = value.toObject(); - + for (const CutterJson flagObject : cmdj("fj@F:classes")) { QString flagName = flagObject[RJsonKey::name].toString(); QRegularExpressionMatch match = classFlagRegExp.match(flagName); @@ -3365,7 +3287,7 @@ QList CutterCore::getAllClassesFromFlags() desc = it.value(); } desc->name = match.captured(1); - desc->addr = flagObject[RJsonKey::offset].toVariant().toULongLong(); + desc->addr = flagObject[RJsonKey::offset].toRVA(); desc->index = RVA_INVALID; continue; } @@ -3390,7 +3312,7 @@ QList CutterCore::getAllClassesFromFlags() BinClassMethodDescription meth; meth.name = match.captured(2); - meth.addr = flagObject[RJsonKey::offset].toVariant().toULongLong(); + meth.addr = flagObject[RJsonKey::offset].toRVA(); classDesc->methods << meth; continue; } @@ -3559,17 +3481,14 @@ QList CutterCore::getAllResources() CORE_LOCK(); QList resources; - QJsonArray resourcesArray = cmdj("iRj").array(); - for (const QJsonValue &value : resourcesArray) { - QJsonObject resourceObject = value.toObject(); - + for (CutterJson resourceObject : cmdj("iRj")) { ResourcesDescription res; res.name = resourceObject[RJsonKey::name].toString(); - res.vaddr = resourceObject[RJsonKey::vaddr].toVariant().toULongLong(); - res.index = resourceObject[RJsonKey::index].toVariant().toULongLong(); + res.vaddr = resourceObject[RJsonKey::vaddr].toRVA(); + res.index = resourceObject[RJsonKey::index].toUt64(); res.type = resourceObject[RJsonKey::type].toString(); - res.size = resourceObject[RJsonKey::size].toVariant().toULongLong(); + res.size = resourceObject[RJsonKey::size].toUt64(); res.lang = resourceObject[RJsonKey::lang].toString(); resources << res; @@ -3582,21 +3501,15 @@ QList CutterCore::getAllVTables() CORE_LOCK(); QList vtables; - QJsonArray vTablesArray = cmdj("avj").array(); - for (const QJsonValue &vTableValue : vTablesArray) { - QJsonObject vTableObject = vTableValue.toObject(); - + for (CutterJson vTableObject : cmdj("avj")) { VTableDescription res; - res.addr = vTableObject[RJsonKey::offset].toVariant().toULongLong(); - QJsonArray methodArray = vTableObject[RJsonKey::methods].toArray(); - - for (const QJsonValue &methodValue : methodArray) { - QJsonObject methodObject = methodValue.toObject(); + res.addr = vTableObject[RJsonKey::offset].toRVA(); + for (CutterJson methodObject : vTableObject[RJsonKey::methods]) { BinClassMethodDescription method; - method.addr = methodObject[RJsonKey::offset].toVariant().toULongLong(); + method.addr = methodObject[RJsonKey::offset].toRVA(); method.name = methodObject[RJsonKey::name].toString(); res.methods << method; @@ -3693,43 +3606,33 @@ QList CutterCore::getAllSearch(QString searchFor, QString spa CORE_LOCK(); QList searchRef; - QJsonArray searchArray; + CutterJson searchArray; { TempConfig cfg; cfg.set("search.in", in); - searchArray = cmdj(QString("%1 %2").arg(space, searchFor)).array(); + searchArray = cmdj(QString("%1 %2").arg(space, searchFor)); } if (space == "/Rj") { - for (const QJsonValue &value : searchArray) { - QJsonObject searchObject = value.toObject(); - + for (CutterJson searchObject : searchArray) { SearchDescription exp; exp.code.clear(); - for (const QJsonValue &value2 : searchObject[RJsonKey::opcodes].toArray()) { - QJsonObject gadget = value2.toObject(); + for (CutterJson gadget : searchObject[RJsonKey::opcodes]) { exp.code += gadget[RJsonKey::opcode].toString() + "; "; } - exp.offset = searchObject[RJsonKey::opcodes] - .toArray() - .first() - .toObject()[RJsonKey::offset] - .toVariant() - .toULongLong(); - exp.size = searchObject[RJsonKey::size].toVariant().toULongLong(); + exp.offset = searchObject[RJsonKey::opcodes].first()[RJsonKey::offset].toRVA(); + exp.size = searchObject[RJsonKey::size].toUt64(); searchRef << exp; } } else { - for (const QJsonValue &value : searchArray) { - QJsonObject searchObject = value.toObject(); - + for (CutterJson searchObject : searchArray) { SearchDescription exp; - exp.offset = searchObject[RJsonKey::offset].toVariant().toULongLong(); - exp.size = searchObject[RJsonKey::len].toVariant().toULongLong(); + exp.offset = searchObject[RJsonKey::offset].toRVA(); + exp.size = searchObject[RJsonKey::len].toUt64(); exp.code = searchObject[RJsonKey::code].toString(); exp.data = searchObject[RJsonKey::data].toString(); @@ -3747,35 +3650,31 @@ BlockStatistics CutterCore::getBlockStatistics(unsigned int blocksCount) return blockStats; } - QJsonObject statsObj; + CutterJson statsObj; // User TempConfig here to set the search boundaries to all sections. This makes sure // that the Visual Navbar will show all the relevant addresses. { TempConfig tempConfig; tempConfig.set("search.in", "bin.sections"); - statsObj = cmdj("p-j " + QString::number(blocksCount)).object(); + statsObj = cmdj("p-j " + QString::number(blocksCount)); } - blockStats.from = statsObj[RJsonKey::from].toVariant().toULongLong(); - blockStats.to = statsObj[RJsonKey::to].toVariant().toULongLong(); - blockStats.blocksize = statsObj[RJsonKey::blocksize].toVariant().toULongLong(); - - QJsonArray blocksArray = statsObj[RJsonKey::blocks].toArray(); - - for (const QJsonValue &value : blocksArray) { - QJsonObject blockObj = value.toObject(); + blockStats.from = statsObj[RJsonKey::from].toRVA(); + blockStats.to = statsObj[RJsonKey::to].toRVA(); + blockStats.blocksize = statsObj[RJsonKey::blocksize].toRVA(); + for (CutterJson blockObj : statsObj[RJsonKey::blocks]) { BlockDescription block; - block.addr = blockObj[RJsonKey::offset].toVariant().toULongLong(); - block.size = blockObj[RJsonKey::size].toVariant().toULongLong(); - block.flags = blockObj[RJsonKey::flags].toInt(0); - block.functions = blockObj[RJsonKey::functions].toInt(0); - block.inFunctions = blockObj[RJsonKey::in_functions].toInt(0); - block.comments = blockObj[RJsonKey::comments].toInt(0); - block.symbols = blockObj[RJsonKey::symbols].toInt(0); - block.strings = blockObj[RJsonKey::strings].toInt(0); + block.addr = blockObj[RJsonKey::offset].toRVA(); + block.size = blockObj[RJsonKey::size].toRVA(); + block.flags = blockObj[RJsonKey::flags].toSt64(); + block.functions = blockObj[RJsonKey::functions].toSt64(); + block.inFunctions = blockObj[RJsonKey::in_functions].toSt64(); + block.comments = blockObj[RJsonKey::comments].toSt64(); + block.symbols = blockObj[RJsonKey::symbols].toSt64(); + block.strings = blockObj[RJsonKey::strings].toSt64(); block.rwx = 0; QString rwxStr = blockObj[RJsonKey::rwx].toString(); @@ -3801,20 +3700,12 @@ QList CutterCore::getXRefsForVariable(QString variableName, boo RVA offset) { QList xrefList = QList(); - QJsonArray xrefsArray; - if (findWrites) { - xrefsArray = cmdjAt("afvWj", offset).array(); - } else { - xrefsArray = cmdjAt("afvRj", offset).array(); - } - for (const QJsonValue &value : xrefsArray) { - QJsonObject xrefObject = value.toObject(); + for (CutterJson xrefObject : cmdjAt(findWrites ? "afvWj" : "afvRj", offset)) { QString name = xrefObject[RJsonKey::name].toString(); if (name == variableName) { - QJsonArray addressArray = xrefObject[RJsonKey::addrs].toArray(); - for (const QJsonValue &address : addressArray) { + for (CutterJson address : xrefObject[RJsonKey::addrs]) { XrefDescription xref; - RVA addr = address.toVariant().toULongLong(); + RVA addr = address.toRVA(); xref.from = addr; xref.to = addr; if (findWrites) { @@ -3890,11 +3781,11 @@ QString CutterCore::listFlagsAsStringAt(RVA addr) QString CutterCore::nearestFlag(RVA offset, RVA *flagOffsetOut) { - auto r = cmdj(QString("fdj @ ") + QString::number(offset)).object(); - QString name = r.value("name").toString(); + auto r = cmdj(QString("fdj @ ") + QString::number(offset)); + QString name = r["name"].toString(); if (flagOffsetOut) { - auto offsetValue = r.value("offset"); - *flagOffsetOut = offsetValue.isUndefined() ? offset : offsetValue.toVariant().toULongLong(); + auto offsetValue = r["offset"]; + *flagOffsetOut = offsetValue.valid() ? offsetValue.toRVA() : offset; } return name; } @@ -3965,18 +3856,15 @@ void CutterCore::loadPDB(const QString &file) QList CutterCore::disassembleLines(RVA offset, int lines) { - QJsonArray array = cmdj(QString("pdJ ") + QString::number(lines) + QString(" @ ") - + QString::number(offset)) - .array(); + CutterJson array = cmdj(QString("pdJ ") + QString::number(lines) + QString(" @ ") + + QString::number(offset)); QList r; - for (const QJsonValueRef &value : array) { - QJsonObject object = value.toObject(); + for (CutterJson object : array) { DisassemblyLine line; - line.offset = object[RJsonKey::offset].toVariant().toULongLong(); + line.offset = object[RJsonKey::offset].toRVA(); line.text = ansiEscapeToHtml(object[RJsonKey::text].toString()); - const auto &arrow = object[RJsonKey::arrow]; - line.arrow = arrow.isNull() ? RVA_INVALID : arrow.toVariant().toULongLong(); + line.arrow = object[RJsonKey::arrow].toRVA(); r << line; } @@ -4094,8 +3982,7 @@ QString CutterCore::getVersionInformation() QList CutterCore::getColorThemes() { QList r; - QJsonDocument themes = cmdj("ecoj"); - for (const QJsonValue &s : themes.array()) { + for (CutterJson s : cmdj("ecoj")) { r << s.toString(); } return r; @@ -4181,13 +4068,13 @@ void CutterCore::setWriteMode(bool enabled) bool CutterCore::isWriteModeEnabled() { - using namespace std; - QJsonArray ans = cmdj("oj").array(); - return find_if(begin(ans), end(ans), - [](const QJsonValue &v) { return v.toObject().value("raised").toBool(); }) - ->toObject() - .value("writable") - .toBool(); + for (CutterJson v : cmdj("oj")) { + if (v["raised"].toBool()) { + return v["writable"].toBool(); + } + } + + return false; } /** diff --git a/src/core/Cutter.h b/src/core/Cutter.h index d8b7a0a1..c1e21e50 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -3,15 +3,16 @@ #include "core/CutterCommon.h" #include "core/CutterDescriptions.h" +#include "core/CutterJson.h" #include "common/BasicInstructionHighlighter.h" #include #include #include #include +#include #include #include -#include #include #include #include @@ -34,6 +35,29 @@ class RizinTaskDialog; class RzCoreLocked; +struct CUTTER_EXPORT AddrRefs +{ + RVA addr; + QString mapname; + QString section; + QString reg; + QString fcn; + QString type; + QString asm_op; + QString perms; + ut64 value; + bool has_value; + QString string; + QSharedPointer ref; +}; + +struct CUTTER_EXPORT RegisterRef +{ + ut64 value; + AddrRefs ref; + QString name; +}; + class CUTTER_EXPORT CutterCore : public QObject { Q_OBJECT @@ -124,16 +148,16 @@ public: seekSilent(oldOffset); } - QJsonDocument cmdj(const char *str); - QJsonDocument cmdj(const QString &str) { return cmdj(str.toUtf8().constData()); } - QJsonDocument cmdjAt(const char *str, RVA address); + CutterJson cmdj(const char *str); + CutterJson cmdj(const QString &str) { return cmdj(str.toUtf8().constData()); } + CutterJson cmdjAt(const char *str, RVA address); QStringList cmdList(const char *str) { return cmd(str).split(QLatin1Char('\n'), CUTTER_QT_SKIP_EMPTY_PARTS); } QStringList cmdList(const QString &str) { return cmdList(str.toUtf8().constData()); } QString cmdTask(const QString &str); - QJsonDocument cmdjTask(const QString &str); + CutterJson cmdjTask(const QString &str); /** * @brief send a command to Rizin and check for ESIL errors * @param command the command you want to execute @@ -159,8 +183,8 @@ public: QString getRizinVersionReadable(); QString getVersionInformation(); - QJsonDocument parseJson(const char *res, const char *cmd = nullptr); - QJsonDocument parseJson(const char *res, const QString &cmd = QString()) + CutterJson parseJson(char *res, const char *cmd = nullptr); + CutterJson parseJson(char *res, const QString &cmd = QString()) { return parseJson(res, cmd.isNull() ? nullptr : cmd.toLocal8Bit().constData()); } @@ -376,8 +400,8 @@ public: bool sdbSet(QString path, QString key, QString val); /* Debug */ - QJsonDocument getRegistersInfo(); - QJsonDocument getRegisterValues(); + CutterJson getRegistersInfo(); + CutterJson getRegisterValues(); QString getRegisterName(QString registerRole); RVA getProgramCounterValue(); void setRegister(QString regName, QString regValue); @@ -391,32 +415,32 @@ public: * @param size number of bytes to scan * @param depth telescoping depth */ - QList getStack(int size = 0x100, int depth = 6); + QList getStack(int size = 0x100, int depth = 6); /** * @brief Recursively dereferences pointers starting at the specified address * up to a given depth * @param addr telescoping addr * @param depth telescoping depth */ - QJsonObject getAddrRefs(RVA addr, int depth); + AddrRefs getAddrRefs(RVA addr, int depth); /** * @brief return a RefDescription with a formatted ref string and configured colors * @param ref the "ref" JSON node from getAddrRefs */ - RefDescription formatRefDesc(QJsonObject ref); + RefDescription formatRefDesc(const AddrRefs &ref); /** * @brief Get a list of a given process's threads * @param pid The pid of the process, -1 for the currently debugged process * @return JSON object result of dptj */ - QJsonDocument getProcessThreads(int pid); + CutterJson getProcessThreads(int pid); /** * @brief Get a list of a given process's child processes * @param pid The pid of the process, -1 for the currently debugged process * @return JSON object result of dptj */ - QJsonDocument getChildProcesses(int pid); - QJsonDocument getBacktrace(); + CutterJson getChildProcesses(int pid); + CutterJson getBacktrace(); /** * @brief Get a list of heap chunks * Uses RZ_API rz_heap_chunks_list to get vector of chunks @@ -532,9 +556,9 @@ public: bool registerDecompiler(Decompiler *decompiler); RVA getOffsetJump(RVA addr); - QJsonDocument getFileInfo(); - QJsonDocument getSignatureInfo(); - QJsonDocument getFileVersionInfo(); + CutterJson getFileInfo(); + CutterJson getSignatureInfo(); + CutterJson getFileVersionInfo(); QStringList getStats(); void setGraphEmpty(bool empty); bool isGraphEmpty(); @@ -631,7 +655,7 @@ public: * @brief returns a list of reg values and their telescoped references * @param depth telescoping depth */ - QList getRegisterRefs(int depth = 6); + QList getRegisterRefs(int depth = 6); QVector getRegisterRefValues(); QList getVariables(RVA at); /** @@ -649,7 +673,7 @@ public: QList getXRefs(RVA addr, bool to, bool whole_function, const QString &filterType = QString()); - QList parseStringsJson(const QJsonDocument &doc); + QList parseStringsJson(const CutterJson &doc); void handleREvent(int type, void *data); diff --git a/src/core/CutterJson.cpp b/src/core/CutterJson.cpp new file mode 100644 index 00000000..dc6667c0 --- /dev/null +++ b/src/core/CutterJson.cpp @@ -0,0 +1,28 @@ +#include "core/CutterJson.h" + +CutterJson CutterJson::last() const +{ + if (!has_children()) { + return CutterJson(); + } + + const RzJson *last = value->children.first; + while (last->next) { + last = last->next; + } + + return CutterJson(last, owner); +} + +QStringList CutterJson::keys() const +{ + QStringList list; + + if (value && value->type == RZ_JSON_OBJECT) { + for (const RzJson *child = value->children.first; child; child = child->next) { + list.append(child->key); + } + } + + return list; +} diff --git a/src/core/CutterJson.h b/src/core/CutterJson.h new file mode 100644 index 00000000..042ca84b --- /dev/null +++ b/src/core/CutterJson.h @@ -0,0 +1,119 @@ +#ifndef CUTTER_JSON_H +#define CUTTER_JSON_H + +#include "core/CutterCommon.h" + +#include +#include +#include +#include + +class CutterJsonOwner; + +class CUTTER_EXPORT CutterJson +{ +public: + class iterator + { + public: + iterator(const RzJson *value, QSharedPointer owner) + : value(value), owner(owner) + { + } + + CutterJson operator*() const { return CutterJson(value, owner); } + + bool operator!=(const iterator &other) const { return value != other.value; } + + iterator &operator++() + { + value = value->next; + return *this; + } + + private: + const RzJson *value; + QSharedPointer owner; + }; + + CutterJson() : value(nullptr), owner(nullptr) {} + + CutterJson(const RzJson *value, QSharedPointer owner) + : value(value), owner(owner) + { + } + + CutterJson first() const + { + return CutterJson(has_children() ? value->children.first : nullptr, owner); + } + + CutterJson last() const; + + CutterJson operator[](const QString &key) const + { + QByteArray utf8 = key.toUtf8(); + return (*this)[utf8.data()]; + } + + CutterJson operator[](const char *key) const + { + return CutterJson( + value && value->type == RZ_JSON_OBJECT ? rz_json_get(value, key) : nullptr, owner); + } + + iterator begin() const + { + return iterator(has_children() ? value->children.first : nullptr, owner); + } + + iterator end() const { return iterator(nullptr, nullptr); } + + bool toBool() const { return value && value->type == RZ_JSON_BOOLEAN && value->num.u_value; } + QString toJson() const { return rz_json_as_string(value); } + st64 toSt64() const { return value && value->type == RZ_JSON_INTEGER ? value->num.s_value : 0; } + ut64 toUt64() const { return value && value->type == RZ_JSON_INTEGER ? value->num.u_value : 0; } + + RVA toRVA() const + { + return value && value->type == RZ_JSON_INTEGER ? value->num.u_value : RVA_INVALID; + } + + QString toString() const + { + return value && value->type == RZ_JSON_STRING ? QString(value->str_value) : QString(); + } + + QString key() const { return value ? value->key : QString(); } + QStringList keys() const; + size_t size() const { return has_children() ? value->children.count : 0; } + RzJsonType type() const { return value ? value->type : RZ_JSON_NULL; } + bool valid() const { return value ? true : false; } + +private: + bool has_children() const + { + return value && (value->type == RZ_JSON_OBJECT || value->type == RZ_JSON_ARRAY); + } + + const RzJson *value; + QSharedPointer owner; +}; + +class CUTTER_EXPORT CutterJsonOwner +{ +public: + CutterJsonOwner(RzJson *value, char *text) : value(value), text(text) {} + + virtual ~CutterJsonOwner() + { + rz_json_free(value); + rz_mem_free(text); + } + +private: + RzJson *value; + char *text; +}; + +#endif // CUTTER_JSON_H diff --git a/src/dialogs/VersionInfoDialog.cpp b/src/dialogs/VersionInfoDialog.cpp index 9d166bb4..7e67d594 100644 --- a/src/dialogs/VersionInfoDialog.cpp +++ b/src/dialogs/VersionInfoDialog.cpp @@ -24,12 +24,12 @@ VersionInfoDialog::~VersionInfoDialog() {} void VersionInfoDialog::fillVersionInfo() { - QJsonDocument doc = Core()->getFileVersionInfo(); + CutterJson doc = Core()->getFileVersionInfo(); // Case ELF - if (doc.object().contains("verneed")) { - QJsonObject verneed = doc.object()["verneed"].toArray().first().toObject(); - QJsonObject versym = doc.object()["versym"].toArray().first().toObject(); + if (doc["verneed"].valid()) { + CutterJson verneed = doc["verneed"].first(); + CutterJson versym = doc["versym"].first(); // Set labels ui->leftLabel->setText("Version symbols"); @@ -43,17 +43,17 @@ void VersionInfoDialog::fillVersionInfo() QTreeWidgetItem *addrItemL = new QTreeWidgetItem(); addrItemL->setText(0, "Address:"); - addrItemL->setText(1, RzAddressString(versym["address"].toDouble())); + addrItemL->setText(1, RzAddressString(versym["address"].toRVA())); ui->leftTreeWidget->addTopLevelItem(addrItemL); QTreeWidgetItem *offItemL = new QTreeWidgetItem(); offItemL->setText(0, "Offset:"); - offItemL->setText(1, RzAddressString(versym["offset"].toDouble())); + offItemL->setText(1, RzAddressString(versym["offset"].toRVA())); ui->leftTreeWidget->addTopLevelItem(offItemL); QTreeWidgetItem *linkItemL = new QTreeWidgetItem(); linkItemL->setText(0, "Link:"); - linkItemL->setText(1, QString::number(versym["link"].toDouble())); + linkItemL->setText(1, QString::number(versym["link"].toRVA())); ui->leftTreeWidget->addTopLevelItem(linkItemL); QTreeWidgetItem *linkNameItemL = new QTreeWidgetItem(); @@ -63,10 +63,9 @@ void VersionInfoDialog::fillVersionInfo() QTreeWidgetItem *entriesItemL = new QTreeWidgetItem(); entriesItemL->setText(0, "Entries:"); - for (QJsonValue val : versym["entries"].toArray()) { - QJsonObject obj = val.toObject(); + for (CutterJson obj : versym["entries"]) { QTreeWidgetItem *tempItem = new QTreeWidgetItem(); - tempItem->setText(0, RzAddressString(obj["idx"].toDouble())); + tempItem->setText(0, RzAddressString(obj["idx"].toRVA())); tempItem->setText(1, obj["value"].toString()); entriesItemL->addChild(tempItem); } @@ -83,17 +82,17 @@ void VersionInfoDialog::fillVersionInfo() QTreeWidgetItem *addrItemR = new QTreeWidgetItem(); addrItemR->setText(0, "Address:"); - addrItemR->setText(1, RzAddressString(verneed["address"].toDouble())); + addrItemR->setText(1, RzAddressString(verneed["address"].toRVA())); ui->rightTreeWidget->addTopLevelItem(addrItemR); QTreeWidgetItem *offItemR = new QTreeWidgetItem(); offItemR->setText(0, "Offset:"); - offItemR->setText(1, RzAddressString(verneed["offset"].toDouble())); + offItemR->setText(1, RzAddressString(verneed["offset"].toRVA())); ui->rightTreeWidget->addTopLevelItem(offItemR); QTreeWidgetItem *linkItemR = new QTreeWidgetItem(); linkItemR->setText(0, "Link:"); - linkItemR->setText(1, QString::number(verneed["link"].toDouble())); + linkItemR->setText(1, QString::number(verneed["link"].toSt64())); ui->rightTreeWidget->addTopLevelItem(linkItemR); QTreeWidgetItem *linkNameItemR = new QTreeWidgetItem(); @@ -103,24 +102,22 @@ void VersionInfoDialog::fillVersionInfo() QTreeWidgetItem *entriesItemR = new QTreeWidgetItem(); entriesItemR->setText(0, "Entries:"); - for (QJsonValue parentVal : verneed["entries"].toArray()) { - QJsonObject parentObj = parentVal.toObject(); + for (CutterJson parentObj : verneed["entries"]) { QTreeWidgetItem *parentItem = new QTreeWidgetItem(); QString parentString; - parentItem->setText(0, RzAddressString(parentObj["idx"].toDouble())); - parentString.append("Version: " + QString::number(parentObj["vn_version"].toDouble()) + parentItem->setText(0, RzAddressString(parentObj["idx"].toRVA())); + parentString.append("Version: " + QString::number(parentObj["vn_version"].toSt64()) + "\t"); parentString.append("File: " + parentObj["file_name"].toString()); parentItem->setText(1, parentString); - for (QJsonValue childVal : parentObj["vernaux"].toArray()) { - QJsonObject childObj = childVal.toObject(); + for (CutterJson childObj : parentObj["vernaux"]) { QTreeWidgetItem *childItem = new QTreeWidgetItem(); QString childString; - childItem->setText(0, RzAddressString(childObj["idx"].toDouble())); + childItem->setText(0, RzAddressString(childObj["idx"].toRVA())); childString.append("Name: " + childObj["name"].toString() + "\t"); childString.append("Flags: " + childObj["flags"].toString() + "\t"); - childString.append("Version: " + QString::number(childObj["version"].toDouble())); + childString.append("Version: " + QString::number(childObj["version"].toSt64())); childItem->setText(1, childString); parentItem->addChild(childItem); } @@ -134,22 +131,22 @@ void VersionInfoDialog::fillVersionInfo() } // Case PE - else if (doc.object().contains("VS_FIXEDFILEINFO")) { - QJsonObject vs = doc.object()["VS_FIXEDFILEINFO"].toObject(); - QJsonObject strings = doc.object()["StringTable"].toObject(); + else if (doc["VS_FIXEDFILEINFO"].valid()) { + CutterJson vs = doc["VS_FIXEDFILEINFO"]; + CutterJson strings = doc["StringTable"]; // Set labels ui->leftLabel->setText("VS Fixed file info"); ui->rightLabel->setText("String table"); // Left tree - for (QString key : vs.keys()) { + for (CutterJson property : vs) { QTreeWidgetItem *tempItem = new QTreeWidgetItem(); - tempItem->setText(0, key); - if (vs[key].isDouble()) - tempItem->setText(1, RzHexString(vs[key].toDouble())); + tempItem->setText(0, property.key()); + if (property.type() == RZ_JSON_INTEGER) + tempItem->setText(1, RzHexString(property.toRVA())); else - tempItem->setText(1, vs[key].toString()); + tempItem->setText(1, property.toString()); ui->leftTreeWidget->addTopLevelItem(tempItem); // Adjust columns to content @@ -157,10 +154,10 @@ void VersionInfoDialog::fillVersionInfo() } // Right tree - for (QString key : strings.keys()) { + for (CutterJson property : strings) { QTreeWidgetItem *tempItem = new QTreeWidgetItem(); - tempItem->setText(0, key); - tempItem->setText(1, strings[key].toString()); + tempItem->setText(0, property.key()); + tempItem->setText(1, property.toString()); ui->rightTreeWidget->addTopLevelItem(tempItem); // Adjust columns to content diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 2c7b8ba8..c2065c9d 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -314,15 +314,15 @@ void DisassemblyContextMenu::addDebugMenu() QVector DisassemblyContextMenu::getThingUsedHere(RVA offset) { QVector result; - const QJsonArray array = Core()->cmdj("anj @ " + QString::number(offset)).array(); + const CutterJson array = Core()->cmdj("anj @ " + QString::number(offset)); result.reserve(array.size()); for (const auto &thing : array) { - auto obj = thing.toObject(); - RVA offset = obj["offset"].toVariant().toULongLong(); + 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.contains("realname")) { + if (Config()->getConfigBool("asm.flags.real") && obj["realname"].valid()) { name = obj["realname"].toString(); } else { name = obj["name"].toString(); @@ -482,29 +482,24 @@ void DisassemblyContextMenu::setupRenaming() void DisassemblyContextMenu::aboutToShowSlot() { // check if set immediate base menu makes sense - QJsonObject instObject = - Core()->cmdj("aoj @ " + QString::number(offset)).array().first().toObject(); - auto keys = instObject.keys(); - bool immBase = keys.contains("val") || keys.contains("ptr"); + CutterJson instObject = Core()->cmdj("aoj @ " + QString::number(offset)).first(); + bool immBase = instObject["val"].valid() || instObject["ptr"].valid(); setBaseMenu->menuAction()->setVisible(immBase); setBitsMenu->menuAction()->setVisible(true); // Create structure offset menu if it makes sense QString memBaseReg; // Base register - QVariant memDisp; // Displacement - if (instObject.contains("opex") && instObject["opex"].toObject().contains("operands")) { - // Loop through both the operands of the instruction - for (const QJsonValue value : instObject["opex"].toObject()["operands"].toArray()) { - QJsonObject operand = value.toObject(); - if (operand.contains("type") && operand["type"].toString() == "mem" - && operand.contains("base") && !operand["base"].toString().contains("bp") - && operand.contains("disp") && operand["disp"].toVariant().toLongLong() > 0) { + st64 memDisp; // Displacement - // The current operand is the one which has an immediate displacement - memBaseReg = operand["base"].toString(); - memDisp = operand["disp"].toVariant(); - break; - } + // Loop through both the operands of the instruction + for (const CutterJson operand : instObject["opex"]["operands"]) { + if (operand["type"].toString() == "mem" && !operand["base"].toString().contains("bp") + && operand["disp"].toSt64() > 0) { + + // The current operand is the one which has an immediate displacement + memBaseReg = operand["base"].toString(); + memDisp = operand["disp"].toSt64(); + break; } } if (memBaseReg.isEmpty()) { @@ -517,7 +512,7 @@ void DisassemblyContextMenu::aboutToShowSlot() // Get the possible offsets using the "ahts" command // TODO: add ahtj command to Rizin and then use it here - QStringList ret = Core()->cmdList("ahts " + memDisp.toString()); + QStringList ret = Core()->cmdList("ahts " + QString::number(memDisp)); for (const QString &val : ret) { if (val.isEmpty()) { continue; @@ -714,12 +709,12 @@ void DisassemblyContextMenu::showReverseJmpQuery() { QString type; - QJsonArray array = Core()->cmdj("pdj 1 @ " + RzAddressString(offset)).array(); - if (array.isEmpty()) { + CutterJson array = Core()->cmdj("pdj 1 @ " + RzAddressString(offset)); + if (!array.size()) { return; } - type = array.first().toObject()["type"].toString(); + type = array.first()["type"].toString(); if (type == "cjmp") { actionJmpReverse.setVisible(true); } else { diff --git a/src/widgets/BacktraceWidget.cpp b/src/widgets/BacktraceWidget.cpp index 793813d7..433a1b1e 100644 --- a/src/widgets/BacktraceWidget.cpp +++ b/src/widgets/BacktraceWidget.cpp @@ -44,13 +44,11 @@ void BacktraceWidget::updateContents() void BacktraceWidget::setBacktraceGrid() { - QJsonArray backtraceValues = Core()->getBacktrace().array(); int i = 0; - for (const QJsonValue &value : backtraceValues) { - QJsonObject backtraceItem = value.toObject(); - QString progCounter = RzAddressString(backtraceItem["pc"].toVariant().toULongLong()); - QString stackPointer = RzAddressString(backtraceItem["sp"].toVariant().toULongLong()); - int frameSize = backtraceItem["frame_size"].toVariant().toInt(); + for (CutterJson backtraceItem : Core()->getBacktrace()) { + QString progCounter = RzAddressString(backtraceItem["pc"].toRVA()); + QString stackPointer = RzAddressString(backtraceItem["sp"].toRVA()); + st64 frameSize = backtraceItem["frame_size"].toSt64(); QString funcName = backtraceItem["fname"].toString(); QString desc = backtraceItem["desc"].toString(); diff --git a/src/widgets/CallGraph.cpp b/src/widgets/CallGraph.cpp index 2bd16b73..c66a862e 100644 --- a/src/widgets/CallGraph.cpp +++ b/src/widgets/CallGraph.cpp @@ -77,8 +77,7 @@ void CallGraphView::loadCurrentGraph() blockContent.clear(); blocks.clear(); - QJsonDocument functionsDoc = Core()->cmdj(global ? "agCj" : QString("agcj @ %1").arg(address)); - auto nodes = functionsDoc.array(); + CutterJson nodes = Core()->cmdj(global ? "agCj" : QString("agcj @ %1").arg(address)); QHash idMapping; @@ -91,11 +90,10 @@ void CallGraphView::loadCurrentGraph() return itemId; }; - for (const QJsonValueRef &value : nodes) { - QJsonObject block = value.toObject(); - QString name = block["name"].toVariant().toString(); + for (CutterJson block : nodes) { + QString name = block["name"].toString(); - auto edges = block["imports"].toArray(); + auto edges = block["imports"]; GraphLayout::GraphBlock layoutBlock; layoutBlock.entry = getId(name); for (auto edge : edges) { diff --git a/src/widgets/ColorThemeListView.h b/src/widgets/ColorThemeListView.h index a1eb5103..8525312d 100644 --- a/src/widgets/ColorThemeListView.h +++ b/src/widgets/ColorThemeListView.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include diff --git a/src/widgets/Dashboard.cpp b/src/widgets/Dashboard.cpp index c641b8b0..4f49739a 100644 --- a/src/widgets/Dashboard.cpp +++ b/src/widgets/Dashboard.cpp @@ -32,16 +32,16 @@ Dashboard::~Dashboard() {} void Dashboard::updateContents() { - QJsonDocument docu = Core()->getFileInfo(); - QJsonObject item = docu.object()["core"].toObject(); - QJsonObject item2 = docu.object()["bin"].toObject(); + CutterJson docu = Core()->getFileInfo(); + CutterJson item = docu["core"]; + CutterJson item2 = docu["bin"]; setPlainText(this->ui->fileEdit, item["file"].toString()); setPlainText(this->ui->formatEdit, item["format"].toString()); setPlainText(this->ui->modeEdit, item["mode"].toString()); setPlainText(this->ui->typeEdit, item["type"].toString()); - setPlainText(this->ui->sizeEdit, qhelpers::formatBytecount(item["size"].toDouble())); - setPlainText(this->ui->fdEdit, QString::number(item["fd"].toDouble())); + setPlainText(this->ui->sizeEdit, qhelpers::formatBytecount(item["size"].toUt64())); + setPlainText(this->ui->fdEdit, QString::number(item["fd"].toUt64())); setPlainText(this->ui->archEdit, item2["arch"].toString()); setPlainText(this->ui->langEdit, item2["lang"].toString().toUpper()); @@ -52,7 +52,7 @@ void Dashboard::updateContents() setPlainText(this->ui->endianEdit, item2["endian"].toString()); setPlainText(this->ui->compilationDateEdit, item2["compiled"].toString()); setPlainText(this->ui->compilerEdit, item2["compiler"].toString()); - setPlainText(this->ui->bitsEdit, QString::number(item2["bits"].toDouble())); + setPlainText(this->ui->bitsEdit, QString::number(item2["bits"].toUt64())); if (!item2["relro"].toString().isEmpty()) { QString relro = item2["relro"].toString().section(QLatin1Char(' '), 0, 0); @@ -62,7 +62,7 @@ void Dashboard::updateContents() setPlainText(this->ui->relroEdit, "N/A"); } - setPlainText(this->ui->baddrEdit, RzAddressString(item2["baddr"].toVariant().toULongLong())); + setPlainText(this->ui->baddrEdit, RzAddressString(item2["baddr"].toRVA())); // set booleans setBool(this->ui->vaEdit, item2, "va"); @@ -110,16 +110,16 @@ void Dashboard::updateContents() hashesLayout->addRow(new QLabel(label), hashLineEdit); } - QJsonObject analinfo = Core()->cmdj("aaij").object(); - setPlainText(ui->functionsLineEdit, QString::number(analinfo["fcns"].toInt())); - setPlainText(ui->xRefsLineEdit, QString::number(analinfo["xrefs"].toInt())); - setPlainText(ui->callsLineEdit, QString::number(analinfo["calls"].toInt())); - setPlainText(ui->stringsLineEdit, QString::number(analinfo["strings"].toInt())); - setPlainText(ui->symbolsLineEdit, QString::number(analinfo["symbols"].toInt())); - setPlainText(ui->importsLineEdit, QString::number(analinfo["imports"].toInt())); - setPlainText(ui->coverageLineEdit, QString::number(analinfo["covrage"].toInt()) + " bytes"); - setPlainText(ui->codeSizeLineEdit, QString::number(analinfo["codesz"].toInt()) + " bytes"); - setPlainText(ui->percentageLineEdit, QString::number(analinfo["percent"].toInt()) + "%"); + CutterJson analinfo = Core()->cmdj("aaij"); + setPlainText(ui->functionsLineEdit, QString::number(analinfo["fcns"].toSt64())); + setPlainText(ui->xRefsLineEdit, QString::number(analinfo["xrefs"].toSt64())); + setPlainText(ui->callsLineEdit, QString::number(analinfo["calls"].toSt64())); + setPlainText(ui->stringsLineEdit, QString::number(analinfo["strings"].toSt64())); + setPlainText(ui->symbolsLineEdit, QString::number(analinfo["symbols"].toSt64())); + setPlainText(ui->importsLineEdit, QString::number(analinfo["imports"].toSt64())); + setPlainText(ui->coverageLineEdit, QString::number(analinfo["covrage"].toSt64()) + " bytes"); + setPlainText(ui->codeSizeLineEdit, QString::number(analinfo["codesz"].toSt64()) + " bytes"); + setPlainText(ui->percentageLineEdit, QString::number(analinfo["percent"].toSt64()) + "%"); QStringList libs = Core()->cmdList("il"); if (!libs.isEmpty()) { @@ -155,10 +155,10 @@ void Dashboard::updateContents() QStringList stats = Core()->getStats(); // Check if signature info and version info available - if (Core()->getSignatureInfo().isEmpty()) { + if (!Core()->getSignatureInfo().size()) { ui->certificateButton->setEnabled(false); } - if (Core()->getFileVersionInfo().isEmpty()) { + if (!Core()->getFileVersionInfo().size()) { ui->versioninfoButton->setEnabled(false); } } @@ -173,8 +173,7 @@ void Dashboard::on_certificateButton_clicked() viewDialog = new QDialog(this); view = new CutterTreeView(viewDialog); model = new JsonModel(); - QJsonDocument qjsonCertificatesDoc = Core()->getSignatureInfo(); - qstrCertificates = qjsonCertificatesDoc.toJson(QJsonDocument::Compact); + qstrCertificates = Core()->getSignatureInfo().toJson(); } if (!viewDialog->isVisible()) { std::string strCertificates = qstrCertificates.toUtf8().constData(); @@ -230,9 +229,9 @@ void Dashboard::setPlainText(QLineEdit *textBox, const QString &text) * @param textBox * @param isTrue */ -void Dashboard::setBool(QLineEdit *textBox, const QJsonObject &jsonObject, const QString &key) +void Dashboard::setBool(QLineEdit *textBox, const CutterJson &jsonObject, const char *key) { - if (jsonObject.contains(key)) { + if (jsonObject[key].valid()) { if (jsonObject[key].toBool()) { setPlainText(textBox, tr("True")); } else { diff --git a/src/widgets/Dashboard.h b/src/widgets/Dashboard.h index 45e578f6..61a2c677 100644 --- a/src/widgets/Dashboard.h +++ b/src/widgets/Dashboard.h @@ -3,6 +3,7 @@ #include #include +#include "core/Cutter.h" #include "CutterDockWidget.h" QT_BEGIN_NAMESPACE @@ -32,7 +33,7 @@ private slots: private: std::unique_ptr ui; void setPlainText(QLineEdit *textBox, const QString &text); - void setBool(QLineEdit *textBox, const QJsonObject &jsonObject, const QString &key); + void setBool(QLineEdit *textBox, const CutterJson &jsonObject, const char *key); QWidget *hashesWidget = nullptr; }; diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index e4bb05b8..09dacdd2 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -182,12 +182,11 @@ void DisassemblerGraphView::loadCurrentGraph() .set("asm.lines", false) .set("asm.lines.fcn", false); - QJsonArray functions; + CutterJson functions; RzAnalysisFunction *fcn = Core()->functionIn(seekable->getOffset()); if (fcn) { currentFcnAddr = fcn->addr; - QJsonDocument functionsDoc = Core()->cmdj("agJ " + RzAddressString(fcn->addr)); - functions = functionsDoc.array(); + functions = Core()->cmdj("agJ " + RzAddressString(fcn->addr)); } disassembly_blocks.clear(); @@ -198,7 +197,7 @@ void DisassemblerGraphView::loadCurrentGraph() highlight_token = nullptr; } - emptyGraph = functions.isEmpty(); + emptyGraph = !functions.size(); if (emptyGraph) { // If there's no function to print, just add a message if (!emptyText) { @@ -215,8 +214,7 @@ void DisassemblerGraphView::loadCurrentGraph() // Refresh global "empty graph" variable so other widget know there is nothing to show here Core()->setGraphEmpty(emptyGraph); - QJsonValue funcRef = functions.first(); - QJsonObject func = funcRef.toObject(); + CutterJson func = functions.first(); windowTitle = tr("Graph"); QString funcName = func["name"].toString().trimmed(); @@ -227,15 +225,14 @@ void DisassemblerGraphView::loadCurrentGraph() } emit nameChanged(windowTitle); - RVA entry = func["offset"].toVariant().toULongLong(); + RVA entry = func["offset"].toRVA(); setEntry(entry); - for (const QJsonValueRef &value : func["blocks"].toArray()) { - QJsonObject block = value.toObject(); - RVA block_entry = block["offset"].toVariant().toULongLong(); - RVA block_size = block["size"].toVariant().toULongLong(); - RVA block_fail = block["fail"].toVariant().toULongLong(); - RVA block_jump = block["jump"].toVariant().toULongLong(); + 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; GraphBlock gb; @@ -259,30 +256,29 @@ void DisassemblerGraphView::loadCurrentGraph() gb.edges.emplace_back(block_jump); } - QJsonObject switchOp = block["switchop"].toObject(); - if (!switchOp.isEmpty()) { - QJsonArray caseArray = switchOp["cases"].toArray(); - for (QJsonValue caseOpValue : caseArray) { - QJsonObject caseOp = caseOpValue.toObject(); - bool ok; - RVA caseJump = caseOp["jump"].toVariant().toULongLong(&ok); - if (!ok) { + CutterJson switchOp = block["switchop"]; + if (switchOp.size()) { + for (CutterJson caseOp : switchOp["cases"]) { + RVA caseJump = caseOp["jump"].toRVA(); + if (caseJump == RVA_INVALID) { continue; } gb.edges.emplace_back(caseJump); } } - QJsonArray opArray = block["ops"].toArray(); - for (int opIndex = 0; opIndex < opArray.size(); opIndex++) { - QJsonObject op = opArray[opIndex].toObject(); + CutterJson opArray = block["ops"]; + CutterJson::iterator iterator = opArray.begin(); + while (iterator != opArray.end()) { + CutterJson op = *iterator; Instr i; - i.addr = op["offset"].toVariant().toULongLong(); + i.addr = op["offset"].toUt64(); - if (opIndex < opArray.size() - 1) { + ++iterator; + + if (iterator != opArray.end()) { // get instruction size from distance to next instruction ... - RVA nextOffset = - opArray[opIndex + 1].toObject()["offset"].toVariant().toULongLong(); + RVA nextOffset = (*iterator)["offset"].toRVA(); i.size = nextOffset - i.addr; } else { // or to the end of the block. @@ -314,7 +310,7 @@ void DisassemblerGraphView::loadCurrentGraph() } cleanupEdges(blocks); - if (!func["blocks"].toArray().isEmpty()) { + if (func["blocks"].size()) { computeGraphPlacement(); } } diff --git a/src/widgets/FunctionsWidget.cpp b/src/widgets/FunctionsWidget.cpp index f77bae3d..ab92ecd9 100644 --- a/src/widgets/FunctionsWidget.cpp +++ b/src/widgets/FunctionsWidget.cpp @@ -562,7 +562,7 @@ void FunctionsWidget::refreshTree() importAddresses.insert(import.plt); } - mainAdress = (ut64)Core()->cmdj("iMj").object()["vaddr"].toInt(); + mainAdress = (ut64)Core()->cmdj("iMj")["vaddr"].toUt64(); functionModel->updateCurrentIndex(); functionModel->endResetModel(); diff --git a/src/widgets/ProcessesWidget.cpp b/src/widgets/ProcessesWidget.cpp index 28a1e335..b8e12435 100644 --- a/src/widgets/ProcessesWidget.cpp +++ b/src/widgets/ProcessesWidget.cpp @@ -106,14 +106,12 @@ QString ProcessesWidget::translateStatus(QString status) void ProcessesWidget::setProcessesGrid() { - QJsonArray processesValues = Core()->getChildProcesses(DEBUGGED_PID).array(); int i = 0; QFont font; - for (const QJsonValue &value : processesValues) { - QJsonObject processesItem = value.toObject(); - int pid = processesItem["pid"].toVariant().toInt(); - int uid = processesItem["uid"].toVariant().toInt(); + for (CutterJson processesItem : Core()->getChildProcesses(DEBUGGED_PID)) { + st64 pid = processesItem["pid"].toSt64(); + st64 uid = processesItem["uid"].toSt64(); QString status = translateStatus(processesItem["status"].toString()); QString path = processesItem["path"].toString(); bool current = processesItem["current"].toBool(); @@ -162,10 +160,9 @@ void ProcessesWidget::onActivated(const QModelIndex &index) // Verify that the selected pid is still in the processes list since dp= will // attach to any given id. If it isn't found simply update the UI. - QJsonArray processesValues = Core()->getChildProcesses(DEBUGGED_PID).array(); - for (QJsonValue value : processesValues) { - QString status = value.toObject()["status"].toString(); - if (pid == value.toObject()["pid"].toInt()) { + for (CutterJson value : Core()->getChildProcesses(DEBUGGED_PID)) { + QString status = value["status"].toString(); + if (pid == value["pid"].toSt64()) { if (QString(QChar(RZ_DBG_PROC_ZOMBIE)) == status || QString(QChar(RZ_DBG_PROC_DEAD)) == status) { QMessageBox msgBox; diff --git a/src/widgets/RegisterRefsWidget.cpp b/src/widgets/RegisterRefsWidget.cpp index adfd67af..d0cfb4dd 100644 --- a/src/widgets/RegisterRefsWidget.cpp +++ b/src/widgets/RegisterRefsWidget.cpp @@ -184,14 +184,13 @@ void RegisterRefsWidget::refreshRegisterRef() registerRefModel->beginResetModel(); - QList regRefs = Core()->getRegisterRefs(); registerRefs.clear(); - for (const QJsonObject ® : regRefs) { + for (const RegisterRef ® : Core()->getRegisterRefs()) { RegisterRefDescription desc; - desc.value = RzAddressString(reg["value"].toVariant().toULongLong()); - desc.reg = reg["name"].toVariant().toString(); - desc.refDesc = Core()->formatRefDesc(reg["ref"].toObject()); + desc.value = RzAddressString(reg.value); + desc.reg = reg.name; + desc.refDesc = Core()->formatRefDesc(reg.ref); registerRefs.push_back(desc); } diff --git a/src/widgets/RizinGraphWidget.cpp b/src/widgets/RizinGraphWidget.cpp index a0b88e15..346cf012 100644 --- a/src/widgets/RizinGraphWidget.cpp +++ b/src/widgets/RizinGraphWidget.cpp @@ -96,12 +96,11 @@ void GenericRizinGraphView::loadCurrentGraph() return; } - QJsonDocument functionsDoc = Core()->cmdj(QString("%1j").arg(graphCommand)); - auto nodes = functionsDoc.object()["nodes"].toArray(); + CutterJson functionsDoc = Core()->cmdj(QString("%1j").arg(graphCommand)); + auto nodes = functionsDoc["nodes"]; - for (const QJsonValueRef &value : nodes) { - QJsonObject block = value.toObject(); - uint64_t id = block["id"].toVariant().toULongLong(); + for (CutterJson block : nodes) { + uint64_t id = block["id"].toUt64(); QString content; QString title = block["title"].toString(); @@ -112,11 +111,11 @@ void GenericRizinGraphView::loadCurrentGraph() content = title + body; } - auto edges = block["out_nodes"].toArray(); + auto edges = block["out_nodes"]; GraphLayout::GraphBlock layoutBlock; layoutBlock.entry = id; for (auto edge : edges) { - auto targetId = edge.toVariant().toULongLong(); + auto targetId = edge.toUt64(); layoutBlock.edges.emplace_back(targetId); } diff --git a/src/widgets/StackWidget.cpp b/src/widgets/StackWidget.cpp index fd68db29..d673f8b1 100644 --- a/src/widgets/StackWidget.cpp +++ b/src/widgets/StackWidget.cpp @@ -145,16 +145,16 @@ StackModel::StackModel(QObject *parent) : QAbstractTableModel(parent) {} void StackModel::reload() { - QList stackItems = Core()->getStack(); + QList stackItems = Core()->getStack(); beginResetModel(); values.clear(); - for (const QJsonObject &stackItem : stackItems) { + for (const AddrRefs &stackItem : stackItems) { Item item; - item.offset = stackItem["addr"].toVariant().toULongLong(); - item.value = RzAddressString(stackItem["value"].toVariant().toULongLong()); - item.refDesc = Core()->formatRefDesc(stackItem["ref"].toObject()); + item.offset = stackItem.addr; + item.value = RzAddressString(stackItem.value); + item.refDesc = Core()->formatRefDesc(*stackItem.ref); values.push_back(item); } diff --git a/src/widgets/ThreadsWidget.cpp b/src/widgets/ThreadsWidget.cpp index b650e7a6..6cdde089 100644 --- a/src/widgets/ThreadsWidget.cpp +++ b/src/widgets/ThreadsWidget.cpp @@ -104,13 +104,11 @@ QString ThreadsWidget::translateStatus(QString status) void ThreadsWidget::setThreadsGrid() { - QJsonArray threadsValues = Core()->getProcessThreads(DEBUGGED_PID).array(); int i = 0; QFont font; - for (const QJsonValue &value : threadsValues) { - QJsonObject threadsItem = value.toObject(); - int pid = threadsItem["pid"].toVariant().toInt(); + for (CutterJson threadsItem : Core()->getProcessThreads(DEBUGGED_PID)) { + st64 pid = threadsItem["pid"].toSt64(); QString status = translateStatus(threadsItem["status"].toString()); QString path = threadsItem["path"].toString(); bool current = threadsItem["current"].toBool(); @@ -152,9 +150,8 @@ void ThreadsWidget::onActivated(const QModelIndex &index) // Verify that the selected tid is still in the threads list since dpt= will // attach to any given id. If it isn't found simply update the UI. - QJsonArray threadsValues = Core()->getProcessThreads(DEBUGGED_PID).array(); - for (QJsonValue value : threadsValues) { - if (tid == value.toObject()["pid"].toInt()) { + for (CutterJson value : Core()->getProcessThreads(DEBUGGED_PID)) { + if (tid == value["pid"].toSt64()) { Core()->setCurrentDebugThread(tid); break; }