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.
This commit is contained in:
Akihiko Odaki 2022-03-14 17:04:49 +09:00 committed by Anton Kochkov
parent ddaa02c0f8
commit 518014ee19
28 changed files with 575 additions and 528 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -5,6 +5,7 @@
#include <QColor>
#include <QObject>
#include "Cutter.h"
#include <QJsonDocument>
#include <QJsonObject>
#define ThemeWorker() (ColorThemeWorker::instance())

View File

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

View File

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

View File

@ -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<char *>(rz_mem_alloc(strlen(res) + 1));
strcpy(copy, res);
return Core()->parseJson(copy, nullptr);
}
const char *RizinCmdTask::getResultRaw()

View File

@ -38,7 +38,7 @@ public:
explicit RizinCmdTask(const QString &cmd, bool transient = true);
QString getResult();
QJsonDocument getResultJson();
CutterJson getResultJson();
const char *getResultRaw();
};

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -3,15 +3,16 @@
#include "core/CutterCommon.h"
#include "core/CutterDescriptions.h"
#include "core/CutterJson.h"
#include "common/BasicInstructionHighlighter.h"
#include <QMap>
#include <QMenu>
#include <QDebug>
#include <QObject>
#include <QSharedPointer>
#include <QStringList>
#include <QMessageBox>
#include <QJsonDocument>
#include <QErrorMessage>
#include <QMutex>
#include <QDir>
@ -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<AddrRefs> 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<QJsonObject> getStack(int size = 0x100, int depth = 6);
QList<AddrRefs> 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<QJsonObject> getRegisterRefs(int depth = 6);
QList<RegisterRef> getRegisterRefs(int depth = 6);
QVector<RegisterRefValueDescription> getRegisterRefValues();
QList<VariableDescription> getVariables(RVA at);
/**
@ -649,7 +673,7 @@ public:
QList<XrefDescription> getXRefs(RVA addr, bool to, bool whole_function,
const QString &filterType = QString());
QList<StringDescription> parseStringsJson(const QJsonDocument &doc);
QList<StringDescription> parseStringsJson(const CutterJson &doc);
void handleREvent(int type, void *data);

28
src/core/CutterJson.cpp Normal file
View File

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

119
src/core/CutterJson.h Normal file
View File

@ -0,0 +1,119 @@
#ifndef CUTTER_JSON_H
#define CUTTER_JSON_H
#include "core/CutterCommon.h"
#include <QSharedPointer>
#include <QString>
#include <QStringList>
#include <rz_project.h>
class CutterJsonOwner;
class CUTTER_EXPORT CutterJson
{
public:
class iterator
{
public:
iterator(const RzJson *value, QSharedPointer<CutterJsonOwner> 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<CutterJsonOwner> owner;
};
CutterJson() : value(nullptr), owner(nullptr) {}
CutterJson(const RzJson *value, QSharedPointer<CutterJsonOwner> 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<CutterJsonOwner> 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

View File

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

View File

@ -314,15 +314,15 @@ void DisassemblyContextMenu::addDebugMenu()
QVector<DisassemblyContextMenu::ThingUsedHere> DisassemblyContextMenu::getThingUsedHere(RVA offset)
{
QVector<ThingUsedHere> 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,31 +482,26 @@ 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")) {
st64 memDisp; // Displacement
// 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) {
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"].toVariant();
memDisp = operand["disp"].toSt64();
break;
}
}
}
if (memBaseReg.isEmpty()) {
// hide structure offset menu
structureOffsetMenu->menuAction()->setVisible(false);
@ -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 {

View File

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

View File

@ -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<QString, uint64_t> 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) {

View File

@ -3,6 +3,7 @@
#include <QTimer>
#include <QListView>
#include <QJsonDocument>
#include <QJsonObject>
#include <QAbstractListModel>
#include <QStyledItemDelegate>

View File

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

View File

@ -3,6 +3,7 @@
#include <QFormLayout>
#include <memory>
#include "core/Cutter.h"
#include "CutterDockWidget.h"
QT_BEGIN_NAMESPACE
@ -32,7 +33,7 @@ private slots:
private:
std::unique_ptr<Ui::Dashboard> 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;
};

View File

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

View File

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

View File

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

View File

@ -184,14 +184,13 @@ void RegisterRefsWidget::refreshRegisterRef()
registerRefModel->beginResetModel();
QList<QJsonObject> regRefs = Core()->getRegisterRefs();
registerRefs.clear();
for (const QJsonObject &reg : regRefs) {
for (const RegisterRef &reg : 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);
}

View File

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

View File

@ -145,16 +145,16 @@ StackModel::StackModel(QObject *parent) : QAbstractTableModel(parent) {}
void StackModel::reload()
{
QList<QJsonObject> stackItems = Core()->getStack();
QList<AddrRefs> 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);
}

View File

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